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.logger.Cat;
40  
41  /**
42   * HtmlGraphics.java. <br>
43   * <br>
44   * Copyright (c) 2003-2024 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://www.tudelft.nl/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 String; the tag for the draw command
106      * @param params Object...; the params for the draw command
107      */
108     protected void addDraw(String drawCommand, 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 Color; the color
140      */
141     protected void addColor(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 String; the tag to use
190      * @param params Object...; the params to send
191      */
192     protected void addTransformFill(String fillCommand, 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 String; the tag to use
212      * @param params Object...; the params
213      */
214     protected void addTransformDraw(String drawCommand, 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 float[]; the array
236      * @param length int; 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 double[]; the array
249      * @param length int; 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 boolean;
276      */
277     protected void addTransformPathFloat(Path2D.Float path, 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 boolean;
350      */
351     protected void addTransformPathDouble(Path2D.Double path, 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 String; the tag to use
412      * @param params Object...; the params
413      */
414     protected void addTransformText(String drawCommand, 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     /** {@inheritDoc} */
428     @Override
429     public void draw(Shape shape)
430     {
431         drawFillShape(shape, false);
432     }
433 
434     /**
435      * Draw or fill a shape.
436      * @param shape Shape; the shape
437      * @param fill boolean; filled or not
438      */
439     protected void drawFillShape(Shape shape, boolean fill)
440     {
441         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.draw(shape: {})", shape.getClass().getSimpleName());
442         if (shape instanceof Ellipse2D.Double)
443         {
444             Ellipse2D.Double ellipse = (Ellipse2D.Double) shape;
445             if (fill)
446                 addTransformFill("fillOval", ellipse.getCenterX(), ellipse.getCenterY(), ellipse.width / 2.0,
447                         ellipse.height / 2.0);
448             else
449                 addTransformDraw("drawOval", ellipse.getCenterX(), ellipse.getCenterY(), ellipse.width / 2.0,
450                         ellipse.height / 2.0);
451         }
452         else if (shape instanceof Ellipse2D.Float)
453         {
454             Ellipse2D.Float ellipse = (Ellipse2D.Float) shape;
455             if (fill)
456                 addTransformFill("fillOval", ellipse.getCenterX(), ellipse.getCenterY(), ellipse.width / 2.0,
457                         ellipse.height / 2.0);
458             else
459                 addTransformDraw("drawOval", ellipse.getCenterX(), ellipse.getCenterY(), ellipse.width / 2.0,
460                         ellipse.height / 2.0);
461         }
462         else if (shape instanceof Line2D.Double)
463         {
464             Line2D.Double line = (Line2D.Double) shape;
465             addTransformDraw("drawLine", line.x1, line.y1, line.x2, line.y2);
466         }
467         else if (shape instanceof Line2D.Float)
468         {
469             Line2D.Float line = (Line2D.Float) shape;
470             addTransformDraw("drawLine", line.x1, line.y1, line.x2, line.y2);
471         }
472         else if (shape instanceof Rectangle2D.Double)
473         {
474             Rectangle2D.Double rect = (Rectangle2D.Double) shape;
475             if (fill)
476                 addTransformFill("fillRect", rect.x, rect.y, rect.width, rect.height);
477             else
478                 addTransformDraw("drawRect", rect.x, rect.y, rect.width, rect.height);
479         }
480         else if (shape instanceof Rectangle2D.Float)
481         {
482             Rectangle2D.Float rect = (Rectangle2D.Float) shape;
483             if (fill)
484                 addTransformFill("fillRect", rect.x, rect.y, rect.width, rect.height);
485             else
486                 addTransformDraw("drawRect", rect.x, rect.y, rect.width, rect.height);
487         }
488         else if (shape instanceof Path2D.Float)
489         {
490             Path2D.Float path = (Path2D.Float) shape;
491             addTransformPathFloat(path, fill);
492         }
493         else if (shape instanceof Path2D.Double)
494         {
495             Path2D.Double path = (Path2D.Double) shape;
496             addTransformPathDouble(path, fill);
497         }
498 
499     }
500 
501     /** {@inheritDoc} */
502     @Override
503     public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs)
504     {
505         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawImage()");
506         return true;
507     }
508 
509     /** {@inheritDoc} */
510     @Override
511     public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y)
512     {
513         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawImage()");
514     }
515 
516     /** {@inheritDoc} */
517     @Override
518     public void drawRenderedImage(RenderedImage img, AffineTransform xform)
519     {
520         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawRenderedImage()");
521     }
522 
523     /** {@inheritDoc} */
524     @Override
525     public void drawRenderableImage(RenderableImage img, AffineTransform xform)
526     {
527         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawRenderableImage()");
528     }
529 
530     /** {@inheritDoc} */
531     @Override
532     public void drawString(String str, int x, int y)
533     {
534         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawString()");
535         addTransformText("drawString", x, y, str);
536     }
537 
538     /** {@inheritDoc} */
539     @Override
540     public void drawString(String str, float x, float y)
541     {
542         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawString()");
543         addTransformText("drawString", x, y, str);
544     }
545 
546     /** {@inheritDoc} */
547     @Override
548     public void drawString(AttributedCharacterIterator iterator, int x, int y)
549     {
550         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawString()");
551     }
552 
553     /** {@inheritDoc} */
554     @Override
555     public void drawString(AttributedCharacterIterator iterator, float x, float y)
556     {
557         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawString()");
558     }
559 
560     /** {@inheritDoc} */
561     @Override
562     public void drawGlyphVector(GlyphVector g, float x, float y)
563     {
564         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawGlyphVector()");
565     }
566 
567     /** {@inheritDoc} */
568     @Override
569     public void fill(Shape shape)
570     {
571         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.fill()");
572         drawFillShape(shape, true);
573     }
574 
575     /** {@inheritDoc} */
576     @Override
577     public boolean hit(Rectangle rect, Shape s, boolean onStroke)
578     {
579         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.hit()");
580         return false;
581     }
582 
583     /** {@inheritDoc} */
584     @Override
585     public GraphicsConfiguration getDeviceConfiguration()
586     {
587         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.getDeviceConfiguration()");
588         return null;
589     }
590 
591     /** {@inheritDoc} */
592     @Override
593     public void setComposite(Composite comp)
594     {
595         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.setComposite()");
596     }
597 
598     /** {@inheritDoc} */
599     @Override
600     public void setPaint(Paint paint)
601     {
602         this.paint = paint;
603         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.setPaint()");
604     }
605 
606     /** {@inheritDoc} */
607     @Override
608     public void setStroke(Stroke s)
609     {
610         this.stroke = s;
611         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.setStroke()");
612     }
613 
614     /** {@inheritDoc} */
615     @Override
616     public void setRenderingHint(Key hintKey, Object hintValue)
617     {
618         this.renderingHints.put(hintKey, hintValue);
619         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.setRenderingHint()");
620     }
621 
622     /** {@inheritDoc} */
623     @Override
624     public Object getRenderingHint(Key hintKey)
625     {
626         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.getRenderingHint()");
627         return this.renderingHints.get(hintKey);
628     }
629 
630     /** {@inheritDoc} */
631     @Override
632     public void setRenderingHints(Map<?, ?> hints)
633     {
634         this.renderingHints.clear();
635         this.renderingHints.putAll(hints);
636         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.setRenderingHints()");
637     }
638 
639     /** {@inheritDoc} */
640     @Override
641     public void addRenderingHints(Map<?, ?> hints)
642     {
643         this.renderingHints.putAll(hints);
644         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.addRenderingHints()");
645     }
646 
647     /** {@inheritDoc} */
648     @Override
649     public RenderingHints getRenderingHints()
650     {
651         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.getRenderingHints()");
652         return this.renderingHints;
653     }
654 
655     /** {@inheritDoc} */
656     @Override
657     public void translate(int x, int y)
658     {
659         this.affineTransform.translate(x, y);
660         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.translate()");
661     }
662 
663     /** {@inheritDoc} */
664     @Override
665     public void translate(double tx, double ty)
666     {
667         this.affineTransform.translate(tx, ty);
668         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.translate()");
669     }
670 
671     /** {@inheritDoc} */
672     @Override
673     public void rotate(double theta)
674     {
675         this.affineTransform.rotate(theta);
676         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.rotate()");
677     }
678 
679     /** {@inheritDoc} */
680     @Override
681     public void rotate(double theta, double x, double y)
682     {
683         this.affineTransform.rotate(theta, x, y);
684         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.rotate()");
685     }
686 
687     /** {@inheritDoc} */
688     @Override
689     public void scale(double sx, double sy)
690     {
691         this.affineTransform.scale(sx, sy);
692         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.scale()");
693     }
694 
695     /** {@inheritDoc} */
696     @Override
697     public void shear(double shx, double shy)
698     {
699         this.affineTransform.shear(shx, shy);
700         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.shear()");
701     }
702 
703     /** {@inheritDoc} */
704     @Override
705     public void transform(AffineTransform Tx)
706     {
707         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.transform()");
708     }
709 
710     /** {@inheritDoc} */
711     @Override
712     public void setTransform(AffineTransform Tx)
713     {
714         this.affineTransform = (AffineTransform) Tx.clone();
715         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.setTransform()");
716     }
717 
718     /** {@inheritDoc} */
719     @Override
720     public AffineTransform getTransform()
721     {
722         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.getTransform()");
723         return this.affineTransform;
724     }
725 
726     /** {@inheritDoc} */
727     @Override
728     public Paint getPaint()
729     {
730         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.getPaint()");
731         return this.paint;
732     }
733 
734     /** {@inheritDoc} */
735     @Override
736     public Composite getComposite()
737     {
738         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.getComposite()");
739         return this.composite;
740     }
741 
742     /** {@inheritDoc} */
743     @Override
744     public void setBackground(Color color)
745     {
746         this.background = color;
747         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.setBackground()");
748     }
749 
750     /** {@inheritDoc} */
751     @Override
752     public Color getBackground()
753     {
754         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.getBackground()");
755         return this.background;
756     }
757 
758     /** {@inheritDoc} */
759     @Override
760     public Stroke getStroke()
761     {
762         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.getStroke()");
763         return this.stroke;
764     }
765 
766     /** {@inheritDoc} */
767     @Override
768     public void clip(Shape s)
769     {
770         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.clip()");
771     }
772 
773     /** {@inheritDoc} */
774     @Override
775     public FontRenderContext getFontRenderContext()
776     {
777         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.getFontRenderContext()");
778         return new FontRenderContext(this.affineTransform, true, true);
779     }
780 
781     /** {@inheritDoc} */
782     @Override
783     public Graphics create()
784     {
785         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.create()");
786         return new HtmlGraphics2D(); // TODO: clone
787     }
788 
789     /** {@inheritDoc} */
790     @Override
791     public Color getColor()
792     {
793         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.getColor()");
794         return this.color;
795     }
796 
797     /** {@inheritDoc} */
798     @Override
799     public void setColor(Color c)
800     {
801         this.color = c;
802         this.paint = c; // TODO see how difference between paint and color should be handled
803         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.setColor()");
804     }
805 
806     /** {@inheritDoc} */
807     @Override
808     public void setPaintMode()
809     {
810         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.setPaintMode()");
811     }
812 
813     /** {@inheritDoc} */
814     @Override
815     public void setXORMode(Color c1)
816     {
817         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.setXORMode()");
818     }
819 
820     /** {@inheritDoc} */
821     @Override
822     public Font getFont()
823     {
824         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.getFont()");
825         return this.font;
826     }
827 
828     /** {@inheritDoc} */
829     @Override
830     public void setFont(Font font)
831     {
832         this.font = font;
833         this.fontMetrics = this.canvas.getFontMetrics(this.font);
834         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.setFont()");
835     }
836 
837     /** {@inheritDoc} */
838     @Override
839     public FontMetrics getFontMetrics(Font f)
840     {
841         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.getFontMetrics()");
842         return this.fontMetrics;
843     }
844 
845     /** {@inheritDoc} */
846     @Override
847     public Rectangle getClipBounds()
848     {
849         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.getClipBounds()");
850         return null;
851     }
852 
853     /** {@inheritDoc} */
854     @Override
855     public void clipRect(int x, int y, int width, int height)
856     {
857         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.clipRect()");
858     }
859 
860     /** {@inheritDoc} */
861     @Override
862     public void setClip(int x, int y, int width, int height)
863     {
864         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.setClip()");
865     }
866 
867     /** {@inheritDoc} */
868     @Override
869     public Shape getClip()
870     {
871         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.getClip()");
872         return null;
873     }
874 
875     /** {@inheritDoc} */
876     @Override
877     public void setClip(Shape clip)
878     {
879         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.setClip()");
880     }
881 
882     /** {@inheritDoc} */
883     @Override
884     public void copyArea(int x, int y, int width, int height, int dx, int dy)
885     {
886         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.copyArea()");
887     }
888 
889     /** {@inheritDoc} */
890     @Override
891     public void drawLine(int x1, int y1, int x2, int y2)
892     {
893         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawLine()");
894         addTransformDraw("drawLine", x1, y1, x2, y2);
895     }
896 
897     /** {@inheritDoc} */
898     @Override
899     public void fillRect(int x, int y, int width, int height)
900     {
901         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.fillRect()");
902         addTransformFill("fillRect", x, y, width, height);
903     }
904 
905     /** {@inheritDoc} */
906     @Override
907     public void clearRect(int x, int y, int width, int height)
908     {
909         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.clearRect()");
910         addTransformDraw("clearRect", x, y, width, height);
911     }
912 
913     /** {@inheritDoc} */
914     @Override
915     public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)
916     {
917         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawRoundRect()");
918     }
919 
920     /** {@inheritDoc} */
921     @Override
922     public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)
923     {
924         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.fillRoundRect()");
925     }
926 
927     /** {@inheritDoc} */
928     @Override
929     public void drawOval(int x, int y, int width, int height)
930     {
931         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawOval()");
932         addTransformDraw("drawOval", x, y, width, height);
933     }
934 
935     /** {@inheritDoc} */
936     @Override
937     public void fillOval(int x, int y, int width, int height)
938     {
939         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.fillOval()");
940         addTransformFill("fillOval", x, y, width, height);
941     }
942 
943     /** {@inheritDoc} */
944     @Override
945     public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)
946     {
947         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawArc()");
948     }
949 
950     /** {@inheritDoc} */
951     @Override
952     public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle)
953     {
954         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.fillArc()");
955     }
956 
957     /** {@inheritDoc} */
958     @Override
959     public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
960     {
961         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.fillPolyline()");
962     }
963 
964     /** {@inheritDoc} */
965     @Override
966     public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
967     {
968         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawPolygon()");
969     }
970 
971     /** {@inheritDoc} */
972     @Override
973     public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
974     {
975         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.fillPolygon()");
976     }
977 
978     /** {@inheritDoc} */
979     @Override
980     public boolean drawImage(Image img, int x, int y, ImageObserver observer)
981     {
982         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawImage()");
983         return false;
984     }
985 
986     /** {@inheritDoc} */
987     @Override
988     public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer)
989     {
990         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawImage()");
991         return false;
992     }
993 
994     /** {@inheritDoc} */
995     @Override
996     public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer)
997     {
998         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawImage()");
999         return false;
1000     }
1001 
1002     /** {@inheritDoc} */
1003     @Override
1004     public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer)
1005     {
1006         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawImage()");
1007         return false;
1008     }
1009 
1010     /** {@inheritDoc} */
1011     @Override
1012     public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
1013             ImageObserver observer)
1014     {
1015         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawImage()");
1016         return false;
1017     }
1018 
1019     /** {@inheritDoc} */
1020     @Override
1021     public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor,
1022             ImageObserver observer)
1023     {
1024         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.drawImage()");
1025         return false;
1026     }
1027 
1028     /** {@inheritDoc} */
1029     @Override
1030     public void dispose()
1031     {
1032         CategoryLogger.filter(Cat.WEB).trace("HtmlGraphics2D.dispose()");
1033     }
1034 
1035 }