View Javadoc
1   package org.opentrafficsim.web.animation;
2   
3   import java.awt.AlphaComposite;
4   import java.awt.BasicStroke;
5   import java.awt.Canvas;
6   import java.awt.Color;
7   import java.awt.Composite;
8   import java.awt.Font;
9   import java.awt.FontMetrics;
10  import java.awt.Graphics;
11  import java.awt.Graphics2D;
12  import java.awt.GraphicsConfiguration;
13  import java.awt.Image;
14  import java.awt.Paint;
15  import java.awt.Rectangle;
16  import java.awt.RenderingHints;
17  import java.awt.RenderingHints.Key;
18  import java.awt.Shape;
19  import java.awt.Stroke;
20  import java.awt.font.FontRenderContext;
21  import java.awt.font.GlyphVector;
22  import java.awt.geom.AffineTransform;
23  import java.awt.geom.Ellipse2D;
24  import java.awt.geom.Line2D;
25  import java.awt.geom.Path2D;
26  import java.awt.geom.PathIterator;
27  import java.awt.geom.Rectangle2D;
28  import java.awt.image.BufferedImage;
29  import java.awt.image.BufferedImageOp;
30  import java.awt.image.ImageObserver;
31  import java.awt.image.RenderedImage;
32  import java.awt.image.renderable.RenderableImage;
33  import java.text.AttributedCharacterIterator;
34  import java.util.LinkedHashMap;
35  import java.util.Map;
36  
37  import org.opentrafficsim.base.OtsRuntimeException;
38  import org.opentrafficsim.base.logger.Logger;
39  
40  /**
41   * HTMLGraphics.java.
42   * <p>
43   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
44   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
45   * </p>
46   * @author <a href="https://github.com/averbraeck" target="_blank">Alexander Verbraeck</a>
47   */
48  public class HtmlGraphics2d extends Graphics2D
49  {
50      /** the current color of the background for drawing. */
51      private Color background = Color.WHITE;
52  
53      /** the current drawing color. */
54      private Color color = Color.BLACK;
55  
56      /** the current font. */
57      private Font font = new Font(Font.SANS_SERIF, Font.PLAIN, 10);
58  
59      /** the drawing canvas. */
60      private Canvas canvas = new Canvas();
61  
62      /** the cached current font properties. */
63      private FontMetrics fontMetrics = this.canvas.getFontMetrics(this.font);
64  
65      /** the current paint. */
66      private Paint paint = Color.BLACK;
67  
68      /** the current stroke. */
69      private Stroke stroke = new BasicStroke();
70  
71      /** TODO: the current rendering hints. */
72      private RenderingHints renderingHints = new RenderingHints(new LinkedHashMap<Key, Object>());
73  
74      /** the current affine transform. */
75      private AffineTransform affineTransform = new AffineTransform();
76  
77      /** TODO: the current composite. What is that? */
78      private Composite composite = AlphaComposite.Clear;
79  
80      /** the commands to send over the channel to the HTML5 code. */
81      private StringBuffer commands = new StringBuffer();
82  
83      /**
84       * Constructor.
85       */
86      public HtmlGraphics2d()
87      {
88          //
89      }
90  
91      /**
92       * Clear the commands and put the start tag in.
93       */
94      public void clearCommand()
95      {
96          this.commands = new StringBuffer();
97          this.commands.append("<animate>\n");
98      }
99  
100     /**
101      * Close the commands and put the end tag in.
102      * @return the current set of commands
103      */
104     public String closeAndGetCommands()
105     {
106         this.commands.append("</animate>\n");
107         return this.commands.toString();
108     }
109 
110     /**
111      * Add a draw command.
112      * @param drawCommand the tag for the draw command
113      * @param params the params for the draw command
114      */
115     protected void addDraw(final String drawCommand, final Object... params)
116     {
117         this.commands.append("<draw>" + drawCommand);
118         for (Object param : params)
119         {
120             this.commands.append("," + param.toString());
121         }
122         this.commands.append("</draw>\n");
123     }
124 
125     /**
126      * add AffineTransform to the command.
127      */
128     protected void addAffineTransform()
129     {
130         this.commands.append(",");
131         this.commands.append(this.affineTransform.getScaleX());
132         this.commands.append(",");
133         this.commands.append(this.affineTransform.getShearY());
134         this.commands.append(",");
135         this.commands.append(this.affineTransform.getShearX());
136         this.commands.append(",");
137         this.commands.append(this.affineTransform.getScaleY());
138         this.commands.append(",");
139         this.commands.append(this.affineTransform.getTranslateX());
140         this.commands.append(",");
141         this.commands.append(this.affineTransform.getTranslateY());
142     }
143 
144     /**
145      * add Color to the command.
146      * @param c the color
147      */
148     protected void addColor(final Color c)
149     {
150         this.commands.append(",");
151         this.commands.append(c.getRed());
152         this.commands.append(",");
153         this.commands.append(c.getGreen());
154         this.commands.append(",");
155         this.commands.append(c.getBlue());
156         this.commands.append(",");
157         this.commands.append(c.getAlpha());
158         this.commands.append(",");
159         this.commands.append(c.getTransparency());
160     }
161 
162     /**
163      * add font data to the command, font-name, font-size, bold/italic/plain.
164      */
165     protected void addFontData()
166     {
167         this.commands.append(",");
168         String javaFontName = this.font.getFontName().toLowerCase();
169         String htmlFontName;
170         if (javaFontName.contains("arial") || javaFontName.contains("helvetica") || javaFontName.contains("verdana")
171                 || javaFontName.contains("tahoma") || javaFontName.contains("segoe") || javaFontName.contains("sans"))
172         {
173             htmlFontName = "sans-serif";
174         }
175         else if (javaFontName.contains("times") || javaFontName.contains("cambria") || javaFontName.contains("georgia")
176                 || javaFontName.contains("serif"))
177         {
178             htmlFontName = "serif";
179         }
180         else if (javaFontName.contains("courier") || javaFontName.contains("consol") || javaFontName.contains("mono"))
181         {
182             htmlFontName = "monospace";
183         }
184         else
185         {
186             htmlFontName = "sans-serif";
187         }
188         this.commands.append(htmlFontName);
189         this.commands.append(",");
190         this.commands.append(this.font.getSize2D());
191         this.commands.append(",");
192         if (this.font.isBold())
193         {
194             this.commands.append("bold");
195         }
196         else if (this.font.isItalic())
197         {
198             this.commands.append("italic");
199         }
200         else
201         {
202             this.commands.append("plain");
203         }
204     }
205 
206     /**
207      * Add fill command, transform.m11(h-scale), transform.m12(h-skew), transform.m21(v-skew), transform.m22(v-scale),
208      * transform.dx(h-translate), transform.dy(v-translate), color.r, color.g, color.b, color.alpha, color.transparency,
209      * params...
210      * @param fillCommand the tag to use
211      * @param params the params to send
212      */
213     protected void addTransformFill(final String fillCommand, final Object... params)
214     {
215         this.commands.append("<transformFill>" + fillCommand);
216         addAffineTransform();
217         if (this.paint instanceof Color)
218         {
219             addColor((Color) this.paint);
220         }
221         else
222         {
223             addColor(this.color);
224         }
225         for (Object param : params)
226         {
227             this.commands.append("," + param.toString());
228         }
229         this.commands.append("</transformFill>\n");
230     }
231 
232     /**
233      * Add command, transform.m11(h-scale), transform.m12(h-skew), transform.m21(v-skew), transform.m22(v-scale),
234      * transform.dx(h-translate), transform.dy(v-translate), linecolor.r, linecolor.g, linecolor.b, linecolor.alpha,
235      * linecolor.transparency, line-width, params...
236      * @param drawCommand the tag to use
237      * @param params the params
238      */
239     protected void addTransformDraw(final String drawCommand, final Object... params)
240     {
241         this.commands.append("<transformDraw>" + drawCommand);
242         addAffineTransform();
243         if (this.paint instanceof Color)
244         {
245             addColor((Color) this.paint);
246         }
247         else
248         {
249             addColor(this.color);
250         }
251         if (this.stroke instanceof BasicStroke)
252         {
253             this.commands.append("," + ((BasicStroke) this.stroke).getLineWidth());
254         }
255         else
256         {
257             this.commands.append(", 0.1");
258         }
259         for (Object param : params)
260         {
261             this.commands.append("," + param.toString());
262         }
263         this.commands.append("</transformDraw>\n");
264     }
265 
266     /**
267      * adds a float array to the command.
268      * @param array the array
269      * @param length the number of points from the array to write
270      */
271     private void addFloatArray(final float[] array, final int length)
272     {
273         for (int i = 0; i < length; i++)
274         {
275             this.commands.append(", " + array[i]);
276         }
277     }
278 
279     /**
280      * adds a double array to the command.
281      * @param array the array
282      * @param length the number of points from the array to write
283      */
284     private void addDoubleArray(final double[] array, final int length)
285     {
286         for (int i = 0; i < length; i++)
287         {
288             this.commands.append(", " + array[i]);
289         }
290     }
291 
292     /**
293      * Add a path2D to the command. In case of fill:<br>
294      * FILL, transform.m11(h-scale), transform.m12(h-skew), transform.m21(v-skew), transform.m22(v-scale),
295      * transform.dx(h-translate), transform.dy(v-translate), fillcolor.r, fillcolor.g, fillcolor.b, fillcolor.alpha,
296      * fillcolor.transparency, winding_rule[WIND_EVEN_ODD/WIND_NON_ZERO], COMMAND, coords, COMMAND, coords, ... <br>
297      * In case of draw:<br>
298      * DRAW, transform.m11(h-scale), transform.m12(h-skew), transform.m21(v-skew), transform.m22(v-scale),
299      * transform.dx(h-translate), transform.dy(v-translate), strokecolor.r, strokecolor.g, strokecolor.b, strokecolor.alpha,
300      * strokecolor.transparency, line_width, COMMAND, coords, COMMAND, coords, ... <br>
301      * where command can be one of the following:<br>
302      * - CLOSE, followed by no coordinates<br>
303      * - CUBICTO, followed by 3 coordinates (6 numbers)<br>
304      * - LINETO, followed by 1 coordinate (2 numbers)<br>
305      * - MOVETO, followed by 1 coordinate (2 numbers)<br>
306      * - QUADTO, followed by 2 coordinates (4 numbers)<br>
307      * @param path Path2D.Float; the path to draw
308      * @param fill fill
309      */
310     protected void addTransformPathFloat(final Path2D.Float path, final boolean fill)
311     {
312         if (fill)
313         {
314             this.commands.append("<transformPath>FILL");
315         }
316         else
317         {
318             this.commands.append("<transformPath>DRAW");
319         }
320         addAffineTransform();
321         addColor(this.color);
322         if (fill)
323         {
324             if (path.getWindingRule() == Path2D.WIND_EVEN_ODD)
325             {
326                 this.commands.append(",WIND_EVEN_ODD");
327             }
328             else
329             {
330                 this.commands.append(",WIND_NON_ZERO");
331             }
332         }
333         else
334         {
335             if (this.stroke instanceof BasicStroke)
336             {
337                 this.commands.append("," + ((BasicStroke) this.stroke).getLineWidth());
338             }
339             else
340             {
341                 this.commands.append(", 0.1");
342             }
343         }
344         float[] coords = new float[6];
345         PathIterator i = path.getPathIterator(null);
346         while (!i.isDone())
347         {
348             int segment = i.currentSegment(coords);
349             switch (segment)
350             {
351                 case PathIterator.SEG_CLOSE:
352                     this.commands.append(",CLOSE");
353                     break;
354                 case PathIterator.SEG_CUBICTO:
355                     this.commands.append(",CUBICTO");
356                     addFloatArray(coords, 6);
357                     break;
358                 case PathIterator.SEG_LINETO:
359                     this.commands.append(",LINETO");
360                     addFloatArray(coords, 2);
361                     break;
362                 case PathIterator.SEG_MOVETO:
363                     this.commands.append(",MOVETO");
364                     addFloatArray(coords, 2);
365                     break;
366                 case PathIterator.SEG_QUADTO:
367                     this.commands.append(",QUADTO");
368                     addFloatArray(coords, 4);
369                     break;
370                 default:
371                     throw new OtsRuntimeException("unkown segment");
372             }
373             i.next();
374         }
375         this.commands.append("</transformPath>\n");
376     }
377 
378     /**
379      * Add a path2D to the command. In case of fill:<br>
380      * FILL, transform.m11(h-scale), transform.m12(h-skew), transform.m21(v-skew), transform.m22(v-scale),
381      * transform.dx(h-translate), transform.dy(v-translate), fillcolor.r, fillcolor.g, fillcolor.b, fillcolor.alpha,
382      * fillcolor.transparency, winding_rule[WIND_EVEN_ODD/WIND_NON_ZERO], COMMAND, coords, COMMAND, coords, ... <br>
383      * In case of draw:<br>
384      * DRAW, transform.m11(h-scale), transform.m12(h-skew), transform.m21(v-skew), transform.m22(v-scale),
385      * transform.dx(h-translate), transform.dy(v-translate), strokecolor.r, strokecolor.g, strokecolor.b, strokecolor.alpha,
386      * strokecolor.transparency, line_width, COMMAND, coords, COMMAND, coords, ... <br>
387      * where command can be one of the following:<br>
388      * - CLOSE, followed by no coordinates<br>
389      * - CUBICTO, followed by 3 coordinates (6 numbers)<br>
390      * - LINETO, followed by 1 coordinate (2 numbers)<br>
391      * - MOVETO, followed by 1 coordinate (2 numbers)<br>
392      * - QUADTO, followed by 2 coordinates (4 numbers)<br>
393      * @param path Path2D.Double; the path to draw
394      * @param fill fill
395      */
396     protected void addTransformPathDouble(final Path2D.Double path, final boolean fill)
397     {
398         if (fill)
399         {
400             this.commands.append("<transformPath>FILL");
401         }
402         else
403         {
404             this.commands.append("<transformPath>DRAW");
405         }
406         addAffineTransform();
407         addColor(this.color);
408         if (fill)
409         {
410             if (path.getWindingRule() == Path2D.WIND_EVEN_ODD)
411             {
412                 this.commands.append(",WIND_EVEN_ODD");
413             }
414             else
415             {
416                 this.commands.append(",WIND_NON_ZERO");
417             }
418         }
419         else
420         {
421             if (this.stroke instanceof BasicStroke)
422             {
423                 this.commands.append("," + ((BasicStroke) this.stroke).getLineWidth());
424             }
425             else
426             {
427                 this.commands.append(", 0.1");
428             }
429         }
430         double[] coords = new double[6];
431         PathIterator i = path.getPathIterator(null);
432         while (!i.isDone())
433         {
434             int segment = i.currentSegment(coords);
435             switch (segment)
436             {
437                 case PathIterator.SEG_CLOSE:
438                     this.commands.append(",CLOSE");
439                     break;
440                 case PathIterator.SEG_CUBICTO:
441                     this.commands.append(",CUBICTO");
442                     addDoubleArray(coords, 6);
443                     break;
444                 case PathIterator.SEG_LINETO:
445                     this.commands.append(",LINETO");
446                     addDoubleArray(coords, 2);
447                     break;
448                 case PathIterator.SEG_MOVETO:
449                     this.commands.append(",MOVETO");
450                     addDoubleArray(coords, 2);
451                     break;
452                 case PathIterator.SEG_QUADTO:
453                     this.commands.append(",QUADTO");
454                     addDoubleArray(coords, 4);
455                     break;
456                 default:
457                     throw new OtsRuntimeException("unkown segment");
458             }
459             i.next();
460         }
461         this.commands.append("</transformPath>\n");
462     }
463 
464     /**
465      * Add string, 0=command, 1=transform.m11(h-scale), 2=transform.m12(h-skew), 3=transform.m21(v-skew),
466      * 4=transform.m22(v-scale), 5=transform.dx(h-translate), 6=transform.dy(v-translate), 7=color.r, 8=color.g, 9=color.b,
467      * 10=color.alpha, 11=color.transparency, 12=fontname, 13=fontsize, 14=fontstyle(normal/italic/bold), 15=x, 16=y, 17=text.
468      * @param drawCommand the tag to use
469      * @param params the params
470      */
471     protected void addTransformText(final String drawCommand, final Object... params)
472     {
473         this.commands.append("<transformText>" + drawCommand);
474         addAffineTransform();
475         addColor(this.color);
476         addFontData();
477         for (Object param : params)
478         {
479             this.commands.append("," + param.toString());
480         }
481         this.commands.append("</transformText>\n");
482     }
483 
484     @Override
485     public void draw(final Shape shape)
486     {
487         drawFillShape(shape, false);
488     }
489 
490     /**
491      * Draw or fill a shape.
492      * @param shape the shape
493      * @param fill filled or not
494      */
495     protected void drawFillShape(final Shape shape, final boolean fill)
496     {
497         Logger.ots().trace("HTMLGraphics2D.draw(shape: {})", shape.getClass().getSimpleName());
498         if (shape instanceof Ellipse2D.Double)
499         {
500             Ellipse2D.Double ellipse = (Ellipse2D.Double) shape;
501             if (fill)
502             {
503                 addTransformFill("fillOval", ellipse.getCenterX(), ellipse.getCenterY(), ellipse.width / 2.0,
504                         ellipse.height / 2.0);
505             }
506             else
507             {
508                 addTransformDraw("drawOval", ellipse.getCenterX(), ellipse.getCenterY(), ellipse.width / 2.0,
509                         ellipse.height / 2.0);
510             }
511         }
512         else if (shape instanceof Ellipse2D.Float)
513         {
514             Ellipse2D.Float ellipse = (Ellipse2D.Float) shape;
515             if (fill)
516             {
517                 addTransformFill("fillOval", ellipse.getCenterX(), ellipse.getCenterY(), ellipse.width / 2.0,
518                         ellipse.height / 2.0);
519             }
520             else
521             {
522                 addTransformDraw("drawOval", ellipse.getCenterX(), ellipse.getCenterY(), ellipse.width / 2.0,
523                         ellipse.height / 2.0);
524             }
525         }
526         else if (shape instanceof Line2D.Double)
527         {
528             Line2D.Double line = (Line2D.Double) shape;
529             addTransformDraw("drawLine", line.x1, line.y1, line.x2, line.y2);
530         }
531         else if (shape instanceof Line2D.Float)
532         {
533             Line2D.Float line = (Line2D.Float) shape;
534             addTransformDraw("drawLine", line.x1, line.y1, line.x2, line.y2);
535         }
536         else if (shape instanceof Rectangle2D.Double)
537         {
538             Rectangle2D.Double rect = (Rectangle2D.Double) shape;
539             if (fill)
540             {
541                 addTransformFill("fillRect", rect.x, rect.y, rect.width, rect.height);
542             }
543             else
544             {
545                 addTransformDraw("drawRect", rect.x, rect.y, rect.width, rect.height);
546             }
547         }
548         else if (shape instanceof Rectangle2D.Float)
549         {
550             Rectangle2D.Float rect = (Rectangle2D.Float) shape;
551             if (fill)
552             {
553                 addTransformFill("fillRect", rect.x, rect.y, rect.width, rect.height);
554             }
555             else
556             {
557                 addTransformDraw("drawRect", rect.x, rect.y, rect.width, rect.height);
558             }
559         }
560         else if (shape instanceof Path2D.Float)
561         {
562             Path2D.Float path = (Path2D.Float) shape;
563             addTransformPathFloat(path, fill);
564         }
565         else if (shape instanceof Path2D.Double)
566         {
567             Path2D.Double path = (Path2D.Double) shape;
568             addTransformPathDouble(path, fill);
569         }
570 
571     }
572 
573     @Override
574     public boolean drawImage(final Image img, final AffineTransform xform, final ImageObserver obs)
575     {
576         Logger.ots().trace("HTMLGraphics2D.drawImage()");
577         return true;
578     }
579 
580     @Override
581     public void drawImage(final BufferedImage img, final BufferedImageOp op, final int x, final int y)
582     {
583         Logger.ots().trace("HTMLGraphics2D.drawImage()");
584     }
585 
586     @Override
587     public void drawRenderedImage(final RenderedImage img, final AffineTransform xform)
588     {
589         Logger.ots().trace("HTMLGraphics2D.drawRenderedImage()");
590     }
591 
592     @Override
593     public void drawRenderableImage(final RenderableImage img, final AffineTransform xform)
594     {
595         Logger.ots().trace("HTMLGraphics2D.drawRenderableImage()");
596     }
597 
598     @Override
599     public void drawString(final String str, final int x, final int y)
600     {
601         Logger.ots().trace("HTMLGraphics2D.drawString()");
602         addTransformText("drawString", x, y, str);
603     }
604 
605     @Override
606     public void drawString(final String str, final float x, final float y)
607     {
608         Logger.ots().trace("HTMLGraphics2D.drawString()");
609         addTransformText("drawString", x, y, str);
610     }
611 
612     @Override
613     public void drawString(final AttributedCharacterIterator iterator, final int x, final int y)
614     {
615         Logger.ots().trace("HTMLGraphics2D.drawString()");
616     }
617 
618     @Override
619     public void drawString(final AttributedCharacterIterator iterator, final float x, final float y)
620     {
621         Logger.ots().trace("HTMLGraphics2D.drawString()");
622     }
623 
624     @Override
625     public void drawGlyphVector(final GlyphVector g, final float x, final float y)
626     {
627         Logger.ots().trace("HTMLGraphics2D.drawGlyphVector()");
628     }
629 
630     @Override
631     public void fill(final Shape shape)
632     {
633         Logger.ots().trace("HTMLGraphics2D.fill()");
634         drawFillShape(shape, true);
635     }
636 
637     @Override
638     public boolean hit(final Rectangle rect, final Shape s, final boolean onStroke)
639     {
640         Logger.ots().trace("HTMLGraphics2D.hit()");
641         return false;
642     }
643 
644     @Override
645     public GraphicsConfiguration getDeviceConfiguration()
646     {
647         Logger.ots().trace("HTMLGraphics2D.getDeviceConfiguration()");
648         return null;
649     }
650 
651     @Override
652     public void setComposite(final Composite comp)
653     {
654         Logger.ots().trace("HTMLGraphics2D.setComposite()");
655     }
656 
657     @Override
658     public void setPaint(final Paint paint)
659     {
660         this.paint = paint;
661         Logger.ots().trace("HTMLGraphics2D.setPaint()");
662     }
663 
664     @Override
665     public void setStroke(final Stroke s)
666     {
667         this.stroke = s;
668         Logger.ots().trace("HTMLGraphics2D.setStroke()");
669     }
670 
671     @Override
672     public void setRenderingHint(final Key hintKey, final Object hintValue)
673     {
674         if (hintValue != null)
675         {
676             this.renderingHints.put(hintKey, hintValue);
677         }
678         Logger.ots().trace("HTMLGraphics2D.setRenderingHint()");
679     }
680 
681     @Override
682     public Object getRenderingHint(final Key hintKey)
683     {
684         Logger.ots().trace("HTMLGraphics2D.getRenderingHint()");
685         return this.renderingHints.get(hintKey);
686     }
687 
688     @Override
689     public void setRenderingHints(final Map<?, ?> hints)
690     {
691         this.renderingHints.clear();
692         this.renderingHints.putAll(hints);
693         Logger.ots().trace("HTMLGraphics2D.setRenderingHints()");
694     }
695 
696     @Override
697     public void addRenderingHints(final Map<?, ?> hints)
698     {
699         this.renderingHints.putAll(hints);
700         Logger.ots().trace("HTMLGraphics2D.addRenderingHints()");
701     }
702 
703     @Override
704     public RenderingHints getRenderingHints()
705     {
706         Logger.ots().trace("HTMLGraphics2D.getRenderingHints()");
707         return this.renderingHints;
708     }
709 
710     @Override
711     public void translate(final int x, final int y)
712     {
713         this.affineTransform.translate(x, y);
714         Logger.ots().trace("HTMLGraphics2D.translate()");
715     }
716 
717     @Override
718     public void translate(final double tx, final double ty)
719     {
720         this.affineTransform.translate(tx, ty);
721         Logger.ots().trace("HTMLGraphics2D.translate()");
722     }
723 
724     @Override
725     public void rotate(final double theta)
726     {
727         this.affineTransform.rotate(theta);
728         Logger.ots().trace("HTMLGraphics2D.rotate()");
729     }
730 
731     @Override
732     public void rotate(final double theta, final double x, final double y)
733     {
734         this.affineTransform.rotate(theta, x, y);
735         Logger.ots().trace("HTMLGraphics2D.rotate()");
736     }
737 
738     @Override
739     public void scale(final double sx, final double sy)
740     {
741         this.affineTransform.scale(sx, sy);
742         Logger.ots().trace("HTMLGraphics2D.scale()");
743     }
744 
745     @Override
746     public void shear(final double shx, final double shy)
747     {
748         this.affineTransform.shear(shx, shy);
749         Logger.ots().trace("HTMLGraphics2D.shear()");
750     }
751 
752     @Override
753     public void transform(final AffineTransform Tx)
754     {
755         Logger.ots().trace("HTMLGraphics2D.transform()");
756     }
757 
758     @Override
759     public void setTransform(final AffineTransform Tx)
760     {
761         this.affineTransform = (AffineTransform) Tx.clone();
762         Logger.ots().trace("HTMLGraphics2D.setTransform()");
763     }
764 
765     @Override
766     public AffineTransform getTransform()
767     {
768         Logger.ots().trace("HTMLGraphics2D.getTransform()");
769         return this.affineTransform;
770     }
771 
772     @Override
773     public Paint getPaint()
774     {
775         Logger.ots().trace("HTMLGraphics2D.getPaint()");
776         return this.paint;
777     }
778 
779     @Override
780     public Composite getComposite()
781     {
782         Logger.ots().trace("HTMLGraphics2D.getComposite()");
783         return this.composite;
784     }
785 
786     @Override
787     public void setBackground(final Color color)
788     {
789         this.background = color;
790         Logger.ots().trace("HTMLGraphics2D.setBackground()");
791     }
792 
793     @Override
794     public Color getBackground()
795     {
796         Logger.ots().trace("HTMLGraphics2D.getBackground()");
797         return this.background;
798     }
799 
800     @Override
801     public Stroke getStroke()
802     {
803         Logger.ots().trace("HTMLGraphics2D.getStroke()");
804         return this.stroke;
805     }
806 
807     @Override
808     public void clip(final Shape s)
809     {
810         Logger.ots().trace("HTMLGraphics2D.clip()");
811     }
812 
813     @Override
814     public FontRenderContext getFontRenderContext()
815     {
816         Logger.ots().trace("HTMLGraphics2D.getFontRenderContext()");
817         return new FontRenderContext(this.affineTransform, true, true);
818     }
819 
820     @Override
821     public Graphics create()
822     {
823         Logger.ots().trace("HTMLGraphics2D.create()");
824         return new HtmlGraphics2d(); // TODO: clone
825     }
826 
827     @Override
828     public Color getColor()
829     {
830         Logger.ots().trace("HTMLGraphics2D.getColor()");
831         return this.color;
832     }
833 
834     @Override
835     public void setColor(final Color c)
836     {
837         this.color = c;
838         this.paint = c; // TODO see how difference between paint and color should be handled
839         Logger.ots().trace("HTMLGraphics2D.setColor()");
840     }
841 
842     @Override
843     public void setPaintMode()
844     {
845         Logger.ots().trace("HTMLGraphics2D.setPaintMode()");
846     }
847 
848     @Override
849     public void setXORMode(final Color c1)
850     {
851         Logger.ots().trace("HTMLGraphics2D.setXORMode()");
852     }
853 
854     @Override
855     public Font getFont()
856     {
857         Logger.ots().trace("HTMLGraphics2D.getFont()");
858         return this.font;
859     }
860 
861     @Override
862     public void setFont(final Font font)
863     {
864         this.font = font;
865         this.fontMetrics = this.canvas.getFontMetrics(this.font);
866         Logger.ots().trace("HTMLGraphics2D.setFont()");
867     }
868 
869     @Override
870     public FontMetrics getFontMetrics(final Font f)
871     {
872         Logger.ots().trace("HTMLGraphics2D.getFontMetrics()");
873         return this.fontMetrics;
874     }
875 
876     @Override
877     public Rectangle getClipBounds()
878     {
879         Logger.ots().trace("HTMLGraphics2D.getClipBounds()");
880         return null;
881     }
882 
883     @Override
884     public void clipRect(final int x, final int y, final int width, final int height)
885     {
886         Logger.ots().trace("HTMLGraphics2D.clipRect()");
887     }
888 
889     @Override
890     public void setClip(final int x, final int y, final int width, final int height)
891     {
892         Logger.ots().trace("HTMLGraphics2D.setClip()");
893     }
894 
895     @Override
896     public Shape getClip()
897     {
898         Logger.ots().trace("HTMLGraphics2D.getClip()");
899         return null;
900     }
901 
902     @Override
903     public void setClip(final Shape clip)
904     {
905         Logger.ots().trace("HTMLGraphics2D.setClip()");
906     }
907 
908     @Override
909     public void copyArea(final int x, final int y, final int width, final int height, final int dx, final int dy)
910     {
911         Logger.ots().trace("HTMLGraphics2D.copyArea()");
912     }
913 
914     @Override
915     public void drawLine(final int x1, final int y1, final int x2, final int y2)
916     {
917         Logger.ots().trace("HTMLGraphics2D.drawLine()");
918         addTransformDraw("drawLine", x1, y1, x2, y2);
919     }
920 
921     @Override
922     public void fillRect(final int x, final int y, final int width, final int height)
923     {
924         Logger.ots().trace("HTMLGraphics2D.fillRect()");
925         addTransformFill("fillRect", x, y, width, height);
926     }
927 
928     @Override
929     public void clearRect(final int x, final int y, final int width, final int height)
930     {
931         Logger.ots().trace("HTMLGraphics2D.clearRect()");
932         addTransformDraw("clearRect", x, y, width, height);
933     }
934 
935     @Override
936     public void drawRoundRect(final int x, final int y, final int width, final int height, final int arcWidth,
937             final int arcHeight)
938     {
939         Logger.ots().trace("HTMLGraphics2D.drawRoundRect()");
940     }
941 
942     @Override
943     public void fillRoundRect(final int x, final int y, final int width, final int height, final int arcWidth,
944             final int arcHeight)
945     {
946         Logger.ots().trace("HTMLGraphics2D.fillRoundRect()");
947     }
948 
949     @Override
950     public void drawOval(final int x, final int y, final int width, final int height)
951     {
952         Logger.ots().trace("HTMLGraphics2D.drawOval()");
953         addTransformDraw("drawOval", x, y, width, height);
954     }
955 
956     @Override
957     public void fillOval(final int x, final int y, final int width, final int height)
958     {
959         Logger.ots().trace("HTMLGraphics2D.fillOval()");
960         addTransformFill("fillOval", x, y, width, height);
961     }
962 
963     @Override
964     public void drawArc(final int x, final int y, final int width, final int height, final int startAngle, final int arcAngle)
965     {
966         Logger.ots().trace("HTMLGraphics2D.drawArc()");
967     }
968 
969     @Override
970     public void fillArc(final int x, final int y, final int width, final int height, final int startAngle, final int arcAngle)
971     {
972         Logger.ots().trace("HTMLGraphics2D.fillArc()");
973     }
974 
975     @Override
976     public void drawPolyline(final int[] xPoints, final int[] yPoints, final int nPoints)
977     {
978         Logger.ots().trace("HTMLGraphics2D.fillPolyline()");
979     }
980 
981     @Override
982     public void drawPolygon(final int[] xPoints, final int[] yPoints, final int nPoints)
983     {
984         Logger.ots().trace("HTMLGraphics2D.drawPolygon()");
985     }
986 
987     @Override
988     public void fillPolygon(final int[] xPoints, final int[] yPoints, final int nPoints)
989     {
990         Logger.ots().trace("HTMLGraphics2D.fillPolygon()");
991     }
992 
993     @Override
994     public boolean drawImage(final Image img, final int x, final int y, final ImageObserver observer)
995     {
996         Logger.ots().trace("HTMLGraphics2D.drawImage()");
997         return false;
998     }
999 
1000     @Override
1001     public boolean drawImage(final Image img, final int x, final int y, final int width, final int height,
1002             final ImageObserver observer)
1003     {
1004         Logger.ots().trace("HTMLGraphics2D.drawImage()");
1005         return false;
1006     }
1007 
1008     @Override
1009     public boolean drawImage(final Image img, final int x, final int y, final Color bgcolor, final ImageObserver observer)
1010     {
1011         Logger.ots().trace("HTMLGraphics2D.drawImage()");
1012         return false;
1013     }
1014 
1015     @Override
1016     public boolean drawImage(final Image img, final int x, final int y, final int width, final int height, final Color bgcolor,
1017             final ImageObserver observer)
1018     {
1019         Logger.ots().trace("HTMLGraphics2D.drawImage()");
1020         return false;
1021     }
1022 
1023     @Override
1024     public boolean drawImage(final Image img, final int dx1, final int dy1, final int dx2, final int dy2, final int sx1,
1025             final int sy1, final int sx2, final int sy2, final ImageObserver observer)
1026     {
1027         Logger.ots().trace("HTMLGraphics2D.drawImage()");
1028         return false;
1029     }
1030 
1031     @Override
1032     public boolean drawImage(final Image img, final int dx1, final int dy1, final int dx2, final int dy2, final int sx1,
1033             final int sy1, final int sx2, final int sy2, final Color bgcolor, final ImageObserver observer)
1034     {
1035         Logger.ots().trace("HTMLGraphics2D.drawImage()");
1036         return false;
1037     }
1038 
1039     @Override
1040     public void dispose()
1041     {
1042         Logger.ots().trace("HTMLGraphics2D.dispose()");
1043     }
1044 
1045 }