feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,261 @@
/*
* Copyright (c) 1997, 2016, 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 sun.java2d.pipe;
import java.awt.BasicStroke;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Rectangle2D;
import java.util.concurrent.ConcurrentLinkedQueue;
import sun.awt.SunHints;
import sun.java2d.ReentrantContext;
import sun.java2d.ReentrantContextProvider;
import sun.java2d.ReentrantContextProviderTL;
import sun.java2d.SunGraphics2D;
/**
* This class is used to convert raw geometry into 8-bit alpha tiles
* using an AATileGenerator for application by the next stage of
* the pipeline.
* This class sets up the Generator and computes the alpha tiles
* and then passes them on to a CompositePipe object for painting.
*/
public final class AAShapePipe
implements ShapeDrawPipe, ParallelogramPipe
{
static final RenderingEngine renderengine = RenderingEngine.getInstance();
// Per-thread TileState (~1K very small so do not use any Weak Reference)
private static final ReentrantContextProvider<TileState> tileStateProvider =
new ReentrantContextProviderTL<TileState>(
ReentrantContextProvider.REF_HARD)
{
@Override
protected TileState newContext() {
return new TileState();
}
};
final CompositePipe outpipe;
public AAShapePipe(CompositePipe pipe) {
outpipe = pipe;
}
@Override
public void draw(SunGraphics2D sg, Shape s) {
final BasicStroke bs;
if (sg.stroke instanceof BasicStroke) {
bs = (BasicStroke) sg.stroke;
} else {
s = sg.stroke.createStrokedShape(s);
bs = null;
}
renderPath(sg, s, bs);
}
@Override
public void fill(SunGraphics2D sg, Shape s) {
renderPath(sg, s, null);
}
@Override
public void fillParallelogram(SunGraphics2D sg,
double ux1, double uy1,
double ux2, double uy2,
double x, double y,
double dx1, double dy1,
double dx2, double dy2)
{
final TileState ts = tileStateProvider.acquire();
try {
final int[] abox = ts.abox;
final AATileGenerator aatg =
renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, 0, 0,
sg.getCompClip(), abox);
if (aatg != null) {
renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2),
aatg, abox, ts);
}
} finally {
tileStateProvider.release(ts);
}
}
@Override
public void drawParallelogram(SunGraphics2D sg,
double ux1, double uy1,
double ux2, double uy2,
double x, double y,
double dx1, double dy1,
double dx2, double dy2,
double lw1, double lw2)
{
final TileState ts = tileStateProvider.acquire();
try {
final int[] abox = ts.abox;
final AATileGenerator aatg =
renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, lw1,
lw2, sg.getCompClip(), abox);
if (aatg != null) {
// Note that bbox is of the original shape, not the wide path.
// This is appropriate for handing to Paint methods...
renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2),
aatg, abox, ts);
}
} finally {
tileStateProvider.release(ts);
}
}
public void renderPath(SunGraphics2D sg, Shape s, BasicStroke bs) {
final boolean adjust = (bs != null &&
sg.strokeHint != SunHints.INTVAL_STROKE_PURE);
final boolean thin = (sg.strokeState <= SunGraphics2D.STROKE_THINDASHED);
final TileState ts = tileStateProvider.acquire();
try {
final int[] abox = ts.abox;
final AATileGenerator aatg =
renderengine.getAATileGenerator(s, sg.transform, sg.getCompClip(),
bs, thin, adjust, abox);
if (aatg != null) {
renderTiles(sg, s, aatg, abox, ts);
}
} finally {
tileStateProvider.release(ts);
}
}
public void renderTiles(SunGraphics2D sg, Shape s,
final AATileGenerator aatg,
final int[] abox, final TileState ts)
{
Object context = null;
try {
// reentrance: outpipe may also use AAShapePipe:
context = outpipe.startSequence(sg, s,
ts.computeDevBox(abox),
abox);
// copy of int[] abox as local variables for performance:
final int x0 = abox[0];
final int y0 = abox[1];
final int x1 = abox[2];
final int y1 = abox[3];
final int tw = aatg.getTileWidth();
final int th = aatg.getTileHeight();
// get tile from thread local storage:
final byte[] alpha = ts.getAlphaTile(tw * th);
byte[] atile;
for (int y = y0; y < y1; y += th) {
final int h = Math.min(th, y1 - y);
for (int x = x0; x < x1; x += tw) {
final int w = Math.min(tw, x1 - x);
final int a = aatg.getTypicalAlpha();
if (a == 0x00 || !outpipe.needTile(context, x, y, w, h)) {
aatg.nextTile();
outpipe.skipTile(context, x, y);
continue;
}
if (a == 0xff) {
atile = null;
aatg.nextTile();
} else {
atile = alpha;
aatg.getAlpha(alpha, 0, tw);
}
outpipe.renderPathTile(context, atile, 0, tw, x, y, w, h);
}
}
} finally {
aatg.dispose();
if (context != null) {
outpipe.endSequence(context);
}
}
}
// Tile state used by AAShapePipe
static final class TileState extends ReentrantContext {
// cached tile (32 x 32 tile by default)
private byte[] theTile = new byte[32 * 32];
// dirty aabox array
final int[] abox = new int[4];
// dirty bbox rectangle
private final Rectangle dev = new Rectangle();
// dirty bbox rectangle2D.Double
private final Rectangle2D.Double bbox2D = new Rectangle2D.Double();
byte[] getAlphaTile(int len) {
byte[] t = theTile;
if (t.length < len) {
// create a larger tile and may free current theTile (too small)
theTile = t = new byte[len];
}
return t;
}
Rectangle computeDevBox(final int[] abox) {
final Rectangle box = this.dev;
box.x = abox[0];
box.y = abox[1];
box.width = abox[2] - abox[0];
box.height = abox[3] - abox[1];
return box;
}
Rectangle2D computeBBox(double ux1, double uy1,
double ux2, double uy2)
{
if ((ux2 -= ux1) < 0.0) {
ux1 += ux2;
ux2 = -ux2;
}
if ((uy2 -= uy1) < 0.0) {
uy1 += uy2;
uy2 = -uy2;
}
final Rectangle2D.Double box = this.bbox2D;
box.x = ux1;
box.y = uy1;
box.width = ux2;
box.height = uy2;
return box;
}
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2000, 2005, 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 sun.java2d.pipe;
import java.awt.font.GlyphVector;
import sun.java2d.SunGraphics2D;
import sun.font.GlyphList;
/**
* A delegate pipe of SG2D for drawing anti-aliased text with
* a solid source colour to an opaque destination.
*/
public class AATextRenderer extends GlyphListLoopPipe
implements LoopBasedPipe
{
protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) {
sg2d.loops.drawGlyphListAALoop.DrawGlyphListAA(sg2d, sg2d.surfaceData,
gl);
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (c) 2007, 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 sun.java2d.pipe;
/**
* The API for an object that generates alpha coverage tiles for a given
* path.
* The {@link RenderingEngine} will be consulted as a factory to return
* one of these objects for a given Shape and a given set of rendering
* attributes.
* This object will iterate through the bounds of the rendering primitive
* and return tiles of a constant size as specified by the getTileWidth()
* and getTileHeight() parameters.
* The iteration order of the tiles will be as specified by the pseudo-code:
* <pre>
* int bbox[] = {left, top, right, bottom};
* AATileGenerator aatg = renderengine.getAATileGenerator(..., bbox);
* int tw = aatg.getTileWidth();
* int th = aatg.getTileHeight();
* byte tile[] = new byte[tw * th];
* for (y = top; y < bottom; y += th) {
* for (x = left; x < right; x += tw) {
* int a = aatg.getTypicalAlpha();
* int w = Math.min(tw, right-x);
* int h = Math.min(th, bottom-y);
* if (a == 0x00) {
* // can skip this tile...
* aatg.nextTile();
* } else if (a == 0xff) {
* // can treat this tile like a fillRect
* aatg.nextTile();
* doFill(x, y, w, h);
* } else {
* aatg.getAlpha(tile, 0, tw);
* handleAlpha(tile, x, y, w, h);
* }
* }
* }
* aatg.dispose();
* </pre>
* The bounding box for the iteration will be returned by the
* {@code RenderingEngine} via an argument to the getAATileGenerator() method.
*/
public interface AATileGenerator {
/**
* Gets the width of the tiles that the generator batches output into.
* @return the width of the standard alpha tile
*/
public int getTileWidth();
/**
* Gets the height of the tiles that the generator batches output into.
* @return the height of the standard alpha tile
*/
public int getTileHeight();
/**
* Gets the typical alpha value that will characterize the current
* tile.
* The answer may be 0x00 to indicate that the current tile has
* no coverage in any of its pixels, or it may be 0xff to indicate
* that the current tile is completely covered by the path, or any
* other value to indicate non-trivial coverage cases.
* @return 0x00 for no coverage, 0xff for total coverage, or any other
* value for partial coverage of the tile
*/
public int getTypicalAlpha();
/**
* Skips the current tile and moves on to the next tile.
* Either this method, or the getAlpha() method should be called
* once per tile, but not both.
*/
public void nextTile();
/**
* Gets the alpha coverage values for the current tile.
* Either this method, or the nextTile() method should be called
* once per tile, but not both.
*/
public void getAlpha(byte tile[], int offset, int rowstride);
/**
* Disposes this tile generator.
* No further calls will be made on this instance.
*/
public void dispose();
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 1997, 2011, 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 sun.java2d.pipe;
import java.awt.Rectangle;
import java.awt.Shape;
import sun.java2d.SunGraphics2D;
/**
* This class implements a CompositePipe that renders path alpha tiles
* into a destination that supports direct alpha compositing of a solid
* color, according to one of the rules in the AlphaComposite class.
*/
public class AlphaColorPipe implements CompositePipe, ParallelogramPipe {
public AlphaColorPipe() {
}
public Object startSequence(SunGraphics2D sg, Shape s, Rectangle dev,
int[] abox) {
return sg;
}
public boolean needTile(Object context, int x, int y, int w, int h) {
return true;
}
public void renderPathTile(Object context,
byte[] atile, int offset, int tilesize,
int x, int y, int w, int h) {
SunGraphics2D sg = (SunGraphics2D) context;
sg.alphafill.MaskFill(sg, sg.getSurfaceData(), sg.composite,
x, y, w, h,
atile, offset, tilesize);
}
public void skipTile(Object context, int x, int y) {
return;
}
public void endSequence(Object context) {
return;
}
public void fillParallelogram(SunGraphics2D sg,
double ux1, double uy1,
double ux2, double uy2,
double x, double y,
double dx1, double dy1,
double dx2, double dy2)
{
sg.alphafill.FillAAPgram(sg, sg.getSurfaceData(), sg.composite,
x, y, dx1, dy1, dx2, dy2);
}
public void drawParallelogram(SunGraphics2D sg,
double ux1, double uy1,
double ux2, double uy2,
double x, double y,
double dx1, double dy1,
double dx2, double dy2,
double lw1, double lw2)
{
sg.alphafill.DrawAAPgram(sg, sg.getSurfaceData(), sg.composite,
x, y, dx1, dy1, dx2, dy2, lw1, lw2);
}
}

View File

@@ -0,0 +1,206 @@
/*
* Copyright (c) 1997, 2002, 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 sun.java2d.pipe;
import java.lang.ref.WeakReference;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.PaintContext;
import java.awt.Transparency;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.awt.image.BufferedImage;
import sun.awt.image.BufImgSurfaceData;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.loops.Blit;
import sun.java2d.loops.MaskBlit;
import sun.java2d.loops.CompositeType;
import sun.java2d.loops.GraphicsPrimitiveMgr;
/**
* This class implements a CompositePipe that renders path alpha tiles
* into a destination according to the Composite attribute of a
* SunGraphics2D.
*/
public class AlphaPaintPipe implements CompositePipe {
static WeakReference cachedLastRaster;
static WeakReference cachedLastColorModel;
static WeakReference cachedLastData;
static class TileContext {
SunGraphics2D sunG2D;
PaintContext paintCtxt;
ColorModel paintModel;
WeakReference lastRaster;
WeakReference lastData;
MaskBlit lastMask;
Blit lastBlit;
SurfaceData dstData;
public TileContext(SunGraphics2D sg, PaintContext pc) {
sunG2D = sg;
paintCtxt = pc;
paintModel = pc.getColorModel();
dstData = sg.getSurfaceData();
synchronized (AlphaPaintPipe.class) {
if (cachedLastColorModel != null &&
cachedLastColorModel.get() == paintModel)
{
this.lastRaster = cachedLastRaster;
this.lastData = cachedLastData;
}
}
}
}
public Object startSequence(SunGraphics2D sg, Shape s, Rectangle devR,
int[] abox) {
PaintContext paintContext =
sg.paint.createContext(sg.getDeviceColorModel(),
devR,
s.getBounds2D(),
sg.cloneTransform(),
sg.getRenderingHints());
return new TileContext(sg, paintContext);
}
public boolean needTile(Object context, int x, int y, int w, int h) {
return true;
}
private static final int TILE_SIZE = 32;
public void renderPathTile(Object ctx,
byte[] atile, int offset, int tilesize,
int x, int y, int w, int h) {
TileContext context = (TileContext) ctx;
PaintContext paintCtxt = context.paintCtxt;
SunGraphics2D sg = context.sunG2D;
SurfaceData dstData = context.dstData;
SurfaceData srcData = null;
Raster lastRas = null;
if (context.lastData != null && context.lastRaster != null) {
srcData = (SurfaceData) context.lastData.get();
lastRas = (Raster) context.lastRaster.get();
if (srcData == null || lastRas == null) {
srcData = null;
lastRas = null;
}
}
ColorModel paintModel = context.paintModel;
for (int rely = 0; rely < h; rely += TILE_SIZE) {
int ty = y + rely;
int th = Math.min(h-rely, TILE_SIZE);
for (int relx = 0; relx < w; relx += TILE_SIZE) {
int tx = x + relx;
int tw = Math.min(w-relx, TILE_SIZE);
Raster srcRaster = paintCtxt.getRaster(tx, ty, tw, th);
if ((srcRaster.getMinX() != 0) || (srcRaster.getMinY() != 0)) {
srcRaster = srcRaster.createTranslatedChild(0, 0);
}
if (lastRas != srcRaster) {
lastRas = srcRaster;
context.lastRaster = new WeakReference(lastRas);
// REMIND: This will fail for a non-Writable raster!
BufferedImage bImg =
new BufferedImage(paintModel,
(WritableRaster) srcRaster,
paintModel.isAlphaPremultiplied(),
null);
srcData = BufImgSurfaceData.createData(bImg);
context.lastData = new WeakReference(srcData);
context.lastMask = null;
context.lastBlit = null;
}
if (atile == null) {
if (context.lastBlit == null) {
CompositeType comptype = sg.imageComp;
if (CompositeType.SrcOverNoEa.equals(comptype) &&
paintModel.getTransparency() == Transparency.OPAQUE)
{
comptype = CompositeType.SrcNoEa;
}
context.lastBlit =
Blit.getFromCache(srcData.getSurfaceType(),
comptype,
dstData.getSurfaceType());
}
context.lastBlit.Blit(srcData, dstData,
sg.composite, null,
0, 0, tx, ty, tw, th);
} else {
if (context.lastMask == null) {
CompositeType comptype = sg.imageComp;
if (CompositeType.SrcOverNoEa.equals(comptype) &&
paintModel.getTransparency() == Transparency.OPAQUE)
{
comptype = CompositeType.SrcNoEa;
}
context.lastMask =
MaskBlit.getFromCache(srcData.getSurfaceType(),
comptype,
dstData.getSurfaceType());
}
int toff = offset + rely * tilesize + relx;
context.lastMask.MaskBlit(srcData, dstData,
sg.composite, null,
0, 0, tx, ty, tw, th,
atile, toff, tilesize);
}
}
}
}
public void skipTile(Object context, int x, int y) {
return;
}
public void endSequence(Object ctx) {
TileContext context = (TileContext) ctx;
if (context.paintCtxt != null) {
context.paintCtxt.dispose();
}
synchronized (AlphaPaintPipe.class) {
if (context.lastData != null) {
cachedLastRaster = context.lastRaster;
if (cachedLastColorModel == null ||
cachedLastColorModel.get() != context.paintModel)
{
// Avoid creating new WeakReference if possible
cachedLastColorModel =
new WeakReference(context.paintModel);
}
cachedLastData = context.lastData;
}
}
}
}

View File

@@ -0,0 +1,393 @@
/*
* Copyright (c) 2007, 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 sun.java2d.pipe;
import java.awt.color.ColorSpace;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.BufferedImageOp;
import java.awt.image.ByteLookupTable;
import java.awt.image.ColorModel;
import java.awt.image.ConvolveOp;
import java.awt.image.IndexColorModel;
import java.awt.image.Kernel;
import java.awt.image.LookupOp;
import java.awt.image.LookupTable;
import java.awt.image.RescaleOp;
import java.awt.image.ShortLookupTable;
import sun.java2d.SurfaceData;
import sun.java2d.loops.CompositeType;
import static sun.java2d.pipe.BufferedOpCodes.*;
public class BufferedBufImgOps {
public static void enableBufImgOp(RenderQueue rq, SurfaceData srcData,
BufferedImage srcImg,
BufferedImageOp biop)
{
if (biop instanceof ConvolveOp) {
enableConvolveOp(rq, srcData, (ConvolveOp)biop);
} else if (biop instanceof RescaleOp) {
enableRescaleOp(rq, srcData, srcImg, (RescaleOp)biop);
} else if (biop instanceof LookupOp) {
enableLookupOp(rq, srcData, srcImg, (LookupOp)biop);
} else {
throw new InternalError("Unknown BufferedImageOp");
}
}
public static void disableBufImgOp(RenderQueue rq, BufferedImageOp biop) {
if (biop instanceof ConvolveOp) {
disableConvolveOp(rq);
} else if (biop instanceof RescaleOp) {
disableRescaleOp(rq);
} else if (biop instanceof LookupOp) {
disableLookupOp(rq);
} else {
throw new InternalError("Unknown BufferedImageOp");
}
}
/**************************** ConvolveOp support ****************************/
public static boolean isConvolveOpValid(ConvolveOp cop) {
Kernel kernel = cop.getKernel();
int kw = kernel.getWidth();
int kh = kernel.getHeight();
// REMIND: we currently can only handle 3x3 and 5x5 kernels,
// but hopefully this is just a temporary restriction;
// see native shader comments for more details
if (!(kw == 3 && kh == 3) && !(kw == 5 && kh == 5)) {
return false;
}
return true;
}
private static void enableConvolveOp(RenderQueue rq,
SurfaceData srcData,
ConvolveOp cop)
{
// assert rq.lock.isHeldByCurrentThread();
boolean edgeZero =
cop.getEdgeCondition() == ConvolveOp.EDGE_ZERO_FILL;
Kernel kernel = cop.getKernel();
int kernelWidth = kernel.getWidth();
int kernelHeight = kernel.getHeight();
int kernelSize = kernelWidth * kernelHeight;
int sizeofFloat = 4;
int totalBytesRequired = 4 + 8 + 12 + (kernelSize * sizeofFloat);
RenderBuffer buf = rq.getBuffer();
rq.ensureCapacityAndAlignment(totalBytesRequired, 4);
buf.putInt(ENABLE_CONVOLVE_OP);
buf.putLong(srcData.getNativeOps());
buf.putInt(edgeZero ? 1 : 0);
buf.putInt(kernelWidth);
buf.putInt(kernelHeight);
buf.put(kernel.getKernelData(null));
}
private static void disableConvolveOp(RenderQueue rq) {
// assert rq.lock.isHeldByCurrentThread();
RenderBuffer buf = rq.getBuffer();
rq.ensureCapacity(4);
buf.putInt(DISABLE_CONVOLVE_OP);
}
/**************************** RescaleOp support *****************************/
public static boolean isRescaleOpValid(RescaleOp rop,
BufferedImage srcImg)
{
int numFactors = rop.getNumFactors();
ColorModel srcCM = srcImg.getColorModel();
if (srcCM instanceof IndexColorModel) {
throw new
IllegalArgumentException("Rescaling cannot be "+
"performed on an indexed image");
}
if (numFactors != 1 &&
numFactors != srcCM.getNumColorComponents() &&
numFactors != srcCM.getNumComponents())
{
throw new IllegalArgumentException("Number of scaling constants "+
"does not equal the number of"+
" of color or color/alpha "+
" components");
}
int csType = srcCM.getColorSpace().getType();
if (csType != ColorSpace.TYPE_RGB &&
csType != ColorSpace.TYPE_GRAY)
{
// Not prepared to deal with other color spaces
return false;
}
if (numFactors == 2 || numFactors > 4) {
// Not really prepared to handle this at the native level, so...
return false;
}
return true;
}
private static void enableRescaleOp(RenderQueue rq,
SurfaceData srcData,
BufferedImage srcImg,
RescaleOp rop)
{
// assert rq.lock.isHeldByCurrentThread();
ColorModel srcCM = srcImg.getColorModel();
boolean nonPremult =
srcCM.hasAlpha() &&
srcCM.isAlphaPremultiplied();
/*
* Note: The user-provided scale factors and offsets are arranged
* in R/G/B/A order, regardless of the raw data order of the
* underlying Raster/DataBuffer. The source image data is ultimately
* converted into RGBA data when uploaded to an OpenGL texture
* (even for TYPE_GRAY), so the scale factors and offsets are already
* in the order expected by the native OpenGL code.
*
* However, the offsets provided by the user are in a range dictated
* by the size of each color/alpha band in the source image. For
* example, for 8/8/8 data each offset is in the range [0,255],
* for 5/5/5 data each offset is in the range [0,31], and so on.
* The OpenGL shader only thinks in terms of [0,1], so below we need
* to normalize the user-provided offset values into the range [0,1].
*/
int numFactors = rop.getNumFactors();
float[] origScaleFactors = rop.getScaleFactors(null);
float[] origOffsets = rop.getOffsets(null);
// To make things easier, we will always pass all four bands
// down to native code...
float[] normScaleFactors;
float[] normOffsets;
if (numFactors == 1) {
normScaleFactors = new float[4];
normOffsets = new float[4];
for (int i = 0; i < 3; i++) {
normScaleFactors[i] = origScaleFactors[0];
normOffsets[i] = origOffsets[0];
}
// Leave alpha untouched...
normScaleFactors[3] = 1.0f;
normOffsets[3] = 0.0f;
} else if (numFactors == 3) {
normScaleFactors = new float[4];
normOffsets = new float[4];
for (int i = 0; i < 3; i++) {
normScaleFactors[i] = origScaleFactors[i];
normOffsets[i] = origOffsets[i];
}
// Leave alpha untouched...
normScaleFactors[3] = 1.0f;
normOffsets[3] = 0.0f;
} else { // (numFactors == 4)
normScaleFactors = origScaleFactors;
normOffsets = origOffsets;
}
// The user-provided offsets are specified in the range
// of each source color band, but the OpenGL shader only wants
// to deal with data in the range [0,1], so we need to normalize
// each offset value to the range [0,1] here.
if (srcCM.getNumComponents() == 1) {
// Gray data
int nBits = srcCM.getComponentSize(0);
int maxValue = (1 << nBits) - 1;
for (int i = 0; i < 3; i++) {
normOffsets[i] /= maxValue;
}
} else {
// RGB(A) data
for (int i = 0; i < srcCM.getNumComponents(); i++) {
int nBits = srcCM.getComponentSize(i);
int maxValue = (1 << nBits) - 1;
normOffsets[i] /= maxValue;
}
}
int sizeofFloat = 4;
int totalBytesRequired = 4 + 8 + 4 + (4 * sizeofFloat * 2);
RenderBuffer buf = rq.getBuffer();
rq.ensureCapacityAndAlignment(totalBytesRequired, 4);
buf.putInt(ENABLE_RESCALE_OP);
buf.putLong(srcData.getNativeOps());
buf.putInt(nonPremult ? 1 : 0);
buf.put(normScaleFactors);
buf.put(normOffsets);
}
private static void disableRescaleOp(RenderQueue rq) {
// assert rq.lock.isHeldByCurrentThread();
RenderBuffer buf = rq.getBuffer();
rq.ensureCapacity(4);
buf.putInt(DISABLE_RESCALE_OP);
}
/**************************** LookupOp support ******************************/
public static boolean isLookupOpValid(LookupOp lop,
BufferedImage srcImg)
{
LookupTable table = lop.getTable();
int numComps = table.getNumComponents();
ColorModel srcCM = srcImg.getColorModel();
if (srcCM instanceof IndexColorModel) {
throw new
IllegalArgumentException("LookupOp cannot be "+
"performed on an indexed image");
}
if (numComps != 1 &&
numComps != srcCM.getNumComponents() &&
numComps != srcCM.getNumColorComponents())
{
throw new IllegalArgumentException("Number of arrays in the "+
" lookup table ("+
numComps+
") is not compatible with"+
" the src image: "+srcImg);
}
int csType = srcCM.getColorSpace().getType();
if (csType != ColorSpace.TYPE_RGB &&
csType != ColorSpace.TYPE_GRAY)
{
// Not prepared to deal with other color spaces
return false;
}
if (numComps == 2 || numComps > 4) {
// Not really prepared to handle this at the native level, so...
return false;
}
// The LookupTable spec says that "all arrays must be the
// same size" but unfortunately the constructors do not
// enforce that. Also, our native code only works with
// arrays no larger than 256 elements, so check both of
// these restrictions here.
if (table instanceof ByteLookupTable) {
byte[][] data = ((ByteLookupTable)table).getTable();
for (int i = 1; i < data.length; i++) {
if (data[i].length > 256 ||
data[i].length != data[i-1].length)
{
return false;
}
}
} else if (table instanceof ShortLookupTable) {
short[][] data = ((ShortLookupTable)table).getTable();
for (int i = 1; i < data.length; i++) {
if (data[i].length > 256 ||
data[i].length != data[i-1].length)
{
return false;
}
}
} else {
return false;
}
return true;
}
private static void enableLookupOp(RenderQueue rq,
SurfaceData srcData,
BufferedImage srcImg,
LookupOp lop)
{
// assert rq.lock.isHeldByCurrentThread();
boolean nonPremult =
srcImg.getColorModel().hasAlpha() &&
srcImg.isAlphaPremultiplied();
LookupTable table = lop.getTable();
int numBands = table.getNumComponents();
int offset = table.getOffset();
int bandLength;
int bytesPerElem;
boolean shortData;
if (table instanceof ShortLookupTable) {
short[][] data = ((ShortLookupTable)table).getTable();
bandLength = data[0].length;
bytesPerElem = 2;
shortData = true;
} else { // (table instanceof ByteLookupTable)
byte[][] data = ((ByteLookupTable)table).getTable();
bandLength = data[0].length;
bytesPerElem = 1;
shortData = false;
}
// Adjust the LUT length so that it ends on a 4-byte boundary
int totalLutBytes = numBands * bandLength * bytesPerElem;
int paddedLutBytes = (totalLutBytes + 3) & (~3);
int padding = paddedLutBytes - totalLutBytes;
int totalBytesRequired = 4 + 8 + 20 + paddedLutBytes;
RenderBuffer buf = rq.getBuffer();
rq.ensureCapacityAndAlignment(totalBytesRequired, 4);
buf.putInt(ENABLE_LOOKUP_OP);
buf.putLong(srcData.getNativeOps());
buf.putInt(nonPremult ? 1 : 0);
buf.putInt(shortData ? 1 : 0);
buf.putInt(numBands);
buf.putInt(bandLength);
buf.putInt(offset);
if (shortData) {
short[][] data = ((ShortLookupTable)table).getTable();
for (int i = 0; i < numBands; i++) {
buf.put(data[i]);
}
} else {
byte[][] data = ((ByteLookupTable)table).getTable();
for (int i = 0; i < numBands; i++) {
buf.put(data[i]);
}
}
if (padding != 0) {
buf.position(buf.position() + padding);
}
}
private static void disableLookupOp(RenderQueue rq) {
// assert rq.lock.isHeldByCurrentThread();
RenderBuffer buf = rq.getBuffer();
rq.ensureCapacity(4);
buf.putInt(DISABLE_LOOKUP_OP);
}
}

View File

@@ -0,0 +1,479 @@
/*
* Copyright (c) 2005, 2016, 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 sun.java2d.pipe;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Paint;
import java.awt.geom.AffineTransform;
import sun.java2d.pipe.hw.AccelSurface;
import sun.java2d.InvalidPipeException;
import sun.java2d.SunGraphics2D;
import sun.java2d.loops.XORComposite;
import static sun.java2d.pipe.BufferedOpCodes.*;
import static sun.java2d.pipe.BufferedRenderPipe.BYTES_PER_SPAN;
import java.lang.annotation.Native;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
/**
* Base context class for managing state in a single-threaded rendering
* environment. Each state-setting operation (e.g. SET_COLOR) is added to
* the provided RenderQueue, which will be processed at a later time by a
* single thread. Note that the RenderQueue lock must be acquired before
* calling the validate() method (or any other method in this class). See
* the RenderQueue class comments for a sample usage scenario.
*
* @see RenderQueue
*/
public abstract class BufferedContext {
/*
* The following flags help the internals of validate() determine
* the appropriate (meaning correct, or optimal) code path when
* setting up the current context. The flags can be bitwise OR'd
* together as needed.
*/
/**
* Indicates that no flags are needed; take all default code paths.
*/
@Native public static final int NO_CONTEXT_FLAGS = (0 << 0);
/**
* Indicates that the source surface (or color value, if it is a simple
* rendering operation) is opaque (has an alpha value of 1.0). If this
* flag is present, it allows us to disable blending in certain
* situations in order to improve performance.
*/
@Native public static final int SRC_IS_OPAQUE = (1 << 0);
/**
* Indicates that the operation uses an alpha mask, which may determine
* the code path that is used when setting up the current paint state.
*/
@Native public static final int USE_MASK = (1 << 1);
protected RenderQueue rq;
protected RenderBuffer buf;
/**
* This is a reference to the most recently validated BufferedContext. If
* this value is null, it means that there is no current context. It is
* provided here so that validate() only needs to do a quick reference
* check to see if the BufferedContext passed to that method is the same
* as the one we've cached here.
*/
protected static BufferedContext currentContext;
private Reference<AccelSurface> validSrcDataRef = new WeakReference<>(null);
private Reference<AccelSurface> validDstDataRef = new WeakReference<>(null);
private Reference<Region> validClipRef = new WeakReference<>(null);
private Reference<Composite> validCompRef = new WeakReference<>(null);
private Reference<Paint> validPaintRef = new WeakReference<>(null);
// renamed from isValidatedPaintAColor as part of a work around for 6764257
private boolean isValidatedPaintJustAColor;
private int validatedRGB;
private int validatedFlags;
private boolean xformInUse;
private AffineTransform transform;
protected BufferedContext(RenderQueue rq) {
this.rq = rq;
this.buf = rq.getBuffer();
}
/**
* Fetches the BufferedContextContext associated with the dst. surface
* and validates the context using the given parameters. Most rendering
* operations will call this method first in order to set the necessary
* state before issuing rendering commands.
*
* Note: must be called while the RenderQueue lock is held.
*
* It's assumed that the type of surfaces has been checked by the Renderer
*
* @throws InvalidPipeException if either src or dest surface is not valid
* or lost
* @see RenderQueue#lock
* @see RenderQueue#unlock
*/
public static void validateContext(AccelSurface srcData,
AccelSurface dstData,
Region clip, Composite comp,
AffineTransform xform,
Paint paint, SunGraphics2D sg2d,
int flags)
{
// assert rq.lock.isHeldByCurrentThread();
BufferedContext context = dstData.getContext();
context.validate(srcData, dstData,
clip, comp, xform, paint, sg2d, flags);
}
/**
* Fetches the BufferedContextassociated with the surface
* and disables all context state settings.
*
* Note: must be called while the RenderQueue lock is held.
*
* It's assumed that the type of surfaces has been checked by the Renderer
*
* @throws InvalidPipeException if the surface is not valid
* or lost
* @see RenderQueue#lock
* @see RenderQueue#unlock
*/
public static void validateContext(AccelSurface surface) {
// assert rt.lock.isHeldByCurrentThread();
validateContext(surface, surface,
null, null, null, null, null, NO_CONTEXT_FLAGS);
}
/**
* Validates the given parameters against the current state for this
* context. If this context is not current, it will be made current
* for the given source and destination surfaces, and the viewport will
* be updated. Then each part of the context state (clip, composite,
* etc.) is checked against the previous value. If the value has changed
* since the last call to validate(), it will be updated accordingly.
*
* Note that the SunGraphics2D parameter is only used for the purposes
* of validating a (non-null) Paint parameter. In all other cases it
* is safe to pass a null SunGraphics2D and it will be ignored.
*
* Note: must be called while the RenderQueue lock is held.
*
* It's assumed that the type of surfaces has been checked by the Renderer
*
* @throws InvalidPipeException if either src or dest surface is not valid
* or lost
*/
public void validate(AccelSurface srcData, AccelSurface dstData,
Region clip, Composite comp,
AffineTransform xform,
Paint paint, SunGraphics2D sg2d, int flags)
{
// assert rq.lock.isHeldByCurrentThread();
boolean updateClip = false;
boolean updatePaint = false;
if (!dstData.isValid() ||
dstData.isSurfaceLost() || srcData.isSurfaceLost())
{
invalidateContext();
throw new InvalidPipeException("bounds changed or surface lost");
}
if (paint instanceof Color) {
// REMIND: not 30-bit friendly
int newRGB = ((Color)paint).getRGB();
if (isValidatedPaintJustAColor) {
if (newRGB != validatedRGB) {
validatedRGB = newRGB;
updatePaint = true;
}
} else {
validatedRGB = newRGB;
updatePaint = true;
isValidatedPaintJustAColor = true;
}
} else if (validPaintRef.get() != paint) {
updatePaint = true;
// this should be set when we are switching from paint to color
// in which case this condition will be true
isValidatedPaintJustAColor = false;
}
final AccelSurface validatedSrcData = validSrcDataRef.get();
final AccelSurface validatedDstData = validDstDataRef.get();
if ((currentContext != this) ||
(srcData != validatedSrcData) ||
(dstData != validatedDstData))
{
if (dstData != validatedDstData) {
// the clip is dependent on the destination surface, so we
// need to update it if we have a new destination surface
updateClip = true;
}
if (paint == null) {
// make sure we update the color state (otherwise, it might
// not be updated if this is the first time the context
// is being validated)
updatePaint = true;
}
// update the current source and destination surfaces
setSurfaces(srcData, dstData);
currentContext = this;
validSrcDataRef = new WeakReference<>(srcData);
validDstDataRef = new WeakReference<>(dstData);
}
// validate clip
final Region validatedClip = validClipRef.get();
if ((clip != validatedClip) || updateClip) {
if (clip != null) {
if (updateClip ||
validatedClip == null ||
!(validatedClip.isRectangular() && clip.isRectangular()) ||
((clip.getLoX() != validatedClip.getLoX() ||
clip.getLoY() != validatedClip.getLoY() ||
clip.getHiX() != validatedClip.getHiX() ||
clip.getHiY() != validatedClip.getHiY())))
{
setClip(clip);
}
} else {
resetClip();
}
validClipRef = new WeakReference<>(clip);
}
// validate composite (note that a change in the context flags
// may require us to update the composite state, even if the
// composite has not changed)
if ((comp != validCompRef.get()) || (flags != validatedFlags)) {
if (comp != null) {
setComposite(comp, flags);
} else {
resetComposite();
}
// the paint state is dependent on the composite state, so make
// sure we update the color below
updatePaint = true;
validCompRef = new WeakReference<>(comp);
validatedFlags = flags;
}
// validate transform
boolean txChanged = false;
if (xform == null) {
if (xformInUse) {
resetTransform();
xformInUse = false;
txChanged = true;
} else if (sg2d != null && !sg2d.transform.equals(transform)) {
txChanged = true;
}
if (sg2d != null && txChanged) {
transform = new AffineTransform(sg2d.transform);
}
} else {
setTransform(xform);
xformInUse = true;
txChanged = true;
}
// non-Color paints may require paint revalidation
if (!isValidatedPaintJustAColor && txChanged) {
updatePaint = true;
}
// validate paint
if (updatePaint) {
if (paint != null) {
BufferedPaints.setPaint(rq, sg2d, paint, flags);
} else {
BufferedPaints.resetPaint(rq);
}
validPaintRef = new WeakReference<>(paint);
}
// mark dstData dirty
// REMIND: is this really needed now? we do it in SunGraphics2D..
dstData.markDirty();
}
/**
* Invalidates the surfaces associated with this context. This is
* useful when the context is no longer needed, and we want to break
* the chain caused by these surface references.
*
* Note: must be called while the RenderQueue lock is held.
*
* @see RenderQueue#lock
* @see RenderQueue#unlock
*/
private void invalidateSurfaces() {
validSrcDataRef.clear();
validDstDataRef.clear();
}
private void setSurfaces(AccelSurface srcData,
AccelSurface dstData)
{
// assert rq.lock.isHeldByCurrentThread();
rq.ensureCapacityAndAlignment(20, 4);
buf.putInt(SET_SURFACES);
buf.putLong(srcData.getNativeOps());
buf.putLong(dstData.getNativeOps());
}
private void resetClip() {
// assert rq.lock.isHeldByCurrentThread();
rq.ensureCapacity(4);
buf.putInt(RESET_CLIP);
}
private void setClip(Region clip) {
// assert rq.lock.isHeldByCurrentThread();
if (clip.isRectangular()) {
rq.ensureCapacity(20);
buf.putInt(SET_RECT_CLIP);
buf.putInt(clip.getLoX()).putInt(clip.getLoY());
buf.putInt(clip.getHiX()).putInt(clip.getHiY());
} else {
rq.ensureCapacity(28); // so that we have room for at least a span
buf.putInt(BEGIN_SHAPE_CLIP);
buf.putInt(SET_SHAPE_CLIP_SPANS);
// include a placeholder for the span count
int countIndex = buf.position();
buf.putInt(0);
int spanCount = 0;
int remainingSpans = buf.remaining() / BYTES_PER_SPAN;
int span[] = new int[4];
SpanIterator si = clip.getSpanIterator();
while (si.nextSpan(span)) {
if (remainingSpans == 0) {
buf.putInt(countIndex, spanCount);
rq.flushNow();
buf.putInt(SET_SHAPE_CLIP_SPANS);
countIndex = buf.position();
buf.putInt(0);
spanCount = 0;
remainingSpans = buf.remaining() / BYTES_PER_SPAN;
}
buf.putInt(span[0]); // x1
buf.putInt(span[1]); // y1
buf.putInt(span[2]); // x2
buf.putInt(span[3]); // y2
spanCount++;
remainingSpans--;
}
buf.putInt(countIndex, spanCount);
rq.ensureCapacity(4);
buf.putInt(END_SHAPE_CLIP);
}
}
private void resetComposite() {
// assert rq.lock.isHeldByCurrentThread();
rq.ensureCapacity(4);
buf.putInt(RESET_COMPOSITE);
}
private void setComposite(Composite comp, int flags) {
// assert rq.lock.isHeldByCurrentThread();
if (comp instanceof AlphaComposite) {
AlphaComposite ac = (AlphaComposite)comp;
rq.ensureCapacity(16);
buf.putInt(SET_ALPHA_COMPOSITE);
buf.putInt(ac.getRule());
buf.putFloat(ac.getAlpha());
buf.putInt(flags);
} else if (comp instanceof XORComposite) {
int xorPixel = ((XORComposite)comp).getXorPixel();
rq.ensureCapacity(8);
buf.putInt(SET_XOR_COMPOSITE);
buf.putInt(xorPixel);
} else {
throw new InternalError("not yet implemented");
}
}
private void resetTransform() {
// assert rq.lock.isHeldByCurrentThread();
rq.ensureCapacity(4);
buf.putInt(RESET_TRANSFORM);
}
private void setTransform(AffineTransform xform) {
// assert rq.lock.isHeldByCurrentThread();
rq.ensureCapacityAndAlignment(52, 4);
buf.putInt(SET_TRANSFORM);
buf.putDouble(xform.getScaleX());
buf.putDouble(xform.getShearY());
buf.putDouble(xform.getShearX());
buf.putDouble(xform.getScaleY());
buf.putDouble(xform.getTranslateX());
buf.putDouble(xform.getTranslateY());
}
/**
* Resets this context's surfaces and all attributes.
*
* Note: must be called while the RenderQueue lock is held.
*
* @see RenderQueue#lock
* @see RenderQueue#unlock
*/
public void invalidateContext() {
resetTransform();
resetComposite();
resetClip();
BufferedPaints.resetPaint(rq);
invalidateSurfaces();
validCompRef.clear();
validClipRef.clear();
validPaintRef.clear();
isValidatedPaintJustAColor = false;
xformInUse = false;
}
/**
* Returns a singleton {@code RenderQueue} object used by the rendering
* pipeline.
*
* @return a render queue
* @see RenderQueue
*/
public abstract RenderQueue getRenderQueue();
/**
* Saves the the state of this context.
* It may reset the current context.
*
* Note: must be called while the RenderQueue lock is held.
*
* @see RenderQueue#lock
* @see RenderQueue#unlock
*/
public abstract void saveState();
/**
* Restores the native state of this context.
* It may reset the current context.
*
* Note: must be called while the RenderQueue lock is held.
*
* @see RenderQueue#lock
* @see RenderQueue#unlock
*/
public abstract void restoreState();
}

View File

@@ -0,0 +1,163 @@
/*
* Copyright (c) 2007, 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 sun.java2d.pipe;
import java.awt.AlphaComposite;
import java.awt.Composite;
import sun.java2d.SurfaceData;
import sun.java2d.loops.Blit;
import sun.java2d.loops.CompositeType;
import sun.java2d.loops.MaskBlit;
import sun.java2d.loops.SurfaceType;
import static sun.java2d.pipe.BufferedOpCodes.*;
/**
* The MaskBlit operation is expressed as:
* dst = ((src <MODE> dst) * pathA) + (dst * (1 - pathA))
*
* The OGL/D3D implementation of the MaskBlit operation differs from the above
* equation because it is not possible to perform such a complex operation in
* OpenGL/Direct3D (without the use of advanced techniques like fragment
* shaders and multitexturing). Therefore, the BufferedMaskBlit operation
* is expressed as:
* dst = (src * pathA) <SrcOver> dst
*
* This simplified formula is only equivalent to the "true" MaskBlit equation
* in the following situations:
* - <MODE> is SrcOver
* - <MODE> is Src, extra alpha == 1.0, and the source surface is opaque
*
* Therefore, we register BufferedMaskBlit primitives for only the SurfaceType
* and CompositeType restrictions mentioned above. In addition for the Src
* case, we must override the composite with a SrcOver (no extra alpha)
* instance, so that we set up the OpenGL/Direct3D blending mode to match the
* BufferedMaskBlit equation.
*/
public abstract class BufferedMaskBlit extends MaskBlit {
private static final int ST_INT_ARGB = 0;
private static final int ST_INT_ARGB_PRE = 1;
private static final int ST_INT_RGB = 2;
private static final int ST_INT_BGR = 3;
private final RenderQueue rq;
private final int srcTypeVal;
private Blit blitop;
protected BufferedMaskBlit(RenderQueue rq,
SurfaceType srcType,
CompositeType compType,
SurfaceType dstType)
{
super(srcType, compType, dstType);
this.rq = rq;
if (srcType == SurfaceType.IntArgb) {
this.srcTypeVal = ST_INT_ARGB;
} else if (srcType == SurfaceType.IntArgbPre) {
this.srcTypeVal = ST_INT_ARGB_PRE;
} else if (srcType == SurfaceType.IntRgb) {
this.srcTypeVal = ST_INT_RGB;
} else if (srcType == SurfaceType.IntBgr) {
this.srcTypeVal = ST_INT_BGR;
} else {
throw new InternalError("unrecognized source surface type");
}
}
@Override
public void MaskBlit(SurfaceData src, SurfaceData dst,
Composite comp, Region clip,
int srcx, int srcy,
int dstx, int dsty,
int width, int height,
byte[] mask, int maskoff, int maskscan)
{
if (width <= 0 || height <= 0) {
return;
}
if (mask == null) {
// no mask involved; delegate to regular blit loop
if (blitop == null) {
blitop = Blit.getFromCache(src.getSurfaceType(),
CompositeType.AnyAlpha,
this.getDestType());
}
blitop.Blit(src, dst,
comp, clip,
srcx, srcy, dstx, dsty,
width, height);
return;
}
AlphaComposite acomp = (AlphaComposite)comp;
if (acomp.getRule() != AlphaComposite.SRC_OVER) {
comp = AlphaComposite.SrcOver;
}
rq.lock();
try {
validateContext(dst, comp, clip);
RenderBuffer buf = rq.getBuffer();
int totalBytesRequired = 20 + (width * height * 4);
/*
* REMIND: we should fix this so that it works with tiles that
* are larger than the entire buffer, but the native
* OGL/D3DMaskBlit isn't even prepared for tiles larger
* than 32x32 pixels, so there's no urgency here...
*/
rq.ensureCapacity(totalBytesRequired);
// enqueue parameters and tile pixels
int newpos = enqueueTile(buf.getAddress(), buf.position(),
src, src.getNativeOps(), srcTypeVal,
mask, mask.length, maskoff, maskscan,
srcx, srcy, dstx, dsty,
width, height);
buf.position(newpos);
} finally {
rq.unlock();
}
}
private native int enqueueTile(long buf, int bpos,
SurfaceData srcData,
long pSrcOps, int srcType,
byte[] mask, int masklen,
int maskoff, int maskscan,
int srcx, int srcy, int dstx, int dsty,
int width, int height);
/**
* Validates the context state using the given destination surface
* and composite/clip values.
*/
protected abstract void validateContext(SurfaceData dstData,
Composite comp, Region clip);
}

View File

@@ -0,0 +1,153 @@
/*
* Copyright (c) 2007, 2013, 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 sun.java2d.pipe;
import java.awt.AlphaComposite;
import java.awt.Composite;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.loops.CompositeType;
import sun.java2d.loops.MaskFill;
import sun.java2d.loops.SurfaceType;
import static sun.java2d.pipe.BufferedOpCodes.*;
/**
* The MaskFill operation is expressed as:
* dst = ((src <MODE> dst) * pathA) + (dst * (1 - pathA))
*
* The OGL/D3D implementation of the MaskFill operation differs from the above
* equation because it is not possible to perform such a complex operation in
* OpenGL/Direct3D (without the use of advanced techniques like fragment
* shaders and multitexturing). Therefore, the BufferedMaskFill operation
* is expressed as:
* dst = (src * pathA) <SrcOver> dst
*
* This simplified formula is only equivalent to the "true" MaskFill equation
* in the following situations:
* - <MODE> is SrcOver
* - <MODE> is Src, extra alpha == 1.0, and the source paint is opaque
*
* Therefore, we register BufferedMaskFill primitives for only the SurfaceType
* and CompositeType restrictions mentioned above. In addition, for the
* SrcNoEa case we must override the incoming composite with a SrcOver (no
* extra alpha) instance, so that we set up the OpenGL/Direct3D blending
* mode to match the BufferedMaskFill equation.
*/
public abstract class BufferedMaskFill extends MaskFill {
protected final RenderQueue rq;
protected BufferedMaskFill(RenderQueue rq,
SurfaceType srcType,
CompositeType compType,
SurfaceType dstType)
{
super(srcType, compType, dstType);
this.rq = rq;
}
@Override
public void MaskFill(SunGraphics2D sg2d, SurfaceData sData,
Composite comp,
final int x, final int y, final int w, final int h,
final byte[] mask,
final int maskoff, final int maskscan)
{
AlphaComposite acomp = (AlphaComposite)comp;
if (acomp.getRule() != AlphaComposite.SRC_OVER) {
comp = AlphaComposite.SrcOver;
}
rq.lock();
try {
validateContext(sg2d, comp, BufferedContext.USE_MASK);
// we adjust the mask length so that the mask ends on a
// 4-byte boundary
int maskBytesRequired;
if (mask != null) {
// we adjust the mask length so that the mask ends on a
// 4-byte boundary
maskBytesRequired = (mask.length + 3) & (~3);
} else {
// mask not needed
maskBytesRequired = 0;
}
int totalBytesRequired = 32 + maskBytesRequired;
RenderBuffer buf = rq.getBuffer();
if (totalBytesRequired <= buf.capacity()) {
if (totalBytesRequired > buf.remaining()) {
// process the queue first and then enqueue the mask
rq.flushNow();
}
buf.putInt(MASK_FILL);
// enqueue parameters
buf.putInt(x).putInt(y).putInt(w).putInt(h);
buf.putInt(maskoff);
buf.putInt(maskscan);
buf.putInt(maskBytesRequired);
if (mask != null) {
// enqueue the mask
int padding = maskBytesRequired - mask.length;
buf.put(mask);
if (padding != 0) {
buf.position(buf.position() + padding);
}
}
} else {
// queue is too small to accommodate entire mask; perform
// the operation directly on the queue flushing thread
rq.flushAndInvokeNow(new Runnable() {
public void run() {
maskFill(x, y, w, h,
maskoff, maskscan, mask.length, mask);
}
});
}
} finally {
rq.unlock();
}
}
/**
* Called as a separate Runnable when the operation is too large to fit
* on the RenderQueue. The OGL/D3D pipelines each have their own (small)
* native implementation of this method.
*/
protected abstract void maskFill(int x, int y, int w, int h,
int maskoff, int maskscan, int masklen,
byte[] mask);
/**
* Validates the state in the provided SunGraphics2D object and sets up
* any special resources for this operation (e.g. enabling gradient
* shading).
*/
protected abstract void validateContext(SunGraphics2D sg2d,
Composite comp, int ctxflags);
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (c) 2005, 2013, 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 sun.java2d.pipe;
import java.lang.annotation.Native;
public class BufferedOpCodes {
// draw ops
@Native public static final int DRAW_LINE = 10;
@Native public static final int DRAW_RECT = 11;
@Native public static final int DRAW_POLY = 12;
@Native public static final int DRAW_PIXEL = 13;
@Native public static final int DRAW_SCANLINES = 14;
@Native public static final int DRAW_PARALLELOGRAM = 15;
@Native public static final int DRAW_AAPARALLELOGRAM = 16;
// fill ops
@Native public static final int FILL_RECT = 20;
@Native public static final int FILL_SPANS = 21;
@Native public static final int FILL_PARALLELOGRAM = 22;
@Native public static final int FILL_AAPARALLELOGRAM = 23;
// copy-related ops
@Native public static final int COPY_AREA = 30;
@Native public static final int BLIT = 31;
@Native public static final int MASK_FILL = 32;
@Native public static final int MASK_BLIT = 33;
@Native public static final int SURFACE_TO_SW_BLIT = 34;
// text-related ops
@Native public static final int DRAW_GLYPH_LIST = 40;
// state-related ops
@Native public static final int SET_RECT_CLIP = 51;
@Native public static final int BEGIN_SHAPE_CLIP = 52;
@Native public static final int SET_SHAPE_CLIP_SPANS = 53;
@Native public static final int END_SHAPE_CLIP = 54;
@Native public static final int RESET_CLIP = 55;
@Native public static final int SET_ALPHA_COMPOSITE = 56;
@Native public static final int SET_XOR_COMPOSITE = 57;
@Native public static final int RESET_COMPOSITE = 58;
@Native public static final int SET_TRANSFORM = 59;
@Native public static final int RESET_TRANSFORM = 60;
// context-related ops
@Native public static final int SET_SURFACES = 70;
@Native public static final int SET_SCRATCH_SURFACE = 71;
@Native public static final int FLUSH_SURFACE = 72;
@Native public static final int DISPOSE_SURFACE = 73;
@Native public static final int DISPOSE_CONFIG = 74;
@Native public static final int INVALIDATE_CONTEXT = 75;
@Native public static final int SYNC = 76;
@Native public static final int RESTORE_DEVICES = 77;
@Native public static final int SAVE_STATE = 78;
@Native public static final int RESTORE_STATE = 79;
// multibuffering ops
@Native public static final int SWAP_BUFFERS = 80;
// special no-op op code (mainly used for achieving 8-byte alignment)
@Native public static final int NOOP = 90;
// paint-related ops
@Native public static final int RESET_PAINT = 100;
@Native public static final int SET_COLOR = 101;
@Native public static final int SET_GRADIENT_PAINT = 102;
@Native public static final int SET_LINEAR_GRADIENT_PAINT = 103;
@Native public static final int SET_RADIAL_GRADIENT_PAINT = 104;
@Native public static final int SET_TEXTURE_PAINT = 105;
// BufferedImageOp-related ops
@Native public static final int ENABLE_CONVOLVE_OP = 120;
@Native public static final int DISABLE_CONVOLVE_OP = 121;
@Native public static final int ENABLE_RESCALE_OP = 122;
@Native public static final int DISABLE_RESCALE_OP = 123;
@Native public static final int ENABLE_LOOKUP_OP = 124;
@Native public static final int DISABLE_LOOKUP_OP = 125;
}

View File

@@ -0,0 +1,535 @@
/*
* Copyright (c) 2007, 2013, 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 sun.java2d.pipe;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.LinearGradientPaint;
import java.awt.MultipleGradientPaint;
import java.awt.MultipleGradientPaint.ColorSpaceType;
import java.awt.MultipleGradientPaint.CycleMethod;
import java.awt.Paint;
import java.awt.RadialGradientPaint;
import java.awt.TexturePaint;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import sun.awt.image.PixelConverter;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.loops.CompositeType;
import sun.java2d.loops.SurfaceType;
import static sun.java2d.pipe.BufferedOpCodes.*;
import java.lang.annotation.Native;
public class BufferedPaints {
static void setPaint(RenderQueue rq, SunGraphics2D sg2d,
Paint paint, int ctxflags)
{
if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {
setColor(rq, sg2d.pixel);
} else {
boolean useMask = (ctxflags & BufferedContext.USE_MASK) != 0;
switch (sg2d.paintState) {
case SunGraphics2D.PAINT_GRADIENT:
setGradientPaint(rq, sg2d,
(GradientPaint)paint, useMask);
break;
case SunGraphics2D.PAINT_LIN_GRADIENT:
setLinearGradientPaint(rq, sg2d,
(LinearGradientPaint)paint, useMask);
break;
case SunGraphics2D.PAINT_RAD_GRADIENT:
setRadialGradientPaint(rq, sg2d,
(RadialGradientPaint)paint, useMask);
break;
case SunGraphics2D.PAINT_TEXTURE:
setTexturePaint(rq, sg2d,
(TexturePaint)paint, useMask);
break;
default:
break;
}
}
}
static void resetPaint(RenderQueue rq) {
// assert rq.lock.isHeldByCurrentThread();
rq.ensureCapacity(4);
RenderBuffer buf = rq.getBuffer();
buf.putInt(RESET_PAINT);
}
/****************************** Color support *******************************/
private static void setColor(RenderQueue rq, int pixel) {
// assert rq.lock.isHeldByCurrentThread();
rq.ensureCapacity(8);
RenderBuffer buf = rq.getBuffer();
buf.putInt(SET_COLOR);
buf.putInt(pixel);
}
/************************* GradientPaint support ****************************/
/**
* Note: This code is factored out into a separate static method
* so that it can be shared by both the Gradient and LinearGradient
* implementations. LinearGradient uses this code (for the
* two-color sRGB case only) because it can be much faster than the
* equivalent implementation that uses fragment shaders.
*
* We use OpenGL's texture coordinate generator to automatically
* apply a smooth gradient (either cyclic or acyclic) to the geometry
* being rendered. This technique is almost identical to the one
* described in the comments for BufferedPaints.setTexturePaint(),
* except the calculations take place in one dimension instead of two.
* Instead of an anchor rectangle in the TexturePaint case, we use
* the vector between the two GradientPaint end points in our
* calculations. The generator uses a single plane equation that
* takes the (x,y) location (in device space) of the fragment being
* rendered to calculate a (u) texture coordinate for that fragment:
* u = Ax + By + Cz + Dw
*
* The gradient renderer uses a two-pixel 1D texture where the first
* pixel contains the first GradientPaint color, and the second pixel
* contains the second GradientPaint color. (Note that we use the
* GL_CLAMP_TO_EDGE wrapping mode for acyclic gradients so that we
* clamp the colors properly at the extremes.) The following diagram
* attempts to show the layout of the texture containing the two
* GradientPaint colors (C1 and C2):
*
* +-----------------+
* | C1 | C2 |
* | | |
* +-----------------+
* u=0 .25 .5 .75 1
*
* We calculate our plane equation constants (A,B,D) such that u=0.25
* corresponds to the first GradientPaint end point in user space and
* u=0.75 corresponds to the second end point. This is somewhat
* non-obvious, but since the gradient colors are generated by
* interpolating between C1 and C2, we want the pure color at the
* end points, and we will get the pure color only when u correlates
* to the center of a texel. The following chart shows the expected
* color for some sample values of u (where C' is the color halfway
* between C1 and C2):
*
* u value acyclic (GL_CLAMP) cyclic (GL_REPEAT)
* ------- ------------------ ------------------
* -0.25 C1 C2
* 0.0 C1 C'
* 0.25 C1 C1
* 0.5 C' C'
* 0.75 C2 C2
* 1.0 C2 C'
* 1.25 C2 C1
*
* Original inspiration for this technique came from UMD's Agile2D
* project (GradientManager.java).
*/
private static void setGradientPaint(RenderQueue rq, AffineTransform at,
Color c1, Color c2,
Point2D pt1, Point2D pt2,
boolean isCyclic, boolean useMask)
{
// convert gradient colors to IntArgbPre format
PixelConverter pc = PixelConverter.ArgbPre.instance;
int pixel1 = pc.rgbToPixel(c1.getRGB(), null);
int pixel2 = pc.rgbToPixel(c2.getRGB(), null);
// calculate plane equation constants
double x = pt1.getX();
double y = pt1.getY();
at.translate(x, y);
// now gradient point 1 is at the origin
x = pt2.getX() - x;
y = pt2.getY() - y;
double len = Math.sqrt(x * x + y * y);
at.rotate(x, y);
// now gradient point 2 is on the positive x-axis
at.scale(2*len, 1);
// now gradient point 2 is at (0.5, 0)
at.translate(-0.25, 0);
// now gradient point 1 is at (0.25, 0), point 2 is at (0.75, 0)
double p0, p1, p3;
try {
at.invert();
p0 = at.getScaleX();
p1 = at.getShearX();
p3 = at.getTranslateX();
} catch (java.awt.geom.NoninvertibleTransformException e) {
p0 = p1 = p3 = 0.0;
}
// assert rq.lock.isHeldByCurrentThread();
rq.ensureCapacityAndAlignment(44, 12);
RenderBuffer buf = rq.getBuffer();
buf.putInt(SET_GRADIENT_PAINT);
buf.putInt(useMask ? 1 : 0);
buf.putInt(isCyclic ? 1 : 0);
buf.putDouble(p0).putDouble(p1).putDouble(p3);
buf.putInt(pixel1).putInt(pixel2);
}
private static void setGradientPaint(RenderQueue rq,
SunGraphics2D sg2d,
GradientPaint paint,
boolean useMask)
{
setGradientPaint(rq, (AffineTransform)sg2d.transform.clone(),
paint.getColor1(), paint.getColor2(),
paint.getPoint1(), paint.getPoint2(),
paint.isCyclic(), useMask);
}
/************************** TexturePaint support ****************************/
/**
* We use OpenGL's texture coordinate generator to automatically
* map the TexturePaint image to the geometry being rendered. The
* generator uses two separate plane equations that take the (x,y)
* location (in device space) of the fragment being rendered to
* calculate (u,v) texture coordinates for that fragment:
* u = Ax + By + Cz + Dw
* v = Ex + Fy + Gz + Hw
*
* Since we use a 2D orthographic projection, we can assume that z=0
* and w=1 for any fragment. So we need to calculate appropriate
* values for the plane equation constants (A,B,D) and (E,F,H) such
* that {u,v}=0 for the top-left of the TexturePaint's anchor
* rectangle and {u,v}=1 for the bottom-right of the anchor rectangle.
* We can easily make the texture image repeat for {u,v} values
* outside the range [0,1] by specifying the GL_REPEAT texture wrap
* mode.
*
* Calculating the plane equation constants is surprisingly simple.
* We can think of it as an inverse matrix operation that takes
* device space coordinates and transforms them into user space
* coordinates that correspond to a location relative to the anchor
* rectangle. First, we translate and scale the current user space
* transform by applying the anchor rectangle bounds. We then take
* the inverse of this affine transform. The rows of the resulting
* inverse matrix correlate nicely to the plane equation constants
* we were seeking.
*/
private static void setTexturePaint(RenderQueue rq,
SunGraphics2D sg2d,
TexturePaint paint,
boolean useMask)
{
BufferedImage bi = paint.getImage();
SurfaceData dstData = sg2d.surfaceData;
SurfaceData srcData =
dstData.getSourceSurfaceData(bi, SunGraphics2D.TRANSFORM_ISIDENT,
CompositeType.SrcOver, null);
boolean filter =
(sg2d.interpolationType !=
AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
// calculate plane equation constants
AffineTransform at = (AffineTransform)sg2d.transform.clone();
Rectangle2D anchor = paint.getAnchorRect();
at.translate(anchor.getX(), anchor.getY());
at.scale(anchor.getWidth(), anchor.getHeight());
double xp0, xp1, xp3, yp0, yp1, yp3;
try {
at.invert();
xp0 = at.getScaleX();
xp1 = at.getShearX();
xp3 = at.getTranslateX();
yp0 = at.getShearY();
yp1 = at.getScaleY();
yp3 = at.getTranslateY();
} catch (java.awt.geom.NoninvertibleTransformException e) {
xp0 = xp1 = xp3 = yp0 = yp1 = yp3 = 0.0;
}
// assert rq.lock.isHeldByCurrentThread();
rq.ensureCapacityAndAlignment(68, 12);
RenderBuffer buf = rq.getBuffer();
buf.putInt(SET_TEXTURE_PAINT);
buf.putInt(useMask ? 1 : 0);
buf.putInt(filter ? 1 : 0);
buf.putLong(srcData.getNativeOps());
buf.putDouble(xp0).putDouble(xp1).putDouble(xp3);
buf.putDouble(yp0).putDouble(yp1).putDouble(yp3);
}
/****************** Shared MultipleGradientPaint support ********************/
/**
* The maximum number of gradient "stops" supported by our native
* fragment shader implementations.
*
* This value has been empirically determined and capped to allow
* our native shaders to run on all shader-level graphics hardware,
* even on the older, more limited GPUs. Even the oldest Nvidia
* hardware could handle 16, or even 32 fractions without any problem.
* But the first-generation boards from ATI would fall back into
* software mode (which is unusably slow) for values larger than 12;
* it appears that those boards do not have enough native registers
* to support the number of array accesses required by our gradient
* shaders. So for now we will cap this value at 12, but we can
* re-evaluate this in the future as hardware becomes more capable.
*/
@Native public static final int MULTI_MAX_FRACTIONS = 12;
/**
* Helper function to convert a color component in sRGB space to
* linear RGB space. Copied directly from the
* MultipleGradientPaintContext class.
*/
public static int convertSRGBtoLinearRGB(int color) {
float input, output;
input = color / 255.0f;
if (input <= 0.04045f) {
output = input / 12.92f;
} else {
output = (float)Math.pow((input + 0.055) / 1.055, 2.4);
}
return Math.round(output * 255.0f);
}
/**
* Helper function to convert a (non-premultiplied) Color in sRGB
* space to an IntArgbPre pixel value, optionally in linear RGB space.
* Based on the PixelConverter.ArgbPre.rgbToPixel() method.
*/
private static int colorToIntArgbPrePixel(Color c, boolean linear) {
int rgb = c.getRGB();
if (!linear && ((rgb >> 24) == -1)) {
return rgb;
}
int a = rgb >>> 24;
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = (rgb ) & 0xff;
if (linear) {
r = convertSRGBtoLinearRGB(r);
g = convertSRGBtoLinearRGB(g);
b = convertSRGBtoLinearRGB(b);
}
int a2 = a + (a >> 7);
r = (r * a2) >> 8;
g = (g * a2) >> 8;
b = (b * a2) >> 8;
return ((a << 24) | (r << 16) | (g << 8) | (b));
}
/**
* Converts the given array of Color objects into an int array
* containing IntArgbPre pixel values. If the linear parameter
* is true, the Color values will be converted into a linear RGB
* color space before being returned.
*/
private static int[] convertToIntArgbPrePixels(Color[] colors,
boolean linear)
{
int[] pixels = new int[colors.length];
for (int i = 0; i < colors.length; i++) {
pixels[i] = colorToIntArgbPrePixel(colors[i], linear);
}
return pixels;
}
/********************** LinearGradientPaint support *************************/
/**
* This method uses techniques that are nearly identical to those
* employed in setGradientPaint() above. The primary difference
* is that at the native level we use a fragment shader to manually
* apply the plane equation constants to the current fragment position
* to calculate the gradient position in the range [0,1] (the native
* code for GradientPaint does the same, except that it uses OpenGL's
* automatic texture coordinate generation facilities).
*
* One other minor difference worth mentioning is that
* setGradientPaint() calculates the plane equation constants
* such that the gradient end points are positioned at 0.25 and 0.75
* (for reasons discussed in the comments for that method). In
* contrast, for LinearGradientPaint we setup the equation constants
* such that the gradient end points fall at 0.0 and 1.0. The
* reason for this difference is that in the fragment shader we
* have more control over how the gradient values are interpreted
* (depending on the paint's CycleMethod).
*/
private static void setLinearGradientPaint(RenderQueue rq,
SunGraphics2D sg2d,
LinearGradientPaint paint,
boolean useMask)
{
boolean linear =
(paint.getColorSpace() == ColorSpaceType.LINEAR_RGB);
Color[] colors = paint.getColors();
int numStops = colors.length;
Point2D pt1 = paint.getStartPoint();
Point2D pt2 = paint.getEndPoint();
AffineTransform at = paint.getTransform();
at.preConcatenate(sg2d.transform);
if (!linear && numStops == 2 &&
paint.getCycleMethod() != CycleMethod.REPEAT)
{
// delegate to the optimized two-color gradient codepath
boolean isCyclic =
(paint.getCycleMethod() != CycleMethod.NO_CYCLE);
setGradientPaint(rq, at,
colors[0], colors[1],
pt1, pt2,
isCyclic, useMask);
return;
}
int cycleMethod = paint.getCycleMethod().ordinal();
float[] fractions = paint.getFractions();
int[] pixels = convertToIntArgbPrePixels(colors, linear);
// calculate plane equation constants
double x = pt1.getX();
double y = pt1.getY();
at.translate(x, y);
// now gradient point 1 is at the origin
x = pt2.getX() - x;
y = pt2.getY() - y;
double len = Math.sqrt(x * x + y * y);
at.rotate(x, y);
// now gradient point 2 is on the positive x-axis
at.scale(len, 1);
// now gradient point 1 is at (0.0, 0), point 2 is at (1.0, 0)
float p0, p1, p3;
try {
at.invert();
p0 = (float)at.getScaleX();
p1 = (float)at.getShearX();
p3 = (float)at.getTranslateX();
} catch (java.awt.geom.NoninvertibleTransformException e) {
p0 = p1 = p3 = 0.0f;
}
// assert rq.lock.isHeldByCurrentThread();
rq.ensureCapacity(20 + 12 + (numStops*4*2));
RenderBuffer buf = rq.getBuffer();
buf.putInt(SET_LINEAR_GRADIENT_PAINT);
buf.putInt(useMask ? 1 : 0);
buf.putInt(linear ? 1 : 0);
buf.putInt(cycleMethod);
buf.putInt(numStops);
buf.putFloat(p0);
buf.putFloat(p1);
buf.putFloat(p3);
buf.put(fractions);
buf.put(pixels);
}
/********************** RadialGradientPaint support *************************/
/**
* This method calculates six m** values and a focusX value that
* are used by the native fragment shader. These techniques are
* based on a whitepaper by Daniel Rice on radial gradient performance
* (attached to the bug report for 6521533). One can refer to that
* document for the complete set of formulas and calculations, but
* the basic goal is to compose a transform that will convert an
* (x,y) position in device space into a "u" value that represents
* the relative distance to the gradient focus point. The resulting
* value can be used to look up the appropriate color by linearly
* interpolating between the two nearest colors in the gradient.
*/
private static void setRadialGradientPaint(RenderQueue rq,
SunGraphics2D sg2d,
RadialGradientPaint paint,
boolean useMask)
{
boolean linear =
(paint.getColorSpace() == ColorSpaceType.LINEAR_RGB);
int cycleMethod = paint.getCycleMethod().ordinal();
float[] fractions = paint.getFractions();
Color[] colors = paint.getColors();
int numStops = colors.length;
int[] pixels = convertToIntArgbPrePixels(colors, linear);
Point2D center = paint.getCenterPoint();
Point2D focus = paint.getFocusPoint();
float radius = paint.getRadius();
// save original (untransformed) center and focus points
double cx = center.getX();
double cy = center.getY();
double fx = focus.getX();
double fy = focus.getY();
// transform from gradient coords to device coords
AffineTransform at = paint.getTransform();
at.preConcatenate(sg2d.transform);
focus = at.transform(focus, focus);
// transform unit circle to gradient coords; we start with the
// unit circle (center=(0,0), focus on positive x-axis, radius=1)
// and then transform into gradient space
at.translate(cx, cy);
at.rotate(fx - cx, fy - cy);
at.scale(radius, radius);
// invert to get mapping from device coords to unit circle
try {
at.invert();
} catch (Exception e) {
at.setToScale(0.0, 0.0);
}
focus = at.transform(focus, focus);
// clamp the focus point so that it does not rest on, or outside
// of, the circumference of the gradient circle
fx = Math.min(focus.getX(), 0.99);
// assert rq.lock.isHeldByCurrentThread();
rq.ensureCapacity(20 + 28 + (numStops*4*2));
RenderBuffer buf = rq.getBuffer();
buf.putInt(SET_RADIAL_GRADIENT_PAINT);
buf.putInt(useMask ? 1 : 0);
buf.putInt(linear ? 1 : 0);
buf.putInt(numStops);
buf.putInt(cycleMethod);
buf.putFloat((float)at.getScaleX());
buf.putFloat((float)at.getShearX());
buf.putFloat((float)at.getTranslateX());
buf.putFloat((float)at.getShearY());
buf.putFloat((float)at.getScaleY());
buf.putFloat((float)at.getTranslateY());
buf.putFloat((float)fx);
buf.put(fractions);
buf.put(pixels);
}
}

View File

@@ -0,0 +1,601 @@
/*
* Copyright (c) 2005, 2013, 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 sun.java2d.pipe;
import java.awt.BasicStroke;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.IllegalPathStateException;
import java.awt.geom.PathIterator;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import sun.java2d.SunGraphics2D;
import sun.java2d.loops.ProcessPath;
import static sun.java2d.pipe.BufferedOpCodes.*;
/**
* Base class for enqueuing rendering operations in a single-threaded
* rendering environment. Instead of each operation being rendered
* immediately by the underlying graphics library, the operation will be
* added to the provided RenderQueue, which will be processed at a later
* time by a single thread.
*
* This class provides implementations of drawLine(), drawRect(), drawPoly(),
* fillRect(), draw(Shape), and fill(Shape), which are useful for a
* hardware-accelerated renderer. The other draw*() and fill*() methods
* simply delegate to draw(Shape) and fill(Shape), respectively.
*/
public abstract class BufferedRenderPipe
implements PixelDrawPipe, PixelFillPipe, ShapeDrawPipe, ParallelogramPipe
{
ParallelogramPipe aapgrampipe = new AAParallelogramPipe();
static final int BYTES_PER_POLY_POINT = 8;
static final int BYTES_PER_SCANLINE = 12;
static final int BYTES_PER_SPAN = 16;
protected RenderQueue rq;
protected RenderBuffer buf;
private BufferedDrawHandler drawHandler;
public BufferedRenderPipe(RenderQueue rq) {
this.rq = rq;
this.buf = rq.getBuffer();
this.drawHandler = new BufferedDrawHandler();
}
public ParallelogramPipe getAAParallelogramPipe() {
return aapgrampipe;
}
/**
* Validates the state in the provided SunGraphics2D object and sets up
* any special resources for this operation (e.g. enabling gradient
* shading).
*/
protected abstract void validateContext(SunGraphics2D sg2d);
protected abstract void validateContextAA(SunGraphics2D sg2d);
public void drawLine(SunGraphics2D sg2d,
int x1, int y1, int x2, int y2)
{
int transx = sg2d.transX;
int transy = sg2d.transY;
rq.lock();
try {
validateContext(sg2d);
rq.ensureCapacity(20);
buf.putInt(DRAW_LINE);
buf.putInt(x1 + transx);
buf.putInt(y1 + transy);
buf.putInt(x2 + transx);
buf.putInt(y2 + transy);
} finally {
rq.unlock();
}
}
public void drawRect(SunGraphics2D sg2d,
int x, int y, int width, int height)
{
rq.lock();
try {
validateContext(sg2d);
rq.ensureCapacity(20);
buf.putInt(DRAW_RECT);
buf.putInt(x + sg2d.transX);
buf.putInt(y + sg2d.transY);
buf.putInt(width);
buf.putInt(height);
} finally {
rq.unlock();
}
}
public void fillRect(SunGraphics2D sg2d,
int x, int y, int width, int height)
{
rq.lock();
try {
validateContext(sg2d);
rq.ensureCapacity(20);
buf.putInt(FILL_RECT);
buf.putInt(x + sg2d.transX);
buf.putInt(y + sg2d.transY);
buf.putInt(width);
buf.putInt(height);
} finally {
rq.unlock();
}
}
public void drawRoundRect(SunGraphics2D sg2d,
int x, int y, int width, int height,
int arcWidth, int arcHeight)
{
draw(sg2d, new RoundRectangle2D.Float(x, y, width, height,
arcWidth, arcHeight));
}
public void fillRoundRect(SunGraphics2D sg2d,
int x, int y, int width, int height,
int arcWidth, int arcHeight)
{
fill(sg2d, new RoundRectangle2D.Float(x, y, width, height,
arcWidth, arcHeight));
}
public void drawOval(SunGraphics2D sg2d,
int x, int y, int width, int height)
{
draw(sg2d, new Ellipse2D.Float(x, y, width, height));
}
public void fillOval(SunGraphics2D sg2d,
int x, int y, int width, int height)
{
fill(sg2d, new Ellipse2D.Float(x, y, width, height));
}
public void drawArc(SunGraphics2D sg2d,
int x, int y, int width, int height,
int startAngle, int arcAngle)
{
draw(sg2d, new Arc2D.Float(x, y, width, height,
startAngle, arcAngle,
Arc2D.OPEN));
}
public void fillArc(SunGraphics2D sg2d,
int x, int y, int width, int height,
int startAngle, int arcAngle)
{
fill(sg2d, new Arc2D.Float(x, y, width, height,
startAngle, arcAngle,
Arc2D.PIE));
}
protected void drawPoly(final SunGraphics2D sg2d,
final int[] xPoints, final int[] yPoints,
final int nPoints, final boolean isClosed)
{
if (xPoints == null || yPoints == null) {
throw new NullPointerException("coordinate array");
}
if (xPoints.length < nPoints || yPoints.length < nPoints) {
throw new ArrayIndexOutOfBoundsException("coordinate array");
}
if (nPoints < 2) {
// render nothing
return;
} else if (nPoints == 2 && !isClosed) {
// render a simple line
drawLine(sg2d, xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
return;
}
rq.lock();
try {
validateContext(sg2d);
int pointBytesRequired = nPoints * BYTES_PER_POLY_POINT;
int totalBytesRequired = 20 + pointBytesRequired;
if (totalBytesRequired <= buf.capacity()) {
if (totalBytesRequired > buf.remaining()) {
// process the queue first and then enqueue the points
rq.flushNow();
}
buf.putInt(DRAW_POLY);
// enqueue parameters
buf.putInt(nPoints);
buf.putInt(isClosed ? 1 : 0);
buf.putInt(sg2d.transX);
buf.putInt(sg2d.transY);
// enqueue the points
buf.put(xPoints, 0, nPoints);
buf.put(yPoints, 0, nPoints);
} else {
// queue is too small to accommodate all points; perform the
// operation directly on the queue flushing thread
rq.flushAndInvokeNow(new Runnable() {
public void run() {
drawPoly(xPoints, yPoints,
nPoints, isClosed,
sg2d.transX, sg2d.transY);
}
});
}
} finally {
rq.unlock();
}
}
protected abstract void drawPoly(int[] xPoints, int[] yPoints,
int nPoints, boolean isClosed,
int transX, int transY);
public void drawPolyline(SunGraphics2D sg2d,
int[] xPoints, int[] yPoints,
int nPoints)
{
drawPoly(sg2d, xPoints, yPoints, nPoints, false);
}
public void drawPolygon(SunGraphics2D sg2d,
int[] xPoints, int[] yPoints,
int nPoints)
{
drawPoly(sg2d, xPoints, yPoints, nPoints, true);
}
public void fillPolygon(SunGraphics2D sg2d,
int[] xPoints, int[] yPoints,
int nPoints)
{
fill(sg2d, new Polygon(xPoints, yPoints, nPoints));
}
private class BufferedDrawHandler
extends ProcessPath.DrawHandler
{
BufferedDrawHandler() {
// these are bogus values; the caller will use validate()
// to ensure that they are set properly prior to each usage
super(0, 0, 0, 0);
}
/**
* This method needs to be called prior to each draw/fillPath()
* operation to ensure the clip bounds are up to date.
*/
void validate(SunGraphics2D sg2d) {
Region clip = sg2d.getCompClip();
setBounds(clip.getLoX(), clip.getLoY(),
clip.getHiX(), clip.getHiY(),
sg2d.strokeHint);
}
/**
* drawPath() support...
*/
public void drawLine(int x1, int y1, int x2, int y2) {
// assert rq.lock.isHeldByCurrentThread();
rq.ensureCapacity(20);
buf.putInt(DRAW_LINE);
buf.putInt(x1);
buf.putInt(y1);
buf.putInt(x2);
buf.putInt(y2);
}
public void drawPixel(int x, int y) {
// assert rq.lock.isHeldByCurrentThread();
rq.ensureCapacity(12);
buf.putInt(DRAW_PIXEL);
buf.putInt(x);
buf.putInt(y);
}
/**
* fillPath() support...
*/
private int scanlineCount;
private int scanlineCountIndex;
private int remainingScanlines;
private void resetFillPath() {
buf.putInt(DRAW_SCANLINES);
scanlineCountIndex = buf.position();
buf.putInt(0);
scanlineCount = 0;
remainingScanlines = buf.remaining() / BYTES_PER_SCANLINE;
}
private void updateScanlineCount() {
buf.putInt(scanlineCountIndex, scanlineCount);
}
/**
* Called from fillPath() to indicate that we are about to
* start issuing drawScanline() calls.
*/
public void startFillPath() {
rq.ensureCapacity(20); // to ensure room for at least a scanline
resetFillPath();
}
public void drawScanline(int x1, int x2, int y) {
if (remainingScanlines == 0) {
updateScanlineCount();
rq.flushNow();
resetFillPath();
}
buf.putInt(x1);
buf.putInt(x2);
buf.putInt(y);
scanlineCount++;
remainingScanlines--;
}
/**
* Called from fillPath() to indicate that we are done
* issuing drawScanline() calls.
*/
public void endFillPath() {
updateScanlineCount();
}
}
protected void drawPath(SunGraphics2D sg2d,
Path2D.Float p2df, int transx, int transy)
{
rq.lock();
try {
validateContext(sg2d);
drawHandler.validate(sg2d);
ProcessPath.drawPath(drawHandler, p2df, transx, transy);
} finally {
rq.unlock();
}
}
protected void fillPath(SunGraphics2D sg2d,
Path2D.Float p2df, int transx, int transy)
{
rq.lock();
try {
validateContext(sg2d);
drawHandler.validate(sg2d);
drawHandler.startFillPath();
ProcessPath.fillPath(drawHandler, p2df, transx, transy);
drawHandler.endFillPath();
} finally {
rq.unlock();
}
}
private native int fillSpans(RenderQueue rq, long buf,
int pos, int limit,
SpanIterator si, long iterator,
int transx, int transy);
protected void fillSpans(SunGraphics2D sg2d, SpanIterator si,
int transx, int transy)
{
rq.lock();
try {
validateContext(sg2d);
rq.ensureCapacity(24); // so that we have room for at least a span
int newpos = fillSpans(rq, buf.getAddress(),
buf.position(), buf.capacity(),
si, si.getNativeIterator(),
transx, transy);
buf.position(newpos);
} finally {
rq.unlock();
}
}
public void fillParallelogram(SunGraphics2D sg2d,
double ux1, double uy1,
double ux2, double uy2,
double x, double y,
double dx1, double dy1,
double dx2, double dy2)
{
rq.lock();
try {
validateContext(sg2d);
rq.ensureCapacity(28);
buf.putInt(FILL_PARALLELOGRAM);
buf.putFloat((float) x);
buf.putFloat((float) y);
buf.putFloat((float) dx1);
buf.putFloat((float) dy1);
buf.putFloat((float) dx2);
buf.putFloat((float) dy2);
} finally {
rq.unlock();
}
}
public void drawParallelogram(SunGraphics2D sg2d,
double ux1, double uy1,
double ux2, double uy2,
double x, double y,
double dx1, double dy1,
double dx2, double dy2,
double lw1, double lw2)
{
rq.lock();
try {
validateContext(sg2d);
rq.ensureCapacity(36);
buf.putInt(DRAW_PARALLELOGRAM);
buf.putFloat((float) x);
buf.putFloat((float) y);
buf.putFloat((float) dx1);
buf.putFloat((float) dy1);
buf.putFloat((float) dx2);
buf.putFloat((float) dy2);
buf.putFloat((float) lw1);
buf.putFloat((float) lw2);
} finally {
rq.unlock();
}
}
private class AAParallelogramPipe implements ParallelogramPipe {
public void fillParallelogram(SunGraphics2D sg2d,
double ux1, double uy1,
double ux2, double uy2,
double x, double y,
double dx1, double dy1,
double dx2, double dy2)
{
rq.lock();
try {
validateContextAA(sg2d);
rq.ensureCapacity(28);
buf.putInt(FILL_AAPARALLELOGRAM);
buf.putFloat((float) x);
buf.putFloat((float) y);
buf.putFloat((float) dx1);
buf.putFloat((float) dy1);
buf.putFloat((float) dx2);
buf.putFloat((float) dy2);
} finally {
rq.unlock();
}
}
public void drawParallelogram(SunGraphics2D sg2d,
double ux1, double uy1,
double ux2, double uy2,
double x, double y,
double dx1, double dy1,
double dx2, double dy2,
double lw1, double lw2)
{
rq.lock();
try {
validateContextAA(sg2d);
rq.ensureCapacity(36);
buf.putInt(DRAW_AAPARALLELOGRAM);
buf.putFloat((float) x);
buf.putFloat((float) y);
buf.putFloat((float) dx1);
buf.putFloat((float) dy1);
buf.putFloat((float) dx2);
buf.putFloat((float) dy2);
buf.putFloat((float) lw1);
buf.putFloat((float) lw2);
} finally {
rq.unlock();
}
}
}
public void draw(SunGraphics2D sg2d, Shape s) {
if (sg2d.strokeState == SunGraphics2D.STROKE_THIN) {
if (s instanceof Polygon) {
if (sg2d.transformState < SunGraphics2D.TRANSFORM_TRANSLATESCALE) {
Polygon p = (Polygon)s;
drawPolygon(sg2d, p.xpoints, p.ypoints, p.npoints);
return;
}
}
Path2D.Float p2df;
int transx, transy;
if (sg2d.transformState <= SunGraphics2D.TRANSFORM_INT_TRANSLATE) {
if (s instanceof Path2D.Float) {
p2df = (Path2D.Float)s;
} else {
p2df = new Path2D.Float(s);
}
transx = sg2d.transX;
transy = sg2d.transY;
} else {
p2df = new Path2D.Float(s, sg2d.transform);
transx = 0;
transy = 0;
}
drawPath(sg2d, p2df, transx, transy);
} else if (sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM) {
ShapeSpanIterator si = LoopPipe.getStrokeSpans(sg2d, s);
try {
fillSpans(sg2d, si, 0, 0);
} finally {
si.dispose();
}
} else {
fill(sg2d, sg2d.stroke.createStrokedShape(s));
}
}
public void fill(SunGraphics2D sg2d, Shape s) {
int transx, transy;
if (sg2d.strokeState == SunGraphics2D.STROKE_THIN) {
// Here we are able to use fillPath() for
// high-quality fills.
Path2D.Float p2df;
if (sg2d.transformState <= SunGraphics2D.TRANSFORM_INT_TRANSLATE) {
if (s instanceof Path2D.Float) {
p2df = (Path2D.Float)s;
} else {
p2df = new Path2D.Float(s);
}
transx = sg2d.transX;
transy = sg2d.transY;
} else {
p2df = new Path2D.Float(s, sg2d.transform);
transx = 0;
transy = 0;
}
fillPath(sg2d, p2df, transx, transy);
return;
}
AffineTransform at;
if (sg2d.transformState <= SunGraphics2D.TRANSFORM_INT_TRANSLATE) {
// Transform (translation) will be done by FillSpans (we could
// delegate to fillPolygon() here, but most hardware accelerated
// libraries cannot handle non-convex polygons, so we will use
// the FillSpans approach by default)
at = null;
transx = sg2d.transX;
transy = sg2d.transY;
} else {
// Transform will be done by the PathIterator
at = sg2d.transform;
transx = transy = 0;
}
ShapeSpanIterator ssi = LoopPipe.getFillSSI(sg2d);
try {
// Subtract transx/y from the SSI clip to match the
// (potentially untranslated) geometry fed to it
Region clip = sg2d.getCompClip();
ssi.setOutputAreaXYXY(clip.getLoX() - transx,
clip.getLoY() - transy,
clip.getHiX() - transx,
clip.getHiY() - transy);
ssi.appendPath(s.getPathIterator(at));
fillSpans(sg2d, ssi, transx, transy);
} finally {
ssi.dispose();
}
}
}

View File

@@ -0,0 +1,170 @@
/*
* Copyright (c) 2007, 2013, 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 sun.java2d.pipe;
import java.awt.AlphaComposite;
import java.awt.Composite;
import sun.font.GlyphList;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import static sun.java2d.pipe.BufferedOpCodes.*;
import java.lang.annotation.Native;
public abstract class BufferedTextPipe extends GlyphListPipe {
@Native private static final int BYTES_PER_GLYPH_IMAGE = 8;
@Native private static final int BYTES_PER_GLYPH_POSITION = 8;
/**
* The following offsets are used to pack the parameters in
* createPackedParams(). (They are also used at the native level when
* unpacking the params.)
*/
@Native private static final int OFFSET_CONTRAST = 8;
@Native private static final int OFFSET_RGBORDER = 2;
@Native private static final int OFFSET_SUBPIXPOS = 1;
@Native private static final int OFFSET_POSITIONS = 0;
/**
* Packs the given parameters into a single int value in order to save
* space on the rendering queue. Note that most of these parameters
* are only used for rendering LCD-optimized text, but conditionalizing
* this work wouldn't make any impact on performance, so we will pack
* those parameters even in the non-LCD case.
*/
private static int createPackedParams(SunGraphics2D sg2d, GlyphList gl) {
return
(((gl.usePositions() ? 1 : 0) << OFFSET_POSITIONS) |
((gl.isSubPixPos() ? 1 : 0) << OFFSET_SUBPIXPOS) |
((gl.isRGBOrder() ? 1 : 0) << OFFSET_RGBORDER ) |
((sg2d.lcdTextContrast & 0xff) << OFFSET_CONTRAST ));
}
protected final RenderQueue rq;
protected BufferedTextPipe(RenderQueue rq) {
this.rq = rq;
}
@Override
protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) {
/*
* The native drawGlyphList() only works with two composite types:
* - CompositeType.SrcOver (with any extra alpha), or
* - CompositeType.Xor
*/
Composite comp = sg2d.composite;
if (comp == AlphaComposite.Src) {
/*
* In addition to the composite types listed above, the logic
* in OGL/D3DSurfaceData.validatePipe() allows for
* CompositeType.SrcNoEa, but only in the presence of an opaque
* color. If we reach this case, we know the color is opaque,
* and therefore SrcNoEa is the same as SrcOverNoEa, so we
* override the composite here.
*/
comp = AlphaComposite.SrcOver;
}
rq.lock();
try {
validateContext(sg2d, comp);
enqueueGlyphList(sg2d, gl);
} finally {
rq.unlock();
}
}
private void enqueueGlyphList(final SunGraphics2D sg2d,
final GlyphList gl)
{
// assert rq.lock.isHeldByCurrentThread();
RenderBuffer buf = rq.getBuffer();
final int totalGlyphs = gl.getNumGlyphs();
int glyphBytesRequired = totalGlyphs * BYTES_PER_GLYPH_IMAGE;
int posBytesRequired =
gl.usePositions() ? totalGlyphs * BYTES_PER_GLYPH_POSITION : 0;
int totalBytesRequired = 24 + glyphBytesRequired + posBytesRequired;
final long[] images = gl.getImages();
final float glyphListOrigX = gl.getX() + 0.5f;
final float glyphListOrigY = gl.getY() + 0.5f;
// make sure the RenderQueue keeps a hard reference to the FontStrike
// so that the associated glyph images are not disposed while enqueued
rq.addReference(gl.getStrike());
if (totalBytesRequired <= buf.capacity()) {
if (totalBytesRequired > buf.remaining()) {
// process the queue first and then enqueue the glyphs
rq.flushNow();
}
rq.ensureAlignment(20);
buf.putInt(DRAW_GLYPH_LIST);
// enqueue parameters
buf.putInt(totalGlyphs);
buf.putInt(createPackedParams(sg2d, gl));
buf.putFloat(glyphListOrigX);
buf.putFloat(glyphListOrigY);
// now enqueue glyph information
buf.put(images, 0, totalGlyphs);
if (gl.usePositions()) {
float[] positions = gl.getPositions();
buf.put(positions, 0, 2*totalGlyphs);
}
} else {
// queue is too small to accommodate glyphs; perform
// the operation directly on the queue flushing thread
rq.flushAndInvokeNow(new Runnable() {
public void run() {
drawGlyphList(totalGlyphs, gl.usePositions(),
gl.isSubPixPos(), gl.isRGBOrder(),
sg2d.lcdTextContrast,
glyphListOrigX, glyphListOrigY,
images, gl.getPositions());
}
});
}
}
/**
* Called as a separate Runnable when the operation is too large to fit
* on the RenderQueue. The OGL/D3D pipelines each have their own (small)
* native implementation of this method.
*/
protected abstract void drawGlyphList(int numGlyphs, boolean usePositions,
boolean subPixPos, boolean rgbOrder,
int lcdContrast,
float glOrigX, float glOrigY,
long[] images, float[] positions);
/**
* Validates the state in the provided SunGraphics2D object.
*/
protected abstract void validateContext(SunGraphics2D sg2d,
Composite comp);
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 1997, 2007, 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 sun.java2d.pipe;
import java.awt.Rectangle;
import java.awt.Shape;
import sun.java2d.SunGraphics2D;
/**
* This interface defines the set of calls used by a rendering pipeline
* based on an AATileGenerator to communicate the alpha tile sequence
* to the output (compositing) stages of the pipeline.
*/
public interface CompositePipe {
public Object startSequence(SunGraphics2D sg, Shape s, Rectangle dev,
int[] abox);
public boolean needTile(Object context, int x, int y, int w, int h);
public void renderPathTile(Object context,
byte[] atile, int offset, int tilesize,
int x, int y, int w, int h);
public void skipTile(Object context, int x, int y);
public void endSequence(Object context);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2001, 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 sun.java2d.pipe;
import java.awt.Color;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ImageObserver;
import java.awt.geom.AffineTransform;
import sun.java2d.SunGraphics2D;
/**
* This interface defines the set of calls that pipeline objects
* can use to pass on responsibility for performing various
* image copy commands.
* There are 3 types of image copies handled by this class:
* - copyImage: These methods simply copy the pixels
* from the src to dest, either from (0, 0) (implicit)
* or from a given (sx, sy) location.
* - scaleImage: These methods copy from src to dest while
* scaling the source image. The src and dest rectangles
* are used to specify the scale.
* - copyImageBg: These methods behave the same as the
* copyImage methods except they substitute the given
* background color for any transparent pixels.
* - scaleImageBg: These methods behave the same as the
* scaleImage methods except they substitute the given
* background color for any transparent pixels.
* - transformImage....
*/
public interface DrawImagePipe {
public boolean copyImage(SunGraphics2D sg, Image img,
int x, int y,
Color bgColor,
ImageObserver observer);
public boolean copyImage(SunGraphics2D sg, Image img,
int dx, int dy, int sx, int sy, int w, int h,
Color bgColor,
ImageObserver observer);
public boolean scaleImage(SunGraphics2D sg, Image img, int x, int y,
int width, int height,
Color bgColor,
ImageObserver observer);
public boolean scaleImage(SunGraphics2D sg, Image img,
int dx1, int dy1, int dx2, int dy2,
int sx1, int sy1, int sx2, int sy2,
Color bgColor,
ImageObserver observer);
public boolean transformImage(SunGraphics2D sg, Image img,
AffineTransform atfm,
ImageObserver observer);
public void transformImage(SunGraphics2D sg, BufferedImage img,
BufferedImageOp op, int x, int y);
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright (c) 1997, 2002, 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 sun.java2d.pipe;
import java.awt.AlphaComposite;
import java.awt.CompositeContext;
import java.awt.PaintContext;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.RenderingHints;
import java.awt.image.ColorModel;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import sun.awt.image.BufImgSurfaceData;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.loops.Blit;
import sun.java2d.loops.MaskBlit;
import sun.java2d.loops.CompositeType;
public class GeneralCompositePipe implements CompositePipe {
class TileContext {
SunGraphics2D sunG2D;
PaintContext paintCtxt;
CompositeContext compCtxt;
ColorModel compModel;
Object pipeState;
public TileContext(SunGraphics2D sg, PaintContext pCtx,
CompositeContext cCtx, ColorModel cModel) {
sunG2D = sg;
paintCtxt = pCtx;
compCtxt = cCtx;
compModel = cModel;
}
}
public Object startSequence(SunGraphics2D sg, Shape s, Rectangle devR,
int[] abox) {
RenderingHints hints = sg.getRenderingHints();
ColorModel model = sg.getDeviceColorModel();
PaintContext paintContext =
sg.paint.createContext(model, devR, s.getBounds2D(),
sg.cloneTransform(),
hints);
CompositeContext compositeContext =
sg.composite.createContext(paintContext.getColorModel(), model,
hints);
return new TileContext(sg, paintContext, compositeContext, model);
}
public boolean needTile(Object ctx, int x, int y, int w, int h) {
return true;
}
/**
* GeneralCompositePipe.renderPathTile works with custom composite operator
* provided by an application
*/
public void renderPathTile(Object ctx,
byte[] atile, int offset, int tilesize,
int x, int y, int w, int h) {
TileContext context = (TileContext) ctx;
PaintContext paintCtxt = context.paintCtxt;
CompositeContext compCtxt = context.compCtxt;
SunGraphics2D sg = context.sunG2D;
Raster srcRaster = paintCtxt.getRaster(x, y, w, h);
ColorModel paintModel = paintCtxt.getColorModel();
Raster dstRaster;
Raster dstIn;
WritableRaster dstOut;
SurfaceData sd = sg.getSurfaceData();
dstRaster = sd.getRaster(x, y, w, h);
if (dstRaster instanceof WritableRaster && atile == null) {
dstOut = (WritableRaster) dstRaster;
dstOut = dstOut.createWritableChild(x, y, w, h, 0, 0, null);
dstIn = dstOut;
} else {
dstIn = dstRaster.createChild(x, y, w, h, 0, 0, null);
dstOut = dstIn.createCompatibleWritableRaster();
}
compCtxt.compose(srcRaster, dstIn, dstOut);
if (dstRaster != dstOut && dstOut.getParent() != dstRaster) {
if (dstRaster instanceof WritableRaster && atile == null) {
((WritableRaster) dstRaster).setDataElements(x, y, dstOut);
} else {
ColorModel cm = sg.getDeviceColorModel();
BufferedImage resImg =
new BufferedImage(cm, dstOut,
cm.isAlphaPremultiplied(),
null);
SurfaceData resData = BufImgSurfaceData.createData(resImg);
if (atile == null) {
Blit blit = Blit.getFromCache(resData.getSurfaceType(),
CompositeType.SrcNoEa,
sd.getSurfaceType());
blit.Blit(resData, sd, AlphaComposite.Src, null,
0, 0, x, y, w, h);
} else {
MaskBlit blit = MaskBlit.getFromCache(resData.getSurfaceType(),
CompositeType.SrcNoEa,
sd.getSurfaceType());
blit.MaskBlit(resData, sd, AlphaComposite.Src, null,
0, 0, x, y, w, h,
atile, offset, tilesize);
}
}
}
}
public void skipTile(Object ctx, int x, int y) {
return;
}
public void endSequence(Object ctx) {
TileContext context = (TileContext) ctx;
if (context.paintCtxt != null) {
context.paintCtxt.dispose();
}
if (context.compCtxt != null) {
context.compCtxt.dispose();
}
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2005, 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 sun.java2d.pipe;
import java.awt.font.GlyphVector;
import sun.awt.SunHints;
import sun.java2d.SunGraphics2D;
import sun.font.GlyphList;
/**
* A delegate pipe of SG2D which implements redispatching of
* for the src mode loops in the drawGlyphVector case where
* the installed loop may not match the glyphvector.
*/
public abstract class GlyphListLoopPipe extends GlyphListPipe
implements LoopBasedPipe
{
protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl,
int aaHint) {
switch (aaHint) {
case SunHints.INTVAL_TEXT_ANTIALIAS_OFF:
sg2d.loops.drawGlyphListLoop.
DrawGlyphList(sg2d, sg2d.surfaceData, gl);
return;
case SunHints.INTVAL_TEXT_ANTIALIAS_ON:
sg2d.loops.drawGlyphListAALoop.
DrawGlyphListAA(sg2d, sg2d.surfaceData, gl);
return;
case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
sg2d.loops.drawGlyphListLCDLoop.
DrawGlyphListLCD(sg2d,sg2d.surfaceData, gl);
return;
}
}
}

View File

@@ -0,0 +1,147 @@
/*
* Copyright (c) 2000, 2011, 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 sun.java2d.pipe;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.TextLayout;
import sun.awt.SunHints;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.font.GlyphList;
import sun.java2d.loops.FontInfo;
/**
* A delegate pipe of SG2D for drawing text.
*/
public abstract class GlyphListPipe implements TextPipe {
public void drawString(SunGraphics2D sg2d, String s,
double x, double y)
{
FontInfo info = sg2d.getFontInfo();
if (info.pixelHeight > OutlineTextRenderer.THRESHHOLD) {
SurfaceData.outlineTextRenderer.drawString(sg2d, s, x, y);
return;
}
float devx, devy;
if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {
double origin[] = {x + info.originX, y + info.originY};
sg2d.transform.transform(origin, 0, origin, 0, 1);
devx = (float)origin[0];
devy = (float)origin[1];
} else {
devx = (float)(x + info.originX + sg2d.transX);
devy = (float)(y + info.originY + sg2d.transY);
}
/* setFromString returns false if shaping is needed, and we then back
* off to a TextLayout. Such text may benefit slightly from a lower
* overhead in this approach over the approach in previous releases.
*/
GlyphList gl = GlyphList.getInstance();
if (gl.setFromString(info, s, devx, devy)) {
drawGlyphList(sg2d, gl);
gl.dispose();
} else {
gl.dispose(); // release this asap.
TextLayout tl = new TextLayout(s, sg2d.getFont(),
sg2d.getFontRenderContext());
tl.draw(sg2d, (float)x, (float)y);
}
}
public void drawChars(SunGraphics2D sg2d,
char data[], int offset, int length,
int ix, int iy)
{
FontInfo info = sg2d.getFontInfo();
float x, y;
if (info.pixelHeight > OutlineTextRenderer.THRESHHOLD) {
SurfaceData.outlineTextRenderer.drawChars(
sg2d, data, offset, length, ix, iy);
return;
}
if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {
double origin[] = {ix + info.originX, iy + info.originY};
sg2d.transform.transform(origin, 0, origin, 0, 1);
x = (float) origin[0];
y = (float) origin[1];
} else {
x = ix + info.originX + sg2d.transX;
y = iy + info.originY + sg2d.transY;
}
GlyphList gl = GlyphList.getInstance();
if (gl.setFromChars(info, data, offset, length, x, y)) {
drawGlyphList(sg2d, gl);
gl.dispose();
} else {
gl.dispose(); // release this asap.
TextLayout tl = new TextLayout(new String(data, offset, length),
sg2d.getFont(),
sg2d.getFontRenderContext());
tl.draw(sg2d, ix, iy);
}
}
public void drawGlyphVector(SunGraphics2D sg2d, GlyphVector gv,
float x, float y)
{
FontRenderContext frc = gv.getFontRenderContext();
FontInfo info = sg2d.getGVFontInfo(gv.getFont(), frc);
if (info.pixelHeight > OutlineTextRenderer.THRESHHOLD) {
SurfaceData.outlineTextRenderer.drawGlyphVector(sg2d, gv, x, y);
return;
}
if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {
double origin[] = {x, y};
sg2d.transform.transform(origin, 0, origin, 0, 1);
x = (float) origin[0];
y = (float) origin[1];
} else {
x += sg2d.transX; // don't use the glyph info origin, already in gv.
y += sg2d.transY;
}
GlyphList gl = GlyphList.getInstance();
gl.setFromGlyphVector(info, gv, x, y);
drawGlyphList(sg2d, gl, info.aaHint);
gl.dispose();
}
protected abstract void drawGlyphList(SunGraphics2D sg2d, GlyphList gl);
protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl,
int aaHint) {
drawGlyphList(sg2d, gl);
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2005, 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 sun.java2d.pipe;
import java.awt.font.GlyphVector;
import sun.java2d.SunGraphics2D;
import sun.font.GlyphList;
import static sun.awt.SunHints.*;
/**
* A delegate pipe of SG2D for drawing LCD text with
* a solid source colour to an opaque destination.
*/
public class LCDTextRenderer extends GlyphListLoopPipe {
protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) {
sg2d.loops.drawGlyphListLCDLoop.
DrawGlyphListLCD(sg2d, sg2d.surfaceData, gl);
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2009, 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 sun.java2d.pipe;
/**
* This is a marker interface used by Pipes that need RenderLoops.
* RenderLoops are validated in SurfaceData when a pipe is recognised to
* implement this interface.
*
* @author Mario Torre <neugens@aicas.com>
*/
public interface LoopBasedPipe {
}

View File

@@ -0,0 +1,377 @@
/*
* Copyright (c) 1999, 2011, 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 sun.java2d.pipe;
import java.awt.Font;
import java.awt.Shape;
import java.awt.BasicStroke;
import java.awt.Polygon;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.geom.RoundRectangle2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Arc2D;
import java.awt.geom.IllegalPathStateException;
import java.awt.geom.Path2D;
import java.awt.font.GlyphVector;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.loops.FontInfo;
import sun.java2d.loops.DrawPolygons;
import sun.java2d.loops.FillParallelogram;
import sun.java2d.loops.DrawParallelogram;
import sun.awt.SunHints;
public class LoopPipe
implements PixelDrawPipe,
PixelFillPipe,
ParallelogramPipe,
ShapeDrawPipe,
LoopBasedPipe
{
final static RenderingEngine RenderEngine = RenderingEngine.getInstance();
public void drawLine(SunGraphics2D sg2d,
int x1, int y1, int x2, int y2)
{
int tX = sg2d.transX;
int tY = sg2d.transY;
sg2d.loops.drawLineLoop.DrawLine(sg2d, sg2d.getSurfaceData(),
x1 + tX, y1 + tY,
x2 + tX, y2 + tY);
}
public void drawRect(SunGraphics2D sg2d,
int x, int y, int width, int height)
{
sg2d.loops.drawRectLoop.DrawRect(sg2d, sg2d.getSurfaceData(),
x + sg2d.transX,
y + sg2d.transY,
width, height);
}
public void drawRoundRect(SunGraphics2D sg2d,
int x, int y, int width, int height,
int arcWidth, int arcHeight)
{
sg2d.shapepipe.draw(sg2d,
new RoundRectangle2D.Float(x, y, width, height,
arcWidth, arcHeight));
}
public void drawOval(SunGraphics2D sg2d,
int x, int y, int width, int height)
{
sg2d.shapepipe.draw(sg2d, new Ellipse2D.Float(x, y, width, height));
}
public void drawArc(SunGraphics2D sg2d,
int x, int y, int width, int height,
int startAngle, int arcAngle)
{
sg2d.shapepipe.draw(sg2d, new Arc2D.Float(x, y, width, height,
startAngle, arcAngle,
Arc2D.OPEN));
}
public void drawPolyline(SunGraphics2D sg2d,
int xPoints[], int yPoints[],
int nPoints)
{
int nPointsArray[] = { nPoints };
sg2d.loops.drawPolygonsLoop.DrawPolygons(sg2d, sg2d.getSurfaceData(),
xPoints, yPoints,
nPointsArray, 1,
sg2d.transX, sg2d.transY,
false);
}
public void drawPolygon(SunGraphics2D sg2d,
int xPoints[], int yPoints[],
int nPoints)
{
int nPointsArray[] = { nPoints };
sg2d.loops.drawPolygonsLoop.DrawPolygons(sg2d, sg2d.getSurfaceData(),
xPoints, yPoints,
nPointsArray, 1,
sg2d.transX, sg2d.transY,
true);
}
public void fillRect(SunGraphics2D sg2d,
int x, int y, int width, int height)
{
sg2d.loops.fillRectLoop.FillRect(sg2d, sg2d.getSurfaceData(),
x + sg2d.transX,
y + sg2d.transY,
width, height);
}
public void fillRoundRect(SunGraphics2D sg2d,
int x, int y, int width, int height,
int arcWidth, int arcHeight)
{
sg2d.shapepipe.fill(sg2d,
new RoundRectangle2D.Float(x, y, width, height,
arcWidth, arcHeight));
}
public void fillOval(SunGraphics2D sg2d,
int x, int y, int width, int height)
{
sg2d.shapepipe.fill(sg2d, new Ellipse2D.Float(x, y, width, height));
}
public void fillArc(SunGraphics2D sg2d,
int x, int y, int width, int height,
int startAngle, int arcAngle)
{
sg2d.shapepipe.fill(sg2d, new Arc2D.Float(x, y, width, height,
startAngle, arcAngle,
Arc2D.PIE));
}
public void fillPolygon(SunGraphics2D sg2d,
int xPoints[], int yPoints[],
int nPoints)
{
ShapeSpanIterator sr = getFillSSI(sg2d);
try {
sr.setOutputArea(sg2d.getCompClip());
sr.appendPoly(xPoints, yPoints, nPoints, sg2d.transX, sg2d.transY);
fillSpans(sg2d, sr);
} finally {
sr.dispose();
}
}
public void draw(SunGraphics2D sg2d, Shape s) {
if (sg2d.strokeState == SunGraphics2D.STROKE_THIN) {
Path2D.Float p2df;
int transX;
int transY;
if (sg2d.transformState <= SunGraphics2D.TRANSFORM_INT_TRANSLATE) {
if (s instanceof Path2D.Float) {
p2df = (Path2D.Float)s;
} else {
p2df = new Path2D.Float(s);
}
transX = sg2d.transX;
transY = sg2d.transY;
} else {
p2df = new Path2D.Float(s, sg2d.transform);
transX = 0;
transY = 0;
}
sg2d.loops.drawPathLoop.DrawPath(sg2d, sg2d.getSurfaceData(),
transX, transY, p2df);
return;
}
if (sg2d.strokeState == SunGraphics2D.STROKE_CUSTOM) {
fill(sg2d, sg2d.stroke.createStrokedShape(s));
return;
}
ShapeSpanIterator sr = getStrokeSpans(sg2d, s);
try {
fillSpans(sg2d, sr);
} finally {
sr.dispose();
}
}
/**
* Return a ShapeSpanIterator instance that normalizes as
* appropriate for a fill operation as per the settings in
* the specified SunGraphics2D object.
*
* The ShapeSpanIterator will be newly constructed and ready
* to start taking in geometry.
*
* Note that the caller is responsible for calling dispose()
* on the returned ShapeSpanIterator inside a try/finally block:
* <pre>
* ShapeSpanIterator ssi = LoopPipe.getFillSSI(sg2d);
* try {
* ssi.setOutputArea(clip);
* ssi.appendPath(...); // or appendPoly
* // iterate the spans from ssi and operate on them
* } finally {
* ssi.dispose();
* }
* </pre>
*/
public static ShapeSpanIterator getFillSSI(SunGraphics2D sg2d) {
boolean adjust = ((sg2d.stroke instanceof BasicStroke) &&
sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE);
return new ShapeSpanIterator(adjust);
}
/*
* Return a ShapeSpanIterator ready to iterate the spans of the wide
* outline of Shape s using the attributes of the SunGraphics2D
* object.
*
* The ShapeSpanIterator returned will be fully constructed
* and filled with the geometry from the Shape widened by the
* appropriate BasicStroke and normalization parameters taken
* from the SunGraphics2D object and be ready to start returning
* spans.
*
* Note that the caller is responsible for calling dispose()
* on the returned ShapeSpanIterator inside a try/finally block.
* <pre>
* ShapeSpanIterator ssi = LoopPipe.getStrokeSpans(sg2d, s);
* try {
* // iterate the spans from ssi and operate on them
* } finally {
* ssi.dispose();
* }
* </pre>
*
* REMIND: This should return a SpanIterator interface object
* but the caller needs to dispose() the object and that method
* is only on ShapeSpanIterator.
* TODO: Add a dispose() method to the SpanIterator interface.
*/
public static ShapeSpanIterator getStrokeSpans(SunGraphics2D sg2d,
Shape s)
{
ShapeSpanIterator sr = new ShapeSpanIterator(false);
try {
sr.setOutputArea(sg2d.getCompClip());
sr.setRule(PathIterator.WIND_NON_ZERO);
BasicStroke bs = (BasicStroke) sg2d.stroke;
boolean thin = (sg2d.strokeState <= SunGraphics2D.STROKE_THINDASHED);
boolean normalize =
(sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE);
RenderEngine.strokeTo(s,
sg2d.transform, bs,
thin, normalize, false, sr);
} catch (Throwable t) {
sr.dispose();
sr = null;
throw new InternalError("Unable to Stroke shape ("+
t.getMessage()+")", t);
}
return sr;
}
public void fill(SunGraphics2D sg2d, Shape s) {
if (sg2d.strokeState == SunGraphics2D.STROKE_THIN) {
Path2D.Float p2df;
int transX;
int transY;
if (sg2d.transformState <= SunGraphics2D.TRANSFORM_INT_TRANSLATE) {
if (s instanceof Path2D.Float) {
p2df = (Path2D.Float)s;
} else {
p2df = new Path2D.Float(s);
}
transX = sg2d.transX;
transY = sg2d.transY;
} else {
p2df = new Path2D.Float(s, sg2d.transform);
transX = 0;
transY = 0;
}
sg2d.loops.fillPathLoop.FillPath(sg2d, sg2d.getSurfaceData(),
transX, transY, p2df);
return;
}
ShapeSpanIterator sr = getFillSSI(sg2d);
try {
sr.setOutputArea(sg2d.getCompClip());
AffineTransform at =
((sg2d.transformState == SunGraphics2D.TRANSFORM_ISIDENT)
? null
: sg2d.transform);
sr.appendPath(s.getPathIterator(at));
fillSpans(sg2d, sr);
} finally {
sr.dispose();
}
}
private static void fillSpans(SunGraphics2D sg2d, SpanIterator si) {
// REMIND: Eventually, the plan is that it will not be possible for
// fs to be null since the FillSpans loop will be the fundamental
// loop implemented for any destination type...
if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) {
si = sg2d.clipRegion.filter(si);
// REMIND: Region.filter produces a Java-only iterator
// with no native counterpart...
} else {
sun.java2d.loops.FillSpans fs = sg2d.loops.fillSpansLoop;
if (fs != null) {
fs.FillSpans(sg2d, sg2d.getSurfaceData(), si);
return;
}
}
int spanbox[] = new int[4];
SurfaceData sd = sg2d.getSurfaceData();
while (si.nextSpan(spanbox)) {
int x = spanbox[0];
int y = spanbox[1];
int w = spanbox[2] - x;
int h = spanbox[3] - y;
sg2d.loops.fillRectLoop.FillRect(sg2d, sd, x, y, w, h);
}
}
public void fillParallelogram(SunGraphics2D sg2d,
double ux1, double uy1,
double ux2, double uy2,
double x, double y,
double dx1, double dy1,
double dx2, double dy2)
{
FillParallelogram fp = sg2d.loops.fillParallelogramLoop;
fp.FillParallelogram(sg2d, sg2d.getSurfaceData(),
x, y, dx1, dy1, dx2, dy2);
}
public void drawParallelogram(SunGraphics2D sg2d,
double ux1, double uy1,
double ux2, double uy2,
double x, double y,
double dx1, double dy1,
double dx2, double dy2,
double lw1, double lw2)
{
DrawParallelogram dp = sg2d.loops.drawParallelogramLoop;
dp.DrawParallelogram(sg2d, sg2d.getSurfaceData(),
x, y, dx1, dy1, dx2, dy2, lw1, lw2);
}
}

View File

@@ -0,0 +1,155 @@
/*
* Copyright (c) 1997, 2003, 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 sun.java2d.pipe;
import java.awt.Color;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ImageObserver;
import java.awt.font.GlyphVector;
import sun.java2d.SunGraphics2D;
/**
* This is a class that implements all of the basic pixel rendering
* methods as NOPs.
* This class is useful for installing as the pipeline when the
* clip is determined to be empty or when the composite operation is
* determined to have no effect (i.e. rule == SRC_OVER, extraAlpha == 0.0).
*/
public class NullPipe
implements PixelDrawPipe, PixelFillPipe, ShapeDrawPipe, TextPipe,
DrawImagePipe
{
public void drawLine(SunGraphics2D sg,
int x1, int y1, int x2, int y2) {
}
public void drawRect(SunGraphics2D sg,
int x, int y, int width, int height) {
}
public void fillRect(SunGraphics2D sg,
int x, int y, int width, int height) {
}
public void drawRoundRect(SunGraphics2D sg,
int x, int y, int width, int height,
int arcWidth, int arcHeight) {
}
public void fillRoundRect(SunGraphics2D sg,
int x, int y, int width, int height,
int arcWidth, int arcHeight) {
}
public void drawOval(SunGraphics2D sg,
int x, int y, int width, int height) {
}
public void fillOval(SunGraphics2D sg,
int x, int y, int width, int height) {
}
public void drawArc(SunGraphics2D sg,
int x, int y, int width, int height,
int startAngle, int arcAngle) {
}
public void fillArc(SunGraphics2D sg,
int x, int y, int width, int height,
int startAngle, int arcAngle) {
}
public void drawPolyline(SunGraphics2D sg,
int xPoints[], int yPoints[],
int nPoints) {
}
public void drawPolygon(SunGraphics2D sg,
int xPoints[], int yPoints[],
int nPoints) {
}
public void fillPolygon(SunGraphics2D sg,
int xPoints[], int yPoints[],
int nPoints) {
}
public void draw(SunGraphics2D sg, Shape s) {
}
public void fill(SunGraphics2D sg, Shape s) {
}
public void drawString(SunGraphics2D sg, String s, double x, double y) {
}
public void drawGlyphVector(SunGraphics2D sg, GlyphVector g,
float x, float y) {
}
public void drawChars(SunGraphics2D sg,
char data[], int offset, int length,
int x, int y) {
}
public boolean copyImage(SunGraphics2D sg, Image img,
int x, int y,
Color bgColor,
ImageObserver observer) {
return false;
}
public boolean copyImage(SunGraphics2D sg, Image img,
int dx, int dy, int sx, int sy, int w, int h,
Color bgColor,
ImageObserver observer) {
return false;
}
public boolean scaleImage(SunGraphics2D sg, Image img, int x, int y,
int w, int h,
Color bgColor,
ImageObserver observer) {
return false;
}
public boolean scaleImage(SunGraphics2D sg, Image img,
int dx1, int dy1, int dx2, int dy2,
int sx1, int sy1, int sx2, int sy2,
Color bgColor,
ImageObserver observer) {
return false;
}
public boolean transformImage(SunGraphics2D sg, Image img,
AffineTransform atfm,
ImageObserver observer) {
return false;
}
public void transformImage(SunGraphics2D sg, BufferedImage img,
BufferedImageOp op, int x, int y) {
}
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright (c) 2000, 2005, 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 sun.java2d.pipe;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.TextLayout;
import sun.java2d.SunGraphics2D;
import sun.font.GlyphList;
import sun.awt.SunHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.font.TextLayout;
/**
* A delegate pipe of SG2D for drawing "large" text with
* a solid source colour to an opaque destination.
* The text is drawn as a filled outline.
* Since the developer is not explicitly requesting this way of
* rendering, this should not be used if the current paint is not
* a solid colour.
*
* If text anti-aliasing is requested by the application, and
* filling path, an anti-aliasing fill pipe needs to
* be invoked.
* This involves making some of the same decisions as in the
* validatePipe call, which may be in a SurfaceData subclass, so
* its awkward to always ensure that the correct pipe is used.
* The easiest thing, rather than reproducing much of that logic
* is to call validatePipe() which works but is expensive, although
* probably not compared to the cost of filling the path.
* Note if AA hint is ON but text-AA hint is OFF this logic will
* produce AA text which perhaps isn't what the user expected.
* Note that the glyphvector obeys its FRC, not the G2D.
*/
public class OutlineTextRenderer implements TextPipe {
// Text with a height greater than the threshhold will be
// drawn via this pipe.
public static final int THRESHHOLD = 100;
public void drawChars(SunGraphics2D g2d,
char data[], int offset, int length,
int x, int y) {
String s = new String(data, offset, length);
drawString(g2d, s, x, y);
}
public void drawString(SunGraphics2D g2d, String str, double x, double y) {
if ("".equals(str)) {
return; // TextLayout constructor throws IAE on "".
}
TextLayout tl = new TextLayout(str, g2d.getFont(),
g2d.getFontRenderContext());
Shape s = tl.getOutline(AffineTransform.getTranslateInstance(x, y));
int textAAHint = g2d.getFontInfo().aaHint;
int prevaaHint = - 1;
if (textAAHint != SunHints.INTVAL_TEXT_ANTIALIAS_OFF &&
g2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) {
prevaaHint = g2d.antialiasHint;
g2d.antialiasHint = SunHints.INTVAL_ANTIALIAS_ON;
g2d.validatePipe();
} else if (textAAHint == SunHints.INTVAL_TEXT_ANTIALIAS_OFF
&& g2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_OFF) {
prevaaHint = g2d.antialiasHint;
g2d.antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF;
g2d.validatePipe();
}
g2d.fill(s);
if (prevaaHint != -1) {
g2d.antialiasHint = prevaaHint;
g2d.validatePipe();
}
}
public void drawGlyphVector(SunGraphics2D g2d, GlyphVector gv,
float x, float y) {
Shape s = gv.getOutline(x, y);
int prevaaHint = - 1;
FontRenderContext frc = gv.getFontRenderContext();
boolean aa = frc.isAntiAliased();
/* aa will be true if any AA mode has been specified.
* ie for LCD and 'gasp' modes too.
* We will check if 'gasp' has resolved AA to be "OFF", and
* in all other cases (ie AA ON and all LCD modes) use AA outlines.
*/
if (aa) {
if (g2d.getGVFontInfo(gv.getFont(), frc).aaHint ==
SunHints.INTVAL_TEXT_ANTIALIAS_OFF) {
aa = false;
}
}
if (aa && g2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) {
prevaaHint = g2d.antialiasHint;
g2d.antialiasHint = SunHints.INTVAL_ANTIALIAS_ON;
g2d.validatePipe();
} else if (!aa && g2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_OFF) {
prevaaHint = g2d.antialiasHint;
g2d.antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF;
g2d.validatePipe();
}
g2d.fill(s);
if (prevaaHint != -1) {
g2d.antialiasHint = prevaaHint;
g2d.validatePipe();
}
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2008, 2012, 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 sun.java2d.pipe;
import sun.java2d.SunGraphics2D;
/**
* This interface defines the set of calls that pipeline objects
* can use to pass on responsibility for drawing arbitrary
* parallelogram shapes.
* Six floating point numbers are provided and the parallelogram
* is defined as the quadrilateral with the following vertices:
* <pre>
* origin: (x, y)
* => (x+dx1, y+dy1)
* => (x+dx1+dx2, y+dy1+dy2)
* => (x+dx2, y+dy2)
* => origin
* </pre>
* The four u[xy][12] parameters are the unsorted extreme coordinates
* of the primitive in user space. They may have been generated by a
* line or a rectangle so they could have u[xy]2 < u[xy]1 in some cases.
* They should be sorted before calculating the bounds of the original
* primitive (such as for calculating the user space bounds for the
* Paint.createContext() method).
*/
public interface ParallelogramPipe {
public void fillParallelogram(SunGraphics2D sg,
double ux1, double uy1,
double ux2, double uy2,
double x, double y,
double dx1, double dy1,
double dx2, double dy2);
/**
* Draw a Parallelogram with the indicated line widths
* assuming a standard BasicStroke with MITER joins.
* lw1 specifies the width of the stroke along the dx1,dy1
* vector and lw2 specifies the width of the stroke along
* the dx2,dy2 vector.
* This is equivalent to outsetting the indicated
* parallelogram by lw/2 pixels, then insetting the
* same parallelogram by lw/2 pixels and filling the
* difference between the outer and inner parallelograms.
*/
public void drawParallelogram(SunGraphics2D sg,
double ux1, double uy1,
double ux2, double uy2,
double x, double y,
double dx1, double dy1,
double dx2, double dy2,
double lw1, double lw2);
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 1997, 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 sun.java2d.pipe;
import sun.java2d.SunGraphics2D;
/**
* This interface defines the set of calls that pipeline objects
* can use to pass on responsibility for drawing various basic
* geometric figures defined by explicit integer coordinates.
* Typically this interface will be used for communication when
* the coordinates of the rendering have been narrowed down to
* actual device pixels, or for communication of untransformed
* coordinates when the coordinates were specified using integers.
* This interface does not cover all of the rendering calls that
* are possible in Graphics since many of the rendering calls can
* be transformed into one or more variants of these calls.
*/
public interface PixelDrawPipe {
public void drawLine(SunGraphics2D sg,
int x1, int y1, int x2, int y2);
public void drawRect(SunGraphics2D sg,
int x, int y, int width, int height);
public void drawRoundRect(SunGraphics2D sg,
int x, int y, int width, int height,
int arcWidth, int arcHeight);
public void drawOval(SunGraphics2D sg,
int x, int y, int width, int height);
public void drawArc(SunGraphics2D sg,
int x, int y, int width, int height,
int startAngle, int arcAngle);
public void drawPolyline(SunGraphics2D sg,
int xPoints[], int yPoints[],
int nPoints);
public void drawPolygon(SunGraphics2D sg,
int xPoints[], int yPoints[],
int nPoints);
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 1997, 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 sun.java2d.pipe;
import sun.java2d.SunGraphics2D;
/**
* This interface defines the set of calls that pipeline objects
* can use to pass on responsibility for filling various basic
* geometric figures defined by explicit integer coordinates.
* Typically this interface will be used for communication when
* the coordinates of the rendering have been narrowed down to
* actual device pixels, or for communication of untransformed
* coordinates when the coordinates were specified using integers.
* This interface does not cover all of the rendering calls that
* are possible in Graphics since many of the rendering calls can
* be transformed into one or more variants of these calls.
*/
public interface PixelFillPipe {
public void fillRect(SunGraphics2D sg,
int x, int y, int width, int height);
public void fillRoundRect(SunGraphics2D sg,
int x, int y, int width, int height,
int arcWidth, int arcHeight);
public void fillOval(SunGraphics2D sg,
int x, int y, int width, int height);
public void fillArc(SunGraphics2D sg,
int x, int y, int width, int height,
int startAngle, int arcAngle);
public void fillPolygon(SunGraphics2D sg,
int xPoints[], int yPoints[],
int nPoints);
}

View File

@@ -0,0 +1,429 @@
/*
* Copyright (c) 2008, 2011, 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 sun.java2d.pipe;
import java.awt.Shape;
import java.awt.BasicStroke;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.AffineTransform;
import sun.java2d.SunGraphics2D;
import sun.awt.SunHints;
/**
* This class converts calls to the basic pixel rendering methods
* into calls to the methods on a ParallelogramPipe.
* Most calls are transformed into calls to the fill(Shape) method
* by the parent PixelToShapeConverter class, but some calls are
* transformed into calls to fill/drawParallelogram().
*/
public class PixelToParallelogramConverter extends PixelToShapeConverter
implements ShapeDrawPipe
{
ParallelogramPipe outrenderer;
double minPenSize;
double normPosition;
double normRoundingBias;
boolean adjustfill;
/**
* @param shapepipe pipeline to forward shape calls to
* @param pgrampipe pipeline to forward parallelogram calls to
* (and drawLine calls if possible)
* @param minPenSize minimum pen size for dropout control
* @param normPosition sub-pixel location to normalize endpoints
* for STROKE_NORMALIZE cases
* @param adjustFill boolean to control whethere normalization
* constants are also applied to fill operations
* (normally true for non-AA, false for AA)
*/
public PixelToParallelogramConverter(ShapeDrawPipe shapepipe,
ParallelogramPipe pgrampipe,
double minPenSize,
double normPosition,
boolean adjustfill)
{
super(shapepipe);
outrenderer = pgrampipe;
this.minPenSize = minPenSize;
this.normPosition = normPosition;
this.normRoundingBias = 0.5 - normPosition;
this.adjustfill = adjustfill;
}
public void drawLine(SunGraphics2D sg2d,
int x1, int y1, int x2, int y2)
{
if (!drawGeneralLine(sg2d, x1, y1, x2, y2)) {
super.drawLine(sg2d, x1, y1, x2, y2);
}
}
public void drawRect(SunGraphics2D sg2d,
int x, int y, int w, int h)
{
if (w >= 0 && h >= 0) {
if (sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM) {
BasicStroke bs = ((BasicStroke) sg2d.stroke);
if (w > 0 && h > 0) {
if (bs.getLineJoin() == BasicStroke.JOIN_MITER &&
bs.getDashArray() == null)
{
double lw = bs.getLineWidth();
drawRectangle(sg2d, x, y, w, h, lw);
return;
}
} else {
// Note: This calls the integer version which
// will verify that the local drawLine optimizations
// work and call super.drawLine(), if not.
drawLine(sg2d, x, y, x+w, y+h);
return;
}
}
super.drawRect(sg2d, x, y, w, h);
}
}
public void fillRect(SunGraphics2D sg2d,
int x, int y, int w, int h)
{
if (w > 0 && h > 0) {
fillRectangle(sg2d, x, y, w, h);
}
}
public void draw(SunGraphics2D sg2d, Shape s) {
if (sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM) {
BasicStroke bs = ((BasicStroke) sg2d.stroke);
if (s instanceof Rectangle2D) {
if (bs.getLineJoin() == BasicStroke.JOIN_MITER &&
bs.getDashArray() == null)
{
Rectangle2D r2d = (Rectangle2D) s;
double w = r2d.getWidth();
double h = r2d.getHeight();
double x = r2d.getX();
double y = r2d.getY();
if (w >= 0 && h >= 0) {
double lw = bs.getLineWidth();
drawRectangle(sg2d, x, y, w, h, lw);
}
return;
}
} else if (s instanceof Line2D) {
Line2D l2d = (Line2D) s;
if (drawGeneralLine(sg2d,
l2d.getX1(), l2d.getY1(),
l2d.getX2(), l2d.getY2()))
{
return;
}
}
}
outpipe.draw(sg2d, s);
}
public void fill(SunGraphics2D sg2d, Shape s) {
if (s instanceof Rectangle2D) {
Rectangle2D r2d = (Rectangle2D) s;
double w = r2d.getWidth();
double h = r2d.getHeight();
if (w > 0 && h > 0) {
double x = r2d.getX();
double y = r2d.getY();
fillRectangle(sg2d, x, y, w, h);
}
return;
}
outpipe.fill(sg2d, s);
}
static double len(double x, double y) {
return ((x == 0) ? Math.abs(y)
: ((y == 0) ? Math.abs(x)
: Math.sqrt(x * x + y * y)));
}
double normalize(double v) {
return Math.floor(v + normRoundingBias) + normPosition;
}
public boolean drawGeneralLine(SunGraphics2D sg2d,
double ux1, double uy1,
double ux2, double uy2)
{
if (sg2d.strokeState == SunGraphics2D.STROKE_CUSTOM ||
sg2d.strokeState == SunGraphics2D.STROKE_THINDASHED)
{
return false;
}
BasicStroke bs = (BasicStroke) sg2d.stroke;
int cap = bs.getEndCap();
if (cap == BasicStroke.CAP_ROUND || bs.getDashArray() != null) {
// TODO: we could construct the GeneralPath directly
// for CAP_ROUND and save a lot of processing in that case...
// And again, we would need to deal with dropout control...
return false;
}
double lw = bs.getLineWidth();
// Save the original dx, dy in case we need it to transform
// the linewidth as a perpendicular vector below
double dx = ux2 - ux1;
double dy = uy2 - uy1;
double x1, y1, x2, y2;
switch (sg2d.transformState) {
case SunGraphics2D.TRANSFORM_GENERIC:
case SunGraphics2D.TRANSFORM_TRANSLATESCALE:
{
double coords[] = {ux1, uy1, ux2, uy2};
sg2d.transform.transform(coords, 0, coords, 0, 2);
x1 = coords[0];
y1 = coords[1];
x2 = coords[2];
y2 = coords[3];
}
break;
case SunGraphics2D.TRANSFORM_ANY_TRANSLATE:
case SunGraphics2D.TRANSFORM_INT_TRANSLATE:
{
double tx = sg2d.transform.getTranslateX();
double ty = sg2d.transform.getTranslateY();
x1 = ux1 + tx;
y1 = uy1 + ty;
x2 = ux2 + tx;
y2 = uy2 + ty;
}
break;
case SunGraphics2D.TRANSFORM_ISIDENT:
x1 = ux1;
y1 = uy1;
x2 = ux2;
y2 = uy2;
break;
default:
throw new InternalError("unknown TRANSFORM state...");
}
if (sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE) {
if (sg2d.strokeState == SunGraphics2D.STROKE_THIN &&
outrenderer instanceof PixelDrawPipe)
{
// PixelDrawPipes will add sg2d.transXY so we need to factor
// that out...
int ix1 = (int) Math.floor(x1 - sg2d.transX);
int iy1 = (int) Math.floor(y1 - sg2d.transY);
int ix2 = (int) Math.floor(x2 - sg2d.transX);
int iy2 = (int) Math.floor(y2 - sg2d.transY);
((PixelDrawPipe)outrenderer).drawLine(sg2d, ix1, iy1, ix2, iy2);
return true;
}
x1 = normalize(x1);
y1 = normalize(y1);
x2 = normalize(x2);
y2 = normalize(y2);
}
if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {
// Transform the linewidth...
// calculate the scaling factor for a unit vector
// perpendicular to the original user space line.
double len = len(dx, dy);
if (len == 0) {
dx = len = 1;
// dy = 0; already
}
// delta transform the transposed (90 degree rotated) unit vector
double unitvector[] = {dy/len, -dx/len};
sg2d.transform.deltaTransform(unitvector, 0, unitvector, 0, 1);
lw *= len(unitvector[0], unitvector[1]);
}
lw = Math.max(lw, minPenSize);
dx = x2 - x1;
dy = y2 - y1;
double len = len(dx, dy);
double udx, udy;
if (len == 0) {
if (cap == BasicStroke.CAP_BUTT) {
return true;
}
udx = lw;
udy = 0;
} else {
udx = lw * dx / len;
udy = lw * dy / len;
}
double px = x1 + udy / 2.0;
double py = y1 - udx / 2.0;
if (cap == BasicStroke.CAP_SQUARE) {
px -= udx / 2.0;
py -= udy / 2.0;
dx += udx;
dy += udy;
}
outrenderer.fillParallelogram(sg2d, ux1, uy1, ux2, uy2,
px, py, -udy, udx, dx, dy);
return true;
}
public void fillRectangle(SunGraphics2D sg2d,
double rx, double ry,
double rw, double rh)
{
double px, py;
double dx1, dy1, dx2, dy2;
AffineTransform txform = sg2d.transform;
dx1 = txform.getScaleX();
dy1 = txform.getShearY();
dx2 = txform.getShearX();
dy2 = txform.getScaleY();
px = rx * dx1 + ry * dx2 + txform.getTranslateX();
py = rx * dy1 + ry * dy2 + txform.getTranslateY();
dx1 *= rw;
dy1 *= rw;
dx2 *= rh;
dy2 *= rh;
if (adjustfill &&
sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM &&
sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE)
{
double newx = normalize(px);
double newy = normalize(py);
dx1 = normalize(px + dx1) - newx;
dy1 = normalize(py + dy1) - newy;
dx2 = normalize(px + dx2) - newx;
dy2 = normalize(py + dy2) - newy;
px = newx;
py = newy;
}
outrenderer.fillParallelogram(sg2d, rx, ry, rx+rw, ry+rh,
px, py, dx1, dy1, dx2, dy2);
}
public void drawRectangle(SunGraphics2D sg2d,
double rx, double ry,
double rw, double rh,
double lw)
{
double px, py;
double dx1, dy1, dx2, dy2;
double lw1, lw2;
AffineTransform txform = sg2d.transform;
dx1 = txform.getScaleX();
dy1 = txform.getShearY();
dx2 = txform.getShearX();
dy2 = txform.getScaleY();
px = rx * dx1 + ry * dx2 + txform.getTranslateX();
py = rx * dy1 + ry * dy2 + txform.getTranslateY();
// lw along dx1,dy1 scale by transformed length of dx2,dy2 vectors
// and vice versa
lw1 = len(dx1, dy1) * lw;
lw2 = len(dx2, dy2) * lw;
dx1 *= rw;
dy1 *= rw;
dx2 *= rh;
dy2 *= rh;
if (sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM &&
sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE)
{
double newx = normalize(px);
double newy = normalize(py);
dx1 = normalize(px + dx1) - newx;
dy1 = normalize(py + dy1) - newy;
dx2 = normalize(px + dx2) - newx;
dy2 = normalize(py + dy2) - newy;
px = newx;
py = newy;
}
lw1 = Math.max(lw1, minPenSize);
lw2 = Math.max(lw2, minPenSize);
double len1 = len(dx1, dy1);
double len2 = len(dx2, dy2);
if (lw1 >= len1 || lw2 >= len2) {
// The line widths are large enough to consume the
// entire hole in the middle of the parallelogram
// so we can just fill the outer parallelogram.
fillOuterParallelogram(sg2d,
rx, ry, rx+rw, ry+rh,
px, py, dx1, dy1, dx2, dy2,
len1, len2, lw1, lw2);
} else {
outrenderer.drawParallelogram(sg2d,
rx, ry, rx+rw, ry+rh,
px, py, dx1, dy1, dx2, dy2,
lw1 / len1, lw2 / len2);
}
}
/**
* This utility function handles the case where a drawRectangle
* operation discovered that the interior hole in the rectangle
* or parallelogram has been completely filled in by the stroke
* width. It calculates the outer parallelogram of the stroke
* and issues a single fillParallelogram request to fill it.
*/
public void fillOuterParallelogram(SunGraphics2D sg2d,
double ux1, double uy1,
double ux2, double uy2,
double px, double py,
double dx1, double dy1,
double dx2, double dy2,
double len1, double len2,
double lw1, double lw2)
{
double udx1 = dx1 / len1;
double udy1 = dy1 / len1;
double udx2 = dx2 / len2;
double udy2 = dy2 / len2;
if (len1 == 0) {
// len1 is 0, replace udxy1 with perpendicular of udxy2
if (len2 == 0) {
// both are 0, use a unit Y vector for udxy2
udx2 = 0;
udy2 = 1;
}
udx1 = udy2;
udy1 = -udx2;
} else if (len2 == 0) {
// len2 is 0, replace udxy2 with perpendicular of udxy1
udx2 = udy1;
udy2 = -udx1;
}
udx1 *= lw1;
udy1 *= lw1;
udx2 *= lw2;
udy2 *= lw2;
px -= (udx1 + udx2) / 2;
py -= (udy1 + udy2) / 2;
dx1 += udx1;
dy1 += udy1;
dx2 += udx2;
dy2 += udy2;
outrenderer.fillParallelogram(sg2d, ux1, uy1, ux2, uy2,
px, py, dx1, dy1, dx2, dy2);
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright (c) 1997, 2013, 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 sun.java2d.pipe;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.geom.GeneralPath;
import sun.java2d.SunGraphics2D;
/**
* This class converts calls to the basic pixel rendering methods
* into calls to a generic Shape rendering pipeline.
*/
public class PixelToShapeConverter
implements PixelDrawPipe, PixelFillPipe
{
ShapeDrawPipe outpipe;
public PixelToShapeConverter(ShapeDrawPipe pipe) {
outpipe = pipe;
}
public void drawLine(SunGraphics2D sg,
int x1, int y1, int x2, int y2) {
outpipe.draw(sg, new Line2D.Float(x1, y1, x2, y2));
}
public void drawRect(SunGraphics2D sg,
int x, int y, int w, int h) {
outpipe.draw(sg, new Rectangle(x, y, w, h));
}
public void fillRect(SunGraphics2D sg,
int x, int y, int w, int h) {
outpipe.fill(sg, new Rectangle(x, y, w, h));
}
public void drawRoundRect(SunGraphics2D sg,
int x, int y, int w, int h,
int aW, int aH) {
outpipe.draw(sg, new RoundRectangle2D.Float(x, y, w, h, aW, aH));
}
public void fillRoundRect(SunGraphics2D sg,
int x, int y, int w, int h,
int aW, int aH) {
outpipe.fill(sg, new RoundRectangle2D.Float(x, y, w, h, aW, aH));
}
public void drawOval(SunGraphics2D sg,
int x, int y, int w, int h) {
outpipe.draw(sg, new Ellipse2D.Float(x, y, w, h));
}
public void fillOval(SunGraphics2D sg,
int x, int y, int w, int h) {
outpipe.fill(sg, new Ellipse2D.Float(x, y, w, h));
}
public void drawArc(SunGraphics2D sg,
int x, int y, int w, int h,
int start, int extent) {
outpipe.draw(sg, new Arc2D.Float(x, y, w, h,
start, extent, Arc2D.OPEN));
}
public void fillArc(SunGraphics2D sg,
int x, int y, int w, int h,
int start, int extent) {
outpipe.fill(sg, new Arc2D.Float(x, y, w, h,
start, extent, Arc2D.PIE));
}
private Shape makePoly(int xPoints[], int yPoints[],
int nPoints, boolean close) {
GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
if (nPoints > 0) {
gp.moveTo(xPoints[0], yPoints[0]);
for (int i = 1; i < nPoints; i++) {
gp.lineTo(xPoints[i], yPoints[i]);
}
if (close) {
gp.closePath();
}
}
return gp;
}
public void drawPolyline(SunGraphics2D sg,
int xPoints[], int yPoints[],
int nPoints) {
outpipe.draw(sg, makePoly(xPoints, yPoints, nPoints, false));
}
public void drawPolygon(SunGraphics2D sg,
int xPoints[], int yPoints[],
int nPoints) {
outpipe.draw(sg, makePoly(xPoints, yPoints, nPoints, true));
}
public void fillPolygon(SunGraphics2D sg,
int xPoints[], int yPoints[],
int nPoints) {
outpipe.fill(sg, makePoly(xPoints, yPoints, nPoints, true));
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,392 @@
/*
* Copyright (c) 1999, 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 sun.java2d.pipe;
import java.awt.geom.PathIterator;
import java.awt.Rectangle;
/**
* This class clips a SpanIterator to a Region and outputs the
* resulting spans as another SpanIterator.
*
* Spans are output in the usual y/x order, unless the input span
* iterator doesn't conform to this order, or the iterator's span
* straddle more than one band of the Region used for clipping.
*
* Principle of operation:
*
* The iterator maintains a several cursors onto the RegionIterator
* in order to avoid having to buffer spans from the SpanIterator.
* They are:
* resetState The initial state of the RegionIterator
* lwm Low Water Mark, a running start point for
* processing each band. Usually goes down, but
* can be reset to resetState if a span has a lower
* start coordinate than the previous one.
* row The start of the current band of the RegionIterator
* box The current span of the current row
*
* The main nextSpan() loop implements a coroutine like structure, with
* three producers to get the next span, row and box calling each other
* to iterate through the span iterator and region.
*
* REMIND: Needs a native implementation!
*/
public class RegionClipSpanIterator implements SpanIterator {
// The inputs to the filter
Region rgn;
SpanIterator spanIter;
// The cursors that track the progress through the region
RegionIterator resetState;
RegionIterator lwm;
RegionIterator row;
RegionIterator box;
// The bounds of the current span iterator span
int spanlox, spanhix, spanloy, spanhiy;
// The extent of the region band marking the low water mark
int lwmloy, lwmhiy;
// The bounds of the current region box
int rgnlox, rgnloy, rgnhix, rgnhiy;
// The bounding box of the input Region. Used for click
// rejection of iterator spans
int rgnbndslox, rgnbndsloy, rgnbndshix, rgnbndshiy;
// The array used to hold coordinates from the region iterator
int rgnbox[] = new int[4];
// The array used to hold coordinates from the span iterator
int spanbox[] = new int[4];
// True if the next iterator span should be read on the next
// iteration of the main nextSpan() loop
boolean doNextSpan;
// True if the next region box should be read on the next
// iteration of the main nextSpan() loop
boolean doNextBox;
// True if there are no more spans or the Region is empty
boolean done = false;
/*
* Creates an instance that filters the spans generated by
* spanIter through the region described by rgn.
*/
public RegionClipSpanIterator(Region rgn, SpanIterator spanIter) {
this.spanIter = spanIter;
resetState = rgn.getIterator();
lwm = resetState.createCopy();
if (!lwm.nextYRange(rgnbox)) {
done = true;
return;
}
rgnloy = lwmloy = rgnbox[1];
rgnhiy = lwmhiy = rgnbox[3];
rgn.getBounds(rgnbox);
rgnbndslox = rgnbox[0];
rgnbndsloy = rgnbox[1];
rgnbndshix = rgnbox[2];
rgnbndshiy = rgnbox[3];
if (rgnbndslox >= rgnbndshix ||
rgnbndsloy >= rgnbndshiy) {
done = true;
return;
}
this.rgn = rgn;
row = lwm.createCopy();
box = row.createCopy();
doNextSpan = true;
doNextBox = false;
}
/*
* Gets the bbox of the available path segments, clipped to the
* Region.
*/
public void getPathBox(int pathbox[]) {
int[] rgnbox = new int[4];
rgn.getBounds(rgnbox);
spanIter.getPathBox(pathbox);
if (pathbox[0] < rgnbox[0]) {
pathbox[0] = rgnbox[0];
}
if (pathbox[1] < rgnbox[1]) {
pathbox[1] = rgnbox[1];
}
if (pathbox[2] > rgnbox[2]) {
pathbox[2] = rgnbox[2];
}
if (pathbox[3] > rgnbox[3]) {
pathbox[3] = rgnbox[3];
}
}
/*
* Intersects the path box with the given bbox.
* Returned spans are clipped to this region, or discarded
* altogether if they lie outside it.
*/
public void intersectClipBox(int lox, int loy, int hix, int hiy) {
spanIter.intersectClipBox(lox, loy, hix, hiy);
}
/*
* Fetches the next span that needs to be operated on.
* If the return value is false then there are no more spans.
*/
public boolean nextSpan(int resultbox[]) {
if (done) {
return false;
}
int resultlox, resultloy, resulthix, resulthiy;
boolean doNextRow = false;
// REMIND: Cache the coordinate inst vars used in this loop
// in locals vars.
while (true) {
// We've exhausted the current span so get the next one
if (doNextSpan) {
if (!spanIter.nextSpan(spanbox)) {
done = true;
return false;
} else {
spanlox = spanbox[0];
// Clip out spans that lie outside of the rgn's bounds
if (spanlox >= rgnbndshix) {
continue;
}
spanloy = spanbox[1];
if (spanloy >= rgnbndshiy) {
continue;
}
spanhix = spanbox[2];
if (spanhix <= rgnbndslox) {
continue;
}
spanhiy = spanbox[3];
if (spanhiy <= rgnbndsloy) {
continue;
}
}
// If the span starts higher up than the low-water mark,
// reset the lwm. This can only happen if spans aren't
// returned in strict y/x order, or the first time through.
if (lwmloy > spanloy) {
lwm.copyStateFrom(resetState);
lwm.nextYRange(rgnbox);
lwmloy = rgnbox[1];
lwmhiy = rgnbox[3];
}
// Skip to the first rgn row whose bottom edge is
// below the top of the current span. This will only
// execute >0 times when the current span starts in a
// lower region row than the previous one, or possibly the
// first time through.
while (lwmhiy <= spanloy) {
if (!lwm.nextYRange(rgnbox))
break;
lwmloy = rgnbox[1];
lwmhiy = rgnbox[3];
}
// If the row overlaps the span, process it, otherwise
// fetch another span
if (lwmhiy > spanloy && lwmloy < spanhiy) {
// Update the current row if it's different from the
// new lwm
if (rgnloy != lwmloy) {
row.copyStateFrom(lwm);
rgnloy = lwmloy;
rgnhiy = lwmhiy;
}
box.copyStateFrom(row);
doNextBox = true;
doNextSpan = false;
}
continue;
}
// The current row's spans are exhausted, do the next one
if (doNextRow) {
// Next time we either do the next span or the next box
doNextRow = false;
// Get the next row
boolean ok = row.nextYRange(rgnbox);
// If there was one, update the bounds
if (ok) {
rgnloy = rgnbox[1];
rgnhiy = rgnbox[3];
}
if (!ok || rgnloy >= spanhiy) {
// If we've exhausted the rows or this one is below the span,
// go onto the next span
doNextSpan = true;
}
else {
// Otherwise get the first box on this row
box.copyStateFrom(row);
doNextBox = true;
}
continue;
}
// Process the next box in the current row
if (doNextBox) {
boolean ok = box.nextXBand(rgnbox);
if (ok) {
rgnlox = rgnbox[0];
rgnhix = rgnbox[2];
}
if (!ok || rgnlox >= spanhix) {
// If there was no next rgn span or it's beyond the
// source span, go onto the next row or span
doNextBox = false;
if (rgnhiy >= spanhiy) {
// If the current row totally overlaps the span,
// go onto the next span
doNextSpan = true;
} else {
// otherwise go onto the next rgn row
doNextRow = true;
}
} else {
// Otherwise, if the new rgn span overlaps the
// spanbox, no need to get another box
doNextBox = rgnhix <= spanlox;
}
continue;
}
// Prepare to do the next box either on this call or
// or the subsequent one
doNextBox = true;
// Clip the current span against the current box
if (spanlox > rgnlox) {
resultlox = spanlox;
}
else {
resultlox = rgnlox;
}
if (spanloy > rgnloy) {
resultloy = spanloy;
}
else {
resultloy = rgnloy;
}
if (spanhix < rgnhix) {
resulthix = spanhix;
}
else {
resulthix = rgnhix;
}
if (spanhiy < rgnhiy) {
resulthiy = spanhiy;
}
else {
resulthiy = rgnhiy;
}
// If the result is empty, try then next box
// otherwise return the box.
// REMIND: I think by definition it's non-empty
// if we're here. Need to think about this some more.
if (resultlox >= resulthix ||
resultloy >= resulthiy) {
continue;
}
else {
break;
}
}
resultbox[0] = resultlox;
resultbox[1] = resultloy;
resultbox[2] = resulthix;
resultbox[3] = resulthiy;
return true;
}
/**
* This method tells the iterator that it may skip all spans
* whose Y range is completely above the indicated Y coordinate.
*/
public void skipDownTo(int y) {
spanIter.skipDownTo(y);
}
/**
* This method returns a native pointer to a function block that
* can be used by a native method to perform the same iteration
* cycle that the above methods provide while avoiding upcalls to
* the Java object.
* The definition of the structure whose pointer is returned by
* this method is defined in:
* <pre>
* src/share/native/sun/java2d/pipe/SpanIterator.h
* </pre>
*/
public long getNativeIterator() {
return 0;
}
/*
* Cleans out all internal data structures.
*/
//public native void dispose();
protected void finalize() {
//dispose();
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (c) 1998, 2012, 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 sun.java2d.pipe;
import java.awt.Rectangle;
/**
* This class defines the API for iterating through the bands
* of a region object.
*/
public class RegionIterator {
Region region;
int curIndex;
int numXbands;
RegionIterator(Region r) {
region = r;
}
/**
* Returns a new RegionIterator object representing the same
* iteration state as this object to allow multiple iteration
* branches from the current position.
*/
public RegionIterator createCopy() {
RegionIterator r = new RegionIterator(region);
r.curIndex = this.curIndex;
r.numXbands = this.numXbands;
return r;
}
/**
* Copies the iteration state from this RegionIterator object
* into another RegionIterator object to allow multiple iteration
* branches from the current position.
*/
public void copyStateFrom(RegionIterator ri) {
if (this.region != ri.region) {
throw new InternalError("region mismatch");
}
this.curIndex = ri.curIndex;
this.numXbands = ri.numXbands;
}
/**
* Moves the iteration state to the beginning of the next
* Y range in the region returning true if one is found
* and recording the low and high Y coordinates of the
* range in the array at locations 1 and 3 respectively.
*/
public boolean nextYRange(int range[]) {
curIndex += numXbands * 2;
numXbands = 0;
if (curIndex >= region.endIndex) {
return false;
}
range[1] = region.bands[curIndex++];
range[3] = region.bands[curIndex++];
numXbands = region.bands[curIndex++];
return true;
}
/**
* Moves the iteration state to the beginning of the next
* X band in the current Y range returning true if one is
* found and recording the low and high X coordinates of
* the range in the array at locations 0 and 2 respectively.
*/
public boolean nextXBand(int range[]) {
if (numXbands <= 0) {
return false;
}
numXbands--;
range[0] = region.bands[curIndex++];
range[2] = region.bands[curIndex++];
return true;
}
}

View File

@@ -0,0 +1,210 @@
/*
* Copyright (c) 1999, 2002, 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 sun.java2d.pipe;
/**
* This class implements the ShapeIterator interface for a Region.
* This is useful as the source iterator of a device clip region
* (in its native guise), and also as the result of clipping a
* Region to a rectangle.
*/
public class RegionSpanIterator implements SpanIterator {
// The RegionIterator that we use to do the work
RegionIterator ri;
// Clipping bounds
int lox, loy, hix, hiy;
// Current Y band limits
int curloy, curhiy;
// Are we done?
boolean done = false;
// Is the associated Region rectangular?
boolean isrect;
/*
REMIND: For native implementation
long pData; // Private storage of rect info
static {
initIDs();
}
public static native void initIDs();
*/
/**
* Constructs an instance based on the given Region
*/
public RegionSpanIterator(Region r) {
int[] bounds = new int[4];
r.getBounds(bounds);
lox = bounds[0];
loy = bounds[1];
hix = bounds[2];
hiy = bounds[3];
isrect = r.isRectangular();
ri = r.getIterator();
}
/**
* Gets the bbox of the available region spans.
*/
public void getPathBox(int pathbox[]) {
pathbox[0] = lox;
pathbox[1] = loy;
pathbox[2] = hix;
pathbox[3] = hiy;
}
/**
* Intersect the box used for clipping the output spans with the
* given box.
*/
public void intersectClipBox(int clox, int cloy, int chix, int chiy) {
if (clox > lox) {
lox = clox;
}
if (cloy > loy) {
loy = cloy;
}
if (chix < hix) {
hix = chix;
}
if (chiy < hiy) {
hiy = chiy;
}
done = lox >= hix || loy >= hiy;
}
/**
* Fetches the next span that needs to be operated on.
* If the return value is false then there are no more spans.
*/
public boolean nextSpan(int spanbox[]) {
// Quick test for end conditions
if (done) {
return false;
}
// If the Region is rectangular, we store our bounds (possibly
// clipped via intersectClipBox()) in spanbox and return true
// so that the caller will process the single span. We set done
// to true to ensure that this will be the last span processed.
if (isrect) {
getPathBox(spanbox);
done = true;
return true;
}
// Local cache of current span's bounds
int curlox, curhix;
int curloy = this.curloy;
int curhiy = this.curhiy;
while (true) {
if (!ri.nextXBand(spanbox)) {
if (!ri.nextYRange(spanbox)) {
done = true;
return false;
}
// Update the current y band and clip it
curloy = spanbox[1];
curhiy = spanbox[3];
if (curloy < loy) {
curloy = loy;
}
if (curhiy > hiy) {
curhiy = hiy;
}
// Check for moving below the clip rect
if (curloy >= hiy) {
done = true;
return false;
}
continue;
}
// Clip the x box
curlox = spanbox[0];
curhix = spanbox[2];
if (curlox < lox) {
curlox = lox;
}
if (curhix > hix) {
curhix = hix;
}
// If it's non- box, we're done
if (curlox < curhix && curloy < curhiy) {
break;
}
}
// Update the result and the store y range
spanbox[0] = curlox;
spanbox[1] = this.curloy = curloy;
spanbox[2] = curhix;
spanbox[3] = this.curhiy = curhiy;
return true;
}
/**
* This method tells the iterator that it may skip all spans
* whose Y range is completely above the indicated Y coordinate.
*/
public void skipDownTo(int y) {
loy = y;
}
/**
* This method returns a native pointer to a function block that
* can be used by a native method to perform the same iteration
* cycle that the above methods provide while avoiding upcalls to
* the Java object.
* The definition of the structure whose pointer is returned by
* this method is defined in:
* <pre>
* src/share/native/sun/java2d/pipe/SpanIterator.h
* </pre>
*/
public long getNativeIterator() {
return 0;
}
/*
* Cleans out all internal data structures.
* REMIND: Native implementation
public native void dispose();
protected void finalize() {
dispose();
}
*/
}

View File

@@ -0,0 +1,295 @@
/*
* Copyright (c) 2005, 2013, 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 sun.java2d.pipe;
import sun.misc.Unsafe;
/**
* The RenderBuffer class is a simplified, high-performance, Unsafe wrapper
* used for buffering rendering operations in a single-threaded rendering
* environment. It's functionality is similar to the ByteBuffer and related
* NIO classes. However, the methods in this class perform little to no
* alignment or bounds checks for performance reasons. Therefore, it is
* the caller's responsibility to ensure that all put() calls are properly
* aligned and within bounds:
* - int and float values must be aligned on 4-byte boundaries
* - long and double values must be aligned on 8-byte boundaries
*
* This class only includes the bare minimum of methods to support
* single-threaded rendering. For example, there is no put(double[]) method
* because we currently have no need for such a method in the STR classes.
*/
public class RenderBuffer {
/**
* These constants represent the size of various data types (in bytes).
*/
protected static final long SIZEOF_BYTE = 1L;
protected static final long SIZEOF_SHORT = 2L;
protected static final long SIZEOF_INT = 4L;
protected static final long SIZEOF_FLOAT = 4L;
protected static final long SIZEOF_LONG = 8L;
protected static final long SIZEOF_DOUBLE = 8L;
/**
* Represents the number of elements at which we have empirically
* determined that the average cost of a JNI call exceeds the expense
* of an element by element copy. In other words, if the number of
* elements in an array to be copied exceeds this value, then we should
* use the copyFromArray() method to complete the bulk put operation.
* (This value can be adjusted if the cost of JNI downcalls is reduced
* in a future release.)
*/
private static final int COPY_FROM_ARRAY_THRESHOLD = 6;
protected final Unsafe unsafe;
protected final long baseAddress;
protected final long endAddress;
protected long curAddress;
protected final int capacity;
protected RenderBuffer(int numBytes) {
unsafe = Unsafe.getUnsafe();
curAddress = baseAddress = unsafe.allocateMemory(numBytes);
endAddress = baseAddress + numBytes;
capacity = numBytes;
}
/**
* Allocates a fresh buffer using the machine endianness.
*/
public static RenderBuffer allocate(int numBytes) {
return new RenderBuffer(numBytes);
}
/**
* Returns the base address of the underlying memory buffer.
*/
public final long getAddress() {
return baseAddress;
}
/**
* The behavior (and names) of the following methods are nearly
* identical to their counterparts in the various NIO Buffer classes.
*/
public final int capacity() {
return capacity;
}
public final int remaining() {
return (int)(endAddress - curAddress);
}
public final int position() {
return (int)(curAddress - baseAddress);
}
public final void position(long numBytes) {
curAddress = baseAddress + numBytes;
}
public final void clear() {
curAddress = baseAddress;
}
public final RenderBuffer skip(long numBytes) {
curAddress += numBytes;
return this;
}
/**
* putByte() methods...
*/
public final RenderBuffer putByte(byte x) {
unsafe.putByte(curAddress, x);
curAddress += SIZEOF_BYTE;
return this;
}
public RenderBuffer put(byte[] x) {
return put(x, 0, x.length);
}
public RenderBuffer put(byte[] x, int offset, int length) {
if (length > COPY_FROM_ARRAY_THRESHOLD) {
long offsetInBytes = offset * SIZEOF_BYTE + Unsafe.ARRAY_BYTE_BASE_OFFSET;
long lengthInBytes = length * SIZEOF_BYTE;
unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes);
position(position() + lengthInBytes);
} else {
int end = offset + length;
for (int i = offset; i < end; i++) {
putByte(x[i]);
}
}
return this;
}
/**
* putShort() methods...
*/
public final RenderBuffer putShort(short x) {
// assert (position() % SIZEOF_SHORT == 0);
unsafe.putShort(curAddress, x);
curAddress += SIZEOF_SHORT;
return this;
}
public RenderBuffer put(short[] x) {
return put(x, 0, x.length);
}
public RenderBuffer put(short[] x, int offset, int length) {
// assert (position() % SIZEOF_SHORT == 0);
if (length > COPY_FROM_ARRAY_THRESHOLD) {
long offsetInBytes = offset * SIZEOF_SHORT + Unsafe.ARRAY_SHORT_BASE_OFFSET;
long lengthInBytes = length * SIZEOF_SHORT;
unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes);
position(position() + lengthInBytes);
} else {
int end = offset + length;
for (int i = offset; i < end; i++) {
putShort(x[i]);
}
}
return this;
}
/**
* putInt() methods...
*/
public final RenderBuffer putInt(int pos, int x) {
// assert (baseAddress + pos % SIZEOF_INT == 0);
unsafe.putInt(baseAddress + pos, x);
return this;
}
public final RenderBuffer putInt(int x) {
// assert (position() % SIZEOF_INT == 0);
unsafe.putInt(curAddress, x);
curAddress += SIZEOF_INT;
return this;
}
public RenderBuffer put(int[] x) {
return put(x, 0, x.length);
}
public RenderBuffer put(int[] x, int offset, int length) {
// assert (position() % SIZEOF_INT == 0);
if (length > COPY_FROM_ARRAY_THRESHOLD) {
long offsetInBytes = offset * SIZEOF_INT + Unsafe.ARRAY_INT_BASE_OFFSET;
long lengthInBytes = length * SIZEOF_INT;
unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes);
position(position() + lengthInBytes);
} else {
int end = offset + length;
for (int i = offset; i < end; i++) {
putInt(x[i]);
}
}
return this;
}
/**
* putFloat() methods...
*/
public final RenderBuffer putFloat(float x) {
// assert (position() % SIZEOF_FLOAT == 0);
unsafe.putFloat(curAddress, x);
curAddress += SIZEOF_FLOAT;
return this;
}
public RenderBuffer put(float[] x) {
return put(x, 0, x.length);
}
public RenderBuffer put(float[] x, int offset, int length) {
// assert (position() % SIZEOF_FLOAT == 0);
if (length > COPY_FROM_ARRAY_THRESHOLD) {
long offsetInBytes = offset * SIZEOF_FLOAT + Unsafe.ARRAY_FLOAT_BASE_OFFSET;
long lengthInBytes = length * SIZEOF_FLOAT;
unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes);
position(position() + lengthInBytes);
} else {
int end = offset + length;
for (int i = offset; i < end; i++) {
putFloat(x[i]);
}
}
return this;
}
/**
* putLong() methods...
*/
public final RenderBuffer putLong(long x) {
// assert (position() % SIZEOF_LONG == 0);
unsafe.putLong(curAddress, x);
curAddress += SIZEOF_LONG;
return this;
}
public RenderBuffer put(long[] x) {
return put(x, 0, x.length);
}
public RenderBuffer put(long[] x, int offset, int length) {
// assert (position() % SIZEOF_LONG == 0);
if (length > COPY_FROM_ARRAY_THRESHOLD) {
long offsetInBytes = offset * SIZEOF_LONG + Unsafe.ARRAY_LONG_BASE_OFFSET;
long lengthInBytes = length * SIZEOF_LONG;
unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes);
position(position() + lengthInBytes);
} else {
int end = offset + length;
for (int i = offset; i < end; i++) {
putLong(x[i]);
}
}
return this;
}
/**
* putDouble() method(s)...
*/
public final RenderBuffer putDouble(double x) {
// assert (position() % SIZEOF_DOUBLE == 0);
unsafe.putDouble(curAddress, x);
curAddress += SIZEOF_DOUBLE;
return this;
}
}

View File

@@ -0,0 +1,223 @@
/*
* Copyright (c) 2005, 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 sun.java2d.pipe;
import java.util.HashSet;
import java.util.Set;
import sun.awt.SunToolkit;
/**
* The RenderQueue class encapsulates a RenderBuffer on which rendering
* operations are enqueued. Note that the RenderQueue lock must be acquired
* before performing any operations on the queue (e.g. enqueuing an operation
* or flushing the queue). A sample usage scenario follows:
*
* public void drawSomething(...) {
* rq.lock();
* try {
* ctx.validate(...);
* rq.ensureCapacity(4);
* rq.getBuffer().putInt(DRAW_SOMETHING);
* ...
* } finally {
* rq.unlock();
* }
* }
*
* If you are enqueuing an operation that involves 8-byte parameters (i.e.
* long or double values), it is imperative that you ensure proper
* alignment of the underlying RenderBuffer. This can be accomplished
* simply by providing an offset to the first 8-byte parameter in your
* operation to the ensureCapacityAndAlignment() method. For example:
*
* public void drawStuff(...) {
* rq.lock();
* try {
* RenderBuffer buf = rq.getBuffer();
* ctx.validate(...);
* // 28 total bytes in the operation, 12 bytes to the first long
* rq.ensureCapacityAndAlignment(28, 12);
* buf.putInt(DRAW_STUFF);
* buf.putInt(x).putInt(y);
* buf.putLong(addr1);
* buf.putLong(addr2);
* } finally {
* rq.unlock();
* }
* }
*/
public abstract class RenderQueue {
/** The size of the underlying buffer, in bytes. */
private static final int BUFFER_SIZE = 32000;
/** The underlying buffer for this queue. */
protected RenderBuffer buf;
/**
* A Set containing hard references to Objects that must stay alive until
* the queue has been completely flushed.
*/
protected Set refSet;
protected RenderQueue() {
refSet = new HashSet();
buf = RenderBuffer.allocate(BUFFER_SIZE);
}
/**
* Locks the queue for read/write access.
*/
public final void lock() {
/*
* Implementation note: In theory we should have two separate locks:
* one lock to synchronize access to the RenderQueue, and then a
* separate lock (the AWT lock) that only needs to be acquired when
* we are about to flush the queue (using native windowing system
* operations). In practice it has been difficult to enforce the
* correct lock ordering; sometimes AWT will have already acquired
* the AWT lock before grabbing the RQ lock (see 6253009), while the
* expected order should be RQ lock and then AWT lock. Due to this
* issue, using two separate locks is prone to deadlocks. Therefore,
* to solve this issue we have decided to eliminate the separate RQ
* lock and instead just acquire the AWT lock here. (Someday it might
* be nice to go back to the old two-lock system, but that would
* require potentially risky changes to AWT to ensure that it never
* acquires the AWT lock before calling into 2D code that wants to
* acquire the RQ lock.)
*/
SunToolkit.awtLock();
}
/**
* Attempts to lock the queue. If successful, this method returns true,
* indicating that the caller is responsible for calling
* <code>unlock</code>; otherwise this method returns false.
*/
public final boolean tryLock() {
return SunToolkit.awtTryLock();
}
/**
* Unlocks the queue.
*/
public final void unlock() {
SunToolkit.awtUnlock();
}
/**
* Adds the given Object to the set of hard references, which will
* prevent that Object from being disposed until the queue has been
* flushed completely. This is useful in cases where some enqueued
* data could become invalid if the reference Object were garbage
* collected before the queue could be processed. (For example, keeping
* a hard reference to a FontStrike will prevent any enqueued glyph
* images associated with that strike from becoming invalid before the
* queue is flushed.) The reference set will be cleared immediately
* after the queue is flushed each time.
*/
public final void addReference(Object ref) {
refSet.add(ref);
}
/**
* Returns the encapsulated RenderBuffer object.
*/
public final RenderBuffer getBuffer() {
return buf;
}
/**
* Ensures that there will be enough room on the underlying buffer
* for the following operation. If the operation will not fit given
* the remaining space, the buffer will be flushed immediately, leaving
* an empty buffer for the impending operation.
*
* @param opsize size (in bytes) of the following operation
*/
public final void ensureCapacity(int opsize) {
if (buf.remaining() < opsize) {
flushNow();
}
}
/**
* Convenience method that is equivalent to calling ensureCapacity()
* followed by ensureAlignment(). The ensureCapacity() call allows for an
* extra 4 bytes of space in case the ensureAlignment() method needs to
* insert a NOOP token on the buffer.
*
* @param opsize size (in bytes) of the following operation
* @param first8ByteValueOffset offset (in bytes) from the current
* position to the first 8-byte value used in the following operation
*/
public final void ensureCapacityAndAlignment(int opsize,
int first8ByteValueOffset)
{
ensureCapacity(opsize + 4);
ensureAlignment(first8ByteValueOffset);
}
/**
* Inserts a 4-byte NOOP token when necessary to ensure that all 8-byte
* parameters for the following operation are added to the underlying
* buffer with an 8-byte memory alignment.
*
* @param first8ByteValueOffset offset (in bytes) from the current
* position to the first 8-byte value used in the following operation
*/
public final void ensureAlignment(int first8ByteValueOffset) {
int first8ByteValuePosition = buf.position() + first8ByteValueOffset;
if ((first8ByteValuePosition & 7) != 0) {
buf.putInt(BufferedOpCodes.NOOP);
}
}
/**
* Immediately processes each operation currently pending on the buffer.
* This method will block until the entire buffer has been flushed. The
* queue lock must be acquired before calling this method.
*/
public abstract void flushNow();
/**
* Immediately processes each operation currently pending on the buffer,
* and then invokes the provided task. This method will block until the
* entire buffer has been flushed and the provided task has been executed.
* The queue lock must be acquired before calling this method.
*/
public abstract void flushAndInvokeNow(Runnable task);
/**
* Updates the current position of the underlying buffer, and then
* flushes the queue immediately. This method is useful when native code
* has added data to the queue and needs to flush immediately.
*/
public void flushNow(int position) {
buf.position(position);
flushNow();
}
}

View File

@@ -0,0 +1,478 @@
/*
* Copyright (c) 2007, 2013, 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 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>
*
* 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.
* 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 =
AccessController.doPrivileged(new PrivilegedAction<RenderingEngine>() {
public RenderingEngine run() {
final String ductusREClass = "sun.dc.DuctusRenderingEngine";
String reClass =
System.getProperty("sun.java2d.renderer", ductusREClass);
if (reClass.equals(ductusREClass)) {
try {
Class<?> cls = Class.forName(ductusREClass);
return (RenderingEngine) cls.newInstance();
} catch (ReflectiveOperationException ignored) {
// not found
}
}
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 = 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[]);
/**
* Construct an antialiased tile generator for the given parallelogram
* store the bounds of the tile iteration in the bbox parameter.
* The parallelogram is specified as a starting point and 2 delta
* vectors that indicate the slopes of the 2 pairs of sides of the
* parallelogram.
* The 4 corners of the parallelogram are defined by the 4 points:
* <ul>
* <li> {@code x}, {@code y}
* <li> {@code x+dx1}, {@code y+dy1}
* <li> {@code x+dx1+dx2}, {@code y+dy1+dy2}
* <li> {@code x+dx2}, {@code y+dy2}
* </ul>
* The {@code lw1} and {@code lw2} parameters provide a specification
* for an optionally stroked parallelogram if they are positive numbers.
* The {@code lw1} parameter is the ratio of the length of the {@code dx1},
* {@code dx2} delta vector to half of the line width in that same
* direction.
* The {@code lw2} parameter provides the same ratio for the other delta
* vector.
* If {@code lw1} and {@code lw2} are both greater than zero, then
* the parallelogram figure is doubled by both expanding and contracting
* each delta vector by its corresponding {@code lw} value.
* If either (@code lw1) or {@code lw2} are also greater than 1, then
* the inner (contracted) parallelogram disappears and the figure is
* simply a single expanded parallelogram.
* 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.
* <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 x the X coordinate of the first corner of the parallelogram
* @param y the Y coordinate of the first corner of the parallelogram
* @param dx1 the X coordinate delta of the first leg of the parallelogram
* @param dy1 the Y coordinate delta of the first leg of the parallelogram
* @param dx2 the X coordinate delta of the second leg of the parallelogram
* @param dy2 the Y coordinate delta of the second leg of the parallelogram
* @param lw1 the line width ratio for the first leg of the parallelogram
* @param lw2 the line width ratio for the second leg of the parallelogram
* @param clip the current clip in effect in device coordinates
* @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(double x, double y,
double dx1, double dy1,
double dx2, double dy2,
double lw1, double lw2,
Region clip,
int bbox[]);
/**
* Returns the minimum pen width that the antialiasing rasterizer
* can represent without dropouts occurring.
* @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);
}
public AATileGenerator getAATileGenerator(double x, double y,
double dx1, double dy1,
double dx2, double dy2,
double lw1, double lw2,
Region clip,
int bbox[])
{
System.out.println(name+".getAATileGenerator("+
x+", "+y+", "+
dx1+", "+dy1+", "+
dx2+", "+dy2+", "+
lw1+", "+lw2+", "+
clip+")");
return target.getAATileGenerator(x, y,
dx1, dy1,
dx2, dy2,
lw1, lw2,
clip, bbox);
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 1997, 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 sun.java2d.pipe;
import java.awt.Shape;
import sun.java2d.SunGraphics2D;
/**
* This interface defines the set of calls that pipeline objects
* can use to pass on responsibility for drawing generic Shape
* objects.
*/
public interface ShapeDrawPipe {
public void draw(SunGraphics2D sg, Shape s);
public void fill(SunGraphics2D sg, Shape s);
}

View File

@@ -0,0 +1,201 @@
/*
* Copyright (c) 1998, 2007, 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 sun.java2d.pipe;
import java.awt.geom.PathIterator;
import java.awt.Rectangle;
import sun.awt.geom.PathConsumer2D;
/**
* This class can iterate individual span elements generated by scan
* converting a Shape.
* This particular implementation flattens the incoming path and then
* performs simple polygon tracing to calculate the spans.
*
* Note that this class holds pointers to native data which must be
* disposed. It is not marked as finalizable since it is intended
* to be very lightweight and finalization is a comparitively expensive
* procedure. The caller must specifically use try{} finally{} to
* manually ensure that the object is disposed after use, otherwise
* native data structures might be leaked.
*
* Here is a code sample for using this class:
*
* public void fillShape(Shape s, Rectangle clipRect) {
* ShapeSpanIterator ssi = new ShapeSpanIterator(false);
* try {
* ssi.setOutputArea(clipRect);
* ssi.appendPath(s.getPathIterator(null));
* int spanbox[] = new int[4];
* while (ssi.nextSpan(spanbox)) {
* int x = spanbox[0];
* int y = spanbox[1];
* int w = spanbox[2] - x;
* int h = spanbox[3] - y;
* fillRect(x, y, w, h);
* }
* } finally {
* ssi.dispose();
* }
* }
*/
public final class ShapeSpanIterator
implements SpanIterator, PathConsumer2D
{
long pData;
static {
initIDs();
}
public static native void initIDs();
public ShapeSpanIterator(boolean adjust) {
setNormalize(adjust);
}
/*
* Appends the geometry and winding rule from the indicated
* path iterator.
*/
public void appendPath(PathIterator pi) {
float coords[] = new float[6];
setRule(pi.getWindingRule());
while (!pi.isDone()) {
addSegment(pi.currentSegment(coords), coords);
pi.next();
}
pathDone();
}
/*
* Appends the geometry from the indicated set of polygon points.
*/
public native void appendPoly(int xPoints[], int yPoints[], int nPoints,
int xoff, int yoff);
/*
* Sets the normalization flag so that incoming data is
* adjusted to nearest (0.25, 0.25) subpixel position.
*/
private native void setNormalize(boolean adjust);
/*
* Sets the rectangle of interest for storing and returning
* span segments.
*/
public void setOutputAreaXYWH(int x, int y, int w, int h) {
setOutputAreaXYXY(x, y, Region.dimAdd(x, w), Region.dimAdd(y, h));
}
/*
* Sets the rectangle of interest for storing and returning
* span segments.
*/
public native void setOutputAreaXYXY(int lox, int loy, int hix, int hiy);
/*
* Sets the rectangle of interest for storing and returning
* span segments to the specified Rectangle.
*/
public void setOutputArea(Rectangle r) {
setOutputAreaXYWH(r.x, r.y, r.width, r.height);
}
/*
* Sets the rectangle of interest for storing and returning
* span segments to the bounds of the specified Region.
*/
public void setOutputArea(Region r) {
setOutputAreaXYXY(r.lox, r.loy, r.hix, r.hiy);
}
/*
* Sets the winding rule in the native data structures.
*/
public native void setRule(int rule);
/*
* Adds a single PathIterator segment to the internal list of
* path element structures.
*/
public native void addSegment(int type, float coords[]);
/*
* Gets the bbox of the available path segments, clipped to the
* OutputArea.
*/
public native void getPathBox(int pathbox[]);
/*
* Intersects the path box with the given bbox.
* Returned spans are clipped to this region, or discarded
* altogether if they lie outside it.
*/
public native void intersectClipBox(int lox, int loy, int hix, int hiy);
/*
* Fetches the next span that needs to be operated on.
* If the return value is false then there are no more spans.
*/
public native boolean nextSpan(int spanbox[]);
/**
* This method tells the iterator that it may skip all spans
* whose Y range is completely above the indicated Y coordinate.
*/
public native void skipDownTo(int y);
/**
* This method returns a native pointer to a function block that
* can be used by a native method to perform the same iteration
* cycle that the above methods provide while avoiding upcalls to
* the Java object.
* The definition of the structure whose pointer is returned by
* this method is defined in:
* <pre>
* src/share/native/sun/java2d/pipe/SpanIterator.h
* </pre>
*/
public native long getNativeIterator();
/*
* Cleans out all internal data structures.
*/
public native void dispose();
public native void moveTo(float x, float y);
public native void lineTo(float x, float y);
public native void quadTo(float x1, float y1,
float x2, float y2);
public native void curveTo(float x1, float y1,
float x2, float y2,
float x3, float y3);
public native void closePath();
public native void pathDone();
public native long getNativeConsumer();
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2000, 2005, 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 sun.java2d.pipe;
import java.awt.font.GlyphVector;
import sun.awt.SunHints;
import sun.java2d.SunGraphics2D;
import sun.font.GlyphList;
/**
* A delegate pipe of SG2D for drawing text with
* a solid source colour to an opaque destination.
*/
public class SolidTextRenderer extends GlyphListLoopPipe
implements LoopBasedPipe
{
protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) {
sg2d.loops.drawGlyphListLoop.DrawGlyphList(sg2d, sg2d.surfaceData, gl);
}
}

View File

@@ -0,0 +1,141 @@
/*
* Copyright (c) 1998, 1999, 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 sun.java2d.pipe;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.PathIterator;
import sun.java2d.SunGraphics2D;
/**
* This class uses a Region iterator to modify the extents of alpha
* tiles created during Shape rendering based upon a non-rectangular
* clipping path.
*/
public class SpanClipRenderer implements CompositePipe
{
CompositePipe outpipe;
static Class RegionClass = Region.class;
static Class RegionIteratorClass = RegionIterator.class;
static {
initIDs(RegionClass, RegionIteratorClass);
}
static native void initIDs(Class rc, Class ric);
public SpanClipRenderer(CompositePipe pipe) {
outpipe = pipe;
}
class SCRcontext {
RegionIterator iterator;
Object outcontext;
int band[];
byte tile[];
public SCRcontext(RegionIterator ri, Object outctx) {
iterator = ri;
outcontext = outctx;
band = new int[4];
}
}
public Object startSequence(SunGraphics2D sg, Shape s, Rectangle devR,
int[] abox) {
RegionIterator ri = sg.clipRegion.getIterator();
return new SCRcontext(ri, outpipe.startSequence(sg, s, devR, abox));
}
public boolean needTile(Object ctx, int x, int y, int w, int h) {
SCRcontext context = (SCRcontext) ctx;
return (outpipe.needTile(context.outcontext, x, y, w, h));
}
public void renderPathTile(Object ctx,
byte[] atile, int offset, int tsize,
int x, int y, int w, int h,
ShapeSpanIterator sr) {
renderPathTile(ctx, atile, offset, tsize, x, y, w, h);
}
public void renderPathTile(Object ctx,
byte[] atile, int offset, int tsize,
int x, int y, int w, int h) {
SCRcontext context = (SCRcontext) ctx;
RegionIterator ri = context.iterator.createCopy();
int[] band = context.band;
band[0] = x;
band[1] = y;
band[2] = x + w;
band[3] = y + h;
if (atile == null) {
int size = w * h;
atile = context.tile;
if (atile != null && atile.length < size) {
atile = null;
}
if (atile == null) {
atile = new byte[size];
context.tile = atile;
}
offset = 0;
tsize = w;
fillTile(ri, atile, offset, tsize, band);
} else {
eraseTile(ri, atile, offset, tsize, band);
}
if (band[2] > band[0] && band[3] > band[1]) {
offset += (band[1] - y) * tsize + (band[0] - x);
outpipe.renderPathTile(context.outcontext,
atile, offset, tsize,
band[0], band[1],
band[2] - band[0],
band[3] - band[1]);
}
}
public native void fillTile(RegionIterator ri,
byte[] alpha, int offset, int tsize,
int[] band);
public native void eraseTile(RegionIterator ri,
byte[] alpha, int offset, int tsize,
int[] band);
public void skipTile(Object ctx, int x, int y) {
SCRcontext context = (SCRcontext) ctx;
outpipe.skipTile(context.outcontext, x, y);
}
public void endSequence(Object ctx) {
SCRcontext context = (SCRcontext) ctx;
outpipe.endSequence(context.outcontext);
}
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright (c) 1998, 1999, 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 sun.java2d.pipe;
/**
* This interface defines a general method for iterating through the
* rectangular "spans" that represent the interior of a filled path.
* <p>
* There can be many kinds of span iterators used in the rendering
* pipeline, the most basic being an iterator that scan converts a
* path defined by any PathIterator, or an nested iterator which
* intersects another iterator's spans with a clip region.
* Other iterators can be created for scan converting some of the
* primitive shapes more explicitly for speed or quality.
*
* @author Jim Graham
*/
public interface SpanIterator {
/**
* This method returns the bounding box of the spans that the
* iterator will be returning.
* The array must be of length at least 4 and upon return, it
* will be filled with the values:
* <pre>
* {PathMinX, PathMinY, PathMaxX, PathMaxY}.
* </pre>
*/
public void getPathBox(int pathbox[]);
/**
* This method constrains the spans returned by nextSpan() to the
* rectangle whose bounds are given.
*/
public void intersectClipBox(int lox, int loy, int hix, int hiy);
/**
* This method returns the next span in the shape being iterated.
* The array must be of length at least 4 and upon return, it
* will be filled with the values:
* <pre>
* {SpanMinX, SpanMinY, SpanMaxX, SpanMaxY}.
* </pre>
*/
public boolean nextSpan(int spanbox[]);
/**
* This method tells the iterator that it may skip all spans
* whose Y range is completely above the indicated Y coordinate.
* This method is used to provide feedback from the caller when
* clipping prevents the display of any data in a given Y range.
* Typically it will only be called when this iterator has returned
* a span whose MaxY coordinate is less than the indicated Y and
* the calling mechanism wants to avoid unnecessary iteration work.
* While this request could technically be ignored (i.e. a NOP),
* doing so could potentially cause the caller to make this callback
* for each span that is being skipped.
*/
public void skipDownTo(int y);
/**
* This method returns a native pointer to a function block that
* can be used by a native method to perform the same iteration
* cycle that the above methods provide while avoiding upcalls to
* the Java object.
* The definition of the structure whose pointer is returned by
* this method is defined in:
* <pre>
* src/share/native/sun/java2d/pipe/SpanIterator.h
* </pre>
*/
public long getNativeIterator();
}

View File

@@ -0,0 +1,216 @@
/*
* Copyright (c) 1998, 2007, 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 sun.java2d.pipe;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.BasicStroke;
import java.awt.geom.PathIterator;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import sun.awt.SunHints;
/**
* This class is used to convert raw geometry into a span iterator
* object using a simple flattening polygon scan converter.
* The iterator can be passed on to special SpanFiller loops to
* perform the actual rendering.
*/
public abstract class SpanShapeRenderer implements ShapeDrawPipe {
final static RenderingEngine RenderEngine = RenderingEngine.getInstance();
public static class Composite extends SpanShapeRenderer {
CompositePipe comppipe;
public Composite(CompositePipe pipe) {
comppipe = pipe;
}
public Object startSequence(SunGraphics2D sg, Shape s,
Rectangle devR, int[] bbox) {
return comppipe.startSequence(sg, s, devR, bbox);
}
public void renderBox(Object ctx, int x, int y, int w, int h) {
comppipe.renderPathTile(ctx, null, 0, w, x, y, w, h);
}
public void endSequence(Object ctx) {
comppipe.endSequence(ctx);
}
}
public static class Simple extends SpanShapeRenderer
implements LoopBasedPipe
{
public Object startSequence(SunGraphics2D sg, Shape s,
Rectangle devR, int[] bbox) {
return sg;
}
public void renderBox(Object ctx, int x, int y, int w, int h) {
SunGraphics2D sg2d = (SunGraphics2D) ctx;
SurfaceData sd = sg2d.getSurfaceData();
sg2d.loops.fillRectLoop.FillRect(sg2d, sd, x, y, w, h);
}
public void endSequence(Object ctx) {
}
}
public void draw(SunGraphics2D sg, Shape s) {
if (sg.stroke instanceof BasicStroke) {
ShapeSpanIterator sr = LoopPipe.getStrokeSpans(sg, s);
try {
renderSpans(sg, sg.getCompClip(), s, sr);
} finally {
sr.dispose();
}
} else {
fill(sg, sg.stroke.createStrokedShape(s));
}
}
public static final int NON_RECTILINEAR_TRANSFORM_MASK =
(AffineTransform.TYPE_GENERAL_TRANSFORM |
AffineTransform.TYPE_GENERAL_ROTATION);
public void fill(SunGraphics2D sg, Shape s) {
if (s instanceof Rectangle2D &&
(sg.transform.getType() & NON_RECTILINEAR_TRANSFORM_MASK) == 0)
{
renderRect(sg, (Rectangle2D) s);
return;
}
Region clipRegion = sg.getCompClip();
ShapeSpanIterator sr = LoopPipe.getFillSSI(sg);
try {
sr.setOutputArea(clipRegion);
sr.appendPath(s.getPathIterator(sg.transform));
renderSpans(sg, clipRegion, s, sr);
} finally {
sr.dispose();
}
}
public abstract Object startSequence(SunGraphics2D sg, Shape s,
Rectangle devR, int[] bbox);
public abstract void renderBox(Object ctx, int x, int y, int w, int h);
public abstract void endSequence(Object ctx);
public void renderRect(SunGraphics2D sg, Rectangle2D r) {
double corners[] = {
r.getX(), r.getY(), r.getWidth(), r.getHeight(),
};
corners[2] += corners[0];
corners[3] += corners[1];
if (corners[2] <= corners[0] || corners[3] <= corners[1]) {
return;
}
sg.transform.transform(corners, 0, corners, 0, 2);
if (corners[2] < corners[0]) {
double t = corners[2];
corners[2] = corners[0];
corners[0] = t;
}
if (corners[3] < corners[1]) {
double t = corners[3];
corners[3] = corners[1];
corners[1] = t;
}
int abox[] = {
(int) corners[0],
(int) corners[1],
(int) corners[2],
(int) corners[3],
};
Rectangle devR = new Rectangle(abox[0], abox[1],
abox[2] - abox[0],
abox[3] - abox[1]);
Region clipRegion = sg.getCompClip();
clipRegion.clipBoxToBounds(abox);
if (abox[0] >= abox[2] || abox[1] >= abox[3]) {
return;
}
Object context = startSequence(sg, r, devR, abox);
if (clipRegion.isRectangular()) {
renderBox(context, abox[0], abox[1],
abox[2] - abox[0],
abox[3] - abox[1]);
} else {
SpanIterator sr = clipRegion.getSpanIterator(abox);
while (sr.nextSpan(abox)) {
renderBox(context, abox[0], abox[1],
abox[2] - abox[0],
abox[3] - abox[1]);
}
}
endSequence(context);
}
public void renderSpans(SunGraphics2D sg, Region clipRegion, Shape s,
ShapeSpanIterator sr)
{
Object context = null;
int abox[] = new int[4];
try {
sr.getPathBox(abox);
Rectangle devR = new Rectangle(abox[0], abox[1],
abox[2] - abox[0],
abox[3] - abox[1]);
clipRegion.clipBoxToBounds(abox);
if (abox[0] >= abox[2] || abox[1] >= abox[3]) {
return;
}
sr.intersectClipBox(abox[0], abox[1], abox[2], abox[3]);
context = startSequence(sg, s, devR, abox);
spanClipLoop(context, sr, clipRegion, abox);
} finally {
if (context != null) {
endSequence(context);
}
}
}
public void spanClipLoop(Object ctx, SpanIterator sr,
Region r, int[] abox) {
if (!r.isRectangular()) {
sr = r.filter(sr);
}
while (sr.nextSpan(abox)) {
int x = abox[0];
int y = abox[1];
renderBox(ctx, x, y, abox[2] - x, abox[3] - y);
}
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 1998, 2003, 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.
*/
/*
* @author Charlton Innovations, Inc.
*/
package sun.java2d.pipe;
import sun.java2d.SunGraphics2D;
import java.awt.font.GlyphVector;
import java.awt.font.TextLayout;
/**
* This interface defines the set of calls that pipeline objects
* can use to pass on responsibility for drawing various text
* representations.
*/
public interface TextPipe {
public void drawString(SunGraphics2D g2d, String s,
double x, double y);
public void drawGlyphVector(SunGraphics2D g2d, GlyphVector g,
float x, float y);
public void drawChars(SunGraphics2D g2d,
char data[], int offset, int length,
int x, int y);
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2000, 2003, 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 sun.java2d.pipe;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Font;
import java.awt.font.GlyphVector;
import sun.java2d.SunGraphics2D;
import sun.java2d.loops.FontInfo;
import sun.font.GlyphList;
/*
* This class uses the alpha graybits arrays from a GlyphList object to
* drive a CompositePipe in much the same way as the antialiasing renderer.
*/
public class TextRenderer extends GlyphListPipe {
CompositePipe outpipe;
public TextRenderer(CompositePipe pipe) {
outpipe = pipe;
}
protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) {
int num = gl.getNumGlyphs();
Region clipRegion = sg2d.getCompClip();
int cx1 = clipRegion.getLoX();
int cy1 = clipRegion.getLoY();
int cx2 = clipRegion.getHiX();
int cy2 = clipRegion.getHiY();
Object ctx = null;
try {
int[] bounds = gl.getBounds();
Rectangle r = new Rectangle(bounds[0], bounds[1],
bounds[2] - bounds[0],
bounds[3] - bounds[1]);
Shape s = sg2d.untransformShape(r);
ctx = outpipe.startSequence(sg2d, s, r, bounds);
for (int i = 0; i < num; i++) {
gl.setGlyphIndex(i);
int metrics[] = gl.getMetrics();
int gx1 = metrics[0];
int gy1 = metrics[1];
int w = metrics[2];
int gx2 = gx1 + w;
int gy2 = gy1 + metrics[3];
int off = 0;
if (gx1 < cx1) {
off = cx1 - gx1;
gx1 = cx1;
}
if (gy1 < cy1) {
off += (cy1 - gy1) * w;
gy1 = cy1;
}
if (gx2 > cx2) gx2 = cx2;
if (gy2 > cy2) gy2 = cy2;
if (gx2 > gx1 && gy2 > gy1 &&
outpipe.needTile(ctx, gx1, gy1, gx2 - gx1, gy2 - gy1))
{
byte alpha[] = gl.getGrayBits();
outpipe.renderPathTile(ctx, alpha, off, w,
gx1, gy1, gx2 - gx1, gy2 - gy1);
} else {
outpipe.skipTile(ctx, gx1, gy1);
}
}
} finally {
if (ctx != null) {
outpipe.endSequence(ctx);
}
}
}
}

View File

@@ -0,0 +1,241 @@
/*
* Copyright (c) 1997, 2003, 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 sun.java2d.pipe;
import java.awt.Color;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ImageObserver;
import sun.java2d.SunGraphics2D;
import java.awt.font.GlyphVector;
/**
* This class is used to force a revalidation of the pipelines of
* the indicated SunGraphics2D object before a draw command.
* After calling SunGraphics2D.validatePipe() to force the pipeline
* to be revalidated, this object redispatches the draw command to
* the new valid pipe object.
*/
public class ValidatePipe
implements PixelDrawPipe, PixelFillPipe, ShapeDrawPipe, TextPipe,
DrawImagePipe
{
/*
* Different subclasses may override this to do various
* other forms of validation and return a return code
* indicating whether or not the validation was successful.
*/
public boolean validate(SunGraphics2D sg) {
sg.validatePipe();
return true;
}
public void drawLine(SunGraphics2D sg,
int x1, int y1, int x2, int y2) {
if (validate(sg)) {
sg.drawpipe.drawLine(sg, x1, y1, x2, y2);
}
}
public void drawRect(SunGraphics2D sg,
int x, int y, int width, int height) {
if (validate(sg)) {
sg.drawpipe.drawRect(sg, x, y, width, height);
}
}
public void fillRect(SunGraphics2D sg,
int x, int y, int width, int height) {
if (validate(sg)) {
sg.fillpipe.fillRect(sg, x, y, width, height);
}
}
public void drawRoundRect(SunGraphics2D sg,
int x, int y, int width, int height,
int arcWidth, int arcHeight) {
if (validate(sg)) {
sg.drawpipe.drawRoundRect(sg, x, y, width, height,
arcWidth, arcHeight);
}
}
public void fillRoundRect(SunGraphics2D sg,
int x, int y, int width, int height,
int arcWidth, int arcHeight) {
if (validate(sg)) {
sg.fillpipe.fillRoundRect(sg, x, y, width, height,
arcWidth, arcHeight);
}
}
public void drawOval(SunGraphics2D sg,
int x, int y, int width, int height) {
if (validate(sg)) {
sg.drawpipe.drawOval(sg, x, y, width, height);
}
}
public void fillOval(SunGraphics2D sg,
int x, int y, int width, int height) {
if (validate(sg)) {
sg.fillpipe.fillOval(sg, x, y, width, height);
}
}
public void drawArc(SunGraphics2D sg,
int x, int y, int width, int height,
int startAngle, int arcAngle) {
if (validate(sg)) {
sg.drawpipe.drawArc(sg, x, y, width, height, startAngle, arcAngle);
}
}
public void fillArc(SunGraphics2D sg,
int x, int y, int width, int height,
int startAngle, int arcAngle) {
if (validate(sg)) {
sg.fillpipe.fillArc(sg, x, y, width, height, startAngle, arcAngle);
}
}
public void drawPolyline(SunGraphics2D sg,
int xPoints[], int yPoints[],
int nPoints) {
if (validate(sg)) {
sg.drawpipe.drawPolyline(sg, xPoints, yPoints, nPoints);
}
}
public void drawPolygon(SunGraphics2D sg,
int xPoints[], int yPoints[],
int nPoints) {
if (validate(sg)) {
sg.drawpipe.drawPolygon(sg, xPoints, yPoints, nPoints);
}
}
public void fillPolygon(SunGraphics2D sg,
int xPoints[], int yPoints[],
int nPoints) {
if (validate(sg)) {
sg.fillpipe.fillPolygon(sg, xPoints, yPoints, nPoints);
}
}
public void draw(SunGraphics2D sg, Shape s) {
if (validate(sg)) {
sg.shapepipe.draw(sg, s);
}
}
public void fill(SunGraphics2D sg, Shape s) {
if (validate(sg)) {
sg.shapepipe.fill(sg, s);
}
}
public void drawString(SunGraphics2D sg, String s, double x, double y) {
if (validate(sg)) {
sg.textpipe.drawString(sg, s, x, y);
}
}
public void drawGlyphVector(SunGraphics2D sg, GlyphVector g,
float x, float y) {
if (validate(sg)) {
sg.textpipe.drawGlyphVector(sg, g, x, y);
}
}
public void drawChars(SunGraphics2D sg,
char data[], int offset, int length,
int x, int y) {
if (validate(sg)) {
sg.textpipe.drawChars(sg, data, offset, length, x, y);
}
}
public boolean copyImage(SunGraphics2D sg, Image img,
int x, int y,
Color bgColor,
ImageObserver observer) {
if (validate(sg)) {
return sg.imagepipe.copyImage(sg, img, x, y, bgColor, observer);
} else {
return false;
}
}
public boolean copyImage(SunGraphics2D sg, Image img,
int dx, int dy, int sx, int sy, int w, int h,
Color bgColor,
ImageObserver observer) {
if (validate(sg)) {
return sg.imagepipe.copyImage(sg, img, dx, dy, sx, sy, w, h,
bgColor, observer);
} else {
return false;
}
}
public boolean scaleImage(SunGraphics2D sg, Image img, int x, int y,
int w, int h,
Color bgColor,
ImageObserver observer) {
if (validate(sg)) {
return sg.imagepipe.scaleImage(sg, img, x, y, w, h, bgColor,
observer);
} else {
return false;
}
}
public boolean scaleImage(SunGraphics2D sg, Image img,
int dx1, int dy1, int dx2, int dy2,
int sx1, int sy1, int sx2, int sy2,
Color bgColor,
ImageObserver observer) {
if (validate(sg)) {
return sg.imagepipe.scaleImage(sg, img, dx1, dy1, dx2, dy2,
sx1, sy1, sx2, sy2, bgColor,
observer);
} else {
return false;
}
}
public boolean transformImage(SunGraphics2D sg, Image img,
AffineTransform atfm,
ImageObserver observer) {
if (validate(sg)) {
return sg.imagepipe.transformImage(sg, img, atfm, observer);
} else {
return false;
}
}
public void transformImage(SunGraphics2D sg, BufferedImage img,
BufferedImageOp op, int x, int y) {
if (validate(sg)) {
sg.imagepipe.transformImage(sg, img, op, x, y);
}
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2007, 2008, 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 sun.java2d.pipe.hw;
/**
* An interface for receiving notifications about imminent accelerated device's
* events. Upon receiving such event appropriate actions can be taken (for
* example, resources associated with the device can be freed).
*/
public interface AccelDeviceEventListener {
/**
* Called when the device is about to be reset.
*
* One must release all native resources associated with the device which
* prevent the device from being reset (such as Default Pool resources for
* the D3D pipeline).
*
* It is safe to remove the listener while in the call back.
*
* Note: this method is called on the rendering thread,
* do not call into user code, do not take RQ lock!
*/
public void onDeviceReset();
/**
* Called when the device is about to be disposed of.
*
* One must release all native resources associated with the device.
*
* It is safe to remove the listener while in the call back.
*
* Note: this method is called on the rendering thread,
* do not call into user code, do not take RQ lock!
*/
public void onDeviceDispose();
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright (c) 2007, 2013, 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 sun.java2d.pipe.hw;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.lang.annotation.Native;
/**
* This class is used to notify listeners about accelerated device's
* events such as device reset or dispose that are about to occur.
*/
public class AccelDeviceEventNotifier {
private static AccelDeviceEventNotifier theInstance;
/**
* A device is about to be reset. The listeners have to release all
* resources associated with the device which are required for the device
* to be reset.
*/
@Native public static final int DEVICE_RESET = 0;
/**
* A device is about to be disposed. The listeners have to release all
* resources associated with the device.
*/
@Native public static final int DEVICE_DISPOSED = 1;
private final Map<AccelDeviceEventListener, Integer> listeners;
private AccelDeviceEventNotifier() {
listeners = Collections.synchronizedMap(
new HashMap<AccelDeviceEventListener, Integer>(1));
}
/**
* Returns a singleton of AccelDeviceEventNotifier if it exists. If the
* passed boolean is false and singleton doesn't exist yet, null is
* returned. If the passed boolean is {@code true} and singleton doesn't
* exist it will be created and returned.
*
* @param create whether to create a singleton instance if doesn't yet
* exist
* @return a singleton instance or null
*/
private static synchronized
AccelDeviceEventNotifier getInstance(boolean create)
{
if (theInstance == null && create) {
theInstance = new AccelDeviceEventNotifier();
}
return theInstance;
}
/**
* Called to indicate that a device event had occurred.
* If a singleton exists, the listeners (those associated with
* the device) will be notified.
*
* @param screen a screen number of the device which is a source of
* the event
* @param eventType a type of the event
* @see #DEVICE_DISPOSED
* @see #DEVICE_RESET
*/
public static final void eventOccured(int screen, int eventType) {
AccelDeviceEventNotifier notifier = getInstance(false);
if (notifier != null) {
notifier.notifyListeners(eventType, screen);
}
}
/**
* Adds the listener associated with a device on particular screen.
*
* Note: the listener must be removed as otherwise it will forever
* be referenced by the notifier.
*
* @param l the listener
* @param screen the screen number indicating which device the listener is
* interested in.
*/
public static final void addListener(AccelDeviceEventListener l,int screen){
getInstance(true).add(l, screen);
}
/**
* Removes the listener.
*
* @param l the listener
*/
public static final void removeListener(AccelDeviceEventListener l) {
getInstance(true).remove(l);
}
private final void add(AccelDeviceEventListener theListener, int screen) {
listeners.put(theListener, screen);
}
private final void remove(AccelDeviceEventListener theListener) {
listeners.remove(theListener);
}
/**
* Notifies the listeners associated with the screen's device about the
* event.
*
* Implementation note: the current list of listeners is first duplicated
* which allows the listeners to remove themselves during the iteration.
*
* @param screen a screen number with which the device which is a source of
* the event is associated with
* @param eventType a type of the event
* @see #DEVICE_DISPOSED
* @see #DEVICE_RESET
*/
private final void notifyListeners(int deviceEventType, int screen) {
HashMap<AccelDeviceEventListener, Integer> listClone;
Set<AccelDeviceEventListener> cloneSet;
synchronized(listeners) {
listClone =
new HashMap<AccelDeviceEventListener, Integer>(listeners);
}
cloneSet = listClone.keySet();
Iterator<AccelDeviceEventListener> itr = cloneSet.iterator();
while (itr.hasNext()) {
AccelDeviceEventListener current = itr.next();
Integer i = listClone.get(current);
// only notify listeners which are interested in this device
if (i != null && i.intValue() != screen) {
continue;
}
if (deviceEventType == DEVICE_RESET) {
current.onDeviceReset();
} else if (deviceEventType == DEVICE_DISPOSED) {
current.onDeviceDispose();
}
}
}
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright (c) 2007, 2008, 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 sun.java2d.pipe.hw;
import java.awt.image.VolatileImage;
/**
* Implementors of this interface provida a way to create a
* {@code VolatileImage} whose destination surface is an
* {@link AccelSurface} of specified type.
*
* @see AccelSurface
*/
public interface AccelGraphicsConfig extends BufferedContextProvider {
/**
* Returns a VolatileImage with specified width, height, transparency
* and guaranteed accelerated surface type. If such image can not be created
* (out of vram error, specific surface type is not supported) null
* is returned.
*
* Note: if {@link AccelSurface#TEXTURE} type is requested, rendering
* to the image will be denied by throwing
* {@code UnsupportedOperationException }
* from {@link java.awt.image.VolatileImage#getGraphics} and
* {@link java.awt.image.VolatileImage#createGraphics}
*
* @param width the width of the returned {@code VolatileImage}
* @param height the height of the returned {@code VolatileImage}
* @param transparency the specified transparency mode
* @param type requested accelerated surface type as specified by constants
* in AccelSurface interface
* @return a {@code VolatileImage} backed up by requested accelerated
* surface type or null
* @throws IllegalArgumentException if the transparency is not a valid value
* @see AccelSurface#TEXTURE
* @see AccelSurface#RT_PLAIN
* @see AccelSurface#RT_TEXTURE
*/
public VolatileImage createCompatibleVolatileImage(int width, int height,
int transparency,
int type);
/**
* Returns object representing capabilities of the context associated
* with this {@code AccelGraphicsConfig}.
*
* @return ContextCapabilities object representing caps
* @see ContextCapabilities
*/
public ContextCapabilities getContextCapabilities();
/**
* Adds an {@code AccelDeviceEventListener} to listen to accelerated
* device's (which is associated with this {@code AccelGraphicsConfig})
* events.
*
* Note: a hard link to the listener may be kept so it must be explicitly
* removed via {@link #removeDeviceEventListener()}.
*
* @param l the listener
* @see AccelDeviceEventListener
*/
public void addDeviceEventListener(AccelDeviceEventListener l);
/**
* Removes an {@code AccelDeviceEventListener} from the list of listeners
* for this device's events.
*
* @param l the listener
* @see AccelDeviceEventListener
*/
public void removeDeviceEventListener(AccelDeviceEventListener l);
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright (c) 2007, 2015, 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 sun.java2d.pipe.hw;
import java.awt.Rectangle;
import sun.java2d.Surface;
import java.lang.annotation.Native;
/**
* Abstraction for a hardware accelerated surface.
*/
public interface AccelSurface extends BufferedContextProvider, Surface {
/**
* Undefined
*/
@Native public static final int UNDEFINED = 0;
/**
* Window (or window substitute) surface
*/
@Native public static final int WINDOW = 1;
/**
* Render-To Plain surface (Render Target surface for Direct3D)
*/
@Native public static final int RT_PLAIN = 2;
/**
* Texture surface
*/
@Native public static final int TEXTURE = 3;
/**
* A back-buffer surface (SwapChain surface for Direct3D, backbuffer for
* OpenGL)
*/
@Native public static final int FLIP_BACKBUFFER = 4;
/**
* Render-To Texture surface (fbobject for OpenGL, texture with render-to
* attribute for Direct3D)
*/
@Native public static final int RT_TEXTURE = 5;
/**
* Returns {@code int} representing surface's type as defined by constants
* in this interface.
*
* @return an integer representing this surface's type
* @see AccelSurface#UNDEFINED
* @see AccelSurface#WINDOW
* @see AccelSurface#RT_PLAIN
* @see AccelSurface#TEXTURE
* @see AccelSurface#FLIP_BACKBUFFER
* @see AccelSurface#RT_TEXTURE
*/
public int getType();
/**
* Returns a pointer to the native surface data associated with this
* surface.
* Note: this pointer is only valid on the rendering thread.
*
* @return pointer to the native surface's data
*/
public long getNativeOps();
/**
* Returns a pointer to the real native resource
* of the specified type associated with this AccelSurface.
* Note: this pointer is only valid on the rendering thread.
*
* @param resType the type of the requested resource
* @return a long containing a pointer to the native resource of the
* specified type or 0L if such resource doesn't exist for this surface
*/
public long getNativeResource(int resType);
/**
* Marks this surface dirty.
*/
public void markDirty();
/**
* Returns whether the pipeline considers this surface valid. A surface
* may become invalid if it is disposed of, or resized.
*
* @return true if valid, false otherwise
*/
public boolean isValid();
/**
* Returns whether this surface is lost. The return value is only valid
* on the render thread, meaning that even if this method returns
* {@code true} it could be lost in the next moment unless it is called
* on the rendering thread.
*
* @return true if the surface is known to be lost, false otherwise
*/
public boolean isSurfaceLost();
/**
* Returns the requested bounds of the destination surface. The real bounds
* of the native accelerated surface may differ. Use
* {@link #getNativeBounds} to get the bounds of the native surface.
*
* @return Rectangle representing java surface's bounds
*/
public Rectangle getBounds();
/**
* Returns real bounds of the native surface, which may differ from those
* returned by {@link #getBounds}.
*
* @return Rectangle representing native surface's bounds
*/
public Rectangle getNativeBounds();
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 2007, 2008, 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 sun.java2d.pipe.hw;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import sun.awt.image.SunVolatileImage;
import static sun.java2d.pipe.hw.AccelSurface.*;
/**
* This is an image with forced type of the accelerated surface.
*/
public class AccelTypedVolatileImage extends SunVolatileImage {
/**
* Creates a volatile image with specified type of accelerated surface.
*
* @param graphicsConfig a GraphicsConfiguration for which this image should
* be created.
* @param width width
* @param height width
* @param transparency type of {@link java.awt.Transparency transparency}
* requested for the image
* @param accType type of the desired accelerated surface as defined in
* AccelSurface interface
* @see sun.java2d.pipe.hw.AccelSurface
*/
public AccelTypedVolatileImage(GraphicsConfiguration graphicsConfig,
int width, int height, int transparency,
int accType)
{
super(null, graphicsConfig, width, height, null, transparency,
null, accType);
}
/**
* {@inheritDoc}
*
* This method will throw {@code UnsupportedOperationException} if it this
* image's destination surface can not be rendered to.
*/
@Override
public Graphics2D createGraphics() {
if (getForcedAccelSurfaceType() == TEXTURE) {
throw new UnsupportedOperationException("Can't render " +
"to a non-RT Texture");
}
return super.createGraphics();
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2007, 2008, 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 sun.java2d.pipe.hw;
import sun.java2d.pipe.BufferedContext;
/**
* Classes implementing this interface can provide the {@code BufferedContext}
* associated with or used by them.
*
* @see sun.java2d.pipe.BufferedContext
*/
public interface BufferedContextProvider {
/**
* Retrieves a context associated with object implementing this
* interface.
*
* @return associated context
* @see sun.java2d.pipe.BufferedContext
*/
public BufferedContext getContext();
}

View File

@@ -0,0 +1,129 @@
/*
* Copyright (c) 2007, 2013, 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 sun.java2d.pipe.hw;
/**
* Represents a set of capabilities of a BufferedContext and associated
* AccelGraphicsConfig.
*
* @see AccelGraphicsConfig
*/
public class ContextCapabilities {
/** Indicates that the context has no capabilities. */
public static final int CAPS_EMPTY = (0 << 0);
/** Indicates that the context supports RT surfaces with alpha channel. */
public static final int CAPS_RT_PLAIN_ALPHA = (1 << 1);
/** Indicates that the context supports RT textures with alpha channel. */
public static final int CAPS_RT_TEXTURE_ALPHA = (1 << 2);
/** Indicates that the context supports opaque RT textures. */
public static final int CAPS_RT_TEXTURE_OPAQUE = (1 << 3);
/** Indicates that the context supports multitexturing. */
public static final int CAPS_MULTITEXTURE = (1 << 4);
/** Indicates that the context supports non-pow2 texture dimensions. */
public static final int CAPS_TEXNONPOW2 = (1 << 5);
/** Indicates that the context supports non-square textures. */
public static final int CAPS_TEXNONSQUARE = (1 << 6);
/** Indicates that the context supports pixel shader 2.0 or better. */
public static final int CAPS_PS20 = (1 << 7);
/** Indicates that the context supports pixel shader 3.0 or better. */
public static final int CAPS_PS30 = (1 << 8);
/*
* Pipeline contexts should use this for defining pipeline-specific
* capabilities, for example:
* int CAPS_D3D_1 = (FIRST_PRIVATE_CAP << 0);
* int CAPS_D3D_2 = (FIRST_PRIVATE_CAP << 1);
*/
protected static final int FIRST_PRIVATE_CAP = (1 << 16);
protected final int caps;
protected final String adapterId;
/**
* Constructs a {@code ContextCapabilities} object.
* @param caps an {@code int} representing the capabilities
* @param a {@code String} representing the name of the adapter, or null,
* in which case the adapterId will be set to "unknown adapter".
*/
protected ContextCapabilities(int caps, String adapterId) {
this.caps = caps;
this.adapterId = adapterId != null ? adapterId : "unknown adapter";
}
/**
* Returns a string representing the name of the graphics adapter if such
* could be determined. It is guaranteed to never return {@code null}.
* @return string representing adapter id
*/
public String getAdapterId() {
return adapterId;
}
/**
* Returns an {@code int} with capabilities (OR-ed constants defined in
* this class and its pipeline-specific subclasses).
* @return capabilities as {@code int}
*/
public int getCaps() {
return caps;
}
@Override
public String toString() {
StringBuffer buf =
new StringBuffer("ContextCapabilities: adapter=" +
adapterId+", caps=");
if (caps == CAPS_EMPTY) {
buf.append("CAPS_EMPTY");
} else {
if ((caps & CAPS_RT_PLAIN_ALPHA) != 0) {
buf.append("CAPS_RT_PLAIN_ALPHA|");
}
if ((caps & CAPS_RT_TEXTURE_ALPHA) != 0) {
buf.append("CAPS_RT_TEXTURE_ALPHA|");
}
if ((caps & CAPS_RT_TEXTURE_OPAQUE) != 0) {
buf.append("CAPS_RT_TEXTURE_OPAQUE|");
}
if ((caps & CAPS_MULTITEXTURE) != 0) {
buf.append("CAPS_MULTITEXTURE|");
}
if ((caps & CAPS_TEXNONPOW2) != 0) {
buf.append("CAPS_TEXNONPOW2|");
}
if ((caps & CAPS_TEXNONSQUARE) != 0) {
buf.append("CAPS_TEXNONSQUARE|");
}
if ((caps & CAPS_PS20) != 0) {
buf.append("CAPS_PS20|");
}
if ((caps & CAPS_PS30) != 0) {
buf.append("CAPS_PS30|");
}
}
return buf.toString();
}
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright (c) 2007, 2008, 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 sun.java2d.pipe.hw;
import java.awt.BufferCapabilities;
import java.awt.ImageCapabilities;
/**
* Provides extended BufferStrategy capabilities, allowing to specify
* the type of vertical refresh synchronization for a buffer strategy.
*
* This BS capability is always page flipping because v-sync is only relevant
* to flipping buffer strategies.
*
* Note that asking for a v-synced BS doesn't necessarily guarantee that it will
* be v-synced since the vsync capability may be disabled in the driver, or
* there may be other restriction (like a number of v-synced buffer strategies
* allowed per vm). Because of this {@code createBufferStrategy} doesn't
* throw {@code AWTException} when a v-synced BS could not be created when
* requested.
*
* @see java.awt.Canvas#createBufferStrategy(int, BufferCapabilities)
* @see java.awt.Window#createBufferStrategy(int, BufferCapabilities)
*/
public class ExtendedBufferCapabilities extends BufferCapabilities {
/**
* Type of synchronization on vertical retrace.
*/
public static enum VSyncType {
/**
* Use the default v-sync mode appropriate for given BufferStrategy
* and situation.
*/
VSYNC_DEFAULT(0),
/**
* Synchronize flip on vertical retrace.
*/
VSYNC_ON(1),
/**
* Do not synchronize flip on vertical retrace.
*/
VSYNC_OFF(2);
/**
* Used to identify the v-sync type (independent of the constants
* order as opposed to {@code ordinal()}).
*/
public int id() {
return id;
}
private VSyncType(int id) {
this.id = id;
}
private int id;
}
private VSyncType vsync;
/**
* Creates an ExtendedBufferCapabilities object with front/back/flip caps
* from the passed cap, and VSYNC_DEFAULT v-sync mode.
*/
public ExtendedBufferCapabilities(BufferCapabilities caps) {
super(caps.getFrontBufferCapabilities(),
caps.getBackBufferCapabilities(),
caps.getFlipContents());
this.vsync = VSyncType.VSYNC_DEFAULT;
}
/**
* Creates an ExtendedBufferCapabilities instance with front/back/flip caps
* from the passed caps, and VSYNC_DEFAULT v-sync mode.
*/
public ExtendedBufferCapabilities(ImageCapabilities front,
ImageCapabilities back, FlipContents flip)
{
super(front, back, flip);
this.vsync = VSyncType.VSYNC_DEFAULT;
}
/**
* Creates an ExtendedBufferCapabilities instance with front/back/flip caps
* from the passed image/flip caps, and the v-sync type.
*/
public ExtendedBufferCapabilities(ImageCapabilities front,
ImageCapabilities back, FlipContents flip,
VSyncType t)
{
super(front, back, flip);
this.vsync = t;
}
/**
* Creates an ExtendedBufferCapabilities instance with front/back/flip caps
* from the passed cap, and the passed v-sync mode.
*/
public ExtendedBufferCapabilities(BufferCapabilities caps, VSyncType t) {
super(caps.getFrontBufferCapabilities(),
caps.getBackBufferCapabilities(),
caps.getFlipContents());
this.vsync = t;
}
/**
* Creates an ExtendedBufferCapabilities instance with front/back/flip caps
* from the object, and passed v-sync mode.
*/
public ExtendedBufferCapabilities derive(VSyncType t) {
return new ExtendedBufferCapabilities(this, t);
}
/**
* Returns the type of v-sync requested by this capabilities instance.
*/
public VSyncType getVSync() {
return vsync;
}
@Override
public final boolean isPageFlipping() {
return true;
}
}