| /* | |
| * Copyright (c) 2011, 2018, 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; | |
| import java.awt.*; | |
| import java.awt.font.*; | |
| import java.awt.geom.*; | |
| import java.awt.image.*; | |
| import java.nio.*; | |
| import sun.awt.*; | |
| import sun.awt.image.*; | |
| import sun.java2d.loops.*; | |
| import sun.java2d.pipe.*; | |
| import sun.lwawt.macosx.*; | |
| import java.lang.annotation.Native; | |
| /* | |
| * This is the SurfaceData for a CGContextRef. | |
| */ | |
| public abstract class OSXSurfaceData extends BufImgSurfaceData { | |
| static final float UPPER_BND = Float.MAX_VALUE / 2.0f; | |
| static final float LOWER_BND = -UPPER_BND; | |
| protected static CRenderer sQuartzPipe = null; | |
| protected static CTextPipe sCocoaTextPipe = null; | |
| protected static CompositeCRenderer sQuartzCompositePipe = null; | |
| private GraphicsConfiguration fConfig; | |
| private Rectangle fBounds; // bounds in user coordinates | |
| static { | |
| sQuartzPipe = new CRenderer(); // Creates the singleton quartz pipe. | |
| } | |
| // NOTE: Any subclasses must eventually call QuartzSurfaceData_InitOps in OSXSurfaceData.h | |
| // This sets up the native side for the SurfaceData, and is required. | |
| public OSXSurfaceData(SurfaceType sType, ColorModel cm) { | |
| this(sType, cm, null, new Rectangle()); | |
| } | |
| public OSXSurfaceData(SurfaceType sType, ColorModel cm, GraphicsConfiguration config, Rectangle bounds) { | |
| super(sType, cm); | |
| this.fConfig = config; | |
| this.fBounds = new Rectangle(bounds.x, bounds.y, bounds.width, bounds.y + bounds.height); | |
| this.fGraphicsStates = getBufferOfSize(kSizeOfParameters); | |
| this.fGraphicsStatesInt = this.fGraphicsStates.asIntBuffer(); | |
| this.fGraphicsStatesFloat = this.fGraphicsStates.asFloatBuffer(); | |
| this.fGraphicsStatesLong = this.fGraphicsStates.asLongBuffer(); | |
| this.fGraphicsStatesObject = new Object[8]; // clip coordinates + | |
| // clip types + | |
| // texture paint image + | |
| // stroke dash array + | |
| // font + font paint + | |
| // linear/radial gradient color + | |
| // linear/radial gradient fractions | |
| // NOTE: All access to the DrawingQueue comes through this OSXSurfaceData instance. Therefore | |
| // every instance method of OSXSurfaceData that accesses the fDrawingQueue is synchronized. | |
| // Thread.dumpStack(); | |
| } | |
| public void validatePipe(SunGraphics2D sg2d) { | |
| if (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) { | |
| if (sCocoaTextPipe == null) { | |
| sCocoaTextPipe = new CTextPipe(); | |
| } | |
| sg2d.imagepipe = sQuartzPipe; | |
| sg2d.drawpipe = sQuartzPipe; | |
| sg2d.fillpipe = sQuartzPipe; | |
| sg2d.shapepipe = sQuartzPipe; | |
| sg2d.textpipe = sCocoaTextPipe; | |
| } else { | |
| setPipesToQuartzComposite(sg2d); | |
| } | |
| } | |
| protected void setPipesToQuartzComposite(SunGraphics2D sg2d) { | |
| if (sQuartzCompositePipe == null) { | |
| sQuartzCompositePipe = new CompositeCRenderer(); | |
| } | |
| if (sCocoaTextPipe == null) { | |
| sCocoaTextPipe = new CTextPipe(); | |
| } | |
| sg2d.imagepipe = sQuartzCompositePipe; | |
| sg2d.drawpipe = sQuartzCompositePipe; | |
| sg2d.fillpipe = sQuartzCompositePipe; | |
| sg2d.shapepipe = sQuartzCompositePipe; | |
| sg2d.textpipe = sCocoaTextPipe; | |
| } | |
| public Rectangle getBounds() { | |
| // gznote: always return a copy, not the rect itself and translate into device space | |
| return new Rectangle(fBounds.x, fBounds.y, fBounds.width, fBounds.height - fBounds.y); | |
| } | |
| public GraphicsConfiguration getDeviceConfiguration() { | |
| return fConfig; | |
| } | |
| protected void setBounds(int x, int y, int w, int h) { | |
| fBounds.setBounds(x, y, w, y + h); | |
| } | |
| // START compositing support API | |
| public abstract BufferedImage copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, BufferedImage image); | |
| public abstract boolean xorSurfacePixels(SunGraphics2D sg2d, BufferedImage srcPixels, int x, int y, int w, int h, int colorXOR); | |
| GraphicsConfiguration sDefaultGraphicsConfiguration = null; | |
| protected BufferedImage getCompositingImage(int w, int h) { | |
| if (sDefaultGraphicsConfiguration == null) { | |
| sDefaultGraphicsConfiguration = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); | |
| } | |
| BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE); | |
| // clear the image. | |
| clearRect(img, w, h); | |
| return img; | |
| } | |
| protected BufferedImage getCompositingImageSame(BufferedImage img, int w, int h) { | |
| if ((img == null) || (img.getWidth() != w) || (img.getHeight() != h)) { | |
| img = getCompositingImage(w, h); | |
| } | |
| return img; | |
| } | |
| BufferedImage sSrcComposite = null; | |
| public BufferedImage getCompositingSrcImage(int w, int h) { | |
| // <rdar://problem/3720263>. Changed from getCompositingImageBiggerOrSame() to | |
| // getCompositingImageSame(). (vm) | |
| BufferedImage bim = getCompositingImageSame(sSrcComposite, w, h); | |
| sSrcComposite = bim; | |
| return bim; | |
| } | |
| BufferedImage sDstInComposite = null; | |
| public BufferedImage getCompositingDstInImage(int w, int h) { | |
| BufferedImage bim = getCompositingImageSame(sDstInComposite, w, h); | |
| sDstInComposite = bim; | |
| return bim; | |
| } | |
| BufferedImage sDstOutComposite = null; | |
| public BufferedImage getCompositingDstOutImage(int w, int h) { | |
| BufferedImage bim = getCompositingImageSame(sDstOutComposite, w, h); | |
| sDstOutComposite = bim; | |
| return bim; | |
| } | |
| public void clearRect(BufferedImage bim, int w, int h) { | |
| Graphics2D g = bim.createGraphics(); | |
| g.setComposite(AlphaComposite.Clear); | |
| g.fillRect(0, 0, w, h); | |
| g.dispose(); | |
| } | |
| // END compositing support API | |
| public void invalidate() { | |
| // always valid | |
| } | |
| // graphics primitives drawing implementation: | |
| // certain primitives don't care about all the states (ex. drawing an image needs not involve setting current paint) | |
| @Native static final int kPrimitive = 0; | |
| @Native static final int kImage = 1; | |
| @Native static final int kText = 2; | |
| @Native static final int kCopyArea = 3; | |
| @Native static final int kExternal = 4; | |
| @Native static final int kLine = 5; // belongs to kPrimitive | |
| @Native static final int kRect = 6; // belongs to kPrimitive | |
| @Native static final int kRoundRect = 7; // belongs to kPrimitive | |
| @Native static final int kOval = 8; // belongs to kPrimitive | |
| @Native static final int kArc = 9; // belongs to kPrimitive | |
| @Native static final int kPolygon = 10; // belongs to kPrimitive | |
| @Native static final int kShape = 11; // belongs to kPrimitive | |
| // static final int kImage = 12; // belongs to kImage | |
| @Native static final int kString = 13; // belongs to kText | |
| @Native static final int kGlyphs = 14; // belongs to kText | |
| @Native static final int kUnicodes = 15; // belongs to kText | |
| // static final int kCopyArea = 16; // belongs to kCopyArea | |
| // static final int kExternal = 17; // belongs to kExternal | |
| @Native static final int kCommonParameterCount = 1 + 1 + 4 + 4; // type + change flags + color info (type(1) align(1) and | |
| // value(2)) + parameters ((x1, y1, x2, y2) OR (x, y, w, h)) | |
| @Native static final int kLineParametersCount = kCommonParameterCount; // kCommonParameterCount | |
| @Native static final int kRectParametersCount = kCommonParameterCount + 1; // kCommonParameterCount + isfill | |
| @Native static final int kRoundRectParametersCount = kCommonParameterCount + 2 + 1; // kCommonParameterCount + arcW + arcH + | |
| // isfill | |
| @Native static final int kOvalParametersCount = kCommonParameterCount + 1; // kCommonParameterCount + isfill | |
| @Native static final int kArcParametersCount = kCommonParameterCount + 2 + 1 + 1;// kCommonParameterCount + startAngle + | |
| // arcAngle + isfill + type | |
| @Native static final int kPolygonParametersCount = 0; // not supported | |
| @Native static final int kShapeParametersCount = 0; // not supported | |
| @Native static final int kImageParametersCount = kCommonParameterCount + 2 + 2 + 4 + 4; // flip horz vert + w&h + src + dst | |
| @Native static final int kStringParametersCount = 0; // not supported | |
| @Native static final int kGlyphsParametersCount = 0; // not supported | |
| @Native static final int kUnicodesParametersCount = 0; // not supported | |
| @Native static final int kPixelParametersCount = 0; // not supported | |
| @Native static final int kExternalParametersCount = 0; // not supported | |
| // for intParameters | |
| // states info | |
| @Native static final int kChangeFlagIndex = 0; // kBoundsChangedBit | .. | kFontChangedBit | |
| // bounds info | |
| @Native static final int kBoundsXIndex = 1; | |
| @Native static final int kBoundsYIndex = 2; | |
| @Native static final int kBoundsWidthIndex = 3; | |
| @Native static final int kBoundsHeightIndex = 4; | |
| // clip info | |
| @Native static final int kClipStateIndex = 5; | |
| @Native static final int kClipNumTypesIndex = 6; | |
| @Native static final int kClipNumCoordsIndex = 7; | |
| @Native static final int kClipWindingRuleIndex = 8; | |
| @Native static final int kClipXIndex = 9; | |
| @Native static final int kClipYIndex = 10; | |
| @Native static final int kClipWidthIndex = 11; | |
| @Native static final int kClipHeightIndex = 12; | |
| // ctm info | |
| @Native static final int kCTMaIndex = 13; | |
| @Native static final int kCTMbIndex = 14; | |
| @Native static final int kCTMcIndex = 15; | |
| @Native static final int kCTMdIndex = 16; | |
| @Native static final int kCTMtxIndex = 17; | |
| @Native static final int kCTMtyIndex = 18; | |
| // color info | |
| @Native static final int kColorStateIndex = 19; // kColorSimple or kColorGradient or kColorTexture | |
| @Native static final int kColorRGBValueIndex = 20; // if kColorSimple | |
| @Native static final int kColorIndexValueIndex = 21; // if kColorSystem | |
| @Native static final int kColorPointerIndex = 22; // | |
| @Native static final int kColorPointerIndex2 = 23; // | |
| @Native static final int kColorRGBValue1Index = 24; // if kColorGradient | |
| @Native static final int kColorWidthIndex = 25; // if kColorTexture | |
| @Native static final int kColorRGBValue2Index = 26; // if kColorGradient | |
| @Native static final int kColorHeightIndex = 27; // if kColorTexture | |
| @Native static final int kColorIsCyclicIndex = 28; // if kColorGradient (kColorNonCyclic or kColorCyclic) | |
| @Native static final int kColorx1Index = 29; | |
| @Native static final int kColortxIndex = 30; | |
| @Native static final int kColory1Index = 31; | |
| @Native static final int kColortyIndex = 32; | |
| @Native static final int kColorx2Index = 33; | |
| @Native static final int kColorsxIndex = 34; | |
| @Native static final int kColory2Index = 35; | |
| @Native static final int kColorsyIndex = 36; | |
| // composite info | |
| @Native static final int kCompositeRuleIndex = 37; // kCGCompositeClear or ... or kCGCompositeXor | |
| @Native static final int kCompositeValueIndex = 38; | |
| // stroke info | |
| @Native static final int kStrokeJoinIndex = 39; // see BasicStroke.java | |
| @Native static final int kStrokeCapIndex = 40; // see BasicStroke.java | |
| @Native static final int kStrokeWidthIndex = 41; | |
| @Native static final int kStrokeDashPhaseIndex = 42; | |
| @Native static final int kStrokeLimitIndex = 43; | |
| // hints info | |
| @Native static final int kHintsAntialiasIndex = 44; | |
| @Native static final int kHintsTextAntialiasIndex = 45; | |
| @Native static final int kHintsFractionalMetricsIndex = 46; | |
| @Native static final int kHintsRenderingIndex = 47; | |
| @Native static final int kHintsInterpolationIndex = 48; | |
| //gradient info | |
| @Native static final int kRadiusIndex = 49; | |
| @Native static final int kSizeOfParameters = kRadiusIndex + 1; | |
| // for objectParameters | |
| @Native static final int kClipCoordinatesIndex = 0; | |
| @Native static final int kClipTypesIndex = 1; | |
| @Native static final int kTextureImageIndex = 2; | |
| @Native static final int kStrokeDashArrayIndex = 3; | |
| @Native static final int kFontIndex = 4; | |
| @Native static final int kFontPaintIndex = 5; | |
| @Native static final int kColorArrayIndex = 6; | |
| @Native static final int kFractionsArrayIndex = 7; | |
| // possible state changes | |
| @Native static final int kBoundsChangedBit = 1 << 0; | |
| @Native static final int kBoundsNotChangedBit = ~kBoundsChangedBit; | |
| @Native static final int kClipChangedBit = 1 << 1; | |
| @Native static final int kClipNotChangedBit = ~kClipChangedBit; | |
| @Native static final int kCTMChangedBit = 1 << 2; | |
| @Native static final int kCTMNotChangedBit = ~kCTMChangedBit; | |
| @Native static final int kColorChangedBit = 1 << 3; | |
| @Native static final int kColorNotChangedBit = ~kColorChangedBit; | |
| @Native static final int kCompositeChangedBit = 1 << 4; | |
| @Native static final int kCompositeNotChangedBit = ~kCompositeChangedBit; | |
| @Native static final int kStrokeChangedBit = 1 << 5; | |
| @Native static final int kStrokeNotChangedBit = ~kStrokeChangedBit; | |
| @Native static final int kHintsChangedBit = 1 << 6; | |
| @Native static final int kHintsNotChangedBit = ~kHintsChangedBit; | |
| @Native static final int kFontChangedBit = 1 << 7; | |
| @Native static final int kFontNotChangedBit = ~kFontChangedBit; | |
| @Native static final int kEverythingChangedFlag = 0xffffffff; | |
| // possible color states | |
| @Native static final int kColorSimple = 0; | |
| @Native static final int kColorSystem = 1; | |
| @Native static final int kColorGradient = 2; | |
| @Native static final int kColorTexture = 3; | |
| @Native static final int kColorLinearGradient = 4; | |
| @Native static final int kColorRadialGradient = 5; | |
| // possible gradient color states | |
| @Native static final int kColorNonCyclic = 0; | |
| @Native static final int kColorCyclic = 1; | |
| // possible clip states | |
| @Native static final int kClipRect = 0; | |
| @Native static final int kClipShape = 1; | |
| static int getRendererTypeForPrimitive(int primitiveType) { | |
| switch (primitiveType) { | |
| case kImage: | |
| return kImage; | |
| case kCopyArea: | |
| return kCopyArea; | |
| case kExternal: | |
| return kExternal; | |
| case kString: | |
| case kGlyphs: | |
| case kUnicodes: | |
| return kText; | |
| default: | |
| return kPrimitive; | |
| } | |
| } | |
| int fChangeFlag; | |
| protected ByteBuffer fGraphicsStates = null; | |
| IntBuffer fGraphicsStatesInt = null; | |
| FloatBuffer fGraphicsStatesFloat = null; | |
| LongBuffer fGraphicsStatesLong = null; | |
| protected Object[] fGraphicsStatesObject = null; | |
| Rectangle userBounds = new Rectangle(); | |
| float lastUserX = 0; | |
| float lastUserY = 0; | |
| float lastUserW = 0; | |
| float lastUserH = 0; | |
| void setUserBounds(SunGraphics2D sg2d, int x, int y, int width, int height) { | |
| if ((lastUserX != x) || (lastUserY != y) || (lastUserW != width) || (lastUserH != height)) { | |
| lastUserX = x; | |
| lastUserY = y; | |
| lastUserW = width; | |
| lastUserH = height; | |
| this.fGraphicsStatesInt.put(kBoundsXIndex, x); | |
| this.fGraphicsStatesInt.put(kBoundsYIndex, y); | |
| this.fGraphicsStatesInt.put(kBoundsWidthIndex, width); | |
| this.fGraphicsStatesInt.put(kBoundsHeightIndex, height); | |
| userBounds.setBounds(x, y, width, height); | |
| this.fChangeFlag = (this.fChangeFlag | kBoundsChangedBit); | |
| } else { | |
| this.fChangeFlag = (this.fChangeFlag & kBoundsNotChangedBit); | |
| } | |
| } | |
| static ByteBuffer getBufferOfSize(int size) { | |
| ByteBuffer buffer = ByteBuffer.allocateDirect(size * 4); | |
| buffer.order(ByteOrder.nativeOrder()); | |
| return buffer; | |
| } | |
| FloatBuffer clipCoordinatesArray = null; | |
| IntBuffer clipTypesArray = null; | |
| Shape lastClipShape = null; | |
| float lastClipX = 0; | |
| float lastClipY = 0; | |
| float lastClipW = 0; | |
| float lastClipH = 0; | |
| void setupClip(SunGraphics2D sg2d) { | |
| switch (sg2d.clipState) { | |
| case SunGraphics2D.CLIP_DEVICE: | |
| case SunGraphics2D.CLIP_RECTANGULAR: { | |
| Region clip = sg2d.getCompClip(); | |
| float x = clip.getLoX(); | |
| float y = clip.getLoY(); | |
| float w = clip.getWidth(); | |
| float h = clip.getHeight(); | |
| if ((this.fGraphicsStatesInt.get(kClipStateIndex) != kClipRect) || | |
| (x != lastClipX) || | |
| (y != lastClipY) || | |
| (w != lastClipW) || | |
| (h != lastClipH)) { | |
| this.fGraphicsStatesFloat.put(kClipXIndex, x); | |
| this.fGraphicsStatesFloat.put(kClipYIndex, y); | |
| this.fGraphicsStatesFloat.put(kClipWidthIndex, w); | |
| this.fGraphicsStatesFloat.put(kClipHeightIndex, h); | |
| lastClipX = x; | |
| lastClipY = y; | |
| lastClipW = w; | |
| lastClipH = h; | |
| this.fChangeFlag = (this.fChangeFlag | kClipChangedBit); | |
| } else { | |
| this.fChangeFlag = (this.fChangeFlag & kClipNotChangedBit); | |
| } | |
| this.fGraphicsStatesInt.put(kClipStateIndex, kClipRect); | |
| break; | |
| } | |
| case SunGraphics2D.CLIP_SHAPE: { | |
| // if (lastClipShape != sg2d.usrClip) shapes are mutable!, and doing "equals" traverses all | |
| // the coordinates, so we might as well do all of it anyhow | |
| lastClipShape = sg2d.usrClip; | |
| GeneralPath gp = null; | |
| if (sg2d.usrClip instanceof GeneralPath) { | |
| gp = (GeneralPath) sg2d.usrClip; | |
| } else { | |
| gp = new GeneralPath(sg2d.usrClip); | |
| } | |
| int shapeLength = getPathLength(gp); | |
| if ((clipCoordinatesArray == null) || (clipCoordinatesArray.capacity() < (shapeLength * 6))) { | |
| clipCoordinatesArray = getBufferOfSize(shapeLength * 6).asFloatBuffer(); // segment can have a | |
| // max of 6 coordinates | |
| } | |
| if ((clipTypesArray == null) || (clipTypesArray.capacity() < shapeLength)) { | |
| clipTypesArray = getBufferOfSize(shapeLength).asIntBuffer(); | |
| } | |
| int windingRule = getPathCoordinates(gp, clipCoordinatesArray, clipTypesArray); | |
| this.fGraphicsStatesInt.put(kClipNumTypesIndex, clipTypesArray.position()); | |
| this.fGraphicsStatesInt.put(kClipNumCoordsIndex, clipCoordinatesArray.position()); | |
| this.fGraphicsStatesInt.put(kClipWindingRuleIndex, windingRule); | |
| this.fGraphicsStatesObject[kClipTypesIndex] = clipTypesArray; | |
| this.fGraphicsStatesObject[kClipCoordinatesIndex] = clipCoordinatesArray; | |
| this.fChangeFlag = (this.fChangeFlag | kClipChangedBit); | |
| this.fGraphicsStatesInt.put(kClipStateIndex, kClipShape); | |
| break; | |
| } | |
| } | |
| } | |
| final double[] lastCTM = new double[6]; | |
| float lastCTMa = 0; | |
| float lastCTMb = 0; | |
| float lastCTMc = 0; | |
| float lastCTMd = 0; | |
| float lastCTMtx = 0; | |
| float lastCTMty = 0; | |
| void setupTransform(SunGraphics2D sg2d) { | |
| sg2d.transform.getMatrix(lastCTM); | |
| float a = (float) lastCTM[0]; | |
| float b = (float) lastCTM[1]; | |
| float c = (float) lastCTM[2]; | |
| float d = (float) lastCTM[3]; | |
| float tx = (float) lastCTM[4]; | |
| float ty = (float) lastCTM[5]; | |
| if (tx != lastCTMtx || | |
| ty != lastCTMty || | |
| a != lastCTMa || | |
| b != lastCTMb || | |
| c != lastCTMc || | |
| d != lastCTMd) { | |
| this.fGraphicsStatesFloat.put(kCTMaIndex, a); | |
| this.fGraphicsStatesFloat.put(kCTMbIndex, b); | |
| this.fGraphicsStatesFloat.put(kCTMcIndex, c); | |
| this.fGraphicsStatesFloat.put(kCTMdIndex, d); | |
| this.fGraphicsStatesFloat.put(kCTMtxIndex, tx); | |
| this.fGraphicsStatesFloat.put(kCTMtyIndex, ty); | |
| lastCTMa = a; | |
| lastCTMb = b; | |
| lastCTMc = c; | |
| lastCTMd = d; | |
| lastCTMtx = tx; | |
| lastCTMty = ty; | |
| this.fChangeFlag = (this.fChangeFlag | kCTMChangedBit); | |
| } else { | |
| this.fChangeFlag = (this.fChangeFlag & kCTMNotChangedBit); | |
| } | |
| } | |
| static AffineTransform sIdentityMatrix = new AffineTransform(); | |
| Paint lastPaint = null; | |
| long lastPaintPtr = 0; | |
| int lastPaintRGB = 0; | |
| int lastPaintIndex = 0; | |
| BufferedImage texturePaintImage = null; | |
| void setGradientViaRasterPath(SunGraphics2D sg2d) { | |
| if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorTexture) || (lastPaint != sg2d.paint) || ((this.fChangeFlag & kBoundsChangedBit) != 0)) { | |
| PaintContext context = sg2d.paint.createContext(sg2d.getDeviceColorModel(), userBounds, userBounds, sIdentityMatrix, sg2d.getRenderingHints()); | |
| WritableRaster raster = (WritableRaster) (context.getRaster(userBounds.x, userBounds.y, userBounds.width, userBounds.height)); | |
| ColorModel cm = context.getColorModel(); | |
| texturePaintImage = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null); | |
| this.fGraphicsStatesInt.put(kColorStateIndex, kColorTexture); | |
| this.fGraphicsStatesInt.put(kColorWidthIndex, texturePaintImage.getWidth()); | |
| this.fGraphicsStatesInt.put(kColorHeightIndex, texturePaintImage.getHeight()); | |
| this.fGraphicsStatesFloat.put(kColortxIndex, (float) userBounds.getX()); | |
| this.fGraphicsStatesFloat.put(kColortyIndex, (float) userBounds.getY()); | |
| this.fGraphicsStatesFloat.put(kColorsxIndex, 1.0f); | |
| this.fGraphicsStatesFloat.put(kColorsyIndex, 1.0f); | |
| this.fGraphicsStatesObject[kTextureImageIndex] = OSXOffScreenSurfaceData.createNewSurface(texturePaintImage); | |
| this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); | |
| } else { | |
| this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); | |
| } | |
| } | |
| void setupPaint(SunGraphics2D sg2d, int x, int y, int w, int h) { | |
| if (sg2d.paint instanceof SystemColor) { | |
| SystemColor color = (SystemColor) sg2d.paint; | |
| int index = color.hashCode(); // depends on Color.java hashCode implementation! (returns "value" of color) | |
| if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorSystem) || (index != this.lastPaintIndex)) { | |
| this.lastPaintIndex = index; | |
| this.fGraphicsStatesInt.put(kColorStateIndex, kColorSystem); | |
| this.fGraphicsStatesInt.put(kColorIndexValueIndex, index); | |
| this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); | |
| } else { | |
| this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); | |
| } | |
| } else if (sg2d.paint instanceof Color) { | |
| Color color = (Color) sg2d.paint; | |
| int rgb = color.getRGB(); | |
| if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorSimple) || (rgb != this.lastPaintRGB)) { | |
| this.lastPaintRGB = rgb; | |
| this.fGraphicsStatesInt.put(kColorStateIndex, kColorSimple); | |
| this.fGraphicsStatesInt.put(kColorRGBValueIndex, rgb); | |
| this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); | |
| } else { | |
| this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); | |
| } | |
| } else if (sg2d.paint instanceof GradientPaint) { | |
| if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorGradient) || (lastPaint != sg2d.paint)) { | |
| GradientPaint color = (GradientPaint) sg2d.paint; | |
| this.fGraphicsStatesInt.put(kColorStateIndex, kColorGradient); | |
| this.fGraphicsStatesInt.put(kColorRGBValue1Index, color.getColor1().getRGB()); | |
| this.fGraphicsStatesInt.put(kColorRGBValue2Index, color.getColor2().getRGB()); | |
| this.fGraphicsStatesInt.put(kColorIsCyclicIndex, (color.isCyclic()) ? kColorCyclic : kColorNonCyclic); | |
| Point2D p = color.getPoint1(); | |
| this.fGraphicsStatesFloat.put(kColorx1Index, (float) p.getX()); | |
| this.fGraphicsStatesFloat.put(kColory1Index, (float) p.getY()); | |
| p = color.getPoint2(); | |
| this.fGraphicsStatesFloat.put(kColorx2Index, (float) p.getX()); | |
| this.fGraphicsStatesFloat.put(kColory2Index, (float) p.getY()); | |
| this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); | |
| } else { | |
| this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); | |
| } | |
| } else if (sg2d.paint instanceof LinearGradientPaint) { | |
| LinearGradientPaint color = (LinearGradientPaint) sg2d.paint; | |
| if (color.getCycleMethod() == LinearGradientPaint.CycleMethod.NO_CYCLE) { | |
| if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorLinearGradient) || (lastPaint != sg2d.paint)) { | |
| this.fGraphicsStatesInt.put(kColorStateIndex, kColorLinearGradient); | |
| int numColor = color.getColors().length; | |
| int[] colorArray = new int[numColor]; | |
| for (int i = 0; i < numColor; i++) { | |
| colorArray[i] = color.getColors()[i].getRGB(); | |
| } | |
| this.fGraphicsStatesObject[kColorArrayIndex] = colorArray; | |
| int numFractions = color.getFractions().length; | |
| float[] fractionArray = new float[numFractions]; | |
| for (int i = 0; i < numFractions; i++) { | |
| fractionArray[i] = color.getFractions()[i]; | |
| } | |
| this.fGraphicsStatesObject[kFractionsArrayIndex] = color.getFractions(); | |
| Point2D p = color.getStartPoint(); | |
| this.fGraphicsStatesFloat.put(kColorx1Index, (float) p.getX()); | |
| this.fGraphicsStatesFloat.put(kColory1Index, (float) p.getY()); | |
| p = color.getEndPoint(); | |
| this.fGraphicsStatesFloat.put(kColorx2Index, (float) p.getX()); | |
| this.fGraphicsStatesFloat.put(kColory2Index, (float) p.getY()); | |
| this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); | |
| } else { | |
| this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); | |
| } | |
| } else { | |
| setGradientViaRasterPath(sg2d); | |
| } | |
| } else if (sg2d.paint instanceof RadialGradientPaint) { | |
| RadialGradientPaint color = (RadialGradientPaint) sg2d.paint; | |
| if (color.getCycleMethod() == RadialGradientPaint.CycleMethod.NO_CYCLE) { | |
| if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorRadialGradient) || (lastPaint != sg2d.paint)) { | |
| this.fGraphicsStatesInt.put(kColorStateIndex, kColorRadialGradient); | |
| int numColor = color.getColors().length; | |
| int[] colorArray = new int[numColor]; | |
| for (int i = 0; i < numColor; i++) { | |
| colorArray[i] = color.getColors()[i].getRGB(); | |
| } | |
| this.fGraphicsStatesObject[kColorArrayIndex] = colorArray; | |
| int numStops = color.getFractions().length; | |
| float[] stopsArray = new float[numStops]; | |
| for (int i = 0; i < numStops; i++) { | |
| stopsArray[i] = color.getFractions()[i]; | |
| } | |
| this.fGraphicsStatesObject[kFractionsArrayIndex] = color.getFractions(); | |
| Point2D p = color.getFocusPoint(); | |
| this.fGraphicsStatesFloat.put(kColorx1Index, (float) p.getX()); | |
| this.fGraphicsStatesFloat.put(kColory1Index, (float) p.getY()); | |
| p = color.getCenterPoint(); | |
| this.fGraphicsStatesFloat.put(kColorx2Index, (float) p.getX()); | |
| this.fGraphicsStatesFloat.put(kColory2Index, (float) p.getY()); | |
| this.fGraphicsStatesFloat.put(kRadiusIndex, color.getRadius()); | |
| this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); | |
| } else { | |
| this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); | |
| } | |
| } else { | |
| setGradientViaRasterPath(sg2d); | |
| } | |
| } else if (sg2d.paint instanceof TexturePaint) { | |
| if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorTexture) || (lastPaint != sg2d.paint)) { | |
| TexturePaint color = (TexturePaint) sg2d.paint; | |
| this.fGraphicsStatesInt.put(kColorStateIndex, kColorTexture); | |
| texturePaintImage = color.getImage(); | |
| SurfaceData textureSurfaceData = OSXOffScreenSurfaceData.createNewSurface(texturePaintImage); | |
| this.fGraphicsStatesInt.put(kColorWidthIndex, texturePaintImage.getWidth()); | |
| this.fGraphicsStatesInt.put(kColorHeightIndex, texturePaintImage.getHeight()); | |
| Rectangle2D anchor = color.getAnchorRect(); | |
| this.fGraphicsStatesFloat.put(kColortxIndex, (float) anchor.getX()); | |
| this.fGraphicsStatesFloat.put(kColortyIndex, (float) anchor.getY()); | |
| this.fGraphicsStatesFloat.put(kColorsxIndex, (float) (anchor.getWidth() / texturePaintImage.getWidth())); | |
| this.fGraphicsStatesFloat.put(kColorsyIndex, (float) (anchor.getHeight() / texturePaintImage.getHeight())); | |
| this.fGraphicsStatesObject[kTextureImageIndex] = textureSurfaceData; | |
| this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); | |
| } else { | |
| this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); | |
| } | |
| } else { | |
| setGradientViaRasterPath(sg2d); | |
| } | |
| lastPaint = sg2d.paint; | |
| } | |
| Composite lastComposite; | |
| int lastCompositeAlphaRule = 0; | |
| float lastCompositeAlphaValue = 0; | |
| void setupComposite(SunGraphics2D sg2d) { | |
| Composite composite = sg2d.composite; | |
| if (lastComposite != composite) { | |
| lastComposite = composite; | |
| // For composite state COMP_ISCOPY, COMP_XOR or COMP_CUSTOM set alpha compositor to COPY: | |
| int alphaRule = AlphaComposite.SRC_OVER; | |
| float alphaValue = 1.0f; | |
| // For composite state COMP_ISCOPY composite could be null. If it's not (or composite state == COMP_ALPHA) | |
| // get alpha compositor's values: | |
| if ((sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) && (composite != null)) { | |
| AlphaComposite alphaComposite = (AlphaComposite) composite; | |
| alphaRule = alphaComposite.getRule(); | |
| alphaValue = alphaComposite.getAlpha(); | |
| } | |
| // 2-17-03 VL: [Radar 3174922] | |
| // For COMP_XOR and COMP_CUSTOM compositing modes we should be setting alphaRule = AlphaComposite.SRC | |
| // which should map to kCGCompositeCopy. | |
| if ((lastCompositeAlphaRule != alphaRule) || (lastCompositeAlphaValue != alphaValue)) { | |
| this.fGraphicsStatesInt.put(kCompositeRuleIndex, alphaRule); | |
| this.fGraphicsStatesFloat.put(kCompositeValueIndex, alphaValue); | |
| lastCompositeAlphaRule = alphaRule; | |
| lastCompositeAlphaValue = alphaValue; | |
| this.fChangeFlag = (this.fChangeFlag | kCompositeChangedBit); | |
| } else { | |
| this.fChangeFlag = (this.fChangeFlag & kCompositeNotChangedBit); | |
| } | |
| } else { | |
| this.fChangeFlag = (this.fChangeFlag & kCompositeNotChangedBit); | |
| } | |
| } | |
| BasicStroke lastStroke = null; | |
| static BasicStroke defaultBasicStroke = new BasicStroke(); | |
| void setupStroke(SunGraphics2D sg2d) { | |
| BasicStroke stroke = defaultBasicStroke; | |
| if (sg2d.stroke instanceof BasicStroke) { | |
| stroke = (BasicStroke) sg2d.stroke; | |
| } | |
| if (lastStroke != stroke) { | |
| this.fGraphicsStatesObject[kStrokeDashArrayIndex] = stroke.getDashArray(); | |
| this.fGraphicsStatesFloat.put(kStrokeDashPhaseIndex, stroke.getDashPhase()); | |
| this.fGraphicsStatesInt.put(kStrokeCapIndex, stroke.getEndCap()); | |
| this.fGraphicsStatesInt.put(kStrokeJoinIndex, stroke.getLineJoin()); | |
| this.fGraphicsStatesFloat.put(kStrokeWidthIndex, stroke.getLineWidth()); | |
| this.fGraphicsStatesFloat.put(kStrokeLimitIndex, stroke.getMiterLimit()); | |
| this.fChangeFlag = (this.fChangeFlag | kStrokeChangedBit); | |
| lastStroke = stroke; | |
| } else { | |
| this.fChangeFlag = (this.fChangeFlag & kStrokeNotChangedBit); | |
| } | |
| } | |
| Font lastFont; | |
| void setupFont(Font font, Paint paint) { | |
| if (font == null) { return; } | |
| // We have to setup the kFontPaintIndex if we have changed the color so we added the last | |
| // test to see if the color has changed - needed for complex strings | |
| // see Radar 3368674 | |
| if ((font != lastFont) || ((this.fChangeFlag & kColorChangedBit) != 0)) { | |
| this.fGraphicsStatesObject[kFontIndex] = font; | |
| this.fGraphicsStatesObject[kFontPaintIndex] = paint; | |
| this.fChangeFlag = (this.fChangeFlag | kFontChangedBit); | |
| lastFont = font; | |
| } else { | |
| this.fChangeFlag = (this.fChangeFlag & kFontNotChangedBit); | |
| } | |
| } | |
| void setupRenderingHints(SunGraphics2D sg2d) { | |
| boolean hintsChanged = false; | |
| // Significant for draw, fill, text, and image ops: | |
| int antialiasHint = sg2d.antialiasHint; | |
| if (this.fGraphicsStatesInt.get(kHintsAntialiasIndex) != antialiasHint) { | |
| this.fGraphicsStatesInt.put(kHintsAntialiasIndex, antialiasHint); | |
| hintsChanged = true; | |
| } | |
| // Significant only for text ops: | |
| int textAntialiasHint = sg2d.textAntialiasHint; | |
| if (this.fGraphicsStatesInt.get(kHintsTextAntialiasIndex) != textAntialiasHint) { | |
| this.fGraphicsStatesInt.put(kHintsTextAntialiasIndex, textAntialiasHint); | |
| hintsChanged = true; | |
| } | |
| // Significant only for text ops: | |
| int fractionalMetricsHint = sg2d.fractionalMetricsHint; | |
| if (this.fGraphicsStatesInt.get(kHintsFractionalMetricsIndex) != fractionalMetricsHint) { | |
| this.fGraphicsStatesInt.put(kHintsFractionalMetricsIndex, fractionalMetricsHint); | |
| hintsChanged = true; | |
| } | |
| // Significant only for image ops: | |
| int renderHint = sg2d.renderHint; | |
| if (this.fGraphicsStatesInt.get(kHintsRenderingIndex) != renderHint) { | |
| this.fGraphicsStatesInt.put(kHintsRenderingIndex, renderHint); | |
| hintsChanged = true; | |
| } | |
| // Significant only for image ops: | |
| Object hintValue = sg2d.getRenderingHint(RenderingHints.KEY_INTERPOLATION); | |
| int interpolationHint = (hintValue != null ? ((SunHints.Value) hintValue).getIndex() : -1); | |
| if (this.fGraphicsStatesInt.get(kHintsInterpolationIndex) != interpolationHint) { | |
| this.fGraphicsStatesInt.put(kHintsInterpolationIndex, interpolationHint); | |
| hintsChanged = true; | |
| } | |
| if (hintsChanged) { | |
| this.fChangeFlag = (this.fChangeFlag | kHintsChangedBit); | |
| } else { | |
| this.fChangeFlag = (this.fChangeFlag & kHintsNotChangedBit); | |
| } | |
| } | |
| SunGraphics2D sg2dCurrent = null; | |
| Thread threadCurrent = null; | |
| void setupGraphicsState(SunGraphics2D sg2d, int primitiveType) { | |
| setupGraphicsState(sg2d, primitiveType, sg2d.font, 0, 0, fBounds.width, fBounds.height); // deviceBounds into userBounds | |
| } | |
| void setupGraphicsState(SunGraphics2D sg2d, int primitiveType, int x, int y, int w, int h) { | |
| setupGraphicsState(sg2d, primitiveType, sg2d.font, x, y, w, h); | |
| } | |
| // the method below is overridden by CPeerSurface to check the last peer used to draw | |
| // if the peer changed we finish lazy drawing | |
| void setupGraphicsState(SunGraphics2D sg2d, int primitiveType, Font font, int x, int y, int w, int h) { | |
| this.fChangeFlag = 0; | |
| setUserBounds(sg2d, x, y, w, h); | |
| Thread thread = Thread.currentThread(); | |
| if ((this.sg2dCurrent != sg2d) || (this.threadCurrent != thread)) { | |
| this.sg2dCurrent = sg2d; | |
| this.threadCurrent = thread; | |
| setupClip(sg2d); | |
| setupTransform(sg2d); | |
| setupPaint(sg2d, x, y, w, h); | |
| setupComposite(sg2d); | |
| setupStroke(sg2d); | |
| setupFont(font, sg2d.paint); | |
| setupRenderingHints(sg2d); | |
| this.fChangeFlag = kEverythingChangedFlag; | |
| } else { | |
| int rendererType = getRendererTypeForPrimitive(primitiveType); | |
| setupClip(sg2d); | |
| setupTransform(sg2d); | |
| if (rendererType != kCopyArea) { | |
| setupComposite(sg2d); | |
| setupRenderingHints(sg2d); | |
| if ((rendererType != kImage)) { | |
| setupPaint(sg2d, x, y, w, h); | |
| setupStroke(sg2d); | |
| } | |
| if (rendererType != kPrimitive) { | |
| setupFont(font, sg2d.paint); | |
| } | |
| } | |
| } | |
| this.fGraphicsStatesInt.put(kChangeFlagIndex, this.fChangeFlag); | |
| } | |
| boolean isCustomPaint(SunGraphics2D sg2d) { | |
| if ((sg2d.paint instanceof Color) || (sg2d.paint instanceof SystemColor) || (sg2d.paint instanceof GradientPaint) || (sg2d.paint instanceof TexturePaint)) { return false; } | |
| return true; | |
| } | |
| final float[] segmentCoordinatesArray = new float[6]; | |
| int getPathLength(GeneralPath gp) { | |
| int length = 0; | |
| PathIterator pi = gp.getPathIterator(null); | |
| while (pi.isDone() == false) { | |
| pi.next(); | |
| length++; | |
| } | |
| return length; | |
| } | |
| int getPathCoordinates(GeneralPath gp, FloatBuffer coordinates, IntBuffer types) { | |
| // System.err.println("getPathCoordinates"); | |
| boolean skip = false; | |
| coordinates.clear(); | |
| types.clear(); | |
| int type; | |
| PathIterator pi = gp.getPathIterator(null); | |
| while (pi.isDone() == false) { | |
| skip = false; | |
| type = pi.currentSegment(segmentCoordinatesArray); | |
| switch (type) { | |
| case PathIterator.SEG_MOVETO: | |
| // System.err.println(" SEG_MOVETO ("+segmentCoordinatesArray[0]+", "+segmentCoordinatesArray[1]+")"); | |
| if (segmentCoordinatesArray[0] < UPPER_BND && segmentCoordinatesArray[0] > LOWER_BND && | |
| segmentCoordinatesArray[1] < UPPER_BND && segmentCoordinatesArray[1] > LOWER_BND) { | |
| coordinates.put(segmentCoordinatesArray[0]); | |
| coordinates.put(segmentCoordinatesArray[1]); | |
| } else { | |
| skip = true; | |
| } | |
| break; | |
| case PathIterator.SEG_LINETO: | |
| // System.err.println(" SEG_LINETO ("+segmentCoordinatesArray[0]+", "+segmentCoordinatesArray[1]+")"); | |
| if (segmentCoordinatesArray[0] < UPPER_BND && segmentCoordinatesArray[0] > LOWER_BND && | |
| segmentCoordinatesArray[1] < UPPER_BND && segmentCoordinatesArray[1] > LOWER_BND) { | |
| coordinates.put(segmentCoordinatesArray[0]); | |
| coordinates.put(segmentCoordinatesArray[1]); | |
| } else { | |
| skip = true; | |
| } | |
| break; | |
| case PathIterator.SEG_QUADTO: | |
| // System.err.println(" SEG_QUADTO ("+segmentCoordinatesArray[0]+", "+segmentCoordinatesArray[1]+"), ("+segmentCoordinatesArray[2]+", "+segmentCoordinatesArray[3]+")"); | |
| if (segmentCoordinatesArray[0] < UPPER_BND && segmentCoordinatesArray[0] > LOWER_BND && | |
| segmentCoordinatesArray[1] < UPPER_BND && segmentCoordinatesArray[1] > LOWER_BND && | |
| segmentCoordinatesArray[2] < UPPER_BND && segmentCoordinatesArray[2] > LOWER_BND && | |
| segmentCoordinatesArray[3] < UPPER_BND && segmentCoordinatesArray[3] > LOWER_BND) { | |
| coordinates.put(segmentCoordinatesArray[0]); | |
| coordinates.put(segmentCoordinatesArray[1]); | |
| coordinates.put(segmentCoordinatesArray[2]); | |
| coordinates.put(segmentCoordinatesArray[3]); | |
| } else { | |
| skip = true; | |
| } | |
| break; | |
| case PathIterator.SEG_CUBICTO: | |
| // System.err.println(" SEG_QUADTO ("+segmentCoordinatesArray[0]+", "+segmentCoordinatesArray[1]+"), ("+segmentCoordinatesArray[2]+", "+segmentCoordinatesArray[3]+"), ("+segmentCoordinatesArray[4]+", "+segmentCoordinatesArray[5]+")"); | |
| if (segmentCoordinatesArray[0] < UPPER_BND && segmentCoordinatesArray[0] > LOWER_BND && | |
| segmentCoordinatesArray[1] < UPPER_BND && segmentCoordinatesArray[1] > LOWER_BND && | |
| segmentCoordinatesArray[2] < UPPER_BND && segmentCoordinatesArray[2] > LOWER_BND && | |
| segmentCoordinatesArray[3] < UPPER_BND && segmentCoordinatesArray[3] > LOWER_BND && | |
| segmentCoordinatesArray[4] < UPPER_BND && segmentCoordinatesArray[4] > LOWER_BND && | |
| segmentCoordinatesArray[5] < UPPER_BND && segmentCoordinatesArray[5] > LOWER_BND) { | |
| coordinates.put(segmentCoordinatesArray[0]); | |
| coordinates.put(segmentCoordinatesArray[1]); | |
| coordinates.put(segmentCoordinatesArray[2]); | |
| coordinates.put(segmentCoordinatesArray[3]); | |
| coordinates.put(segmentCoordinatesArray[4]); | |
| coordinates.put(segmentCoordinatesArray[5]); | |
| } else { | |
| skip = true; | |
| } | |
| break; | |
| case PathIterator.SEG_CLOSE: | |
| // System.err.println(" SEG_CLOSE"); | |
| break; | |
| } | |
| if (!skip) { | |
| types.put(type); | |
| } | |
| pi.next(); | |
| } | |
| return pi.getWindingRule(); | |
| } | |
| public void doLine(CRenderer renderer, SunGraphics2D sg2d, float x1, float y1, float x2, float y2) { | |
| // System.err.println("-- doLine x1="+x1+" y1="+y1+" x2="+x2+" y2="+y2+" paint="+sg2d.paint); | |
| setupGraphicsState(sg2d, kLine, sg2d.font, 0, 0, fBounds.width, fBounds.height); | |
| renderer.doLine(this, x1, y1, x2, y2); | |
| } | |
| public void doRect(CRenderer renderer, SunGraphics2D sg2d, float x, float y, float width, float height, boolean isfill) { | |
| // System.err.println("-- doRect x="+x+" y="+y+" w="+width+" h="+height+" isfill="+isfill+" paint="+sg2d.paint); | |
| if ((isfill) && (isCustomPaint(sg2d))) { | |
| setupGraphicsState(sg2d, kRect, (int) x, (int) y, (int) width, (int) height); | |
| } else { | |
| setupGraphicsState(sg2d, kRect, sg2d.font, 0, 0, fBounds.width, fBounds.height); | |
| } | |
| renderer.doRect(this, x, y, width, height, isfill); | |
| } | |
| public void doRoundRect(CRenderer renderer, SunGraphics2D sg2d, float x, float y, float width, float height, float arcW, float arcH, boolean isfill) { | |
| // System.err.println("--- doRoundRect"); | |
| if ((isfill) && (isCustomPaint(sg2d))) { | |
| setupGraphicsState(sg2d, kRoundRect, (int) x, (int) y, (int) width, (int) height); | |
| } else { | |
| setupGraphicsState(sg2d, kRoundRect, sg2d.font, 0, 0, fBounds.width, fBounds.height); | |
| } | |
| renderer.doRoundRect(this, x, y, width, height, arcW, arcH, isfill); | |
| } | |
| public void doOval(CRenderer renderer, SunGraphics2D sg2d, float x, float y, float width, float height, boolean isfill) { | |
| // System.err.println("--- doOval"); | |
| if ((isfill) && (isCustomPaint(sg2d))) { | |
| setupGraphicsState(sg2d, kOval, (int) x, (int) y, (int) width, (int) height); | |
| } else { | |
| setupGraphicsState(sg2d, kOval, sg2d.font, 0, 0, fBounds.width, fBounds.height); | |
| } | |
| renderer.doOval(this, x, y, width, height, isfill); | |
| } | |
| public void doArc(CRenderer renderer, SunGraphics2D sg2d, float x, float y, float width, float height, float startAngle, float arcAngle, int type, boolean isfill) { | |
| // System.err.println("--- doArc"); | |
| if ((isfill) && (isCustomPaint(sg2d))) { | |
| setupGraphicsState(sg2d, kArc, (int) x, (int) y, (int) width, (int) height); | |
| } else { | |
| setupGraphicsState(sg2d, kArc, sg2d.font, 0, 0, fBounds.width, fBounds.height); | |
| } | |
| renderer.doArc(this, x, y, width, height, startAngle, arcAngle, type, isfill); | |
| } | |
| public void doPolygon(CRenderer renderer, SunGraphics2D sg2d, int[] xpoints, int[] ypoints, int npoints, boolean ispolygon, boolean isfill) { | |
| // System.err.println("--- doPolygon"); | |
| if ((isfill) && (isCustomPaint(sg2d))) { | |
| int minx = xpoints[0]; | |
| int miny = ypoints[0]; | |
| int maxx = minx; | |
| int maxy = miny; | |
| for (int i = 1; i < npoints; i++) { | |
| int x = xpoints[i]; | |
| if (x < minx) { | |
| minx = x; | |
| } else if (x > maxx) { | |
| maxx = x; | |
| } | |
| int y = ypoints[i]; | |
| if (y < miny) { | |
| miny = y; | |
| } else if (y > maxy) { | |
| maxy = y; | |
| } | |
| } | |
| setupGraphicsState(sg2d, kPolygon, minx, miny, maxx - minx, maxy - miny); | |
| } else { | |
| setupGraphicsState(sg2d, kPolygon, sg2d.font, 0, 0, fBounds.width, fBounds.height); | |
| } | |
| renderer.doPoly(this, xpoints, ypoints, npoints, ispolygon, isfill); | |
| } | |
| FloatBuffer shapeCoordinatesArray = null; | |
| IntBuffer shapeTypesArray = null; | |
| public void drawfillShape(CRenderer renderer, SunGraphics2D sg2d, GeneralPath gp, boolean isfill, boolean shouldApplyOffset) { | |
| // System.err.println("--- drawfillShape"); | |
| if ((isfill) && (isCustomPaint(sg2d))) { | |
| Rectangle bounds = gp.getBounds(); | |
| setupGraphicsState(sg2d, kShape, bounds.x, bounds.y, bounds.width, bounds.height); | |
| } else { | |
| setupGraphicsState(sg2d, kShape, sg2d.font, 0, 0, fBounds.width, fBounds.height); | |
| } | |
| int shapeLength = getPathLength(gp); | |
| if ((shapeCoordinatesArray == null) || (shapeCoordinatesArray.capacity() < (shapeLength * 6))) { | |
| shapeCoordinatesArray = getBufferOfSize(shapeLength * 6).asFloatBuffer(); // segment can have a max of 6 | |
| // coordinates | |
| } | |
| if ((shapeTypesArray == null) || (shapeTypesArray.capacity() < shapeLength)) { | |
| shapeTypesArray = getBufferOfSize(shapeLength).asIntBuffer(); | |
| } | |
| int windingRule = getPathCoordinates(gp, shapeCoordinatesArray, shapeTypesArray); | |
| renderer.doShape(this, shapeLength, shapeCoordinatesArray, shapeTypesArray, windingRule, isfill, shouldApplyOffset); | |
| } | |
| public void blitImage(CRenderer renderer, SunGraphics2D sg2d, SurfaceData img, boolean fliph, boolean flipv, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, Color bgColor) { | |
| // System.err.println("--- blitImage sx="+sx+", sy="+sy+", sw="+sw+", sh="+sh+", img="+img); | |
| OSXOffScreenSurfaceData osxsd = (OSXOffScreenSurfaceData) img; | |
| synchronized (osxsd.getLockObject()) { | |
| int w = osxsd.bim.getWidth(); | |
| int h = osxsd.bim.getHeight(); | |
| // the image itself can have outstanding graphics primitives that might need to be flushed | |
| setupGraphicsState(sg2d, kImage, sg2d.font, 0, 0, fBounds.width, fBounds.height); | |
| // 04/06/04 cmc: radr://3612381 Graphics.drawImage ignores bgcolor parameter | |
| if (bgColor != null) { | |
| img = osxsd.getCopyWithBgColor(bgColor); | |
| } | |
| renderer.doImage(this, img, fliph, flipv, w, h, sx, sy, sw, sh, dx, dy, dw, dh); | |
| } | |
| } | |
| public interface CGContextDrawable { | |
| public void drawIntoCGContext(final long cgContext); | |
| } | |
| public void drawString(CTextPipe renderer, SunGraphics2D sg2d, long nativeStrikePtr, String str, double x, double y) { | |
| // System.err.println("--- drawString str=\""+str+"\""); | |
| // see <rdar://problem/3825795>. We don't want to call anything if the string is empty! | |
| if (str.length() == 0) { return; } | |
| setupGraphicsState(sg2d, kString, sg2d.font, 0, 0, fBounds.width, fBounds.height); | |
| renderer.doDrawString(this, nativeStrikePtr, str, x, y); | |
| } | |
| public void drawGlyphs(CTextPipe renderer, SunGraphics2D sg2d, long nativeStrikePtr, GlyphVector gv, float x, float y) { | |
| // System.err.println("--- drawGlyphs"); | |
| setupGraphicsState(sg2d, kGlyphs, gv.getFont(), 0, 0, fBounds.width, fBounds.height); | |
| renderer.doDrawGlyphs(this, nativeStrikePtr, gv, x, y); | |
| } | |
| public void drawUnicodes(CTextPipe renderer, SunGraphics2D sg2d, long nativeStrikePtr, char[] unicodes, int offset, int length, float x, float y) { | |
| // System.err.println("--- drawUnicodes "+(new String(unicodes, offset, length))); | |
| setupGraphicsState(sg2d, kUnicodes, sg2d.font, 0, 0, fBounds.width, fBounds.height); | |
| if (length == 1) { | |
| renderer.doOneUnicode(this, nativeStrikePtr, unicodes[offset], x, y); | |
| } else { | |
| renderer.doUnicodes(this, nativeStrikePtr, unicodes, offset, length, x, y); | |
| } | |
| } | |
| // used by copyArea: | |
| Rectangle srcCopyAreaRect = new Rectangle(); | |
| Rectangle dstCopyAreaRect = new Rectangle(); | |
| Rectangle finalCopyAreaRect = new Rectangle(); | |
| Rectangle copyAreaBounds = new Rectangle(); | |
| void intersection(Rectangle r1, Rectangle r2, Rectangle r3) { | |
| // this code is taken from Rectangle.java (modified to put results in r3) | |
| int tx1 = r1.x; | |
| int ty1 = r1.y; | |
| long tx2 = tx1 + r1.width; | |
| long ty2 = ty1 + r1.height; | |
| int rx1 = r2.x; | |
| int ry1 = r2.y; | |
| long rx2 = rx1 + r2.width; | |
| long ry2 = ry1 + r2.height; | |
| if (tx1 < rx1) tx1 = rx1; | |
| if (ty1 < ry1) ty1 = ry1; | |
| if (tx2 > rx2) tx2 = rx2; | |
| if (ty2 > ry2) ty2 = ry2; | |
| tx2 -= tx1; | |
| ty2 -= ty1; | |
| // tx2,ty2 will never overflow (they will never be | |
| // larger than the smallest of the two source w,h) | |
| // they might underflow, though... | |
| if (tx2 < Integer.MIN_VALUE) tx2 = Integer.MIN_VALUE; | |
| if (ty2 < Integer.MIN_VALUE) ty2 = Integer.MIN_VALUE; | |
| r3.setBounds(tx1, ty1, (int) tx2, (int) ty2); | |
| } | |
| /** | |
| * Clips the copy area to the heavyweight bounds and returns the clipped rectangle. | |
| * The returned clipped rectangle is in the coordinate space of the surface. | |
| */ | |
| protected Rectangle clipCopyArea(SunGraphics2D sg2d, int x, int y, int w, int h, int dx, int dy) { | |
| // we need to clip against the heavyweight bounds | |
| copyAreaBounds.setBounds(sg2d.devClip.getLoX(), sg2d.devClip.getLoY(), sg2d.devClip.getWidth(), sg2d.devClip.getHeight()); | |
| // clip src rect | |
| srcCopyAreaRect.setBounds(x, y, w, h); | |
| intersection(srcCopyAreaRect, copyAreaBounds, srcCopyAreaRect); | |
| if ((srcCopyAreaRect.width <= 0) || (srcCopyAreaRect.height <= 0)) { | |
| // src rect outside bounds | |
| return null; | |
| } | |
| // clip dst rect | |
| dstCopyAreaRect.setBounds(srcCopyAreaRect.x + dx, srcCopyAreaRect.y + dy, srcCopyAreaRect.width, srcCopyAreaRect.height); | |
| intersection(dstCopyAreaRect, copyAreaBounds, dstCopyAreaRect); | |
| if ((dstCopyAreaRect.width <= 0) || (dstCopyAreaRect.height <= 0)) { | |
| // dst rect outside clip | |
| return null; | |
| } | |
| x = dstCopyAreaRect.x - dx; | |
| y = dstCopyAreaRect.y - dy; | |
| w = dstCopyAreaRect.width; | |
| h = dstCopyAreaRect.height; | |
| finalCopyAreaRect.setBounds(x, y, w, h); | |
| return finalCopyAreaRect; | |
| } | |
| // <rdar://3785539> We only need to mark dirty on screen surfaces. This method is | |
| // marked as protected and it is intended for subclasses to override if they need to | |
| // be notified when the surface is dirtied. See CPeerSurfaceData.markDirty() for implementation. | |
| // We don't do anything for buffered images. | |
| protected void markDirty(boolean markAsDirty) { | |
| // do nothing by default | |
| } | |
| // LazyDrawing optimization implementation: | |
| @Override | |
| public boolean canRenderLCDText(SunGraphics2D sg2d) { | |
| if (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && | |
| sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR && | |
| sg2d.clipState <= SunGraphics2D.CLIP_RECTANGULAR && | |
| // sg2d.surfaceData.getTransparency() == Transparency.OPAQUE && | |
| // This last test is a workaround until we fix loop selection | |
| // in the pipe validation | |
| sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) { return true; } | |
| return false; /* for now - in the future we may want to search */ | |
| } | |
| public static boolean IsSimpleColor(Object c) { | |
| return ((c instanceof Color) || (c instanceof SystemColor) || (c instanceof javax.swing.plaf.ColorUIResource)); | |
| } | |
| static { | |
| if ((kColorPointerIndex % 2) != 0) { | |
| System.err.println("kColorPointerIndex=" + kColorPointerIndex + " is NOT aligned for 64 bit"); | |
| System.exit(0); | |
| } | |
| } | |
| } |