/* * 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.x11; import java.awt.Polygon; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; import java.awt.geom.Path2D; import java.awt.geom.IllegalPathStateException; import sun.awt.SunToolkit; import sun.java2d.SunGraphics2D; import sun.java2d.SurfaceData; import sun.java2d.loops.GraphicsPrimitive; import sun.java2d.pipe.Region; import sun.java2d.pipe.PixelDrawPipe; import sun.java2d.pipe.PixelFillPipe; import sun.java2d.pipe.ShapeDrawPipe; import sun.java2d.pipe.SpanIterator; import sun.java2d.pipe.ShapeSpanIterator; import sun.java2d.pipe.LoopPipe; public class X11Renderer implements PixelDrawPipe, PixelFillPipe, ShapeDrawPipe { public static X11Renderer getInstance() { return (GraphicsPrimitive.tracingEnabled() ? new X11TracingRenderer() : new X11Renderer()); } private final long validate(SunGraphics2D sg2d) { // NOTE: getCompClip() will revalidateAll() if the // surfaceData is invalid. This should ensure that // the clip and pixel that we are validating against // are the most current. // // The assumption is that the pipeline after that // revalidation will either be another X11 pipe // (because the drawable format never changes on X11) // or a null pipeline if the surface is disposed. // // Since we do not get the ops structure of the SurfaceData // until the actual call down to the native level we will // pick up the most recently validated copy. // Note that if the surface is disposed, a NullSurfaceData // (with null native data structure) will be set in // sg2d, so we have to protect against it in native code. X11SurfaceData x11sd = (X11SurfaceData)sg2d.surfaceData; return x11sd.getRenderGC(sg2d.getCompClip(), sg2d.compositeState, sg2d.composite, sg2d.pixel); } native void XDrawLine(long pXSData, long xgc, int x1, int y1, int x2, int y2); public void drawLine(SunGraphics2D sg2d, int x1, int y1, int x2, int y2) { SunToolkit.awtLock(); try { long xgc = validate(sg2d); int transx = sg2d.transX; int transy = sg2d.transY; XDrawLine(sg2d.surfaceData.getNativeOps(), xgc, x1+transx, y1+transy, x2+transx, y2+transy); } finally { SunToolkit.awtUnlock(); } } native void XDrawRect(long pXSData, long xgc, int x, int y, int w, int h); public void drawRect(SunGraphics2D sg2d, int x, int y, int width, int height) { SunToolkit.awtLock(); try { long xgc = validate(sg2d); XDrawRect(sg2d.surfaceData.getNativeOps(), xgc, x+sg2d.transX, y+sg2d.transY, width, height); } finally { SunToolkit.awtUnlock(); } } native void XDrawRoundRect(long pXSData, long xgc, int x, int y, int w, int h, int arcW, int arcH); public void drawRoundRect(SunGraphics2D sg2d, int x, int y, int width, int height, int arcWidth, int arcHeight) { SunToolkit.awtLock(); try { long xgc = validate(sg2d); XDrawRoundRect(sg2d.surfaceData.getNativeOps(), xgc, x+sg2d.transX, y+sg2d.transY, width, height, arcWidth, arcHeight); } finally { SunToolkit.awtUnlock(); } } native void XDrawOval(long pXSData, long xgc, int x, int y, int w, int h); public void drawOval(SunGraphics2D sg2d, int x, int y, int width, int height) { SunToolkit.awtLock(); try { long xgc = validate(sg2d); XDrawOval(sg2d.surfaceData.getNativeOps(), xgc, x+sg2d.transX, y+sg2d.transY, width, height); } finally { SunToolkit.awtUnlock(); } } native void XDrawArc(long pXSData, long xgc, int x, int y, int w, int h, int angleStart, int angleExtent); public void drawArc(SunGraphics2D sg2d, int x, int y, int width, int height, int startAngle, int arcAngle) { SunToolkit.awtLock(); try { long xgc = validate(sg2d); XDrawArc(sg2d.surfaceData.getNativeOps(), xgc, x+sg2d.transX, y+sg2d.transY, width, height, startAngle, arcAngle); } finally { SunToolkit.awtUnlock(); } } native void XDrawPoly(long pXSData, long xgc, int transx, int transy, int[] xpoints, int[] ypoints, int npoints, boolean isclosed); public void drawPolyline(SunGraphics2D sg2d, int xpoints[], int ypoints[], int npoints) { SunToolkit.awtLock(); try { long xgc = validate(sg2d); XDrawPoly(sg2d.surfaceData.getNativeOps(), xgc, sg2d.transX, sg2d.transY, xpoints, ypoints, npoints, false); } finally { SunToolkit.awtUnlock(); } } public void drawPolygon(SunGraphics2D sg2d, int xpoints[], int ypoints[], int npoints) { SunToolkit.awtLock(); try { long xgc = validate(sg2d); XDrawPoly(sg2d.surfaceData.getNativeOps(), xgc, sg2d.transX, sg2d.transY, xpoints, ypoints, npoints, true); } finally { SunToolkit.awtUnlock(); } } native void XFillRect(long pXSData, long xgc, int x, int y, int w, int h); public void fillRect(SunGraphics2D sg2d, int x, int y, int width, int height) { SunToolkit.awtLock(); try { long xgc = validate(sg2d); XFillRect(sg2d.surfaceData.getNativeOps(), xgc, x+sg2d.transX, y+sg2d.transY, width, height); } finally { SunToolkit.awtUnlock(); } } native void XFillRoundRect(long pXSData, long xgc, int x, int y, int w, int h, int arcW, int arcH); public void fillRoundRect(SunGraphics2D sg2d, int x, int y, int width, int height, int arcWidth, int arcHeight) { SunToolkit.awtLock(); try { long xgc = validate(sg2d); XFillRoundRect(sg2d.surfaceData.getNativeOps(), xgc, x+sg2d.transX, y+sg2d.transY, width, height, arcWidth, arcHeight); } finally { SunToolkit.awtUnlock(); } } native void XFillOval(long pXSData, long xgc, int x, int y, int w, int h); public void fillOval(SunGraphics2D sg2d, int x, int y, int width, int height) { SunToolkit.awtLock(); try { long xgc = validate(sg2d); XFillOval(sg2d.surfaceData.getNativeOps(), xgc, x+sg2d.transX, y+sg2d.transY, width, height); } finally { SunToolkit.awtUnlock(); } } native void XFillArc(long pXSData, long xgc, int x, int y, int w, int h, int angleStart, int angleExtent); public void fillArc(SunGraphics2D sg2d, int x, int y, int width, int height, int startAngle, int arcAngle) { SunToolkit.awtLock(); try { long xgc = validate(sg2d); XFillArc(sg2d.surfaceData.getNativeOps(), xgc, x+sg2d.transX, y+sg2d.transY, width, height, startAngle, arcAngle); } finally { SunToolkit.awtUnlock(); } } native void XFillPoly(long pXSData, long xgc, int transx, int transy, int[] xpoints, int[] ypoints, int npoints); public void fillPolygon(SunGraphics2D sg2d, int xpoints[], int ypoints[], int npoints) { SunToolkit.awtLock(); try { long xgc = validate(sg2d); XFillPoly(sg2d.surfaceData.getNativeOps(), xgc, sg2d.transX, sg2d.transY, xpoints, ypoints, npoints); } finally { SunToolkit.awtUnlock(); } } native void XFillSpans(long pXSData, long xgc, SpanIterator si, long iterator, int transx, int transy); native void XDoPath(SunGraphics2D sg2d, long pXSData, long xgc, int transX, int transY, Path2D.Float p2df, boolean isFill); private void doPath(SunGraphics2D sg2d, Shape s, boolean isFill) { 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; } SunToolkit.awtLock(); try { long xgc = validate(sg2d); XDoPath(sg2d, sg2d.surfaceData.getNativeOps(), xgc, transx, transy, p2df, isFill); } finally { SunToolkit.awtUnlock(); } } public void draw(SunGraphics2D sg2d, Shape s) { if (sg2d.strokeState == SunGraphics2D.STROKE_THIN) { // Delegate to drawPolygon() if possible... if (s instanceof Polygon && sg2d.transformState < SunGraphics2D.TRANSFORM_TRANSLATESCALE) { Polygon p = (Polygon) s; drawPolygon(sg2d, p.xpoints, p.ypoints, p.npoints); return; } // Otherwise we will use drawPath() for // high-quality thin paths. doPath(sg2d, s, false); } else if (sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM) { // REMIND: X11 can handle uniform scaled wide lines // and dashed lines itself if we set the appropriate // XGC attributes (TBD). ShapeSpanIterator si = LoopPipe.getStrokeSpans(sg2d, s); try { SunToolkit.awtLock(); try { long xgc = validate(sg2d); XFillSpans(sg2d.surfaceData.getNativeOps(), xgc, si, si.getNativeIterator(), 0, 0); } finally { SunToolkit.awtUnlock(); } } finally { si.dispose(); } } else { fill(sg2d, sg2d.stroke.createStrokedShape(s)); } } public void fill(SunGraphics2D sg2d, Shape s) { if (sg2d.strokeState == SunGraphics2D.STROKE_THIN) { // Delegate to fillPolygon() if possible... if (s instanceof Polygon && sg2d.transformState < SunGraphics2D.TRANSFORM_TRANSLATESCALE) { Polygon p = (Polygon) s; fillPolygon(sg2d, p.xpoints, p.ypoints, p.npoints); return; } // Otherwise we will use fillPath() for // high-quality fills. doPath(sg2d, s, true); return; } AffineTransform at; int transx, transy; if (sg2d.transformState < SunGraphics2D.TRANSFORM_TRANSLATESCALE) { // Transform (translation) will be done by XFillSpans 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)); SunToolkit.awtLock(); try { long xgc = validate(sg2d); XFillSpans(sg2d.surfaceData.getNativeOps(), xgc, ssi, ssi.getNativeIterator(), transx, transy); } finally { SunToolkit.awtUnlock(); } } finally { ssi.dispose(); } } native void devCopyArea(long sdOps, long xgc, int srcx, int srcy, int dstx, int dsty, int w, int h); public static class X11TracingRenderer extends X11Renderer { void XDrawLine(long pXSData, long xgc, int x1, int y1, int x2, int y2) { GraphicsPrimitive.tracePrimitive("X11DrawLine"); super.XDrawLine(pXSData, xgc, x1, y1, x2, y2); } void XDrawRect(long pXSData, long xgc, int x, int y, int w, int h) { GraphicsPrimitive.tracePrimitive("X11DrawRect"); super.XDrawRect(pXSData, xgc, x, y, w, h); } void XDrawRoundRect(long pXSData, long xgc, int x, int y, int w, int h, int arcW, int arcH) { GraphicsPrimitive.tracePrimitive("X11DrawRoundRect"); super.XDrawRoundRect(pXSData, xgc, x, y, w, h, arcW, arcH); } void XDrawOval(long pXSData, long xgc, int x, int y, int w, int h) { GraphicsPrimitive.tracePrimitive("X11DrawOval"); super.XDrawOval(pXSData, xgc, x, y, w, h); } void XDrawArc(long pXSData, long xgc, int x, int y, int w, int h, int angleStart, int angleExtent) { GraphicsPrimitive.tracePrimitive("X11DrawArc"); super.XDrawArc(pXSData, xgc, x, y, w, h, angleStart, angleExtent); } void XDrawPoly(long pXSData, long xgc, int transx, int transy, int[] xpoints, int[] ypoints, int npoints, boolean isclosed) { GraphicsPrimitive.tracePrimitive("X11DrawPoly"); super.XDrawPoly(pXSData, xgc, transx, transy, xpoints, ypoints, npoints, isclosed); } void XDoPath(SunGraphics2D sg2d, long pXSData, long xgc, int transX, int transY, Path2D.Float p2df, boolean isFill) { GraphicsPrimitive.tracePrimitive(isFill ? "X11FillPath" : "X11DrawPath"); super.XDoPath(sg2d, pXSData, xgc, transX, transY, p2df, isFill); } void XFillRect(long pXSData, long xgc, int x, int y, int w, int h) { GraphicsPrimitive.tracePrimitive("X11FillRect"); super.XFillRect(pXSData, xgc, x, y, w, h); } void XFillRoundRect(long pXSData, long xgc, int x, int y, int w, int h, int arcW, int arcH) { GraphicsPrimitive.tracePrimitive("X11FillRoundRect"); super.XFillRoundRect(pXSData, xgc, x, y, w, h, arcW, arcH); } void XFillOval(long pXSData, long xgc, int x, int y, int w, int h) { GraphicsPrimitive.tracePrimitive("X11FillOval"); super.XFillOval(pXSData, xgc, x, y, w, h); } void XFillArc(long pXSData, long xgc, int x, int y, int w, int h, int angleStart, int angleExtent) { GraphicsPrimitive.tracePrimitive("X11FillArc"); super.XFillArc(pXSData, xgc, x, y, w, h, angleStart, angleExtent); } void XFillPoly(long pXSData, long xgc, int transx, int transy, int[] xpoints, int[] ypoints, int npoints) { GraphicsPrimitive.tracePrimitive("X11FillPoly"); super.XFillPoly(pXSData, xgc, transx, transy, xpoints, ypoints, npoints); } void XFillSpans(long pXSData, long xgc, SpanIterator si, long iterator, int transx, int transy) { GraphicsPrimitive.tracePrimitive("X11FillSpans"); super.XFillSpans(pXSData, xgc, si, iterator, transx, transy); } void devCopyArea(long sdOps, long xgc, int srcx, int srcy, int dstx, int dsty, int w, int h) { GraphicsPrimitive.tracePrimitive("X11CopyArea"); super.devCopyArea(sdOps, xgc, srcx, srcy, dstx, dsty, w, h); } } }