1 |
/* GdkGraphics2D.java |
/* GdkGraphics2D.java |
2 |
Copyright (C) 2003, 2004 Free Software Foundation, Inc. |
Copyright (C) 2003, 2004 Free Software Foundation, Inc. |
3 |
|
|
4 |
This file is part of GNU Classpath. |
This file is part of GNU Classpath. |
5 |
|
|
38 |
|
|
39 |
package gnu.java.awt.peer.gtk; |
package gnu.java.awt.peer.gtk; |
40 |
|
|
41 |
import java.awt.*; |
import gnu.classpath.Configuration; |
42 |
import java.awt.geom.*; |
import gnu.java.awt.ClasspathToolkit; |
43 |
import java.awt.font.*; |
import gnu.java.awt.peer.ClasspathFontPeer; |
|
import java.awt.color.*; |
|
|
import java.awt.image.*; |
|
|
import java.awt.image.renderable.*; |
|
|
import java.util.HashMap; |
|
|
import java.util.Map; |
|
44 |
|
|
45 |
|
import java.awt.AlphaComposite; |
46 |
|
import java.awt.BasicStroke; |
47 |
|
import java.awt.Color; |
48 |
|
import java.awt.Composite; |
49 |
|
import java.awt.Font; |
50 |
|
import java.awt.FontMetrics; |
51 |
|
import java.awt.GradientPaint; |
52 |
|
import java.awt.Graphics; |
53 |
|
import java.awt.Graphics2D; |
54 |
|
import java.awt.GraphicsConfiguration; |
55 |
|
import java.awt.Image; |
56 |
|
import java.awt.Paint; |
57 |
|
import java.awt.Rectangle; |
58 |
|
import java.awt.RenderingHints; |
59 |
|
import java.awt.Shape; |
60 |
|
import java.awt.Stroke; |
61 |
|
import java.awt.TexturePaint; |
62 |
|
import java.awt.Toolkit; |
63 |
|
import java.awt.color.ColorSpace; |
64 |
|
import java.awt.font.FontRenderContext; |
65 |
|
import java.awt.font.GlyphVector; |
66 |
|
import java.awt.font.GlyphJustificationInfo; |
67 |
|
import java.awt.geom.Arc2D; |
68 |
|
import java.awt.geom.GeneralPath; |
69 |
|
import java.awt.geom.NoninvertibleTransformException; |
70 |
|
import java.awt.geom.PathIterator; |
71 |
|
import java.awt.geom.Point2D; |
72 |
|
import java.awt.geom.Rectangle2D; |
73 |
|
import java.awt.geom.AffineTransform; |
74 |
|
import java.awt.image.AffineTransformOp; |
75 |
|
import java.awt.image.BufferedImage; |
76 |
|
import java.awt.image.BufferedImageOp; |
77 |
|
import java.awt.image.ColorModel; |
78 |
|
import java.awt.image.CropImageFilter; |
79 |
|
import java.awt.image.DataBuffer; |
80 |
|
import java.awt.image.DataBufferInt; |
81 |
|
import java.awt.image.FilteredImageSource; |
82 |
|
import java.awt.image.ImageConsumer; |
83 |
|
import java.awt.image.ImageObserver; |
84 |
|
import java.awt.image.ImagingOpException; |
85 |
|
import java.awt.image.SampleModel; |
86 |
|
import java.awt.image.Raster; |
87 |
|
import java.awt.image.RenderedImage; |
88 |
|
import java.awt.image.WritableRaster; |
89 |
|
import java.awt.image.renderable.RenderableImage; |
90 |
|
import java.awt.image.renderable.RenderContext; |
91 |
import java.text.AttributedCharacterIterator; |
import java.text.AttributedCharacterIterator; |
92 |
|
import java.util.HashMap; |
93 |
|
import java.util.Map; |
94 |
import java.util.Stack; |
import java.util.Stack; |
|
import java.lang.Integer; |
|
|
import gnu.java.awt.ClasspathToolkit; |
|
|
import gnu.java.awt.peer.ClasspathFontPeer; |
|
|
import gnu.classpath.Configuration; |
|
95 |
|
|
96 |
public class GdkGraphics2D extends Graphics2D |
public class GdkGraphics2D extends Graphics2D |
97 |
{ |
{ |
134 |
native public void dispose (); |
native public void dispose (); |
135 |
native private int[] getImagePixels(); |
native private int[] getImagePixels(); |
136 |
native private void cairoSurfaceSetFilter(int filter); |
native private void cairoSurfaceSetFilter(int filter); |
137 |
|
native void connectSignals (GtkComponentPeer component); |
138 |
|
|
139 |
public void finalize () |
public void finalize () |
140 |
{ |
{ |
155 |
{ |
{ |
156 |
paint = g.paint; |
paint = g.paint; |
157 |
stroke = g.stroke; |
stroke = g.stroke; |
158 |
hints = g.hints; |
setRenderingHints (g.hints); |
159 |
|
|
160 |
if (g.fg.getAlpha() != -1) |
if (g.fg.getAlpha() != -1) |
161 |
fg = new Color (g.fg.getRed (), g.fg.getGreen (), |
fg = new Color (g.fg.getRed (), g.fg.getGreen (), |
210 |
GdkGraphics2D (GtkComponentPeer component) |
GdkGraphics2D (GtkComponentPeer component) |
211 |
{ |
{ |
212 |
this.component = component; |
this.component = component; |
213 |
|
|
214 |
|
setFont (new Font("SansSerif", Font.PLAIN, 12)); |
215 |
|
|
216 |
|
if (component.isRealized ()) |
217 |
|
initComponentGraphics2D (); |
218 |
|
else |
219 |
|
connectSignals (component); |
220 |
|
} |
221 |
|
|
222 |
|
void initComponentGraphics2D () |
223 |
|
{ |
224 |
initState (component); |
initState (component); |
225 |
|
|
226 |
setColor (component.awtComponent.getForeground ()); |
setColor (component.awtComponent.getForeground ()); |
227 |
setBackground (component.awtComponent.getBackground ()); |
setBackground (component.awtComponent.getBackground ()); |
228 |
setPaint (getColor()); |
setPaint (getColor()); |
|
setFont (new Font("SansSerif", Font.PLAIN, 12)); |
|
229 |
setTransform (new AffineTransform ()); |
setTransform (new AffineTransform ()); |
230 |
setStroke (new BasicStroke ()); |
setStroke (new BasicStroke ()); |
231 |
setRenderingHints (getDefaultHints()); |
setRenderingHints (getDefaultHints()); |
276 |
private native void cairoSave (); |
private native void cairoSave (); |
277 |
private native void cairoRestore (); |
private native void cairoRestore (); |
278 |
private native void cairoSetMatrix (double m[]); |
private native void cairoSetMatrix (double m[]); |
|
private native void cairoSetFont (GdkClasspathFontPeer peer); |
|
|
private native void cairoShowGlyphs (int codes[], |
|
|
float positions[]); |
|
279 |
private native void cairoSetOperator (int cairoOperator); |
private native void cairoSetOperator (int cairoOperator); |
280 |
private native void cairoSetRGBColor (double red, double green, double blue); |
private native void cairoSetRGBColor (double red, double green, double blue); |
281 |
private native void cairoSetAlpha (double alpha); |
private native void cairoSetAlpha (double alpha); |
355 |
cairoRestore (); |
cairoRestore (); |
356 |
} |
} |
357 |
|
|
358 |
|
// Some operations (drawing rather than filling) require that their |
359 |
|
// coords be shifted to land on 0.5-pixel boundaries, in order to land on |
360 |
|
// "middle of pixel" coordinates and light up complete pixels. |
361 |
|
|
362 |
double x; |
private boolean shiftDrawCalls = false; |
363 |
double y; |
private final double shifted(double coord, boolean doShift) |
|
private void setPos (double nx, double ny) |
|
364 |
{ |
{ |
365 |
x = nx; |
if (doShift) |
366 |
y = ny; |
return Math.floor(coord) + 0.5; |
367 |
|
else |
368 |
|
return coord; |
369 |
} |
} |
370 |
|
|
371 |
private void walkPath(PathIterator p) |
private final void walkPath(PathIterator p, boolean doShift) |
372 |
{ |
{ |
373 |
|
double x = 0; |
374 |
|
double y = 0; |
375 |
double coords[] = new double[6]; |
double coords[] = new double[6]; |
376 |
|
|
377 |
cairoSetFillRule (p.getWindingRule ()); |
cairoSetFillRule (p.getWindingRule ()); |
382 |
{ |
{ |
383 |
|
|
384 |
case PathIterator.SEG_MOVETO: |
case PathIterator.SEG_MOVETO: |
385 |
setPos(coords[0], coords[1]); |
x = shifted(coords[0], doShift); |
386 |
cairoMoveTo (coords[0], coords[1]); |
y = shifted(coords[1], doShift); |
387 |
|
cairoMoveTo (x, y); |
388 |
break; |
break; |
389 |
|
|
390 |
case PathIterator.SEG_LINETO: |
case PathIterator.SEG_LINETO: |
391 |
setPos(coords[0], coords[1]); |
x = shifted(coords[0], doShift); |
392 |
cairoLineTo (coords[0], coords[1]); |
y = shifted(coords[1], doShift); |
393 |
|
cairoLineTo (x, y); |
394 |
break; |
break; |
395 |
|
|
396 |
case PathIterator.SEG_QUADTO: |
case PathIterator.SEG_QUADTO: |
398 |
// splitting a quadratic bezier into a cubic: |
// splitting a quadratic bezier into a cubic: |
399 |
// see: http://pfaedit.sourceforge.net/bezier.html |
// see: http://pfaedit.sourceforge.net/bezier.html |
400 |
|
|
401 |
double x1 = x + (2.0/3.0) * (coords[0] - x); |
double x1 = x + (2.0/3.0) * (shifted(coords[0], doShift) - x); |
402 |
double y1 = y + (2.0/3.0) * (coords[1] - y); |
double y1 = y + (2.0/3.0) * (shifted(coords[1], doShift) - y); |
403 |
|
|
404 |
double x2 = x1 + (1.0/3.0) * (coords[2] - x); |
double x2 = x1 + (1.0/3.0) * (shifted(coords[2], doShift) - x); |
405 |
double y2 = y1 + (1.0/3.0) * (coords[3] - y); |
double y2 = y1 + (1.0/3.0) * (shifted(coords[3], doShift) - y); |
406 |
|
|
407 |
setPos(coords[2], coords[3]); |
x = shifted(coords[2], doShift); |
408 |
|
y = shifted(coords[3], doShift); |
409 |
cairoCurveTo (x1, y1, |
cairoCurveTo (x1, y1, |
410 |
x2, y2, |
x2, y2, |
411 |
coords[2], coords[3]); |
x, y); |
412 |
break; |
break; |
413 |
|
|
414 |
case PathIterator.SEG_CUBICTO: |
case PathIterator.SEG_CUBICTO: |
415 |
setPos(coords[4], coords[5]); |
x = shifted(coords[4], doShift); |
416 |
cairoCurveTo (coords[0], coords[1], |
y = shifted(coords[5], doShift); |
417 |
coords[2], coords[3], |
cairoCurveTo (shifted(coords[0], doShift), shifted(coords[1], doShift), |
418 |
coords[4], coords[5]); |
shifted(coords[2], doShift), shifted(coords[3], doShift), |
419 |
|
x, y); |
420 |
break; |
break; |
421 |
|
|
422 |
case PathIterator.SEG_CLOSE: |
case PathIterator.SEG_CLOSE: |
427 |
} |
} |
428 |
|
|
429 |
|
|
430 |
private Map getDefaultHints() |
private final Map getDefaultHints() |
431 |
{ |
{ |
432 |
HashMap defaultHints = new HashMap (); |
HashMap defaultHints = new HashMap (); |
433 |
|
|
450 |
|
|
451 |
} |
} |
452 |
|
|
453 |
private void updateBufferedImage() |
private final void updateBufferedImage() |
454 |
{ |
{ |
455 |
int[] pixels = getImagePixels(); |
int[] pixels = getImagePixels(); |
456 |
updateImagePixels(pixels); |
updateImagePixels(pixels); |
457 |
} |
} |
458 |
|
|
459 |
|
|
460 |
private boolean isBufferedImageGraphics () |
private final boolean isBufferedImageGraphics () |
461 |
{ |
{ |
462 |
|
return bimage != null; |
|
if (bimage != null) |
|
|
return true; |
|
|
else |
|
|
return false; |
|
463 |
} |
} |
464 |
|
|
465 |
private void updateImagePixels (int[] pixels) |
private final void updateImagePixels (int[] pixels) |
466 |
{ |
{ |
467 |
|
|
468 |
// This function can only be used if |
// This function can only be used if |
497 |
} |
} |
498 |
|
|
499 |
|
|
500 |
private boolean drawImage(Image img, |
private final boolean drawImage(Image img, |
501 |
AffineTransform xform, |
AffineTransform xform, |
502 |
Color bgcolor, |
Color bgcolor, |
503 |
ImageObserver obs) |
ImageObserver obs) |
504 |
{ |
{ |
505 |
if (img instanceof GtkOffScreenImage && |
if (img instanceof GtkOffScreenImage && |
506 |
img.getGraphics () instanceof GdkGraphics2D && |
img.getGraphics () instanceof GdkGraphics2D && |
533 |
|
|
534 |
try |
try |
535 |
{ |
{ |
536 |
invertedXform = xform.createInverse(); |
invertedXform = xform.createInverse(); |
537 |
if (img instanceof BufferedImage) |
if (img instanceof BufferedImage) |
538 |
{ |
{ |
539 |
// draw an image which has actually been loaded |
// draw an image which has actually been loaded |
540 |
// into memory fully |
// into memory fully |
541 |
|
|
542 |
BufferedImage b = (BufferedImage) img; |
BufferedImage b = (BufferedImage) img; |
543 |
return drawRaster (b.getColorModel (), |
return drawRaster (b.getColorModel (), |
544 |
b.getData (), |
b.getData (), |
545 |
invertedXform, |
invertedXform, |
546 |
bgcolor); |
bgcolor); |
547 |
} |
} |
548 |
else |
else |
549 |
{ |
{ |
550 |
// begin progressive loading in a separate thread |
return this.drawImage(GdkPixbufDecoder.createBufferedImage(img.getSource()), |
551 |
new PainterThread (this, img, invertedXform, bgcolor); |
xform, bgcolor,obs); |
|
return false; |
|
552 |
} |
} |
553 |
} |
} |
554 |
catch (NoninvertibleTransformException e) |
catch (NoninvertibleTransformException e) |
574 |
return; |
return; |
575 |
} |
} |
576 |
|
|
|
stateSave (); |
|
577 |
cairoNewPath (); |
cairoNewPath (); |
|
|
|
|
boolean normalize; |
|
|
normalize = hints.containsValue (RenderingHints.VALUE_STROKE_NORMALIZE) |
|
|
|| hints.containsValue (RenderingHints.VALUE_STROKE_DEFAULT); |
|
|
|
|
|
if (normalize) |
|
|
translate (0.5,0.5); |
|
578 |
|
|
579 |
if (s instanceof Rectangle2D) |
if (s instanceof Rectangle2D) |
580 |
{ |
{ |
581 |
Rectangle2D r = (Rectangle2D)s; |
Rectangle2D r = (Rectangle2D)s; |
582 |
cairoRectangle (r.getX (), r.getY (), r.getWidth (), r.getHeight ()); |
cairoRectangle (shifted(r.getX (), shiftDrawCalls), |
583 |
|
shifted(r.getY (), shiftDrawCalls), |
584 |
|
r.getWidth (), r.getHeight ()); |
585 |
} |
} |
586 |
else |
else |
587 |
walkPath (s.getPathIterator (null)); |
walkPath (s.getPathIterator (null), shiftDrawCalls); |
588 |
cairoStroke (); |
cairoStroke (); |
589 |
|
|
|
if (normalize) |
|
|
translate (-0.5,-0.5); |
|
|
|
|
|
stateRestore (); |
|
|
|
|
590 |
if (isBufferedImageGraphics ()) |
if (isBufferedImageGraphics ()) |
591 |
updateBufferedImage(); |
updateBufferedImage(); |
|
|
|
592 |
} |
} |
593 |
|
|
594 |
public void fill (Shape s) |
public void fill (Shape s) |
595 |
{ |
{ |
|
stateSave(); |
|
596 |
cairoNewPath (); |
cairoNewPath (); |
597 |
if (s instanceof Rectangle2D) |
if (s instanceof Rectangle2D) |
598 |
{ |
{ |
600 |
cairoRectangle (r.getX (), r.getY (), r.getWidth (), r.getHeight ()); |
cairoRectangle (r.getX (), r.getY (), r.getWidth (), r.getHeight ()); |
601 |
} |
} |
602 |
else |
else |
603 |
walkPath (s.getPathIterator (null)); |
walkPath (s.getPathIterator (null), false); |
604 |
cairoFill (); |
cairoFill (); |
|
stateRestore (); |
|
605 |
|
|
606 |
if (isBufferedImageGraphics ()) |
if (isBufferedImageGraphics ()) |
607 |
updateBufferedImage(); |
updateBufferedImage(); |
635 |
r.getWidth (), r.getHeight ()); |
r.getWidth (), r.getHeight ()); |
636 |
} |
} |
637 |
else |
else |
638 |
walkPath (clip.getPathIterator (null)); |
walkPath (clip.getPathIterator (null), false); |
639 |
cairoClosePath (); |
// cairoClosePath (); |
640 |
cairoClip (); |
cairoClip (); |
641 |
} |
} |
642 |
} |
} |
782 |
{ |
{ |
783 |
BasicStroke bs = (BasicStroke) stroke; |
BasicStroke bs = (BasicStroke) stroke; |
784 |
cairoSetLineCap (bs.getEndCap()); |
cairoSetLineCap (bs.getEndCap()); |
785 |
cairoSetLineWidth (bs.getLineWidth() / 2.0); |
cairoSetLineWidth (bs.getLineWidth()); |
786 |
cairoSetLineJoin (bs.getLineJoin()); |
cairoSetLineJoin (bs.getLineJoin()); |
787 |
cairoSetMiterLimit (bs.getMiterLimit()); |
cairoSetMiterLimit (bs.getMiterLimit()); |
788 |
float dashes[] = bs.getDashArray(); |
float dashes[] = bs.getDashArray(); |
848 |
return clip.getBounds (); |
return clip.getBounds (); |
849 |
} |
} |
850 |
|
|
851 |
protected Rectangle2D getClipInDevSpace () |
protected Rectangle2D getClipInDevSpace () |
852 |
{ |
{ |
853 |
Rectangle2D uclip = clip.getBounds2D (); |
Rectangle2D uclip = clip.getBounds2D (); |
854 |
if (transform == null) |
if (transform == null) |
855 |
return uclip; |
return uclip; |
856 |
else |
else |
857 |
{ |
{ |
858 |
Point2D pos = transform.transform (new Point2D.Double(uclip.getX (), |
Point2D pos = transform.transform (new Point2D.Double(uclip.getX (), |
859 |
uclip.getY ()), |
uclip.getY ()), |
860 |
(Point2D)null); |
(Point2D)null); |
861 |
Point2D extent = transform.deltaTransform (new Point2D.Double(uclip.getWidth (), |
Point2D extent = transform.deltaTransform (new Point2D.Double(uclip.getWidth (), |
862 |
uclip.getHeight ()), |
uclip.getHeight ()), |
863 |
(Point2D)null); |
(Point2D)null); |
864 |
return new Rectangle2D.Double (pos.getX (), pos.getY (), |
return new Rectangle2D.Double (pos.getX (), pos.getY (), |
865 |
extent.getX (), extent.getY ()); |
extent.getX (), extent.getY ()); |
866 |
} |
} |
867 |
} |
} |
868 |
|
|
869 |
public void setClip (int x, int y, int width, int height) |
public void setClip (int x, int y, int width, int height) |
870 |
{ |
{ |
885 |
r.getWidth (), r.getHeight ()); |
r.getWidth (), r.getHeight ()); |
886 |
} |
} |
887 |
else |
else |
888 |
walkPath (s.getPathIterator (null)); |
walkPath (s.getPathIterator (null), false); |
889 |
cairoClosePath (); |
// cairoClosePath (); |
890 |
cairoClip (); |
cairoClip (); |
891 |
} |
} |
892 |
} |
} |
893 |
|
|
894 |
|
private static BasicStroke draw3DRectStroke = new BasicStroke(); |
895 |
|
|
896 |
public void draw3DRect(int x, int y, int width, |
public void draw3DRect(int x, int y, int width, |
897 |
int height, boolean raised) |
int height, boolean raised) |
898 |
{ |
{ |
899 |
Color std = fg; |
Stroke tmp = stroke; |
900 |
Color light = std.brighter(); |
setStroke(draw3DRectStroke); |
901 |
Color dark = std.darker(); |
super.draw3DRect(x, y, width, height, raised); |
902 |
|
setStroke(tmp); |
|
if (!raised) |
|
|
{ |
|
|
Color t = light; |
|
|
light = dark; |
|
|
dark = t; |
|
|
} |
|
|
|
|
|
double x1 = (double) x; |
|
|
double x2 = (double) x + width; |
|
|
|
|
|
double y1 = (double) y; |
|
|
double y2 = (double) y + height; |
|
|
|
|
|
stateSave (); |
|
|
|
|
|
cairoNewPath (); |
|
|
|
|
|
boolean normalize; |
|
|
normalize = hints.containsValue (RenderingHints.VALUE_STROKE_NORMALIZE) |
|
|
|| hints.containsValue (RenderingHints.VALUE_STROKE_DEFAULT); |
|
|
|
|
|
if (normalize) |
|
|
{ |
|
|
x1 += 0.5; |
|
|
y1 += 0.5; |
|
|
x2 += 0.5; |
|
|
y2 += 0.5; |
|
|
} |
|
|
|
|
|
setColor (light); |
|
|
cairoMoveTo (x1, y1); |
|
|
cairoLineTo (x2, y1); |
|
|
cairoLineTo (x2, y2); |
|
|
cairoStroke (); |
|
|
|
|
|
cairoNewPath (); |
|
|
setColor (dark); |
|
|
cairoMoveTo (x1, y1); |
|
|
cairoLineTo (x1, y2); |
|
|
cairoLineTo (x2, y2); |
|
|
cairoStroke (); |
|
|
|
|
|
stateRestore (); |
|
|
|
|
903 |
if (isBufferedImageGraphics ()) |
if (isBufferedImageGraphics ()) |
904 |
updateBufferedImage(); |
updateBufferedImage(); |
|
|
|
905 |
} |
} |
906 |
|
|
907 |
public void fill3DRect(int x, int y, int width, |
public void fill3DRect(int x, int y, int width, |
908 |
int height, boolean raised) |
int height, boolean raised) |
909 |
{ |
{ |
910 |
double step = 1.0; |
Stroke tmp = stroke; |
911 |
if (stroke != null && stroke instanceof BasicStroke) |
setStroke(draw3DRectStroke); |
912 |
{ |
super.fill3DRect(x, y, width, height, raised); |
913 |
BasicStroke bs = (BasicStroke) stroke; |
setStroke(tmp); |
|
step = bs.getLineWidth(); |
|
|
} |
|
|
|
|
|
Color bright = fg.brighter (); |
|
|
Color dark = fg.darker (); |
|
|
|
|
|
draw3DRect (x, y, width, height, raised); |
|
|
|
|
|
stateSave (); |
|
|
translate (step/2.0, step/2.0); |
|
|
cairoNewPath (); |
|
|
cairoRectangle ((double) x, (double) y, |
|
|
((double) width) - step, |
|
|
((double) height) - step ); |
|
|
cairoClosePath (); |
|
|
cairoFill (); |
|
|
stateRestore (); |
|
|
|
|
914 |
if (isBufferedImageGraphics ()) |
if (isBufferedImageGraphics ()) |
915 |
updateBufferedImage(); |
updateBufferedImage(); |
|
|
|
916 |
} |
} |
917 |
|
|
918 |
|
|
923 |
|
|
924 |
public void fillRect (int x, int y, int width, int height) |
public void fillRect (int x, int y, int width, int height) |
925 |
{ |
{ |
926 |
fill(new Rectangle (x, y, width, height)); |
cairoNewPath (); |
927 |
|
cairoRectangle (x, y, width, height); |
928 |
|
cairoFill (); |
929 |
} |
} |
930 |
|
|
931 |
public void clearRect (int x, int y, int width, int height) |
public void clearRect (int x, int y, int width, int height) |
932 |
{ |
{ |
|
stateSave (); |
|
933 |
cairoSetRGBColor (bg.getRed() / 255.0, |
cairoSetRGBColor (bg.getRed() / 255.0, |
934 |
bg.getGreen() / 255.0, |
bg.getGreen() / 255.0, |
935 |
bg.getBlue() / 255.0); |
bg.getBlue() / 255.0); |
936 |
cairoSetAlpha (1.0); |
cairoSetAlpha (1.0); |
937 |
cairoNewPath (); |
cairoNewPath (); |
938 |
cairoRectangle (x, y, width, height); |
cairoRectangle (x, y, width, height); |
|
cairoClosePath (); |
|
939 |
cairoFill (); |
cairoFill (); |
940 |
stateRestore (); |
setColor (fg); |
941 |
|
|
942 |
if (isBufferedImageGraphics ()) |
if (isBufferedImageGraphics ()) |
943 |
updateBufferedImage(); |
updateBufferedImage(); |
954 |
return bg; |
return bg; |
955 |
} |
} |
956 |
|
|
957 |
private void doPolygon(int[] xPoints, int[] yPoints, int nPoints, |
private final void doPolygon(int[] xPoints, int[] yPoints, int nPoints, |
958 |
boolean close, boolean fill) |
boolean close, boolean fill) |
959 |
{ |
{ |
960 |
if (nPoints < 1) |
if (nPoints < 1) |
961 |
return; |
return; |
1010 |
doPolygon (xPoints, yPoints, nPoints, false, false); |
doPolygon (xPoints, yPoints, nPoints, false, false); |
1011 |
} |
} |
1012 |
|
|
1013 |
private boolean drawRaster (ColorModel cm, Raster r, |
private final boolean drawRaster (ColorModel cm, Raster r, |
1014 |
AffineTransform imageToUser, |
AffineTransform imageToUser, |
1015 |
Color bgcolor) |
Color bgcolor) |
1016 |
{ |
{ |
1017 |
if (r == null) |
if (r == null) |
1018 |
return false; |
return false; |
1071 |
} |
} |
1072 |
} |
} |
1073 |
|
|
|
stateSave (); |
|
|
translate (x, y); |
|
1074 |
drawPixels (pixels, r.getWidth (), r.getHeight (), r.getWidth (), i2u); |
drawPixels (pixels, r.getWidth (), r.getHeight (), r.getWidth (), i2u); |
|
stateRestore (); |
|
1075 |
|
|
1076 |
if (isBufferedImageGraphics ()) |
if (isBufferedImageGraphics ()) |
1077 |
updateBufferedImage(); |
updateBufferedImage(); |
1114 |
} |
} |
1115 |
|
|
1116 |
|
|
|
//////////////////////////////////////// |
|
|
////// Supporting Private Classes ////// |
|
|
//////////////////////////////////////// |
|
|
|
|
|
private class PainterThread implements Runnable, ImageConsumer |
|
|
{ |
|
|
|
|
|
// this is a helper which is spun off when someone tries to do |
|
|
// Graphics2D.drawImage on an image we cannot determine to be either |
|
|
// one of our own offscreen images or a BufferedImage; that is, when |
|
|
// someone wants to draw an image which is possibly still loading over |
|
|
// a network or something. you run it in a separate thread and it |
|
|
// writes through to the underlying Graphics2D as pixels becomg |
|
|
// available. |
|
|
|
|
|
GdkGraphics2D gr; |
|
|
Image image; |
|
|
ColorModel defaultModel; |
|
|
AffineTransform xform; |
|
|
Color bgcolor; |
|
|
|
|
|
public PainterThread (GdkGraphics2D g, Image im, |
|
|
AffineTransform xf, Color bg) |
|
|
{ |
|
|
image = im; |
|
|
xform = xf; |
|
|
bgcolor = bg; |
|
|
this.gr = (GdkGraphics2D) g.create (); |
|
|
new Thread (this).start (); |
|
|
} |
|
|
|
|
|
public void imageComplete (int status) |
|
|
{ |
|
|
} |
|
|
|
|
|
public void setColorModel (ColorModel model) |
|
|
{ |
|
|
defaultModel = model; |
|
|
} |
|
|
|
|
|
public void setDimensions (int width, int height) |
|
|
{ |
|
|
} |
|
|
|
|
|
public void setHints (int hintflags) |
|
|
{ |
|
|
} |
|
|
|
|
|
public void setPixels (int x, int y, int w, int h, ColorModel model, |
|
|
byte[] pixels, int off, int scansize) |
|
|
{ |
|
|
} |
|
|
|
|
|
public void setPixels (int x, int y, int w, int h, ColorModel model, |
|
|
int[] pixels, int off, int scansize) |
|
|
{ |
|
|
gr.stateSave (); |
|
|
gr.translate (x, y); |
|
|
|
|
|
if (model == null) |
|
|
model = defaultModel; |
|
|
|
|
|
int pixels2[]; |
|
|
if (model != null) |
|
|
{ |
|
|
pixels2 = new int[pixels.length]; |
|
|
for (int yy = 0; yy < h; yy++) |
|
|
for (int xx = 0; xx < w; xx++) |
|
|
{ |
|
|
int i = yy * scansize + xx; |
|
|
pixels2[i] = model.getRGB (pixels[i]); |
|
|
} |
|
|
} |
|
|
else |
|
|
pixels2 = pixels; |
|
|
|
|
|
// change all transparent pixels in the image to the |
|
|
// specified bgcolor |
|
|
|
|
|
if (bgcolor != null) |
|
|
{ |
|
|
for (int i = 0; i < pixels2.length; i++) |
|
|
{ |
|
|
if (model.getAlpha (pixels2[i]) == 0) |
|
|
pixels2[i] = bgcolor.getRGB (); |
|
|
} |
|
|
} |
|
|
|
|
|
double[] xf = new double[6]; |
|
|
xform.getMatrix(xf); |
|
|
gr.drawPixels (pixels2, w, h, scansize, xf); |
|
|
gr.stateRestore (); |
|
|
} |
|
|
|
|
|
public void setProperties (java.util.Hashtable props) |
|
|
{ |
|
|
} |
|
|
|
|
|
public void run () |
|
|
{ |
|
|
image.getSource ().startProduction (this); |
|
|
gr.dispose (); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
1117 |
/////////////////////////////////////////////// |
/////////////////////////////////////////////// |
1118 |
////// Unimplemented Stubs and Overloads ////// |
////// Unimplemented Stubs and Overloads ////// |
1119 |
/////////////////////////////////////////////// |
/////////////////////////////////////////////// |
1173 |
else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) |
else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) |
1174 |
cairoSurfaceSetFilter(4); |
cairoSurfaceSetFilter(4); |
1175 |
|
|
1176 |
} |
} |
1177 |
|
|
1178 |
|
shiftDrawCalls = hints.containsValue (RenderingHints.VALUE_STROKE_NORMALIZE) |
1179 |
|
|| hints.containsValue (RenderingHints.VALUE_STROKE_DEFAULT); |
1180 |
|
|
1181 |
} |
} |
1182 |
|
|
1183 |
public Object getRenderingHint(RenderingHints.Key hintKey) |
public Object getRenderingHint(RenderingHints.Key hintKey) |
1210 |
else if(hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) |
else if(hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) |
1211 |
cairoSurfaceSetFilter(4); |
cairoSurfaceSetFilter(4); |
1212 |
} |
} |
1213 |
|
|
1214 |
|
shiftDrawCalls = hints.containsValue (RenderingHints.VALUE_STROKE_NORMALIZE) |
1215 |
|
|| hints.containsValue (RenderingHints.VALUE_STROKE_DEFAULT); |
1216 |
} |
} |
1217 |
|
|
1218 |
public void addRenderingHints(Map hints) |
public void addRenderingHints(Map hints) |
1238 |
return new FontRenderContext (transform, true, true); |
return new FontRenderContext (transform, true, true); |
1239 |
} |
} |
1240 |
|
|
|
public void drawGlyphVector (GlyphVector g, float x, float y) |
|
|
{ |
|
|
stateSave (); |
|
|
setFont (g.getFont ()); |
|
|
translate ((double)x, (double)y); |
|
|
cairoMoveTo (0, 0); |
|
|
int nglyphs = g.getNumGlyphs (); |
|
|
int codes[] = g.getGlyphCodes (0, nglyphs, (int []) null); |
|
|
float posns[] = g.getGlyphPositions (0, nglyphs, (float []) null); |
|
|
cairoShowGlyphs (codes, posns); |
|
|
|
|
|
if (isBufferedImageGraphics ()) |
|
|
updateBufferedImage(); |
|
|
|
|
|
stateRestore (); |
|
|
} |
|
|
|
|
1241 |
public void copyArea (int x, int y, int width, int height, int dx, int dy) |
public void copyArea (int x, int y, int width, int height, int dx, int dy) |
1242 |
{ |
{ |
1243 |
throw new java.lang.UnsupportedOperationException (); |
throw new java.lang.UnsupportedOperationException (); |
1369 |
drawLine (x1, y + height, x2, y + height); |
drawLine (x1, y + height, x2, y + height); |
1370 |
} |
} |
1371 |
|
|
1372 |
public void drawString (String str, int x, int y) |
// these are the most accelerated painting paths |
1373 |
|
native void cairoDrawGdkGlyphVector (GdkFontPeer f, GdkGlyphVector gv, float x, float y); |
1374 |
|
native void cairoDrawGdkTextLayout (GdkFontPeer f, GdkTextLayout gl, float x, float y); |
1375 |
|
native void cairoDrawString (GdkFontPeer f, String str, float x, float y); |
1376 |
|
|
1377 |
|
GdkFontPeer getFontPeer() |
1378 |
{ |
{ |
1379 |
drawString (str, (float)x, (float)y); |
return (GdkFontPeer) getFont().getPeer(); |
1380 |
|
} |
1381 |
|
|
1382 |
|
public void drawGdkGlyphVector(GdkGlyphVector gv, float x, float y) |
1383 |
|
{ |
1384 |
|
cairoDrawGdkGlyphVector(getFontPeer(), gv, x, y); |
1385 |
|
if (isBufferedImageGraphics ()) |
1386 |
|
updateBufferedImage(); |
1387 |
|
} |
1388 |
|
|
1389 |
|
public void drawGdkTextLayout(GdkTextLayout gl, float x, float y) |
1390 |
|
{ |
1391 |
|
cairoDrawGdkTextLayout(getFontPeer(), gl, x, y); |
1392 |
|
if (isBufferedImageGraphics ()) |
1393 |
|
updateBufferedImage(); |
1394 |
} |
} |
1395 |
|
|
1396 |
public void drawString (String str, float x, float y) |
public void drawString (String str, float x, float y) |
1397 |
{ |
{ |
1398 |
GlyphVector gv = font.createGlyphVector (getFontRenderContext(), str); |
cairoDrawString(getFontPeer(), str, x, y); |
1399 |
drawGlyphVector (gv, x, y); |
if (isBufferedImageGraphics ()) |
1400 |
|
updateBufferedImage(); |
1401 |
|
} |
1402 |
|
|
1403 |
|
public void drawString (String str, int x, int y) |
1404 |
|
{ |
1405 |
|
drawString (str, (float)x, (float)y); |
1406 |
} |
} |
1407 |
|
|
1408 |
public void drawString (AttributedCharacterIterator ci, int x, int y) |
public void drawString (AttributedCharacterIterator ci, int x, int y) |
1410 |
drawString (ci, (float)x, (float)y); |
drawString (ci, (float)x, (float)y); |
1411 |
} |
} |
1412 |
|
|
1413 |
|
public void drawGlyphVector (GlyphVector gv, float x, float y) |
1414 |
|
{ |
1415 |
|
if (gv instanceof GdkGlyphVector) |
1416 |
|
drawGdkGlyphVector((GdkGlyphVector)gv, x, y); |
1417 |
|
else |
1418 |
|
throw new java.lang.UnsupportedOperationException (); |
1419 |
|
} |
1420 |
|
|
1421 |
public void drawString (AttributedCharacterIterator ci, float x, float y) |
public void drawString (AttributedCharacterIterator ci, float x, float y) |
1422 |
{ |
{ |
1423 |
GlyphVector gv = font.createGlyphVector (getFontRenderContext(), ci); |
GlyphVector gv = font.createGlyphVector (getFontRenderContext(), ci); |
1463 |
return font; |
return font; |
1464 |
} |
} |
1465 |
|
|
1466 |
|
// Until such time as pango is happy to talk directly to cairo, we |
1467 |
|
// actually need to redirect some calls from the GtkFontPeer and |
1468 |
|
// GtkFontMetrics into the drawing kit and ask cairo ourselves. |
1469 |
|
|
1470 |
|
static native void releasePeerGraphicsResource(GdkFontPeer f); |
1471 |
|
static native void getPeerTextMetrics (GdkFontPeer f, String str, double [] metrics); |
1472 |
|
static native void getPeerFontMetrics (GdkFontPeer f, double [] metrics); |
1473 |
|
|
1474 |
public FontMetrics getFontMetrics () |
public FontMetrics getFontMetrics () |
1475 |
{ |
{ |
1476 |
|
// the reason we go via the toolkit here is to try to get |
1477 |
|
// a cached object. the toolkit keeps such a cache. |
1478 |
return Toolkit.getDefaultToolkit ().getFontMetrics (font); |
return Toolkit.getDefaultToolkit ().getFontMetrics (font); |
1479 |
} |
} |
1480 |
|
|
1481 |
public FontMetrics getFontMetrics (Font f) |
public FontMetrics getFontMetrics (Font f) |
1482 |
{ |
{ |
1483 |
|
// the reason we go via the toolkit here is to try to get |
1484 |
|
// a cached object. the toolkit keeps such a cache. |
1485 |
return Toolkit.getDefaultToolkit ().getFontMetrics (f); |
return Toolkit.getDefaultToolkit ().getFontMetrics (f); |
1486 |
} |
} |
1487 |
|
|
1488 |
public void setFont (Font f) |
public void setFont (Font f) |
1489 |
{ |
{ |
1490 |
if (f.getPeer() instanceof GdkClasspathFontPeer) |
if (f.getPeer() instanceof GdkFontPeer) |
1491 |
font = f; |
font = f; |
1492 |
else |
else |
1493 |
font = |
font = |
1494 |
((ClasspathToolkit)(Toolkit.getDefaultToolkit ())) |
((ClasspathToolkit)(Toolkit.getDefaultToolkit ())) |
1495 |
.getFont (f.getName(), f.getAttributes ()); |
.getFont (f.getName(), f.getAttributes ()); |
|
|
|
|
if (f != null && |
|
|
f.getPeer() instanceof GdkClasspathFontPeer) |
|
|
cairoSetFont ((GdkClasspathFontPeer) f.getPeer()); |
|
1496 |
} |
} |
1497 |
|
|
1498 |
public String toString() |
public String toString() |
1499 |
{ |
{ |
1500 |
return getClass ().getName () + |
return getClass ().getName () + |