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