001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Alexey A. Petrenko
019: * @version $Revision$
020: */package org.apache.harmony.awt.gl.windows;
021:
022: import java.awt.AlphaComposite;
023: import java.awt.BasicStroke;
024: import java.awt.Color;
025: import java.awt.Dimension;
026: import java.awt.GradientPaint;
027: import java.awt.Graphics;
028: import java.awt.GraphicsConfiguration;
029: import java.awt.Paint;
030: import java.awt.Rectangle;
031: import java.awt.RenderingHints;
032: import java.awt.Shape;
033: import java.awt.Stroke;
034: import java.awt.font.GlyphVector;
035: import java.awt.geom.AffineTransform;
036: import java.awt.geom.PathIterator;
037: import java.awt.geom.Point2D;
038: import java.util.Map;
039:
040: import org.apache.harmony.awt.gl.CommonGraphics2D;
041: import org.apache.harmony.awt.gl.MultiRectArea;
042: import org.apache.harmony.awt.gl.XORComposite;
043: import org.apache.harmony.awt.gl.font.FontManager;
044: import org.apache.harmony.awt.gl.font.NativeFont;
045: import org.apache.harmony.awt.gl.font.fontlib.FLTextRenderer;
046: import org.apache.harmony.awt.wtk.NativeWindow;
047:
048: /**
049: * Graphics2D implementation for Windows GDI+ library
050: *
051: */
052: public class WinGDIPGraphics2D extends CommonGraphics2D {
053: private NativeWindow nw = null;
054: private long hdc = 0;
055: private long gi = 0;
056: private char pageUnit = 1;
057:
058: private final Dimension size;
059:
060: GraphicsConfiguration config = null;
061:
062: private WinVolatileImage img = null;
063:
064: // These two flags shows are current Stroke and
065: // Paint transferred to native objects or not.
066: private boolean nativePen = false;
067: private boolean nativeBrush = false;
068:
069: // This array is used for passing Path data to
070: // native code.
071: // It is not thread safe.
072: // But WTK guys think that Graphics should not
073: // be called from different threads
074: private float[] pathArray = null;
075: private float[] pathPoints = null;
076:
077: private static final long gdipToken;
078:
079: static {
080: System.loadLibrary("gl"); //$NON-NLS-1$
081:
082: // GDI+ startup
083: gdipToken = gdiPlusStartup();
084:
085: // Prepare GDI+ shutdown
086: GDIPShutdown hook = new GDIPShutdown();
087: Runtime.getRuntime().addShutdownHook(hook);
088: }
089:
090: public WinGDIPGraphics2D(NativeWindow nw, int tx, int ty,
091: MultiRectArea clip) {
092: super (tx, ty, clip);
093: this .nw = nw;
094:
095: Rectangle b = clip.getBounds();
096: size = new Dimension(b.width, b.height);
097:
098: gi = createGraphicsInfo(this .nw.getId(), tx, ty, b.width,
099: b.height);
100: if (!FontManager.IS_FONTLIB) {
101: jtr = GDIPTextRenderer.inst;
102: }
103: dstSurf = new GDISurface(gi);
104: blitter = GDIBlitter.getInstance();
105: setTransform(getTransform());
106: }
107:
108: public WinGDIPGraphics2D(NativeWindow nw, int tx, int ty,
109: int width, int height) {
110: super (tx, ty);
111: this .nw = nw;
112:
113: size = new Dimension(width, height);
114:
115: gi = createGraphicsInfo(this .nw.getId(), tx, ty, width, height);
116: if (!FontManager.IS_FONTLIB) {
117: jtr = GDIPTextRenderer.inst;
118: }
119: dstSurf = new GDISurface(gi);
120: blitter = GDIBlitter.getInstance();
121: if (debugOutput) {
122: System.err
123: .println("WinGDIPGraphics2D(" + nw + ", " + tx + ", " + ty + ", " + width + ", " + height + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
124: }
125: setTransform(getTransform());
126:
127: }
128:
129: public WinGDIPGraphics2D(WinVolatileImage img, int width, int height) {
130: this (img, 0, width, height);
131: }
132:
133: public WinGDIPGraphics2D(WinVolatileImage img, long ogi, int width,
134: int height) {
135: super ();
136: size = new Dimension(width, height);
137: this .img = img;
138: if (ogi != 0) {
139: this .gi = copyImageInfo(ogi);
140: } else {
141: this .gi = copyImageInfo(img.gi);
142: }
143: dstSurf = img.getImageSurface();
144: blitter = GDIBlitter.getInstance();
145: if (!FontManager.IS_FONTLIB) {
146: jtr = GDIPTextRenderer.inst;
147: }
148: setTransform(getTransform());
149: }
150:
151: /**
152: * Create G2D associated with the specified device context.
153: *
154: * @param hdc pointer to DC handle
155: * @param pageUnit one of Gdiplus::Unit specifying how to convert Graphics
156: * coordinates to DC coordinates
157: * @param width Graphics width
158: * @param height Graphics height
159: */
160: public WinGDIPGraphics2D(final long hdc, final char pageUnit,
161: final int width, final int height) {
162: this .hdc = hdc;
163: this .pageUnit = pageUnit;
164: size = new Dimension(width, height);
165: gi = createGraphicsInfoFor(hdc, pageUnit);
166:
167: if (!FontManager.IS_FONTLIB) {
168: jtr = GDIPTextRenderer.inst;
169: }
170:
171: dstSurf = new GDISurface(gi);
172: blitter = GDIBlitter.getInstance();
173: }
174:
175: @Override
176: public void addRenderingHints(Map<?, ?> hints) {
177: super .addRenderingHints(hints);
178: if (!FontManager.IS_FONTLIB) {
179: Object value = this
180: .getRenderingHint(RenderingHints.KEY_ANTIALIASING);
181: if (value == RenderingHints.VALUE_ANTIALIAS_ON) {
182: NativeFont.setAntialiasing(gi, true);
183: } else {
184: NativeFont.setAntialiasing(gi, false);
185: }
186: }
187: }
188:
189: @Override
190: public void copyArea(int x, int y, int width, int height, int dx,
191: int dy) {
192: copyArea(gi, x, y, width, height, dx, dy);
193: }
194:
195: @Override
196: public Graphics create() {
197: if (debugOutput) {
198: System.err.println("WinGDIPGraphics2D.create()"); //$NON-NLS-1$
199: }
200:
201: final WinGDIPGraphics2D res;
202:
203: if (img != null) {
204: res = new WinGDIPGraphics2D(img, gi, size.width,
205: size.height);
206: } else if (nw != null) {
207: res = new WinGDIPGraphics2D(nw, origPoint.x, origPoint.y,
208: size.width, size.height);
209: } else {
210: res = new WinGDIPGraphics2D(getDC(), pageUnit, size.width,
211: size.height);
212: }
213:
214: copyInternalFields(res);
215: return res;
216: }
217:
218: @Override
219: public GraphicsConfiguration getDeviceConfiguration() {
220: if (config == null) {
221: if (nw != null) {
222: config = new WinGraphicsConfiguration(nw.getId(),
223: getDC());
224: } else if (img != null) {
225: final long hwnd = img.getHWND();
226:
227: if (hwnd != 0) {
228: config = new WinGraphicsConfiguration(hwnd, getDC());
229: } else {
230: config = img.getGraphicsConfiguration();
231: }
232: }
233: }
234:
235: return config;
236: }
237:
238: @Override
239: protected void fillMultiRectAreaPaint(MultiRectArea mra) {
240: if (nativeBrush && composite == AlphaComposite.SrcOver) {
241: fillRects(gi, mra.rect, mra.rect[0] - 1);
242: } else {
243: super .fillMultiRectAreaPaint(mra);
244: }
245: }
246:
247: /***************************************************************************
248: *
249: * Overriden methods
250: *
251: ***************************************************************************/
252:
253: @Override
254: public void setColor(Color color) {
255: if (color == null) {
256: return;
257: }
258: super .setColor(color);
259: setSolidBrush(gi, color.getRed(), color.getGreen(), color
260: .getBlue(), color.getAlpha());
261: nativeBrush = true;
262: setStroke(getStroke());
263: }
264:
265: //REMARK: It seems that transform affects paints too
266: //REMARK: Think how to implement this
267: @Override
268: public void setPaint(Paint paint) {
269: if (paint == null)
270: return;
271:
272: if (paint instanceof Color) {
273: setColor((Color) paint);
274: } else {
275: this .paint = paint;
276: nativeBrush = false;
277: if (paint instanceof GradientPaint) {
278: GradientPaint p = (GradientPaint) paint;
279: if (!p.isCyclic()) {
280: return;
281: }
282: Color c1 = p.getColor1();
283: Color c2 = p.getColor2();
284: Point2D p1 = transform.transform(p.getPoint1(), null);
285: Point2D p2 = transform.transform(p.getPoint2(), null);
286: setLinearGradientBrush(gi, (int) Math.round(p1.getX()),
287: (int) Math.round(p1.getY()), c1.getRed(), c1
288: .getGreen(), c1.getBlue(), c1
289: .getAlpha(), (int) Math
290: .round(p2.getX()), (int) Math.round(p2
291: .getY()), c2.getRed(), c2.getGreen(),
292: c2.getBlue(), c2.getAlpha(), p.isCyclic());
293: nativeBrush = true;
294: }
295: setStroke(getStroke());
296: }
297: }
298:
299: @Override
300: public void dispose() {
301: if (gi == 0) {
302: return;
303: }
304: if (dstSurf instanceof GDISurface) {
305: dstSurf.dispose();
306: }
307: disposeGraphicsInfo(gi);
308: gi = 0;
309: super .dispose();
310: if (debugOutput) {
311: System.err.println("WinGDIPGraphics2D.dispose()"); //$NON-NLS-1$
312: }
313: }
314:
315: @Override
316: public void drawGlyphVector(GlyphVector gv, float x, float y) {
317: jtr.drawGlyphVector(this , gv, x, y);
318: }
319:
320: @Override
321: public void drawString(String str, float x, float y) {
322: jtr.drawString(this , str, x, y);
323: }
324:
325: @Override
326: public void setStroke(Stroke stroke) {
327: super .setStroke(stroke);
328: nativePen = nativeBrush && stroke instanceof BasicStroke;
329: if (!nativePen) {
330: deletePen(gi);
331: return;
332: }
333:
334: BasicStroke bs = (BasicStroke) stroke;
335: float[] dash = bs.getDashArray();
336: if (dash != null && dash.length % 2 == 1) {
337: // If dash len is odd then we need to double the array
338: float[] newDash = new float[dash.length * 2];
339: System.arraycopy(dash, 0, newDash, 0, dash.length);
340: System
341: .arraycopy(dash, 0, newDash, dash.length,
342: dash.length);
343: dash = newDash;
344: }
345: setPen(gi, bs.getLineWidth(), bs.getEndCap(), bs.getLineJoin(),
346: bs.getMiterLimit(), dash, (dash != null) ? dash.length
347: : 0, bs.getDashPhase());
348: }
349:
350: @Override
351: public void draw(Shape s) {
352: if (!nativePen || composite != AlphaComposite.SrcOver) {
353: super .draw(s);
354: return;
355: }
356:
357: PathIterator pi = s.getPathIterator(transform, 0.5);
358: int len = getPathArray(pi);
359: drawShape(gi, pathArray, len, pi.getWindingRule());
360: }
361:
362: @Override
363: public void drawLine(int x1, int y1, int x2, int y2) {
364: if (!nativePen || composite != AlphaComposite.SrcOver) {
365: super .drawLine(x1, y1, x2, y2);
366: return;
367: }
368:
369: drawLine(gi, x1, y1, x2, y2);
370: }
371:
372: @Override
373: public void drawRect(int x, int y, int width, int height) {
374: if (!nativePen || composite != AlphaComposite.SrcOver) {
375: super .drawRect(x, y, width, height);
376: return;
377: }
378:
379: drawRect(gi, x, y, width, height);
380: }
381:
382: @Override
383: public void drawOval(int x, int y, int width, int height) {
384: if (!nativePen || composite != AlphaComposite.SrcOver) {
385: super .drawOval(x, y, width, height);
386: return;
387: }
388:
389: drawOval(gi, x, y, width, height);
390: }
391:
392: @Override
393: public void fill(Shape s) {
394: if (!nativeBrush || composite != AlphaComposite.SrcOver) {
395: super .fill(s);
396: return;
397: }
398:
399: PathIterator pi = s.getPathIterator(transform, 0.5);
400: int len = getPathArray(pi);
401: fillShape(gi, pathArray, len, pi.getWindingRule());
402: }
403:
404: @Override
405: public void fillRect(int x, int y, int width, int height) {
406: if (!nativeBrush || composite != AlphaComposite.SrcOver) {
407: super .fillRect(x, y, width, height);
408: return;
409: }
410:
411: fillRect(gi, x, y, width, height);
412: }
413:
414: /**
415: * Sets native clip to specified area
416: *
417: * @param clip Transformed clip to set
418: */
419: @Override
420: protected void setTransformedClip(MultiRectArea clip) {
421: super .setTransformedClip(clip);
422: if (gi == 0) {
423: return;
424: }
425: if (clip == null) {
426: resetClip(gi);
427: } else {
428: setClip(gi, clip.rect, clip.rect[0] - 1);
429: }
430: }
431:
432: /***************************************************************************
433: *
434: * Transformation methods
435: *
436: ***************************************************************************/
437:
438: @Override
439: public void setTransform(AffineTransform transform) {
440: super .setTransform(transform);
441: if (gi == 0) {
442: return;
443: }
444:
445: setNativeTransform(gi, matrix);
446: }
447:
448: @Override
449: public void rotate(double theta) {
450: super .rotate(theta);
451:
452: setNativeTransform(gi, matrix);
453: }
454:
455: @Override
456: public void rotate(double theta, double x, double y) {
457: super .rotate(theta, x, y);
458:
459: setNativeTransform(gi, matrix);
460: }
461:
462: @Override
463: public void scale(double sx, double sy) {
464: super .scale(sx, sy);
465:
466: setNativeTransform(gi, matrix);
467: }
468:
469: @Override
470: public void shear(double shx, double shy) {
471: super .shear(shx, shy);
472:
473: setNativeTransform(gi, matrix);
474: }
475:
476: @Override
477: public void transform(AffineTransform at) {
478: super .transform(at);
479:
480: setNativeTransform(gi, matrix);
481: }
482:
483: @Override
484: public void translate(double tx, double ty) {
485: super .translate(tx, ty);
486:
487: setNativeTransform(gi, matrix);
488: }
489:
490: @Override
491: public void translate(int tx, int ty) {
492: super .translate(tx, ty);
493:
494: setNativeTransform(gi, matrix);
495: }
496:
497: /***************************************************************************
498: *
499: * Class specific methods
500: *
501: ***************************************************************************/
502:
503: /**
504: * Returns handle to underlying device context
505: */
506: public long getDC() {
507: if (hdc == 0) {
508: hdc = getDC(gi);
509: }
510: return hdc;
511: }
512:
513: /**
514: * Returns pointer to underlying native GraphicsInfo structure
515: *
516: * @return Pointer to GraphicsInfo structure
517: */
518: public long getGraphicsInfo() {
519: return gi;
520: }
521:
522: /***************************************************************************
523: *
524: * Private methods
525: *
526: ***************************************************************************/
527: /**
528: * Converts PathIterator into array of int values. This array is
529: * stored in pathArray field.
530: * Array then used to pass Shape to native drawing routines
531: *
532: * @param pi PathIterator recieved from Shape
533: * @return Number of result array elements.
534: */
535: private int getPathArray(PathIterator pi) {
536: if (pathArray == null) {
537: pathArray = new float[8192];
538: pathPoints = new float[6];
539: }
540:
541: int i = 0;
542:
543: while (!pi.isDone()) {
544: int seg = pi.currentSegment(pathPoints);
545: pathArray[i++] = seg;
546: switch (seg) {
547: case PathIterator.SEG_MOVETO:
548: case PathIterator.SEG_LINETO:
549: pathArray[i++] = pathPoints[0];
550: pathArray[i++] = pathPoints[1];
551: break;
552: case PathIterator.SEG_CLOSE:
553: break;
554: }
555: pi.next();
556: }
557: return i;
558: }
559:
560: /***************************************************************************
561: *
562: * Native methods
563: *
564: ***************************************************************************/
565:
566: // GDI+ system startup/shutdown methods
567: private native static long gdiPlusStartup();
568:
569: private native static void gdiPlusShutdown(long token);
570:
571: // Creates native GraphicsInfo structure
572: private native long createGraphicsInfo(long hwnd, int x, int y,
573: int width, int height);
574:
575: private native long createGraphicsInfoFor(long hdc, char pageUnit);
576:
577: static native long createCompatibleImageInfo(long hwnd, int width,
578: int height);
579:
580: static native long createCompatibleImageInfo(byte[] bytes,
581: int width, int height);
582:
583: private native long copyImageInfo(long gi);
584:
585: // Releases GraphicsInfo structure
586: static native void disposeGraphicsInfo(long gi);
587:
588: private native void copyArea(long gi, int x, int y, int width,
589: int height, int dx, int dy);
590:
591: // Methods to set solid and gradient brushes
592: private native void setSolidBrush(long gi, int r, int g, int b,
593: int a);
594:
595: private native void setLinearGradientBrush(long gi, int x1, int y1,
596: int r1, int g1, int b1, int a1, int x2, int y2, int r2,
597: int g2, int b2, int a2, boolean cyclic);
598:
599: // Fills specified rectangles by native brush
600: private native void fillRects(long gi, int[] vertices, int len);
601:
602: private native long getDC(long gi);
603:
604: //Pen manipulation routins
605: private native boolean setPen(long gi, float lineWidth, int endCap,
606: int lineJoin, float miterLimit, float[] dashArray,
607: int dashLen, float dashPhase);
608:
609: private native void deletePen(long gi);
610:
611: // Draw/Fill Shape/GraphicsPath
612: private native void drawShape(long gi, float[] path, int len,
613: int winding);
614:
615: private native void fillShape(long gi, float[] path, int len,
616: int winding);
617:
618: // Draw native primitives
619: private native void drawLine(long gi, int x1, int y1, int x2, int y2);
620:
621: private native void drawRect(long gi, int x, int y, int width,
622: int height);
623:
624: private native void drawOval(long gi, int x, int y, int width,
625: int height);
626:
627: // Fill native primitives
628: private native void fillRect(long gi, int x, int y, int width,
629: int height);
630:
631: @Override
632: public void setRenderingHint(RenderingHints.Key key, Object value) {
633: super .setRenderingHint(key, value);
634: if (!FontManager.IS_FONTLIB) {
635: Object val = this
636: .getRenderingHint(RenderingHints.KEY_ANTIALIASING);
637: if (val == RenderingHints.VALUE_ANTIALIAS_ON) {
638: NativeFont.setAntialiasing(gi, true);
639: } else {
640: NativeFont.setAntialiasing(gi, false);
641: }
642: }
643: }
644:
645: @Override
646: public void setRenderingHints(Map<?, ?> hints) {
647: super .setRenderingHints(hints);
648: if (!FontManager.IS_FONTLIB) {
649: Object value = this
650: .getRenderingHint(RenderingHints.KEY_ANTIALIASING);
651: if (value == RenderingHints.VALUE_ANTIALIAS_ON) {
652: NativeFont.setAntialiasing(gi, true);
653: } else {
654: NativeFont.setAntialiasing(gi, false);
655: }
656: }
657: }
658:
659: // Set native clip
660: private native void setClip(long gi, int[] vertices, int len);
661:
662: private native void resetClip(long gi);
663:
664: // Update native affine transform matrix
665: private native void setNativeTransform(long gi, double[] matrix);
666:
667: /***************************************************************************
668: *
669: * Shutdown class
670: *
671: ***************************************************************************/
672: /**
673: * We need to shutdown GDI+ before exit.
674: */
675: private static class GDIPShutdown extends Thread {
676: @Override
677: public void run() {
678: WinGDIPGraphics2D
679: .gdiPlusShutdown(WinGDIPGraphics2D.gdipToken);
680: }
681: }
682: }
|