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