2344 lines
81 KiB
C#
2344 lines
81 KiB
C#
/*
|
|
Copyright (C) 2002, 2004, 2005, 2006, 2007 Jeroen Frijters
|
|
Copyright (C) 2006 Active Endpoints, Inc.
|
|
Copyright (C) 2006 - 2014 Volker Berlin (i-net software)
|
|
Copyright (C) 2011 Karsten Heinrich (i-net software)
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
Jeroen Frijters
|
|
jeroen@frijters.net
|
|
|
|
*/
|
|
|
|
using System;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Drawing.Text;
|
|
using System.Globalization;
|
|
using System.Windows.Forms;
|
|
using java.awt.image;
|
|
using java.util;
|
|
|
|
namespace ikvm.awt
|
|
{
|
|
|
|
internal class BitmapGraphics : NetGraphics
|
|
{
|
|
private readonly Bitmap bitmap;
|
|
private readonly BufferedImage image;
|
|
|
|
internal BitmapGraphics(Bitmap bitmap, Object destination, java.awt.Font font, Color fgcolor, Color bgcolor)
|
|
: base(createGraphics(bitmap), destination, font, fgcolor, bgcolor)
|
|
{
|
|
this.bitmap = bitmap;
|
|
image = destination as BufferedImage;
|
|
}
|
|
|
|
internal BitmapGraphics(Bitmap bitmap, Object destination)
|
|
: this(bitmap, destination, null, Color.White, Color.Black)
|
|
{
|
|
}
|
|
|
|
internal override Graphics g
|
|
{
|
|
get {
|
|
if (image != null)
|
|
{
|
|
image.toBitmap();
|
|
}
|
|
return base.g;
|
|
}
|
|
}
|
|
|
|
protected override SizeF GetSize() {
|
|
return bitmap.Size;
|
|
}
|
|
|
|
private static Graphics createGraphics(Bitmap bitmap)
|
|
{
|
|
// lock to prevent the exception
|
|
// System.InvalidOperationException: Object is currently in use elsewhere
|
|
lock (bitmap)
|
|
{
|
|
return Graphics.FromImage(bitmap);
|
|
}
|
|
}
|
|
|
|
public override java.awt.Graphics create()
|
|
{
|
|
BitmapGraphics newGraphics = (BitmapGraphics)MemberwiseClone();
|
|
newGraphics.init(createGraphics(bitmap));
|
|
return newGraphics;
|
|
}
|
|
|
|
public override void copyArea(int x, int y, int width, int height, int dx, int dy)
|
|
{
|
|
Bitmap copy = new Bitmap(width, height);
|
|
using (Graphics gCopy = Graphics.FromImage(copy))
|
|
{
|
|
gCopy.DrawImage(bitmap, new Rectangle(0, 0, width, height), x, y, width, height, GraphicsUnit.Pixel);
|
|
}
|
|
g.DrawImageUnscaled(copy, x + dx, y + dy);
|
|
}
|
|
}
|
|
|
|
internal class ComponentGraphics : NetGraphics
|
|
{
|
|
private readonly Control control;
|
|
|
|
internal ComponentGraphics(Control control, java.awt.Component target, java.awt.Color fgColor, java.awt.Color bgColor, java.awt.Font font)
|
|
: base(control.CreateGraphics(), target, font, J2C.ConvertColor(fgColor), J2C.ConvertColor(bgColor))
|
|
{
|
|
this.control = control;
|
|
}
|
|
|
|
protected override SizeF GetSize() {
|
|
return control.Size;
|
|
}
|
|
|
|
public override java.awt.Graphics create()
|
|
{
|
|
ComponentGraphics newGraphics = (ComponentGraphics)MemberwiseClone();
|
|
newGraphics.init(control.CreateGraphics());
|
|
return newGraphics;
|
|
}
|
|
|
|
private Point getPointToScreenImpl(Point point)
|
|
{
|
|
return this.control.PointToScreen(point);
|
|
}
|
|
|
|
private Point getPointToScreen(Point point)
|
|
{
|
|
return (Point)this.control.Invoke(new Converter<Point,Point>(getPointToScreenImpl),point);
|
|
}
|
|
|
|
public override void copyArea(int x, int y, int width, int height, int dx, int dy)
|
|
{
|
|
Matrix t = g.Transform;
|
|
Point src = getPointToScreen(new Point(x + (int)t.OffsetX, y + (int)t.OffsetY));
|
|
Bitmap copy = new Bitmap(width, height);
|
|
using (Graphics gCopy = Graphics.FromImage(copy))
|
|
{
|
|
gCopy.CopyFromScreen(src, new Point(0, 0), new Size(width, height));
|
|
}
|
|
g.DrawImageUnscaled(copy, x + dx, y + dy);
|
|
}
|
|
|
|
public override void clip(java.awt.Shape shape)
|
|
{
|
|
if (shape == null)
|
|
{
|
|
// the API specification says that this will clear
|
|
// the clip, but in fact the reference implementation throws a
|
|
// NullPointerException - see the following entry in the bug parade:
|
|
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6206189
|
|
throw new java.lang.NullPointerException();
|
|
}
|
|
base.clip(shape);
|
|
}
|
|
}
|
|
|
|
internal class PrintGraphicsContext
|
|
{
|
|
internal PrintGraphics Current;
|
|
}
|
|
|
|
internal class PrintGraphics : NetGraphics
|
|
{
|
|
private NetGraphicsState myState;
|
|
private PrintGraphicsContext baseContext;
|
|
private bool disposed = false;
|
|
private bool isBase = true;
|
|
|
|
internal PrintGraphics(Graphics g)
|
|
: base(g, null, null, Color.White, Color.Black)
|
|
{
|
|
baseContext = new PrintGraphicsContext();
|
|
baseContext.Current = this;
|
|
}
|
|
|
|
public override java.awt.Graphics create()
|
|
{
|
|
checkState();
|
|
myState = new NetGraphicsState();
|
|
myState.saveGraphics(this);
|
|
PrintGraphics newGraphics = (PrintGraphics)MemberwiseClone();
|
|
newGraphics.myState = null;
|
|
newGraphics.isBase = false;
|
|
newGraphics.baseContext = baseContext;
|
|
baseContext.Current = newGraphics; // since it is very likely that the next op will be on that graphics
|
|
// this is similar to init
|
|
myState.restoreGraphics(newGraphics);
|
|
return newGraphics;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks whether the properties of this instance are set to the bse Graphics. If not, the context
|
|
/// of the currently PrintGraphics is saved and the context if this instance is restored.
|
|
/// </summary>
|
|
private void checkState()
|
|
{
|
|
// this is required to simulate Graphics.create(), which is not possible in .NET
|
|
// we simply call Save on create() an restore this state, if any method is called
|
|
// on the current graphics. This will work for almost any use case of create()
|
|
if (baseContext != null && baseContext.Current != this)
|
|
{
|
|
if (!baseContext.Current.disposed)
|
|
{
|
|
if (baseContext.Current.myState == null)
|
|
{
|
|
baseContext.Current.myState = new NetGraphicsState(baseContext.Current);
|
|
}
|
|
else
|
|
{
|
|
baseContext.Current.myState.saveGraphics(baseContext.Current);
|
|
}
|
|
}
|
|
baseContext.Current = this;
|
|
if (myState != null) // is only null, if this instance was already disposed
|
|
{
|
|
myState.restoreGraphics(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void copyArea(int x, int y, int width, int height, int dx, int dy)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override void clearRect(int x, int y, int width, int height)
|
|
{
|
|
checkState();
|
|
base.clearRect(x, y, width, height);
|
|
}
|
|
|
|
public override void clipRect(int x, int y, int w, int h)
|
|
{
|
|
checkState();
|
|
base.clearRect(x, y, w, h);
|
|
}
|
|
|
|
public override void clip(java.awt.Shape shape)
|
|
{
|
|
checkState();
|
|
base.clip(shape);
|
|
}
|
|
|
|
public override void dispose()
|
|
{
|
|
myState = null;
|
|
if (pen != null) pen.Dispose();
|
|
if (brush != null) brush.Dispose();
|
|
disposed = true;
|
|
if (!isBase)
|
|
{
|
|
// only dispose the underlying Graphics if this is the base PrintGraphics!
|
|
return;
|
|
}
|
|
base.dispose();
|
|
}
|
|
|
|
public override void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)
|
|
{
|
|
checkState();
|
|
base.drawArc(x, y, width, height, startAngle, arcAngle);
|
|
}
|
|
|
|
public override void drawBytes(byte[] data, int offset, int length, int x, int y)
|
|
{
|
|
checkState();
|
|
base.drawBytes(data, offset, length, x, y);
|
|
}
|
|
|
|
public override void drawChars(char[] data, int offset, int length, int x, int y)
|
|
{
|
|
checkState();
|
|
base.drawChars(data, offset, length, x, y);
|
|
}
|
|
|
|
public override bool drawImage(java.awt.Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, java.awt.Color color, java.awt.image.ImageObserver observer)
|
|
{
|
|
checkState();
|
|
return base.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, color, observer);
|
|
}
|
|
|
|
public override bool drawImage(java.awt.Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, java.awt.image.ImageObserver observer)
|
|
{
|
|
checkState();
|
|
return base.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer);
|
|
}
|
|
|
|
public override bool drawImage(java.awt.Image img, int x, int y, int width, int height, java.awt.Color bgcolor, java.awt.image.ImageObserver observer)
|
|
{
|
|
checkState();
|
|
return base.drawImage( img, x, y, width, height, bgcolor, observer);
|
|
}
|
|
|
|
public override bool drawImage(java.awt.Image img, int x, int y, java.awt.Color bgcolor, java.awt.image.ImageObserver observer)
|
|
{
|
|
checkState();
|
|
return base.drawImage(img, x, y, bgcolor, observer);
|
|
}
|
|
|
|
public override bool drawImage(java.awt.Image img, int x, int y, int width, int height, java.awt.image.ImageObserver observer)
|
|
{
|
|
checkState();
|
|
return base.drawImage( img, x, y, width, height, observer);
|
|
}
|
|
|
|
public override bool drawImage(java.awt.Image img, int x, int y, java.awt.image.ImageObserver observer)
|
|
{
|
|
checkState();
|
|
return base.drawImage(img, x, y, observer);
|
|
}
|
|
|
|
public override void drawLine(int x1, int y1, int x2, int y2)
|
|
{
|
|
checkState();
|
|
base.drawLine(x1, y1, x2, y2);
|
|
}
|
|
|
|
public override void drawOval(int x, int y, int w, int h)
|
|
{
|
|
checkState();
|
|
base.drawOval(x, y, w, h);
|
|
}
|
|
|
|
public override void drawPolygon(java.awt.Polygon polygon)
|
|
{
|
|
checkState();
|
|
base.drawPolygon(polygon);
|
|
}
|
|
|
|
public override void drawPolygon(int[] aX, int[] aY, int aLength)
|
|
{
|
|
checkState();
|
|
base.drawPolygon(aX, aY, aLength);
|
|
}
|
|
|
|
public override void drawPolyline(int[] aX, int[] aY, int aLength)
|
|
{
|
|
checkState();
|
|
base.drawPolyline(aX, aY, aLength);
|
|
}
|
|
|
|
public override void drawRect(int x, int y, int width, int height)
|
|
{
|
|
checkState();
|
|
base.drawRect(x, y, width, height);
|
|
}
|
|
|
|
public override void drawRoundRect(int x, int y, int w, int h, int arcWidth, int arcHeight)
|
|
{
|
|
checkState();
|
|
base.drawRoundRect(x, y, w, h, arcWidth, arcHeight);
|
|
}
|
|
|
|
public override void fill3DRect(int x, int y, int width, int height, bool raised)
|
|
{
|
|
checkState();
|
|
base.fill3DRect(x, y, width, height, raised);
|
|
}
|
|
|
|
public override void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle)
|
|
{
|
|
checkState();
|
|
base.fillArc(x, y, width, height, startAngle, arcAngle);
|
|
}
|
|
|
|
public override void fillOval(int x, int y, int w, int h)
|
|
{
|
|
checkState();
|
|
base.fillOval(x, y, w, h);
|
|
}
|
|
|
|
public override void fillPolygon(java.awt.Polygon polygon)
|
|
{
|
|
checkState();
|
|
base.fillPolygon(polygon);
|
|
}
|
|
|
|
public override void fillPolygon(int[] aX, int[] aY, int aLength)
|
|
{
|
|
checkState();
|
|
base.fillPolygon(aX, aY, aLength);
|
|
}
|
|
|
|
public override void fillRect(int x, int y, int width, int height)
|
|
{
|
|
checkState();
|
|
base.fillRect(x, y, width, height);
|
|
}
|
|
|
|
public override void fillRoundRect(int x, int y, int w, int h, int arcWidth, int arcHeight)
|
|
{
|
|
checkState();
|
|
base.fillRoundRect(x, y, w, h, arcWidth, arcHeight);
|
|
}
|
|
|
|
public override java.awt.Shape getClip()
|
|
{
|
|
checkState();
|
|
return base.getClip();
|
|
}
|
|
|
|
public override java.awt.Rectangle getClipBounds(java.awt.Rectangle r)
|
|
{
|
|
checkState();
|
|
return base.getClipBounds( r );
|
|
}
|
|
|
|
public override java.awt.Rectangle getClipBounds()
|
|
{
|
|
checkState();
|
|
return base.getClipBounds();
|
|
}
|
|
|
|
[Obsolete]
|
|
public override java.awt.Rectangle getClipRect()
|
|
{
|
|
checkState();
|
|
return base.getClipRect();
|
|
}
|
|
|
|
public override java.awt.Color getColor()
|
|
{
|
|
checkState();
|
|
return base.getColor();
|
|
}
|
|
|
|
public override java.awt.Font getFont()
|
|
{
|
|
checkState();
|
|
return base.getFont();
|
|
}
|
|
|
|
public override java.awt.FontMetrics getFontMetrics(java.awt.Font f)
|
|
{
|
|
checkState();
|
|
return base.getFontMetrics(f);
|
|
}
|
|
|
|
public override java.awt.FontMetrics getFontMetrics()
|
|
{
|
|
checkState();
|
|
return base.getFontMetrics();
|
|
}
|
|
|
|
public override void setClip(int x, int y, int width, int height)
|
|
{
|
|
checkState();
|
|
base.setClip(x,y,width,height);
|
|
}
|
|
|
|
public override void setClip(java.awt.Shape shape)
|
|
{
|
|
checkState();
|
|
base.setClip(shape);
|
|
}
|
|
|
|
public override void setColor(java.awt.Color color)
|
|
{
|
|
checkState();
|
|
base.setColor(color);
|
|
}
|
|
|
|
public override void setFont(java.awt.Font f)
|
|
{
|
|
checkState();
|
|
base.setFont(f);
|
|
}
|
|
|
|
public override void setPaintMode()
|
|
{
|
|
checkState();
|
|
base.setPaintMode();
|
|
}
|
|
|
|
public override void setXORMode(java.awt.Color param)
|
|
{
|
|
checkState();
|
|
base.setXORMode(param);
|
|
}
|
|
|
|
public override void translate(int x, int y)
|
|
{
|
|
checkState();
|
|
base.translate(x, y);
|
|
}
|
|
|
|
public override void draw(java.awt.Shape shape)
|
|
{
|
|
checkState();
|
|
base.draw(shape);
|
|
}
|
|
|
|
public override bool drawImage(java.awt.Image img, java.awt.geom.AffineTransform xform, ImageObserver observer)
|
|
{
|
|
checkState();
|
|
return base.drawImage(img, xform, observer);
|
|
}
|
|
|
|
public override void drawImage(java.awt.image.BufferedImage image, BufferedImageOp op, int x, int y)
|
|
{
|
|
checkState();
|
|
base.drawImage(image, op, x, y);
|
|
}
|
|
|
|
public override void drawRenderedImage(java.awt.image.RenderedImage img, java.awt.geom.AffineTransform xform)
|
|
{
|
|
checkState();
|
|
base.drawRenderedImage(img, xform);
|
|
}
|
|
|
|
public override void drawRenderableImage(java.awt.image.renderable.RenderableImage image, java.awt.geom.AffineTransform xform)
|
|
{
|
|
checkState();
|
|
base.drawRenderableImage(image, xform);
|
|
}
|
|
|
|
public override void drawString(string str, int x, int y)
|
|
{
|
|
checkState();
|
|
base.drawString(str, x, y);
|
|
}
|
|
|
|
public override void drawString(string text, float x, float y)
|
|
{
|
|
checkState();
|
|
base.drawString(text, x, y);
|
|
}
|
|
|
|
public override void drawString(java.text.AttributedCharacterIterator iterator, int x, int y)
|
|
{
|
|
checkState();
|
|
base.drawString(iterator, x, y);
|
|
}
|
|
|
|
public override void drawString(java.text.AttributedCharacterIterator iterator, float x, float y)
|
|
{
|
|
checkState();
|
|
base.drawString(iterator, x, y);
|
|
}
|
|
|
|
public override void fill(java.awt.Shape shape)
|
|
{
|
|
checkState();
|
|
base.fill(shape);
|
|
}
|
|
|
|
public override bool hit(java.awt.Rectangle rect, java.awt.Shape s, bool onStroke)
|
|
{
|
|
checkState();
|
|
return base.hit(rect, s, onStroke);
|
|
}
|
|
|
|
public override java.awt.GraphicsConfiguration getDeviceConfiguration()
|
|
{
|
|
// no check here, since invariant
|
|
return base.getDeviceConfiguration();
|
|
}
|
|
|
|
public override void setComposite(java.awt.Composite comp)
|
|
{
|
|
checkState();
|
|
base.setComposite(comp);
|
|
}
|
|
|
|
public override void setPaint(java.awt.Paint paint)
|
|
{
|
|
checkState();
|
|
base.setPaint(paint);
|
|
}
|
|
|
|
public override void setStroke(java.awt.Stroke stroke)
|
|
{
|
|
checkState();
|
|
base.setStroke(stroke);
|
|
}
|
|
|
|
public override void setRenderingHint(java.awt.RenderingHints.Key hintKey, Object hintValue)
|
|
{
|
|
checkState();
|
|
base.setRenderingHint(hintKey, hintValue);
|
|
}
|
|
|
|
public override object getRenderingHint(java.awt.RenderingHints.Key hintKey)
|
|
{
|
|
checkState();
|
|
return base.getRenderingHint(hintKey);
|
|
}
|
|
|
|
public override void setRenderingHints(java.util.Map hints)
|
|
{
|
|
checkState();
|
|
base.setRenderingHints(hints);
|
|
}
|
|
|
|
public override void addRenderingHints(java.util.Map hints)
|
|
{
|
|
checkState();
|
|
base.addRenderingHints(hints);
|
|
}
|
|
|
|
public override java.awt.RenderingHints getRenderingHints()
|
|
{
|
|
checkState();
|
|
return base.getRenderingHints();
|
|
}
|
|
|
|
public override void translate(double x, double y)
|
|
{
|
|
checkState();
|
|
base.translate(x, y);
|
|
}
|
|
|
|
public override void rotate(double theta)
|
|
{
|
|
checkState();
|
|
base.rotate(theta);
|
|
}
|
|
|
|
public override void rotate(double theta, double x, double y)
|
|
{
|
|
checkState();
|
|
base.rotate(theta, x, y);
|
|
}
|
|
|
|
public override void scale(double scaleX, double scaleY)
|
|
{
|
|
checkState();
|
|
base.scale(scaleX, scaleY);
|
|
}
|
|
|
|
public override void shear(double shearX, double shearY)
|
|
{
|
|
checkState();
|
|
base.shear(shearX, shearY);
|
|
}
|
|
|
|
public override void transform(java.awt.geom.AffineTransform tx)
|
|
{
|
|
checkState();
|
|
base.transform(tx);
|
|
}
|
|
|
|
public override void setTransform(java.awt.geom.AffineTransform tx)
|
|
{
|
|
checkState();
|
|
base.setTransform(tx);
|
|
}
|
|
|
|
public override java.awt.geom.AffineTransform getTransform()
|
|
{
|
|
checkState();
|
|
return base.getTransform();
|
|
}
|
|
|
|
public override java.awt.Paint getPaint()
|
|
{
|
|
checkState();
|
|
return base.getPaint();
|
|
}
|
|
|
|
public override java.awt.Composite getComposite()
|
|
{
|
|
checkState();
|
|
return base.getComposite();
|
|
}
|
|
|
|
public override void setBackground(java.awt.Color color)
|
|
{
|
|
checkState();
|
|
base.setBackground(color);
|
|
}
|
|
|
|
public override java.awt.Color getBackground()
|
|
{
|
|
checkState();
|
|
return base.getBackground();
|
|
}
|
|
|
|
public override java.awt.Stroke getStroke()
|
|
{
|
|
checkState();
|
|
return base.getStroke();
|
|
}
|
|
|
|
public override java.awt.font.FontRenderContext getFontRenderContext()
|
|
{
|
|
checkState();
|
|
return base.getFontRenderContext();
|
|
}
|
|
|
|
public override void drawGlyphVector(java.awt.font.GlyphVector gv, float x, float y)
|
|
{
|
|
checkState();
|
|
base.drawGlyphVector(gv, x, y);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// State to store/restore the state of a NetGraphics/Graphics object
|
|
/// </summary>
|
|
internal class NetGraphicsState
|
|
{
|
|
private Brush brush;
|
|
private Pen pen;
|
|
|
|
// Graphics State
|
|
private Matrix Transform;
|
|
private Region Clip;
|
|
private SmoothingMode SmoothingMode;
|
|
private PixelOffsetMode PixelOffsetMode;
|
|
private TextRenderingHint TextRenderingHint;
|
|
private InterpolationMode InterpolationMode;
|
|
private CompositingMode CompositingMode;
|
|
|
|
private bool savedGraphics = false;
|
|
|
|
public NetGraphicsState()
|
|
{
|
|
}
|
|
|
|
public NetGraphicsState( NetGraphics netG )
|
|
{
|
|
saveGraphics(netG);
|
|
}
|
|
|
|
public void saveGraphics(NetGraphics netG)
|
|
{
|
|
if (netG == null )
|
|
{
|
|
return;
|
|
}
|
|
if (netG.g != null )
|
|
{
|
|
this.Transform = netG.g.Transform;
|
|
this.Clip = netG.g.Clip;
|
|
this.SmoothingMode = netG.g.SmoothingMode;
|
|
this.PixelOffsetMode = netG.g.PixelOffsetMode;
|
|
this.TextRenderingHint = netG.g.TextRenderingHint;
|
|
this.InterpolationMode = netG.g.InterpolationMode;
|
|
this.CompositingMode = netG.g.CompositingMode;
|
|
savedGraphics = true;
|
|
}
|
|
if (netG.pen != null && netG.brush != null)
|
|
{
|
|
pen = (Pen)netG.pen.Clone();
|
|
brush = (Brush)netG.brush.Clone();
|
|
}
|
|
}
|
|
|
|
public void restoreGraphics(NetGraphics netG)
|
|
{
|
|
if (netG == null)
|
|
{
|
|
return;
|
|
}
|
|
if (netG.g != null)
|
|
{
|
|
if (savedGraphics)
|
|
{
|
|
netG.g.Transform = Transform;
|
|
netG.g.Clip = Clip;
|
|
netG.g.SmoothingMode = SmoothingMode;
|
|
netG.g.PixelOffsetMode = PixelOffsetMode;
|
|
netG.setTextRenderingHint(TextRenderingHint);
|
|
netG.g.InterpolationMode = InterpolationMode;
|
|
netG.g.CompositingMode = CompositingMode;
|
|
}
|
|
else
|
|
{
|
|
// default values that Java used
|
|
netG.g.InterpolationMode = InterpolationMode.NearestNeighbor;
|
|
}
|
|
}
|
|
if ( pen != null && brush != null )
|
|
{
|
|
netG.pen = (Pen)pen.Clone();
|
|
netG.brush = (Brush)brush.Clone();
|
|
}
|
|
else
|
|
{
|
|
netG.pen = new Pen(netG.color);
|
|
netG.brush = new SolidBrush(netG.color);
|
|
netG.setRenderingHint(java.awt.RenderingHints.KEY_TEXT_ANTIALIASING, java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal abstract class NetGraphics : java.awt.Graphics2D//sun.java2d.SunGraphics2D
|
|
{
|
|
private Graphics graphics;
|
|
private java.awt.Color javaColor;
|
|
private java.awt.Paint javaPaint;
|
|
internal Color color;
|
|
private Color bgcolor;
|
|
private java.awt.Font font;
|
|
private java.awt.Stroke stroke;
|
|
private static java.awt.BasicStroke defaultStroke = new java.awt.BasicStroke();
|
|
private Font netfont;
|
|
private int baseline;
|
|
internal Brush brush;
|
|
internal Pen pen;
|
|
private CompositeHelper composite;
|
|
private java.awt.Composite javaComposite = java.awt.AlphaComposite.SrcOver;
|
|
private Object textAntialiasHint;
|
|
private Object fractionalHint = java.awt.RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT;
|
|
|
|
private static System.Collections.Generic.Dictionary<String, Int32> baselines = new System.Collections.Generic.Dictionary<String, Int32>();
|
|
|
|
internal static readonly StringFormat FORMAT = new StringFormat(StringFormat.GenericTypographic);
|
|
static NetGraphics()
|
|
{
|
|
FORMAT.FormatFlags = StringFormatFlags.MeasureTrailingSpaces | StringFormatFlags.NoWrap | StringFormatFlags.FitBlackBox;
|
|
FORMAT.Trimming = StringTrimming.None;
|
|
}
|
|
|
|
protected NetGraphics(Graphics g, Object destination, java.awt.Font font, Color fgcolor, Color bgcolor) //: base( new sun.java2d.SurfaceData(destination) )
|
|
{
|
|
if (font == null)
|
|
{
|
|
font = new java.awt.Font("Dialog", java.awt.Font.PLAIN, 12);
|
|
}
|
|
this.font = font;
|
|
netfont = font.getNetFont();
|
|
this.color = fgcolor;
|
|
this.bgcolor = bgcolor;
|
|
composite = CompositeHelper.Create(javaComposite, g);
|
|
init(g);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The current C# Graphics
|
|
/// </summary>
|
|
internal virtual Graphics g
|
|
{
|
|
get { return graphics; }
|
|
set { graphics = value; }
|
|
}
|
|
|
|
protected void init(Graphics graphics)
|
|
{
|
|
NetGraphicsState state = new NetGraphicsState();
|
|
state.saveGraphics(this);
|
|
g = graphics;
|
|
state.restoreGraphics(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the size of the graphics. This is used as a hind for some hacks.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
protected virtual SizeF GetSize() {
|
|
return g.ClipBounds.Size;
|
|
}
|
|
|
|
public override void clearRect(int x, int y, int width, int height)
|
|
{
|
|
using (Brush br = bgcolor != Color.Empty ? new SolidBrush(bgcolor) : brush)
|
|
{
|
|
CompositingMode tempMode = g.CompositingMode;
|
|
g.CompositingMode = CompositingMode.SourceCopy;
|
|
g.FillRectangle(br, x, y, width, height);
|
|
g.CompositingMode = tempMode;
|
|
}
|
|
}
|
|
|
|
public override void clipRect(int x, int y, int w, int h)
|
|
{
|
|
g.IntersectClip(new Rectangle(x, y, w, h));
|
|
}
|
|
|
|
public override void clip(java.awt.Shape shape)
|
|
{
|
|
if (shape == null)
|
|
{
|
|
// note that ComponentGraphics overrides clip() to throw a NullPointerException when shape is null
|
|
g.ResetClip();
|
|
}
|
|
else
|
|
{
|
|
g.IntersectClip(new Region(J2C.ConvertShape(shape)));
|
|
}
|
|
}
|
|
|
|
public override void dispose()
|
|
{
|
|
if (pen!=null) pen.Dispose();
|
|
if (brush!=null) brush.Dispose();
|
|
graphics.Dispose(); //for dispose we does not need to synchronize the buffer of a bitmap
|
|
}
|
|
|
|
public override void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)
|
|
{
|
|
g.DrawArc(pen, x, y, width, height, 360 - startAngle - arcAngle, arcAngle);
|
|
}
|
|
|
|
public override void drawBytes(byte[] data, int offset, int length, int x, int y)
|
|
{
|
|
char[] chars = new char[length];
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
chars[i] = (char)data[offset + i];
|
|
}
|
|
drawChars(chars, 0, length, x, y);
|
|
}
|
|
|
|
public override void drawChars(char[] data, int offset, int length, int x, int y)
|
|
{
|
|
drawString(new String(data, offset, length), x, y);
|
|
}
|
|
|
|
public override bool drawImage(java.awt.Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, java.awt.Color color, java.awt.image.ImageObserver observer)
|
|
{
|
|
Image image = J2C.ConvertImage(img);
|
|
if (image == null)
|
|
{
|
|
return false;
|
|
}
|
|
Rectangle destRect = new Rectangle(dx1, dy1, dx2 - dx1, dy2 - dy1);
|
|
using (Brush brush = new SolidBrush(composite.GetColor(color))) {
|
|
g.FillRectangle(brush, destRect);
|
|
}
|
|
lock (image)
|
|
{
|
|
g.DrawImage(image, destRect, sx1, sy1, sx2 - sx1, sy2 - sy1, GraphicsUnit.Pixel, composite.GetImageAttributes());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public override bool drawImage(java.awt.Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, java.awt.image.ImageObserver observer)
|
|
{
|
|
Image image = J2C.ConvertImage(img);
|
|
if (image == null)
|
|
{
|
|
return false;
|
|
}
|
|
Rectangle destRect = new Rectangle(dx1, dy1, dx2 - dx1, dy2 - dy1);
|
|
lock (image)
|
|
{
|
|
g.DrawImage(image, destRect, sx1, sy1, sx2 - sx1, sy2 - sy1, GraphicsUnit.Pixel, composite.GetImageAttributes());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public override bool drawImage(java.awt.Image img, int x, int y, int width, int height, java.awt.Color bgcolor, java.awt.image.ImageObserver observer)
|
|
{
|
|
Image image = J2C.ConvertImage(img);
|
|
if (image == null)
|
|
{
|
|
return false;
|
|
}
|
|
using (Brush brush = new SolidBrush(composite.GetColor(bgcolor))) {
|
|
g.FillRectangle(brush, x, y, width, height);
|
|
}
|
|
lock (image)
|
|
{
|
|
g.DrawImage(image, new Rectangle( x, y, width, height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, composite.GetImageAttributes());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public override bool drawImage(java.awt.Image img, int x, int y, java.awt.Color bgcolor, java.awt.image.ImageObserver observer)
|
|
{
|
|
if (img == null) {
|
|
return false;
|
|
}
|
|
return drawImage(img, x, y, img.getWidth(observer), img.getHeight(observer), bgcolor, observer);
|
|
}
|
|
|
|
public override bool drawImage(java.awt.Image img, int x, int y, int width, int height, java.awt.image.ImageObserver observer)
|
|
{
|
|
Image image = J2C.ConvertImage(img);
|
|
if (image == null)
|
|
{
|
|
return false;
|
|
}
|
|
lock (image)
|
|
{
|
|
g.DrawImage(image, new Rectangle(x, y, width, height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, composite.GetImageAttributes());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public override bool drawImage(java.awt.Image img, int x, int y, java.awt.image.ImageObserver observer)
|
|
{
|
|
if (img == null) {
|
|
return false;
|
|
}
|
|
return drawImage(img, x, y, img.getWidth(observer), img.getHeight(observer), observer);
|
|
}
|
|
|
|
public override void drawLine(int x1, int y1, int x2, int y2)
|
|
{
|
|
// HACK DrawLine doesn't appear to draw the last pixel, so for single pixel lines, we have
|
|
// a freaky workaround
|
|
if (x1 == x2 && y1 == y2)
|
|
{
|
|
g.DrawLine(pen, x1, y1, x1 + 0.01f, y2 + 0.01f);
|
|
}
|
|
else
|
|
{
|
|
g.DrawLine(pen, x1, y1, x2, y2);
|
|
}
|
|
}
|
|
|
|
public override void drawOval(int x, int y, int w, int h)
|
|
{
|
|
g.DrawEllipse(pen, x, y, w, h);
|
|
}
|
|
|
|
public override void drawPolygon(java.awt.Polygon polygon)
|
|
{
|
|
drawPolygon(polygon.xpoints, polygon.ypoints, polygon.npoints);
|
|
}
|
|
|
|
public override void drawPolygon(int[] aX, int[] aY, int aLength)
|
|
{
|
|
Point[] points = new Point[aLength];
|
|
for (int i = 0; i < aLength; i++)
|
|
{
|
|
points[i].X = aX[i];
|
|
points[i].Y = aY[i];
|
|
}
|
|
g.DrawPolygon(pen, points);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Draw a sequence of connected lines
|
|
/// </summary>
|
|
/// <param name="aX">Array of x coordinates</param>
|
|
/// <param name="aY">Array of y coordinates</param>
|
|
/// <param name="aLength">Length of coordinate arrays</param>
|
|
public override void drawPolyline(int[] aX, int[] aY, int aLength)
|
|
{
|
|
for (int i = 0; i < aLength - 1; i++)
|
|
{
|
|
Point point1 = new Point(aX[i], aY[i]);
|
|
Point point2 = new Point(aX[i + 1], aY[i + 1]);
|
|
g.DrawLine(pen, point1, point2);
|
|
}
|
|
}
|
|
|
|
public override void drawRect(int x, int y, int width, int height)
|
|
{
|
|
g.DrawRectangle(pen, x, y, width, height);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Apparently there is no rounded rec function in .Net. Draw the
|
|
/// rounded rectangle by using lines and arcs.
|
|
/// </summary>
|
|
public override void drawRoundRect(int x, int y, int w, int h, int arcWidth, int arcHeight)
|
|
{
|
|
using (GraphicsPath gp = J2C.ConvertRoundRect(x, y, w, h, arcWidth, arcHeight))
|
|
g.DrawPath(pen, gp);
|
|
}
|
|
|
|
public override void fill3DRect(int x, int y, int width, int height, bool raised)
|
|
{
|
|
java.awt.Paint p = getPaint();
|
|
java.awt.Color c = getColor();
|
|
java.awt.Color brighter = c.brighter();
|
|
java.awt.Color darker = c.darker();
|
|
|
|
if( !raised ) {
|
|
setColor(darker);
|
|
} else if( p != c ) {
|
|
setColor(c);
|
|
}
|
|
fillRect(x + 1, y + 1, width - 2, height - 2);
|
|
setColor(raised ? brighter : darker);
|
|
fillRect(x, y, 1, height);
|
|
fillRect(x + 1, y, width - 2, 1);
|
|
setColor(raised ? darker : brighter);
|
|
fillRect(x + 1, y + height - 1, width - 1, 1);
|
|
fillRect(x + width - 1, y, 1, height - 1);
|
|
setPaint(p);
|
|
}
|
|
|
|
public override void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle)
|
|
{
|
|
g.FillPie(brush, x, y, width, height, 360 - startAngle - arcAngle, arcAngle);
|
|
}
|
|
|
|
public override void fillOval(int x, int y, int w, int h)
|
|
{
|
|
g.FillEllipse(brush, x, y, w, h);
|
|
}
|
|
|
|
public override void fillPolygon(java.awt.Polygon polygon)
|
|
{
|
|
fillPolygon(polygon.xpoints, polygon.ypoints, polygon.npoints);
|
|
}
|
|
|
|
public override void fillPolygon(int[] aX, int[] aY, int aLength)
|
|
{
|
|
Point[] points = new Point[aLength];
|
|
for (int i = 0; i < aLength; i++)
|
|
{
|
|
points[i].X = aX[i];
|
|
points[i].Y = aY[i];
|
|
}
|
|
g.FillPolygon(brush, points);
|
|
}
|
|
|
|
public override void fillRect(int x, int y, int width, int height)
|
|
{
|
|
g.FillRectangle(brush, x, y, width, height);
|
|
}
|
|
|
|
public override void fillRoundRect(int x, int y, int w, int h, int arcWidth, int arcHeight)
|
|
{
|
|
GraphicsPath gp = J2C.ConvertRoundRect(x, y, w, h, arcWidth, arcHeight);
|
|
g.FillPath(brush, gp);
|
|
gp.Dispose();
|
|
}
|
|
|
|
public override java.awt.Shape getClip()
|
|
{
|
|
return getClipBounds();
|
|
}
|
|
|
|
public override java.awt.Rectangle getClipBounds(java.awt.Rectangle r)
|
|
{
|
|
using (Region clip = g.Clip)
|
|
{
|
|
if (!clip.IsInfinite(g))
|
|
{
|
|
RectangleF rec = clip.GetBounds(g);
|
|
r.x = (int) rec.X;
|
|
r.y = (int) rec.Y;
|
|
r.width = (int) rec.Width;
|
|
r.height = (int) rec.Height;
|
|
}
|
|
return r;
|
|
}
|
|
}
|
|
|
|
public override java.awt.Rectangle getClipBounds()
|
|
{
|
|
using (Region clip = g.Clip)
|
|
{
|
|
if (clip.IsInfinite(g))
|
|
{
|
|
return null;
|
|
}
|
|
RectangleF rec = clip.GetBounds(g);
|
|
return C2J.ConvertRectangle(rec);
|
|
}
|
|
}
|
|
|
|
[Obsolete]
|
|
public override java.awt.Rectangle getClipRect()
|
|
{
|
|
return getClipBounds();
|
|
}
|
|
|
|
public override java.awt.Color getColor()
|
|
{
|
|
if (javaColor == null)
|
|
{
|
|
javaColor = composite.GetColor(color);
|
|
}
|
|
return javaColor;
|
|
}
|
|
|
|
public override java.awt.Font getFont()
|
|
{
|
|
return font;
|
|
}
|
|
|
|
public override java.awt.FontMetrics getFontMetrics(java.awt.Font f)
|
|
{
|
|
return sun.font.FontDesignMetrics.getMetrics(f);
|
|
}
|
|
|
|
public override java.awt.FontMetrics getFontMetrics()
|
|
{
|
|
return sun.font.FontDesignMetrics.getMetrics(font);
|
|
}
|
|
|
|
public override void setClip(int x, int y, int width, int height)
|
|
{
|
|
g.Clip = new Region(new Rectangle(x, y, width, height));
|
|
}
|
|
|
|
public override void setClip(java.awt.Shape shape)
|
|
{
|
|
if (shape == null)
|
|
{
|
|
Region clip = g.Clip;
|
|
clip.MakeInfinite();
|
|
g.Clip = clip;
|
|
}
|
|
else
|
|
{
|
|
g.Clip = new Region(J2C.ConvertShape(shape));
|
|
}
|
|
}
|
|
|
|
public override void setColor(java.awt.Color color)
|
|
{
|
|
if (color == null || color == this.javaPaint)
|
|
{
|
|
// Does not change the color, if it is null like in SunGraphics2D
|
|
return;
|
|
}
|
|
this.javaPaint = this.javaColor = color;
|
|
this.color = composite.GetColor(color);
|
|
if (brush is SolidBrush)
|
|
{
|
|
((SolidBrush)brush).Color = this.color;
|
|
}
|
|
else
|
|
{
|
|
brush.Dispose();
|
|
brush = new SolidBrush(this.color);
|
|
}
|
|
pen.Color = this.color;
|
|
pen.Brush = brush;
|
|
}
|
|
|
|
public override void setFont(java.awt.Font f)
|
|
{
|
|
if (f != null && f != font)
|
|
{
|
|
netfont = f.getNetFont();
|
|
font = f;
|
|
baseline = getBaseline( netfont, g.TextRenderingHint );
|
|
}
|
|
}
|
|
|
|
public override void setPaintMode()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override void setXORMode(java.awt.Color param)
|
|
{
|
|
if( param == null ) {
|
|
throw new java.lang.IllegalArgumentException("null XORColor");
|
|
}
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override void translate(int x, int y)
|
|
{
|
|
Matrix transform = g.Transform;
|
|
transform.Translate(x, y);
|
|
g.Transform = transform;
|
|
}
|
|
|
|
public override void draw(java.awt.Shape shape)
|
|
{
|
|
using (GraphicsPath gp = J2C.ConvertShape(shape))
|
|
{
|
|
g.DrawPath(pen, gp);
|
|
}
|
|
}
|
|
|
|
public override bool drawImage(java.awt.Image img, java.awt.geom.AffineTransform xform, ImageObserver observer)
|
|
{
|
|
if (img == null) {
|
|
return true;
|
|
}
|
|
|
|
if (xform == null || xform.isIdentity()) {
|
|
return drawImage(img, 0, 0, null, observer);
|
|
}
|
|
|
|
NetGraphics clone = (NetGraphics)create();
|
|
clone.transform(xform);
|
|
bool rendered = clone.drawImage(img, 0, 0, null, observer);
|
|
clone.dispose();
|
|
return rendered;
|
|
}
|
|
|
|
public override void drawImage(java.awt.image.BufferedImage image, BufferedImageOp op, int x, int y)
|
|
{
|
|
|
|
if( op == null ) {
|
|
drawImage(image, x, y, null);
|
|
} else {
|
|
if( !(op is AffineTransformOp) ) {
|
|
drawImage(op.filter(image, null), x, y, null);
|
|
} else {
|
|
Console.WriteLine(new System.Diagnostics.StackTrace());
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void drawRenderedImage(java.awt.image.RenderedImage img, java.awt.geom.AffineTransform xform)
|
|
{
|
|
if (img == null) {
|
|
return;
|
|
}
|
|
|
|
// BufferedImage case: use a simple drawImage call
|
|
if (img is BufferedImage) {
|
|
BufferedImage bufImg = (BufferedImage)img;
|
|
drawImage(bufImg,xform,null);
|
|
return;
|
|
}
|
|
throw new NotImplementedException("drawRenderedImage not implemented for images which are not BufferedImages.");
|
|
}
|
|
|
|
public override void drawRenderableImage(java.awt.image.renderable.RenderableImage image, java.awt.geom.AffineTransform xform)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override void drawString(string str, int x, int y)
|
|
{
|
|
drawString(str, (float)x, (float)y);
|
|
}
|
|
|
|
public override void drawString(String text, float x, float y) {
|
|
if (text.Length == 0) {
|
|
return;
|
|
}
|
|
CompositingMode origCM = g.CompositingMode;
|
|
try {
|
|
if (origCM != CompositingMode.SourceOver) {
|
|
// Java has a different behaviar for AlphaComposite and Text Antialiasing
|
|
g.CompositingMode = CompositingMode.SourceOver;
|
|
}
|
|
|
|
bool fractional = isFractionalMetrics();
|
|
if (fractional || !sun.font.StandardGlyphVector.isSimpleString(font, text)) {
|
|
g.DrawString(text, netfont, brush, x, y - baseline, FORMAT);
|
|
} else {
|
|
// fixed metric for simple text, we position every character to simulate the Java behaviour
|
|
java.awt.font.FontRenderContext frc = new java.awt.font.FontRenderContext(null, isAntiAlias(), fractional);
|
|
sun.font.FontDesignMetrics metrics = sun.font.FontDesignMetrics.getMetrics(font, frc);
|
|
y -= baseline;
|
|
for (int i = 0; i < text.Length; i++) {
|
|
g.DrawString(text.Substring(i, 1), netfont, brush, x, y, FORMAT);
|
|
x += metrics.charWidth(text[i]);
|
|
}
|
|
}
|
|
} finally {
|
|
if (origCM != CompositingMode.SourceOver) {
|
|
g.CompositingMode = origCM;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void drawString(java.text.AttributedCharacterIterator iterator, int x, int y)
|
|
{
|
|
drawString(iterator, (float) x, (float) y);
|
|
}
|
|
|
|
public override void drawString(java.text.AttributedCharacterIterator iterator, float x, float y)
|
|
{
|
|
if( iterator == null ) {
|
|
throw new java.lang.NullPointerException("AttributedCharacterIterator is null");
|
|
}
|
|
if( iterator.getBeginIndex() == iterator.getEndIndex() ) {
|
|
return; /* nothing to draw */
|
|
}
|
|
java.awt.font.TextLayout tl = new java.awt.font.TextLayout(iterator, getFontRenderContext());
|
|
tl.draw(this, x, y);
|
|
}
|
|
|
|
public override void fill(java.awt.Shape shape)
|
|
{
|
|
g.FillPath(brush, J2C.ConvertShape(shape));
|
|
}
|
|
|
|
public override bool hit(java.awt.Rectangle rect, java.awt.Shape s, bool onStroke)
|
|
{
|
|
if (onStroke)
|
|
{
|
|
//TODO use stroke
|
|
//s = stroke.createStrokedShape(s);
|
|
}
|
|
return s.intersects(rect);
|
|
}
|
|
|
|
public override java.awt.GraphicsConfiguration getDeviceConfiguration()
|
|
{
|
|
return new NetGraphicsConfiguration(Screen.PrimaryScreen);
|
|
}
|
|
|
|
public override void setComposite(java.awt.Composite comp)
|
|
{
|
|
if (javaComposite == comp) {
|
|
return;
|
|
}
|
|
if (comp == null)
|
|
{
|
|
throw new java.lang.IllegalArgumentException("null Composite");
|
|
}
|
|
this.javaComposite = comp;
|
|
java.awt.Paint oldPaint = getPaint(); //getPaint() is never null
|
|
composite = CompositeHelper.Create(comp, g);
|
|
javaPaint = null;
|
|
setPaint(oldPaint);
|
|
}
|
|
|
|
public override void setPaint(java.awt.Paint paint)
|
|
{
|
|
if (paint is java.awt.Color)
|
|
{
|
|
setColor((java.awt.Color)paint);
|
|
return;
|
|
}
|
|
|
|
if (paint == null || this.javaPaint == paint)
|
|
{
|
|
return;
|
|
}
|
|
this.javaPaint = paint;
|
|
|
|
if (paint is java.awt.GradientPaint)
|
|
{
|
|
java.awt.GradientPaint gradient = (java.awt.GradientPaint)paint;
|
|
LinearGradientBrush linear;
|
|
if (gradient.isCyclic())
|
|
{
|
|
linear = new LinearGradientBrush(
|
|
J2C.ConvertPoint(gradient.getPoint1()),
|
|
J2C.ConvertPoint(gradient.getPoint2()),
|
|
composite.GetColor(gradient.getColor1()),
|
|
composite.GetColor(gradient.getColor2()));
|
|
}
|
|
else
|
|
{
|
|
//HACK because .NET does not support continue gradient like Java else Tile Gradient
|
|
//that we receize the rectangle very large (factor z) and set 4 color values
|
|
// a exact solution will calculate the size of the Graphics with the current transform
|
|
Color color1 = composite.GetColor(gradient.getColor1());
|
|
Color color2 = composite.GetColor(gradient.getColor2());
|
|
float x1 = (float)gradient.getPoint1().getX();
|
|
float x2 = (float)gradient.getPoint2().getX();
|
|
float y1 = (float)gradient.getPoint1().getY();
|
|
float y2 = (float)gradient.getPoint2().getY();
|
|
float diffX = x2 - x1;
|
|
float diffY = y2 - y1;
|
|
const float z = 60; //HACK zoom factor, with a larger factor .NET will make the gradient wider.
|
|
linear = new LinearGradientBrush(
|
|
new PointF(x1 - z * diffX, y1 - z * diffY),
|
|
new PointF(x2 + z * diffX, y2 + z * diffY),
|
|
color1,
|
|
color1);
|
|
ColorBlend colorBlend = new ColorBlend(4);
|
|
Color[] colors = colorBlend.Colors;
|
|
colors[0] = colors[1] = color1;
|
|
colors[2] = colors[3] = color2;
|
|
float[] positions = colorBlend.Positions;
|
|
positions[1] = z / (2 * z + 1);
|
|
positions[2] = (z + 1) / (2 * z + 1);
|
|
positions[3] = 1.0f;
|
|
linear.InterpolationColors = colorBlend;
|
|
}
|
|
linear.WrapMode = WrapMode.TileFlipXY;
|
|
brush = linear;
|
|
pen.Brush = brush;
|
|
return;
|
|
}
|
|
|
|
if (paint is java.awt.TexturePaint)
|
|
{
|
|
java.awt.TexturePaint texture = (java.awt.TexturePaint)paint;
|
|
Bitmap txtr = J2C.ConvertImage(texture.getImage());
|
|
java.awt.geom.Rectangle2D anchor = texture.getAnchorRect();
|
|
TextureBrush txtBrush;
|
|
brush = txtBrush = new TextureBrush(txtr, new Rectangle(0, 0, txtr.Width, txtr.Height), composite.GetImageAttributes());
|
|
txtBrush.TranslateTransform((float)anchor.getX(), (float)anchor.getY());
|
|
txtBrush.ScaleTransform((float)anchor.getWidth() / txtr.Width, (float)anchor.getHeight() / txtr.Height);
|
|
txtBrush.WrapMode = WrapMode.Tile;
|
|
pen.Brush = brush;
|
|
return;
|
|
}
|
|
|
|
if (paint is java.awt.LinearGradientPaint) {
|
|
java.awt.LinearGradientPaint gradient = (java.awt.LinearGradientPaint)paint;
|
|
PointF start = J2C.ConvertPoint(gradient.getStartPoint());
|
|
PointF end = J2C.ConvertPoint(gradient.getEndPoint());
|
|
|
|
java.awt.Color[] javaColors = gradient.getColors();
|
|
ColorBlend colorBlend;
|
|
Color[] colors;
|
|
bool noCycle = gradient.getCycleMethod() == java.awt.MultipleGradientPaint.CycleMethod.NO_CYCLE;
|
|
if (noCycle) {
|
|
//HACK because .NET does not support continue gradient like Java else Tile Gradient
|
|
//that we receize the rectangle very large (factor z) and set 2 additional color values
|
|
//an exact solution will calculate the size of the Graphics with the current transform
|
|
float diffX = end.X - start.X;
|
|
float diffY = end.Y - start.Y;
|
|
SizeF size = GetSize();
|
|
//HACK zoom factor, with a larger factor .NET will make the gradient wider.
|
|
float z = Math.Min(10, Math.Max(size.Width / diffX, size.Height / diffY));
|
|
start.X -= z * diffX;
|
|
start.Y -= z * diffY;
|
|
end.X += z * diffX;
|
|
end.Y += z * diffY;
|
|
|
|
colorBlend = new ColorBlend(javaColors.Length + 2);
|
|
colors = colorBlend.Colors;
|
|
float[] fractions = gradient.getFractions();
|
|
float[] positions = colorBlend.Positions;
|
|
for (int i = 0; i < javaColors.Length; i++) {
|
|
colors[i + 1] = composite.GetColor(javaColors[i]);
|
|
positions[i + 1] = (z + fractions[i]) / (2 * z + 1);
|
|
}
|
|
colors[0] = colors[1];
|
|
colors[colors.Length - 1] = colors[colors.Length - 2];
|
|
positions[positions.Length - 1] = 1.0f;
|
|
} else {
|
|
colorBlend = new ColorBlend(javaColors.Length);
|
|
colors = colorBlend.Colors;
|
|
colorBlend.Positions = gradient.getFractions();
|
|
for (int i = 0; i < javaColors.Length; i++) {
|
|
colors[i] = composite.GetColor(javaColors[i]);
|
|
}
|
|
}
|
|
LinearGradientBrush linear = new LinearGradientBrush(start, end, colors[0], colors[colors.Length - 1]);
|
|
linear.InterpolationColors = colorBlend;
|
|
switch (gradient.getCycleMethod().ordinal()) {
|
|
case (int)java.awt.MultipleGradientPaint.CycleMethod.__Enum.NO_CYCLE:
|
|
case (int)java.awt.MultipleGradientPaint.CycleMethod.__Enum.REFLECT:
|
|
linear.WrapMode = WrapMode.TileFlipXY;
|
|
break;
|
|
case (int)java.awt.MultipleGradientPaint.CycleMethod.__Enum.REPEAT:
|
|
linear.WrapMode = WrapMode.Tile;
|
|
break;
|
|
}
|
|
brush = linear;
|
|
pen.Brush = brush;
|
|
return;
|
|
}
|
|
|
|
if (paint is java.awt.RadialGradientPaint )
|
|
{
|
|
java.awt.RadialGradientPaint gradient = (java.awt.RadialGradientPaint)paint;
|
|
GraphicsPath path = new GraphicsPath();
|
|
SizeF size = GetSize();
|
|
|
|
PointF center = J2C.ConvertPoint(gradient.getCenterPoint());
|
|
|
|
float radius = gradient.getRadius();
|
|
int factor = (int)Math.Ceiling(Math.Max(size.Width, size.Height) / radius);
|
|
|
|
float diameter = radius * factor;
|
|
path.AddEllipse(center.X - diameter, center.Y - diameter, diameter * 2, diameter * 2);
|
|
|
|
java.awt.Color[] javaColors = gradient.getColors();
|
|
float[] fractions = gradient.getFractions();
|
|
int length = javaColors.Length;
|
|
ColorBlend colorBlend = new ColorBlend(length * factor);
|
|
Color[] colors = colorBlend.Colors;
|
|
float[] positions = colorBlend.Positions;
|
|
|
|
for (int c = 0, j = length - 1; j >= 0; )
|
|
{
|
|
positions[c] = (1 - fractions[j]) / factor;
|
|
colors[c++] = composite.GetColor(javaColors[j--]);
|
|
}
|
|
|
|
java.awt.MultipleGradientPaint.CycleMethod.__Enum cycle = (java.awt.MultipleGradientPaint.CycleMethod.__Enum)gradient.getCycleMethod().ordinal();
|
|
for (int f = 1; f < factor; f++)
|
|
{
|
|
int off = f * length;
|
|
for (int c = 0, j = length - 1; j >= 0; j--, c++)
|
|
{
|
|
switch (cycle)
|
|
{
|
|
case java.awt.MultipleGradientPaint.CycleMethod.__Enum.REFLECT:
|
|
if (f % 2 == 0)
|
|
{
|
|
positions[off + c] = (f + 1 - fractions[j]) / factor;
|
|
colors[off + c] = colors[c];
|
|
}
|
|
else
|
|
{
|
|
positions[off + c] = (f + fractions[c]) / factor;
|
|
colors[off + c] = colors[j];
|
|
}
|
|
break;
|
|
case java.awt.MultipleGradientPaint.CycleMethod.__Enum.NO_CYCLE:
|
|
positions[off + c] = (f + 1 - fractions[j]) / factor;
|
|
break;
|
|
default: //CycleMethod.REPEAT
|
|
positions[off + c] = (f + 1 - fractions[j]) / factor;
|
|
colors[off + c] = colors[c];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (cycle == java.awt.MultipleGradientPaint.CycleMethod.__Enum.NO_CYCLE && factor > 1)
|
|
{
|
|
Array.Copy(colors, 0, colors, colors.Length - length, length);
|
|
Color color = colors[length - 1];
|
|
for (int i = colors.Length - length - 1; i >= 0; i--)
|
|
{
|
|
colors[i] = color;
|
|
}
|
|
}
|
|
|
|
PathGradientBrush pathBrush = new PathGradientBrush(path);
|
|
pathBrush.CenterPoint = center;
|
|
pathBrush.InterpolationColors = colorBlend;
|
|
|
|
brush = pathBrush;
|
|
pen.Brush = brush;
|
|
return;
|
|
}
|
|
|
|
//generic paint to brush conversion for custom paints
|
|
//the tranform of the graphics should not change between the creation and it usage
|
|
using (Matrix transform = g.Transform)
|
|
{
|
|
SizeF size = GetSize();
|
|
int width = (int)size.Width;
|
|
int height = (int)size.Height;
|
|
java.awt.Rectangle bounds = new java.awt.Rectangle(0, 0, width, height);
|
|
|
|
java.awt.PaintContext context = paint.createContext(ColorModel.getRGBdefault(), bounds, bounds, C2J.ConvertMatrix(transform), getRenderingHints());
|
|
WritableRaster raster = (WritableRaster)context.getRaster(0, 0, width, height);
|
|
BufferedImage txtrImage = new BufferedImage(context.getColorModel(), raster, true, null);
|
|
Bitmap txtr = J2C.ConvertImage(txtrImage);
|
|
|
|
TextureBrush txtBrush;
|
|
brush = txtBrush = new TextureBrush(txtr, new Rectangle(0, 0, width, height), composite.GetImageAttributes());
|
|
transform.Invert();
|
|
txtBrush.Transform = transform;
|
|
txtBrush.WrapMode = WrapMode.Tile;
|
|
pen.Brush = brush;
|
|
return;
|
|
}
|
|
}
|
|
|
|
public override void setStroke(java.awt.Stroke stroke)
|
|
{
|
|
if (this.stroke != null && this.stroke.Equals(stroke))
|
|
{
|
|
return;
|
|
}
|
|
this.stroke = stroke;
|
|
if (stroke is java.awt.BasicStroke)
|
|
{
|
|
java.awt.BasicStroke s = (java.awt.BasicStroke)stroke;
|
|
|
|
pen = new Pen(pen.Brush, s.getLineWidth());
|
|
|
|
SetLineJoin(s);
|
|
SetLineDash(s);
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Unknown Stroke type: " + stroke.GetType().FullName);
|
|
}
|
|
}
|
|
|
|
private void SetLineJoin(java.awt.BasicStroke s)
|
|
{
|
|
pen.MiterLimit = s.getMiterLimit();
|
|
pen.LineJoin = J2C.ConvertLineJoin(s.getLineJoin());
|
|
}
|
|
|
|
private void SetLineDash(java.awt.BasicStroke s)
|
|
{
|
|
float[] dash = s.getDashArray();
|
|
if (dash == null)
|
|
{
|
|
pen.DashStyle = DashStyle.Solid;
|
|
} else {
|
|
if (dash.Length % 2 == 1)
|
|
{
|
|
int len = dash.Length;
|
|
Array.Resize(ref dash, len * 2);
|
|
Array.Copy(dash, 0, dash, len, len);
|
|
}
|
|
float lineWidth = s.getLineWidth();
|
|
if (lineWidth > 1) // for values < 0 there is no correctur needed
|
|
{
|
|
for (int i = 0; i < dash.Length; i++)
|
|
{
|
|
//dividing by line thickness because of the representation difference
|
|
dash[i] = dash[i] / lineWidth;
|
|
}
|
|
}
|
|
// To fix the problem where solid style in Java can be represented at { 1.0, 0.0 }.
|
|
// In .NET, however, array can only have positive value
|
|
if (dash.Length == 2 && dash[dash.Length - 1] == 0)
|
|
{
|
|
Array.Resize(ref dash, 1);
|
|
}
|
|
|
|
float dashPhase = s.getDashPhase();
|
|
// correct the dash cap
|
|
switch (s.getEndCap())
|
|
{
|
|
case java.awt.BasicStroke.CAP_BUTT:
|
|
pen.DashCap = DashCap.Flat;
|
|
break;
|
|
case java.awt.BasicStroke.CAP_ROUND:
|
|
pen.DashCap = DashCap.Round;
|
|
break;
|
|
case java.awt.BasicStroke.CAP_SQUARE:
|
|
pen.DashCap = DashCap.Flat;
|
|
// there is no equals DashCap in .NET, we need to emulate it
|
|
dashPhase += lineWidth / 2;
|
|
for (int i = 0; i < dash.Length; i++)
|
|
{
|
|
if (i % 2 == 0)
|
|
{
|
|
dash[i] += 1;
|
|
}
|
|
else
|
|
{
|
|
dash[i] = Math.Max(0.00001F, dash[i] - 1);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
Console.WriteLine("Unknown dash cap type:" + s.getEndCap());
|
|
break;
|
|
}
|
|
|
|
// calc the dash offset
|
|
if (lineWidth > 0)
|
|
{
|
|
//dividing by line thickness because of the representation difference
|
|
pen.DashOffset = dashPhase / lineWidth;
|
|
}
|
|
else
|
|
{
|
|
// thickness == 0
|
|
if (dashPhase > 0)
|
|
{
|
|
pen.Width = lineWidth = 0.001F; // hack to prevent a division with 0
|
|
pen.DashOffset = dashPhase / lineWidth;
|
|
}
|
|
else
|
|
{
|
|
pen.DashOffset = 0;
|
|
}
|
|
}
|
|
|
|
// set the final dash pattern
|
|
pen.DashPattern = dash;
|
|
}
|
|
}
|
|
|
|
public override void setRenderingHint(java.awt.RenderingHints.Key hintKey, Object hintValue)
|
|
{
|
|
if (hintKey == java.awt.RenderingHints.KEY_ANTIALIASING)
|
|
{
|
|
if (hintValue == java.awt.RenderingHints.VALUE_ANTIALIAS_DEFAULT)
|
|
{
|
|
g.SmoothingMode = SmoothingMode.Default;
|
|
g.PixelOffsetMode = PixelOffsetMode.Default;
|
|
return;
|
|
}
|
|
if (hintValue == java.awt.RenderingHints.VALUE_ANTIALIAS_OFF)
|
|
{
|
|
g.SmoothingMode = SmoothingMode.None;
|
|
g.PixelOffsetMode = PixelOffsetMode.Default;
|
|
return;
|
|
}
|
|
if (hintValue == java.awt.RenderingHints.VALUE_ANTIALIAS_ON)
|
|
{
|
|
g.SmoothingMode = SmoothingMode.AntiAlias;
|
|
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
if (hintKey == java.awt.RenderingHints.KEY_INTERPOLATION)
|
|
{
|
|
if (hintValue == java.awt.RenderingHints.VALUE_INTERPOLATION_BILINEAR)
|
|
{
|
|
g.InterpolationMode = InterpolationMode.HighQualityBilinear;
|
|
return;
|
|
}
|
|
if (hintValue == java.awt.RenderingHints.VALUE_INTERPOLATION_BICUBIC)
|
|
{
|
|
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
|
return;
|
|
}
|
|
if (hintValue == java.awt.RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)
|
|
{
|
|
g.InterpolationMode = InterpolationMode.NearestNeighbor;
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
if (hintKey == java.awt.RenderingHints.KEY_TEXT_ANTIALIASING)
|
|
{
|
|
if (hintValue == java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT ||
|
|
hintValue == java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)
|
|
{
|
|
setTextRenderingHint(TextRenderingHint.SingleBitPerPixelGridFit);
|
|
textAntialiasHint = hintValue;
|
|
return;
|
|
}
|
|
if (hintValue == java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON)
|
|
{
|
|
setTextRenderingHint(TextRenderingHint.AntiAlias);
|
|
textAntialiasHint = hintValue;
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
if (hintKey == java.awt.RenderingHints.KEY_FRACTIONALMETRICS)
|
|
{
|
|
if (hintValue == java.awt.RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT ||
|
|
hintValue == java.awt.RenderingHints.VALUE_FRACTIONALMETRICS_OFF ||
|
|
hintValue == java.awt.RenderingHints.VALUE_FRACTIONALMETRICS_ON)
|
|
{
|
|
fractionalHint = hintValue;
|
|
}
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
public override object getRenderingHint(java.awt.RenderingHints.Key hintKey)
|
|
{
|
|
return getRenderingHints().get(hintKey);
|
|
}
|
|
|
|
public override void setRenderingHints(java.util.Map hints)
|
|
{
|
|
addRenderingHints(hints);
|
|
//TODO all not included values should reset to default, but was is default?
|
|
}
|
|
|
|
public override void addRenderingHints(java.util.Map hints)
|
|
{
|
|
Iterator iterator = hints.entrySet().iterator();
|
|
while (iterator.hasNext())
|
|
{
|
|
java.util.Map.Entry entry = (java.util.Map.Entry)iterator.next();
|
|
setRenderingHint((java.awt.RenderingHints.Key)entry.getKey(), entry.getValue());
|
|
}
|
|
}
|
|
|
|
public override java.awt.RenderingHints getRenderingHints()
|
|
{
|
|
java.awt.RenderingHints hints = new java.awt.RenderingHints(null);
|
|
switch (g.SmoothingMode)
|
|
{
|
|
case SmoothingMode.Default:
|
|
hints.put(java.awt.RenderingHints.KEY_ANTIALIASING, java.awt.RenderingHints.VALUE_ANTIALIAS_DEFAULT);
|
|
break;
|
|
case SmoothingMode.None:
|
|
hints.put(java.awt.RenderingHints.KEY_ANTIALIASING, java.awt.RenderingHints.VALUE_ANTIALIAS_OFF);
|
|
break;
|
|
case SmoothingMode.AntiAlias:
|
|
hints.put(java.awt.RenderingHints.KEY_ANTIALIASING, java.awt.RenderingHints.VALUE_ANTIALIAS_ON);
|
|
break;
|
|
}
|
|
|
|
switch (g.InterpolationMode)
|
|
{
|
|
case InterpolationMode.Bilinear:
|
|
case InterpolationMode.HighQualityBilinear:
|
|
hints.put(java.awt.RenderingHints.KEY_INTERPOLATION, java.awt.RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
|
break;
|
|
case InterpolationMode.Bicubic:
|
|
case InterpolationMode.HighQualityBicubic:
|
|
hints.put(java.awt.RenderingHints.KEY_INTERPOLATION, java.awt.RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
|
break;
|
|
case InterpolationMode.NearestNeighbor:
|
|
hints.put(java.awt.RenderingHints.KEY_INTERPOLATION, java.awt.RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
|
|
break;
|
|
}
|
|
|
|
hints.put(java.awt.RenderingHints.KEY_TEXT_ANTIALIASING, textAntialiasHint);
|
|
hints.put(java.awt.RenderingHints.KEY_FRACTIONALMETRICS, fractionalHint);
|
|
return hints;
|
|
}
|
|
|
|
public override void translate(double x, double y)
|
|
{
|
|
Matrix transform = g.Transform;
|
|
transform.Translate((float)x, (float)y);
|
|
g.Transform = transform;
|
|
}
|
|
|
|
private static double RadiansToDegrees(double radians)
|
|
{
|
|
return radians * (180 / Math.PI);
|
|
}
|
|
|
|
public override void rotate(double theta)
|
|
{
|
|
Matrix transform = g.Transform;
|
|
transform.Rotate((float)RadiansToDegrees(theta));
|
|
g.Transform = transform;
|
|
}
|
|
|
|
public override void rotate(double theta, double x, double y)
|
|
{
|
|
Matrix transform = g.Transform;
|
|
transform.Translate((float)x, (float)y);
|
|
transform.Rotate((float)RadiansToDegrees(theta));
|
|
transform.Translate(-(float)x, -(float)y);
|
|
g.Transform = transform;
|
|
}
|
|
|
|
public override void scale(double scaleX, double scaleY)
|
|
{
|
|
using (Matrix transform = g.Transform)
|
|
{
|
|
transform.Scale((float)scaleX, (float)scaleY);
|
|
g.Transform = transform;
|
|
}
|
|
}
|
|
|
|
public override void shear(double shearX, double shearY)
|
|
{
|
|
using (Matrix transform = g.Transform)
|
|
{
|
|
transform.Shear((float)shearX, (float)shearY);
|
|
g.Transform = transform;
|
|
}
|
|
}
|
|
|
|
public override void transform(java.awt.geom.AffineTransform tx)
|
|
{
|
|
using (Matrix transform = g.Transform,
|
|
matrix = J2C.ConvertTransform(tx))
|
|
{
|
|
transform.Multiply(matrix);
|
|
g.Transform = transform;
|
|
}
|
|
}
|
|
|
|
public override void setTransform(java.awt.geom.AffineTransform tx)
|
|
{
|
|
g.Transform = J2C.ConvertTransform(tx);
|
|
}
|
|
|
|
public override java.awt.geom.AffineTransform getTransform()
|
|
{
|
|
using (Matrix matrix = g.Transform)
|
|
{
|
|
return C2J.ConvertMatrix(matrix);
|
|
}
|
|
}
|
|
|
|
public override java.awt.Paint getPaint()
|
|
{
|
|
if( javaPaint == null ) {
|
|
javaPaint = composite.GetColor(color);
|
|
}
|
|
return javaPaint;
|
|
}
|
|
|
|
public override java.awt.Composite getComposite()
|
|
{
|
|
return javaComposite;
|
|
}
|
|
|
|
public override void setBackground(java.awt.Color backcolor)
|
|
{
|
|
bgcolor = backcolor == null ? Color.Empty : Color.FromArgb(backcolor.getRGB());
|
|
}
|
|
|
|
public override java.awt.Color getBackground()
|
|
{
|
|
return bgcolor == Color.Empty ? null : new java.awt.Color(color.ToArgb(), true);
|
|
}
|
|
|
|
public override java.awt.Stroke getStroke()
|
|
{
|
|
if (stroke == null)
|
|
{
|
|
return defaultStroke;
|
|
}
|
|
return stroke;
|
|
}
|
|
|
|
internal void setTextRenderingHint(TextRenderingHint hint)
|
|
{
|
|
g.TextRenderingHint = hint;
|
|
baseline = getBaseline(netfont, hint);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Caclulate the baseline from a font and a TextRenderingHint
|
|
/// </summary>
|
|
/// <param name="font">the font</param>
|
|
/// <param name="hint">the used TextRenderingHint</param>
|
|
/// <returns></returns>
|
|
private static int getBaseline(Font font, TextRenderingHint hint)
|
|
{
|
|
lock (baselines)
|
|
{
|
|
String key = font.ToString() + hint.ToString();
|
|
int baseline;
|
|
if (!baselines.TryGetValue(key, out baseline))
|
|
{
|
|
FontFamily family = font.FontFamily;
|
|
FontStyle style = font.Style;
|
|
float ascent = family.GetCellAscent(style);
|
|
float lineSpace = family.GetLineSpacing(style);
|
|
|
|
baseline = (int)Math.Round(font.GetHeight() * ascent / lineSpace);
|
|
|
|
// Until this point the calulation use only the Font. But with different TextRenderingHint there are smal differences.
|
|
// There is no API that calulate the offset from TextRenderingHint that we messure it.
|
|
const int w = 3;
|
|
const int h = 3;
|
|
|
|
Bitmap bitmap = new Bitmap(w, h);
|
|
Graphics g = Graphics.FromImage(bitmap);
|
|
g.TextRenderingHint = hint;
|
|
g.FillRectangle(new SolidBrush(Color.White), 0, 0, w, h);
|
|
g.DrawString("A", font, new SolidBrush(Color.Black), 0, -baseline, FORMAT);
|
|
g.DrawString("X", font, new SolidBrush(Color.Black), 0, -baseline, FORMAT);
|
|
g.Dispose();
|
|
|
|
int y = 0;
|
|
LINE:
|
|
while (y < h)
|
|
{
|
|
for (int x = 0; x < w; x++)
|
|
{
|
|
Color color = bitmap.GetPixel(x, y);
|
|
if (color.GetBrightness() < 0.5)
|
|
{
|
|
//there is a black pixel, we continue in the next line.
|
|
baseline++;
|
|
y++;
|
|
goto LINE;
|
|
}
|
|
}
|
|
break; // there was a line without black pixel
|
|
}
|
|
|
|
|
|
baselines[key] = baseline;
|
|
}
|
|
return baseline;
|
|
}
|
|
}
|
|
|
|
private bool isAntiAlias()
|
|
{
|
|
switch (g.TextRenderingHint)
|
|
{
|
|
case TextRenderingHint.AntiAlias:
|
|
case TextRenderingHint.AntiAliasGridFit:
|
|
case TextRenderingHint.ClearTypeGridFit:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private bool isFractionalMetrics()
|
|
{
|
|
return fractionalHint == java.awt.RenderingHints.VALUE_FRACTIONALMETRICS_ON;
|
|
}
|
|
|
|
public override java.awt.font.FontRenderContext getFontRenderContext()
|
|
{
|
|
return new java.awt.font.FontRenderContext(getTransform(), isAntiAlias(), isFractionalMetrics());
|
|
}
|
|
|
|
public override void drawGlyphVector(java.awt.font.GlyphVector gv, float x, float y)
|
|
{
|
|
java.awt.font.FontRenderContext frc = gv.getFontRenderContext();
|
|
Matrix currentMatrix = null;
|
|
Font currentFont = netfont;
|
|
TextRenderingHint currentHint = g.TextRenderingHint;
|
|
int currentBaseline = baseline;
|
|
try
|
|
{
|
|
java.awt.Font javaFont = gv.getFont();
|
|
if (javaFont != null)
|
|
{
|
|
netfont = javaFont.getNetFont();
|
|
}
|
|
TextRenderingHint hint;
|
|
if (frc.isAntiAliased()) {
|
|
if( frc.usesFractionalMetrics() ){
|
|
hint = TextRenderingHint.AntiAlias;
|
|
} else {
|
|
hint = TextRenderingHint.AntiAliasGridFit;
|
|
}
|
|
} else {
|
|
if (frc.usesFractionalMetrics()) {
|
|
hint = TextRenderingHint.SingleBitPerPixel;
|
|
} else {
|
|
hint = TextRenderingHint.SingleBitPerPixelGridFit;
|
|
}
|
|
}
|
|
g.TextRenderingHint = hint;
|
|
baseline = getBaseline(netfont, hint);
|
|
if (!frc.getTransform().equals(getTransform()))
|
|
{
|
|
// save the old context and use the transformation from the renderContext
|
|
currentMatrix = g.Transform;
|
|
g.Transform = J2C.ConvertTransform(frc.getTransform());
|
|
}
|
|
drawString(J2C.ConvertGlyphVector(gv), x, y);
|
|
}
|
|
finally
|
|
{
|
|
// Restore the old context if needed
|
|
g.TextRenderingHint = currentHint;
|
|
baseline = currentBaseline;
|
|
netfont = currentFont;
|
|
if (currentMatrix != null)
|
|
{
|
|
g.Transform = currentMatrix;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sealed class NetGraphicsConfiguration : java.awt.GraphicsConfiguration
|
|
{
|
|
internal readonly Screen screen;
|
|
|
|
public NetGraphicsConfiguration(Screen screen)
|
|
{
|
|
this.screen = screen;
|
|
}
|
|
|
|
public override java.awt.image.BufferedImage createCompatibleImage(int width, int height, int transparency)
|
|
{
|
|
switch (transparency)
|
|
{
|
|
case java.awt.Transparency.__Fields.OPAQUE:
|
|
return new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
|
case java.awt.Transparency.__Fields.BITMASK:
|
|
return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
|
|
case java.awt.Transparency.__Fields.TRANSLUCENT:
|
|
return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
|
default:
|
|
throw new java.lang.IllegalArgumentException("transparency:" + transparency);
|
|
}
|
|
}
|
|
|
|
public override java.awt.image.BufferedImage createCompatibleImage(int width, int height)
|
|
{
|
|
return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
|
}
|
|
|
|
public override java.awt.image.VolatileImage createCompatibleVolatileImage(int param1, int param2, java.awt.ImageCapabilities param3)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override java.awt.image.VolatileImage createCompatibleVolatileImage(int width, int height)
|
|
{
|
|
return new NetVolatileImage(width, height);
|
|
}
|
|
|
|
public override java.awt.Rectangle getBounds()
|
|
{
|
|
System.Drawing.Rectangle bounds = screen.Bounds;
|
|
return new java.awt.Rectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height);
|
|
}
|
|
|
|
public override java.awt.BufferCapabilities getBufferCapabilities()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override java.awt.image.ColorModel getColorModel(int transparency)
|
|
{
|
|
if (transparency == java.awt.Transparency.__Fields.TRANSLUCENT)
|
|
{
|
|
//we return the default ColorModel because this produce the fewest problems with convertions
|
|
return ColorModel.getRGBdefault();
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public override java.awt.image.ColorModel getColorModel()
|
|
{
|
|
//we return the default ColorModel because this produce the fewest problems with convertions
|
|
return ColorModel.getRGBdefault();
|
|
}
|
|
|
|
public override java.awt.geom.AffineTransform getDefaultTransform()
|
|
{
|
|
return new java.awt.geom.AffineTransform();
|
|
}
|
|
|
|
public override java.awt.GraphicsDevice getDevice()
|
|
{
|
|
return new NetGraphicsDevice(screen);
|
|
}
|
|
|
|
public override java.awt.ImageCapabilities getImageCapabilities()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override java.awt.geom.AffineTransform getNormalizingTransform()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override VolatileImage createCompatibleVolatileImage(int width, int height, int transparency)
|
|
{
|
|
return new NetVolatileImage(width, height);
|
|
}
|
|
|
|
public override VolatileImage createCompatibleVolatileImage(int width, int height, java.awt.ImageCapabilities caps, int transparency)
|
|
{
|
|
return new NetVolatileImage(width, height);
|
|
}
|
|
|
|
public override bool isTranslucencyCapable()
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
class NetGraphicsDevice : java.awt.GraphicsDevice
|
|
{
|
|
internal readonly Screen screen;
|
|
|
|
internal NetGraphicsDevice(Screen screen)
|
|
{
|
|
this.screen = screen;
|
|
}
|
|
|
|
public override java.awt.GraphicsConfiguration[] getConfigurations()
|
|
{
|
|
Screen[] screens = Screen.AllScreens;
|
|
NetGraphicsConfiguration[] configs = new NetGraphicsConfiguration[screens.Length];
|
|
for (int i = 0; i < screens.Length; i++)
|
|
{
|
|
configs[i] = new NetGraphicsConfiguration(screens[i]);
|
|
}
|
|
return configs;
|
|
}
|
|
|
|
public override java.awt.GraphicsConfiguration getDefaultConfiguration()
|
|
{
|
|
return new NetGraphicsConfiguration(screen);
|
|
}
|
|
|
|
public override string getIDstring()
|
|
{
|
|
return screen.DeviceName;
|
|
}
|
|
|
|
public override int getType()
|
|
{
|
|
return TYPE_RASTER_SCREEN;
|
|
}
|
|
}
|
|
|
|
public class NetGraphicsEnvironment : sun.java2d.SunGraphicsEnvironment
|
|
{
|
|
|
|
public override bool isDisplayLocal()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Create a bitmap with the dimensions of the argument image. Then
|
|
// create a graphics objects from the bitmap. All paint operations will
|
|
// then paint the bitmap.
|
|
public override java.awt.Graphics2D createGraphics(BufferedImage bi)
|
|
{
|
|
return new BitmapGraphics(bi.getBitmap(), bi );
|
|
}
|
|
|
|
public override java.awt.Font[] getAllFonts()
|
|
{
|
|
#if WINFX
|
|
System.Collections.Generic.ICollection<Typeface> typefaces = System.Windows.Media.Fonts.SystemTypefaces;
|
|
java.awt.Font[] fonts = new java.awt.Font[typefaces.Count];
|
|
int i = 0;
|
|
foreach (Typeface face in typefaces)
|
|
{
|
|
FontFamily family = face.FontFamily;
|
|
fonts[i++] = new java.awt.Font(family.GetName(0), face.Style, 1);
|
|
}
|
|
#else
|
|
String[] names = getAvailableFontFamilyNames();
|
|
java.awt.Font[] fonts = new java.awt.Font[names.Length];
|
|
for(int i=0; i<fonts.Length; i++)
|
|
{
|
|
fonts[i] = new java.awt.Font(names[i], 0, 1);
|
|
}
|
|
return fonts;
|
|
#endif
|
|
}
|
|
|
|
public override String[] getAvailableFontFamilyNames()
|
|
{
|
|
int language = CultureInfo.CurrentCulture.LCID;
|
|
return getAvailableFontFamilyNames(language);
|
|
}
|
|
|
|
public override string[] getAvailableFontFamilyNames(Locale locale)
|
|
{
|
|
int language = CultureInfo.GetCultureInfo(locale.toString()).LCID;
|
|
return getAvailableFontFamilyNames(language);
|
|
}
|
|
|
|
private String[] getAvailableFontFamilyNames(int language)
|
|
{
|
|
FontFamily[] families = FontFamily.Families;
|
|
String[] results = new String[families.Length + 5];
|
|
int i = 0;
|
|
for (; i < families.Length; i++)
|
|
{
|
|
results[i] = families[i].GetName(language);
|
|
}
|
|
results[i++] = "Dialog";
|
|
results[i++] = "DialogInput";
|
|
results[i++] = "Serif";
|
|
results[i++] = "SansSerif";
|
|
results[i++] = "Monospaced";
|
|
Array.Sort(results);
|
|
return results;
|
|
}
|
|
|
|
public override java.awt.GraphicsDevice getDefaultScreenDevice()
|
|
{
|
|
return new NetGraphicsDevice(Screen.PrimaryScreen);
|
|
}
|
|
|
|
public override java.awt.GraphicsDevice[] getScreenDevices()
|
|
{
|
|
Screen[] screens = Screen.AllScreens;
|
|
NetGraphicsDevice[] devices = new NetGraphicsDevice[screens.Length];
|
|
for (int i = 0; i < screens.Length; i++)
|
|
{
|
|
devices[i] = new NetGraphicsDevice(screens[i]);
|
|
}
|
|
return devices;
|
|
}
|
|
}
|
|
|
|
} |