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