* Rendering hint map.
*/
private RenderingHints hints;
+
+ /**
+ * Status of the anti-alias flag in cairo.
+ */
+ private boolean antialias = false;
+ private boolean ignoreAA = false;
/**
* Some operations (drawing rather than filling) require that their
setPaint(Color.black);
setStroke(new BasicStroke());
setTransform(new AffineTransform());
+ cairoSetAntialias(nativePointer, antialias);
}
/**
if (g.fg.getAlpha() != -1)
foreground = new Color(g.fg.getRed(), g.fg.getGreen(), g.fg.getBlue(),
- g.fg.getAlpha());
+ g.fg.getAlpha());
else
foreground = new Color(g.fg.getRGB());
setTransformImpl(transform);
setClip(clip);
setComposite(comp);
+
+ antialias = !g.antialias;
+ setAntialias(g.antialias);
}
/**
public abstract GraphicsConfiguration getDeviceConfiguration();
- protected abstract void copyAreaImpl(int x, int y,
- int width, int height, int dx, int dy);
+ protected abstract void copyAreaImpl(int x, int y, int width, int height,
+ int dx, int dy);
/**
int g2, int b2, int a2, boolean cyclic);
protected native void setPaintPixels(long pointer, int[] pixels, int w,
- int h, int stride, boolean repeat,
- int x, int y);
+ int h, int stride, boolean repeat,
+ int x, int y);
/**
* Set the current transform matrix
/*
* Draws a Glyph Vector
*/
- native void cairoDrawGlyphVector(long pointer, GdkFontPeer font,
+ protected native void cairoDrawGlyphVector(long pointer, GdkFontPeer font,
float x, float y, int n,
- int[] codes, float[] positions);
+ int[] codes, float[] positions, long[] fontset);
/**
* Set the font in cairo.
protected native void cairoClip(long pointer);
/**
- * Save clip
+ * Clear clip
*/
protected native void cairoResetClip(long pointer);
+
+ /**
+ * Set antialias.
+ */
+ protected native void cairoSetAntialias(long pointer, boolean aa);
+
///////////////////////// TRANSFORMS ///////////////////////////////////
/**
setColor((Color) paint);
customPaint = false;
}
+
else if (paint instanceof TexturePaint)
{
- TexturePaint tp = (TexturePaint) paint;
- BufferedImage img = tp.getImage();
+ TexturePaint tp = (TexturePaint) paint;
+ BufferedImage img = tp.getImage();
- // map the image to the anchor rectangle
- int width = (int) tp.getAnchorRect().getWidth();
- int height = (int) tp.getAnchorRect().getHeight();
+ // map the image to the anchor rectangle
+ int width = (int) tp.getAnchorRect().getWidth();
+ int height = (int) tp.getAnchorRect().getHeight();
- double scaleX = width / (double) img.getWidth();
- double scaleY = height / (double) img.getHeight();
+ double scaleX = width / (double) img.getWidth();
+ double scaleY = height / (double) img.getHeight();
- AffineTransform at = new AffineTransform(scaleX, 0, 0, scaleY, 0, 0);
- AffineTransformOp op = new AffineTransformOp(at, getRenderingHints());
- BufferedImage texture = op.filter(img, null);
- int[] pixels = texture.getRGB(0, 0, width, height, null, 0, width);
- setPaintPixels(nativePointer, pixels, width, height, width, true, 0, 0);
+ AffineTransform at = new AffineTransform(scaleX, 0, 0, scaleY, 0, 0);
+ AffineTransformOp op = new AffineTransformOp(at, getRenderingHints());
+ BufferedImage texture = op.filter(img, null);
+ int[] pixels = texture.getRGB(0, 0, width, height, null, 0, width);
+ setPaintPixels(nativePointer, pixels, width, height, width, true, 0, 0);
customPaint = false;
}
+
else if (paint instanceof GradientPaint)
{
- GradientPaint gp = (GradientPaint) paint;
- Point2D p1 = gp.getPoint1();
- Point2D p2 = gp.getPoint2();
- Color c1 = gp.getColor1();
- Color c2 = gp.getColor2();
- setGradient(nativePointer, p1.getX(), p1.getY(), p2.getX(), p2.getY(),
+ GradientPaint gp = (GradientPaint) paint;
+ Point2D p1 = gp.getPoint1();
+ Point2D p2 = gp.getPoint2();
+ Color c1 = gp.getColor1();
+ Color c2 = gp.getColor2();
+ setGradient(nativePointer, p1.getX(), p1.getY(), p2.getX(), p2.getY(),
c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha(),
c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha(),
gp.isCyclic());
int userHeight = bounds.height;
// Find bounds in device space
- Point2D origin = transform.transform(new Point2D.Double(userX, userY),
- null);
- Point2D extreme = transform.transform(new Point2D.Double(userWidth + userX,
- userHeight + userY),
- null);
- int deviceX = (int)origin.getX();
- int deviceY = (int)origin.getY();
- int deviceWidth = (int)Math.ceil(extreme.getX() - origin.getX());
- int deviceHeight = (int)Math.ceil(extreme.getY() - origin.getY());
+ Rectangle2D bounds2D = getTransformedBounds(bounds, transform);
+ int deviceX = (int)bounds2D.getX();
+ int deviceY = (int)bounds2D.getY();
+ int deviceWidth = (int)Math.ceil(bounds2D.getWidth());
+ int deviceHeight = (int)Math.ceil(bounds2D.getHeight());
// Get raster of the paint background
PaintContext pc = paint.createContext(CairoSurface.cairoColorModel,
stroke = st;
if (stroke instanceof BasicStroke)
{
- BasicStroke bs = (BasicStroke) stroke;
- cairoSetLine(nativePointer, bs.getLineWidth(), bs.getEndCap(),
- bs.getLineJoin(), bs.getMiterLimit());
-
- float[] dashes = bs.getDashArray();
- if (dashes != null)
- {
- double[] double_dashes = new double[dashes.length];
- for (int i = 0; i < dashes.length; i++)
- double_dashes[i] = dashes[i];
- cairoSetDash(nativePointer, double_dashes, double_dashes.length,
- (double) bs.getDashPhase());
- }
- else
- cairoSetDash(nativePointer, new double[0], 0, 0.0);
+ BasicStroke bs = (BasicStroke) stroke;
+ cairoSetLine(nativePointer, bs.getLineWidth(), bs.getEndCap(),
+ bs.getLineJoin(), bs.getMiterLimit());
+
+ float[] dashes = bs.getDashArray();
+ if (dashes != null)
+ {
+ double[] double_dashes = new double[dashes.length];
+ for (int i = 0; i < dashes.length; i++)
+ double_dashes[i] = dashes[i];
+
+ cairoSetDash(nativePointer, double_dashes, double_dashes.length,
+ (double) bs.getDashPhase());
+ }
+ else
+ cairoSetDash(nativePointer, new double[0], 0, 0.0);
}
}
{
if (fg == null)
fg = Color.BLACK;
+
cairoSetRGBAColor(nativePointer, fg.getRed() / 255.0,
fg.getGreen() / 255.0,fg.getBlue() / 255.0,
fg.getAlpha() / 255.0);
if (transform == null)
return uclip;
else
- {
- Point2D pos = transform.transform(new Point2D.Double(uclip.getX(),
- uclip.getY()),
- (Point2D) null);
- Point2D extent = transform.deltaTransform(new Point2D.Double(uclip
- .getWidth(),
- uclip
- .getHeight()),
- (Point2D) null);
- return new Rectangle2D.Double(pos.getX(), pos.getY(), extent.getX(),
- extent.getY());
- }
+ return getTransformedBounds(clip.getBounds2D(), transform);
}
public void setClip(int x, int y, int width, int height)
// initial clip properly.
if( firstClip )
{
- originalClip = s;
- firstClip = false;
+ originalClip = s;
+ firstClip = false;
}
clip = s;
if (comp instanceof AlphaComposite)
{
- AlphaComposite a = (AlphaComposite) comp;
+ AlphaComposite a = (AlphaComposite) comp;
cairoSetOperator(nativePointer, a.getRule());
}
Rectangle r = findStrokedBounds(s);
setCustomPaint(r);
}
-
+
+ setAntialias(!hints.get(RenderingHints.KEY_ANTIALIASING)
+ .equals(RenderingHints.VALUE_ANTIALIAS_OFF));
createPath(s, true);
cairoStroke(nativePointer);
}
if (customPaint)
setCustomPaint(s.getBounds());
-
+
+ setAntialias(!hints.get(RenderingHints.KEY_ANTIALIASING)
+ .equals(RenderingHints.VALUE_ANTIALIAS_OFF));
double alpha = 1.0;
if (comp instanceof AlphaComposite)
alpha = ((AlphaComposite) comp).getAlpha();
public void copyArea(int ox, int oy, int owidth, int oheight,
int odx, int ody)
{
+ // FIXME: does this handle a rotation transform properly?
+ // (the width/height might not be correct)
Point2D pos = transform.transform(new Point2D.Double(ox, oy),
- (Point2D) null);
+ (Point2D) null);
Point2D dim = transform.transform(new Point2D.Double(ox + owidth,
- oy + oheight),
- (Point2D) null);
+ oy + oheight),
+ (Point2D) null);
Point2D p2 = transform.transform(new Point2D.Double(ox + odx, oy + ody),
- (Point2D) null);
+ (Point2D) null);
int x = (int)pos.getX();
int y = (int)pos.getY();
int width = (int)(dim.getX() - pos.getX());
// Clip edges if necessary
if( x + dx < r.getX() ) // left
{
- width = x + dx + width;
- x = (int)r.getX() - dx;
+ width = x + dx + width;
+ x = (int)r.getX() - dx;
}
if( y + dy < r.getY() ) // top
{
- height = y + dy + height;
- y = (int)r.getY() - dy;
+ height = y + dy + height;
+ y = (int)r.getY() - dy;
}
if( x + dx + width >= r.getWidth() ) // right
return hints.get(hintKey);
}
- public void setRenderingHints(Map hints)
+ public void setRenderingHints(Map<?,?> hints)
{
this.hints = new RenderingHints(getDefaultHints());
- this.hints.add(new RenderingHints(hints));
+ this.hints.putAll(hints);
shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE)
|| hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT);
public void addRenderingHints(Map hints)
{
- this.hints.add(new RenderingHints(hints));
+ this.hints.putAll(hints);
}
public RenderingHints getRenderingHints()
// Do bilinear interpolation as default
return INTERPOLATION_BILINEAR;
}
+
+ /**
+ * Set antialias if needed. If the ignoreAA flag is set, this method will
+ * return without doing anything.
+ *
+ * @param needAA RenderingHints.VALUE_ANTIALIAS_ON or RenderingHints.VALUE_ANTIALIAS_OFF
+ */
+ private void setAntialias(boolean needAA)
+ {
+ if (ignoreAA)
+ return;
+
+ if (needAA != antialias)
+ {
+ antialias = !antialias;
+ cairoSetAntialias(nativePointer, antialias);
+ }
+ }
///////////////////////// IMAGE. METHODS ///////////////////////////////////
try
{
- invertedXform = xform.createInverse();
+ invertedXform = xform.createInverse();
}
catch (NoninvertibleTransformException e)
{
- throw new ImagingOpException("Unable to invert transform "
- + xform.toString());
+ throw new ImagingOpException("Unable to invert transform "
+ + xform.toString());
}
// Unrecognized image - convert to a BufferedImage
img = AsyncImage.realImage(img, obs);
if( !(img instanceof BufferedImage) )
{
- ImageProducer source = img.getSource();
- if (source == null)
- return false;
- img = Toolkit.getDefaultToolkit().createImage(source);
+ ImageProducer source = img.getSource();
+ if (source == null)
+ return false;
+ img = Toolkit.getDefaultToolkit().createImage(source);
}
BufferedImage b = (BufferedImage) img;
// use the cached CairoSurface that BIG is drawing onto
if( BufferedImageGraphics.bufferedImages.get( b ) != null )
- raster = (Raster)BufferedImageGraphics.bufferedImages.get( b );
+ raster = BufferedImageGraphics.bufferedImages.get( b );
else
raster = b.getRaster();
if (comp instanceof AlphaComposite)
alpha = ((AlphaComposite) comp).getAlpha();
- if(raster instanceof CairoSurface)
+ if(raster instanceof CairoSurface
+ && ((CairoSurface)raster).sharedBuffer == true)
{
- ((CairoSurface)raster).drawSurface(nativePointer, i2u, alpha,
- getInterpolation());
+ drawCairoSurface((CairoSurface)raster, xform, alpha, getInterpolation());
updateColor();
- return true;
+ return true;
}
if( bgcolor != null )
Color oldColor = bg;
setBackground(bgcolor);
- double[] origin = new double[] {0,0};
- double[] dimensions = new double[] {width, height};
- xform.transform(origin, 0, origin, 0, 1);
- xform.deltaTransform(dimensions, 0, dimensions, 0, 1);
- clearRect((int)origin[0], (int)origin[1],
- (int)dimensions[0], (int)dimensions[1]);
+ Rectangle2D bounds = new Rectangle2D.Double(0, 0, width, height);
+ bounds = getTransformedBounds(bounds, xform);
+
+ clearRect((int)bounds.getX(), (int)bounds.getY(),
+ (int)bounds.getWidth(), (int)bounds.getHeight());
setBackground(oldColor);
}
int[] pixels = b.getRGB(0, 0, width, height, null, 0, width);
-
// FIXME: The above method returns data in the standard ARGB colorspace,
// meaning data should NOT be alpha pre-multiplied; however Cairo expects
// data to be premultiplied.
+
+ cairoSave(nativePointer);
+ Rectangle2D bounds = new Rectangle2D.Double(0, 0, width, height);
+ bounds = getTransformedBounds(bounds, xform);
+ cairoRectangle(nativePointer, bounds.getX(), bounds.getY(),
+ bounds.getWidth(), bounds.getHeight());
+ cairoClip(nativePointer);
drawPixels(nativePointer, pixels, width, height, width, i2u, alpha,
getInterpolation());
+
+ cairoRestore(nativePointer);
// Cairo seems to lose the current color which must be restored.
updateColor();
{
return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, observer);
}
+
+ /**
+ * Optimized method for drawing a CairoSurface onto this graphics context.
+ *
+ * @param surface The surface to draw.
+ * @param tx The transformation matrix (cannot be null).
+ * @param alpha The alpha value to paint with ( 0 <= alpha <= 1).
+ * @param interpolation The interpolation type.
+ */
+ protected void drawCairoSurface(CairoSurface surface, AffineTransform tx,
+ double alpha, int interpolation)
+ {
+ // Find offset required if this surface is a sub-raster, and append offset
+ // to transformation.
+ if (surface.getSampleModelTranslateX() != 0
+ || surface.getSampleModelTranslateY() != 0)
+ {
+ Point2D origin = new Point2D.Double(0, 0);
+ Point2D offset = new Point2D.Double(surface.getSampleModelTranslateX(),
+ surface.getSampleModelTranslateY());
+
+ tx.transform(origin, origin);
+ tx.transform(offset, offset);
+
+ tx.translate(offset.getX() - origin.getX(),
+ offset.getY() - origin.getY());
+ }
+
+ // Find dimensions of this surface relative to the root parent surface
+ Rectangle bounds = new Rectangle(-surface.getSampleModelTranslateX(),
+ -surface.getSampleModelTranslateY(),
+ surface.width, surface.height);
+
+ // Clip to the translated image
+ // We use direct cairo methods to avoid the overhead of maintaining a
+ // java copy of the clip, since we will be reverting it immediately
+ // after drawing
+ Shape newBounds = tx.createTransformedShape(bounds);
+ cairoSave(nativePointer);
+ walkPath(newBounds.getPathIterator(null), false);
+ cairoClip(nativePointer);
+
+ // Draw the surface
+ try
+ {
+ double[] i2u = new double[6];
+ tx.createInverse().getMatrix(i2u);
+ surface.nativeDrawSurface(surface.surfacePointer, nativePointer, i2u,
+ alpha, interpolation);
+ }
+ catch (NoninvertibleTransformException ex)
+ {
+ // This should never happen(?), so we don't need to do anything here.
+ ;
+ }
+
+ // Restore clip
+ cairoRestore(nativePointer);
+ }
+
///////////////////////// TEXT METHODS ////////////////////////////////////
tl = new TextLayout( str, getFont(), getFontRenderContext() );
fontPeer.textLayoutCache.put(str, tl);
}
+
+ // Set antialias to text_antialiasing, and set the ignoreAA flag so that
+ // the setting doesn't get overridden in a draw() or fill() call.
+ setAntialias(!hints.get(RenderingHints.KEY_TEXT_ANTIALIASING)
+ .equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF));
+ ignoreAA = true;
+
tl.draw(this, x, y);
+ ignoreAA = false;
}
public void drawString(String str, int x, int y)
if (comp instanceof AlphaComposite)
alpha = ((AlphaComposite) comp).getAlpha();
+
+ setAntialias(!hints.get(RenderingHints.KEY_TEXT_ANTIALIASING)
+ .equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF));
+ ignoreAA = true;
+
if (gv instanceof FreetypeGlyphVector && alpha == 1.0)
{
int n = gv.getNumGlyphs ();
int[] codes = gv.getGlyphCodes (0, n, null);
+ long[] fontset = ((FreetypeGlyphVector)gv).getGlyphFonts (0, n, null);
float[] positions = gv.getGlyphPositions (0, n, null);
setFont (gv.getFont ());
GdkFontPeer fontPeer = (GdkFontPeer) font.getPeer();
- synchronized (fontPeer)
- {
- cairoDrawGlyphVector(nativePointer, fontPeer,
- x, y, n, codes, positions);
- }
+ synchronized (fontPeer)
+ {
+ cairoDrawGlyphVector(nativePointer, fontPeer,
+ x, y, n, codes, positions, fontset);
+ }
}
else
{
fill(gv.getOutline());
translate(-x, -y);
}
+
+ ignoreAA = false;
}
public void drawString(AttributedCharacterIterator ci, float x, float y)
{
if( onStroke )
{
- Shape stroked = stroke.createStrokedShape( s );
- return stroked.intersects( (double)rect.x, (double)rect.y,
- (double)rect.width, (double)rect.height );
+ Shape stroked = stroke.createStrokedShape( s );
+ return stroked.intersects( (double)rect.x, (double)rect.y,
+ (double)rect.width, (double)rect.height );
}
return s.intersects( (double)rect.x, (double)rect.y,
(double)rect.width, (double)rect.height );
imageToUser.getMatrix(i2u);
else
{
- i2u[0] = 1;
- i2u[1] = 0;
- i2u[2] = 0;
- i2u[3] = 1;
- i2u[4] = 0;
- i2u[5] = 0;
+ i2u[0] = 1;
+ i2u[1] = 0;
+ i2u[2] = 0;
+ i2u[3] = 1;
+ i2u[4] = 0;
+ i2u[5] = 0;
}
int[] pixels = findSimpleIntegerArray(cm, r);
if (pixels == null)
{
- // FIXME: I don't think this code will work correctly with a non-RGB
- // MultiPixelPackedSampleModel. Although this entire method should
- // probably be rewritten to better utilize Cairo's different supported
- // data formats.
- if (sm instanceof MultiPixelPackedSampleModel)
- {
- pixels = r.getPixels(0, 0, r.getWidth(), r.getHeight(), pixels);
- for (int i = 0; i < pixels.length; i++)
- pixels[i] = cm.getRGB(pixels[i]);
- }
- else
- {
- pixels = new int[r.getWidth() * r.getHeight()];
- for (int i = 0; i < pixels.length; i++)
- pixels[i] = cm.getRGB(db.getElem(i));
- }
+ // FIXME: I don't think this code will work correctly with a non-RGB
+ // MultiPixelPackedSampleModel. Although this entire method should
+ // probably be rewritten to better utilize Cairo's different supported
+ // data formats.
+ if (sm instanceof MultiPixelPackedSampleModel)
+ {
+ pixels = r.getPixels(0, 0, r.getWidth(), r.getHeight(), pixels);
+ for (int i = 0; i < pixels.length; i++)
+ pixels[i] = cm.getRGB(pixels[i]);
+ }
+ else
+ {
+ pixels = new int[r.getWidth() * r.getHeight()];
+ for (int i = 0; i < pixels.length; i++)
+ pixels[i] = cm.getRGB(db.getElem(i));
+ }
}
// Change all transparent pixels in the image to the specified bgcolor,
// correctly.
if (cm.hasAlpha())
{
- if (bgcolor != null && cm.hasAlpha())
- for (int i = 0; i < pixels.length; i++)
- {
- if (cm.getAlpha(pixels[i]) == 0)
- pixels[i] = bgcolor.getRGB();
- }
+ if (bgcolor != null && cm.hasAlpha())
+ for (int i = 0; i < pixels.length; i++)
+ {
+ if (cm.getAlpha(pixels[i]) == 0)
+ pixels[i] = bgcolor.getRGB();
+ }
}
else
for (int i = 0; i < pixels.length; i++)
- pixels[i] |= 0xFF000000;
+ pixels[i] |= 0xFF000000;
double alpha = 1.0;
if (comp instanceof AlphaComposite)
alpha = ((AlphaComposite) comp).getAlpha();
+
drawPixels(nativePointer, pixels, r.getWidth(), r.getHeight(),
r.getWidth(), i2u, alpha, getInterpolation());
double shift = 0.5;
if (!transform.isIdentity())
shift /= transform.getScaleX();
- return Math.round(coord) + shift;
+ return (coord + shift);
}
else
return coord;
double shift = 0.5;
if (!transform.isIdentity())
shift /= transform.getScaleY();
- return Math.round(coord) + shift;
+ return (coord + shift);
}
else
return coord;
cairoSetFillRule(nativePointer, p.getWindingRule());
for (; ! p.isDone(); p.next())
{
- int seg = p.currentSegment(coords);
- switch (seg)
- {
- case PathIterator.SEG_MOVETO:
- x = shiftX(coords[0], doShift);
- y = shiftY(coords[1], doShift);
- cairoMoveTo(nativePointer, x, y);
- break;
- case PathIterator.SEG_LINETO:
- x = shiftX(coords[0], doShift);
- y = shiftY(coords[1], doShift);
- cairoLineTo(nativePointer, x, y);
- break;
- case PathIterator.SEG_QUADTO:
- // splitting a quadratic bezier into a cubic:
- // see: http://pfaedit.sourceforge.net/bezier.html
- double x1 = x + (2.0 / 3.0) * (shiftX(coords[0], doShift) - x);
- double y1 = y + (2.0 / 3.0) * (shiftY(coords[1], doShift) - y);
-
- double x2 = x1 + (1.0 / 3.0) * (shiftX(coords[2], doShift) - x);
- double y2 = y1 + (1.0 / 3.0) * (shiftY(coords[3], doShift) - y);
-
- x = shiftX(coords[2], doShift);
- y = shiftY(coords[3], doShift);
- cairoCurveTo(nativePointer, x1, y1, x2, y2, x, y);
- break;
- case PathIterator.SEG_CUBICTO:
- x = shiftX(coords[4], doShift);
- y = shiftY(coords[5], doShift);
- cairoCurveTo(nativePointer, shiftX(coords[0], doShift),
- shiftY(coords[1], doShift),
- shiftX(coords[2], doShift),
- shiftY(coords[3], doShift), x, y);
- break;
- case PathIterator.SEG_CLOSE:
- cairoClosePath(nativePointer);
- break;
- }
+ int seg = p.currentSegment(coords);
+ switch (seg)
+ {
+ case PathIterator.SEG_MOVETO:
+ x = shiftX(coords[0], doShift);
+ y = shiftY(coords[1], doShift);
+ cairoMoveTo(nativePointer, x, y);
+ break;
+ case PathIterator.SEG_LINETO:
+ x = shiftX(coords[0], doShift);
+ y = shiftY(coords[1], doShift);
+ cairoLineTo(nativePointer, x, y);
+ break;
+ case PathIterator.SEG_QUADTO:
+ // splitting a quadratic bezier into a cubic:
+ // see: http://pfaedit.sourceforge.net/bezier.html
+ double x1 = x + (2.0 / 3.0) * (shiftX(coords[0], doShift) - x);
+ double y1 = y + (2.0 / 3.0) * (shiftY(coords[1], doShift) - y);
+
+ double x2 = x1 + (1.0 / 3.0) * (shiftX(coords[2], doShift) - x);
+ double y2 = y1 + (1.0 / 3.0) * (shiftY(coords[3], doShift) - y);
+
+ x = shiftX(coords[2], doShift);
+ y = shiftY(coords[3], doShift);
+ cairoCurveTo(nativePointer, x1, y1, x2, y2, x, y);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ x = shiftX(coords[4], doShift);
+ y = shiftY(coords[5], doShift);
+ cairoCurveTo(nativePointer, shiftX(coords[0], doShift),
+ shiftY(coords[1], doShift),
+ shiftX(coords[2], doShift),
+ shiftY(coords[3], doShift), x, y);
+ break;
+ case PathIterator.SEG_CLOSE:
+ cairoClosePath(nativePointer);
+ break;
+ }
}
}
/**
* Used by setRenderingHints()
*/
- private Map getDefaultHints()
+ private Map<RenderingHints.Key, Object> getDefaultHints()
{
- HashMap defaultHints = new HashMap();
+ HashMap<RenderingHints.Key, Object> defaultHints =
+ new HashMap<RenderingHints.Key, Object>();
defaultHints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
if (clip == null)
return;
- if (! (clip instanceof GeneralPath))
- clip = new GeneralPath(clip);
-
- GeneralPath p = (GeneralPath) clip;
- p.transform(t);
+ // If the clip is a rectangle, and the transformation preserves the shape
+ // (translate/stretch only), then keep the clip as a rectangle
+ double[] matrix = new double[4];
+ t.getMatrix(matrix);
+ if (clip instanceof Rectangle2D && matrix[1] == 0 && matrix[2] == 0)
+ {
+ Rectangle2D rect = (Rectangle2D)clip;
+ double[] origin = new double[] {rect.getX(), rect.getY()};
+ double[] dimensions = new double[] {rect.getWidth(), rect.getHeight()};
+ t.transform(origin, 0, origin, 0, 1);
+ t.deltaTransform(dimensions, 0, dimensions, 0, 1);
+ rect.setRect(origin[0], origin[1], dimensions[0], dimensions[1]);
+ }
+ else
+ {
+ if (! (clip instanceof GeneralPath))
+ clip = new GeneralPath(clip);
+
+ GeneralPath p = (GeneralPath) clip;
+ p.transform(t);
+ }
}
private static Rectangle computeIntersection(int x, int y, int w, int h,
return rect;
}
+
+ static Rectangle2D getTransformedBounds(Rectangle2D bounds, AffineTransform tx)
+ {
+ double x1 = bounds.getX();
+ double x2 = bounds.getX() + bounds.getWidth();
+ double x3 = x1;
+ double x4 = x2;
+ double y1 = bounds.getY();
+ double y2 = y1;
+ double y3 = bounds.getY() + bounds.getHeight();
+ double y4 = y3;
+
+ double[] points = new double[] {x1, y1, x2, y2, x3, y3, x4, y4};
+ tx.transform(points, 0, points, 0, 4);
+
+ double minX = points[0];
+ double maxX = minX;
+ double minY = points[1];
+ double maxY = minY;
+ for (int i = 0; i < 8; i++)
+ {
+ if (points[i] < minX)
+ minX = points[i];
+ if (points[i] > maxX)
+ maxX = points[i];
+ i++;
+
+ if (points[i] < minY)
+ minY = points[i];
+ if (points[i] > maxY)
+ maxY = points[i];
+ }
+
+ return new Rectangle2D.Double(minX, minY, (maxX - minX), (maxY - minY));
+ }
}