View Javadoc

1   // Copyright 2000-2007, FreeHEP
2   package org.freehep.graphics2d;
3   
4   import java.awt.BasicStroke;
5   import java.awt.Color;
6   import java.awt.Dimension;
7   import java.awt.Font;
8   import java.awt.Insets;
9   import java.awt.Paint;
10  import java.awt.Rectangle;
11  import java.awt.Shape;
12  import java.awt.Stroke;
13  import java.awt.font.TextLayout;
14  import java.awt.geom.AffineTransform;
15  import java.awt.geom.Arc2D;
16  import java.awt.geom.Area;
17  import java.awt.geom.Ellipse2D;
18  import java.awt.geom.GeneralPath;
19  import java.awt.geom.Line2D;
20  import java.awt.geom.Point2D;
21  import java.awt.geom.Rectangle2D;
22  import java.awt.geom.RoundRectangle2D;
23  import java.text.AttributedCharacterIterator;
24  import java.util.Properties;
25  
26  import org.freehep.graphics2d.font.FontUtilities;
27  import org.freehep.util.UserProperties;
28  
29  /**
30   * This class implements all conversions from integer to double as well as a few
31   * other convenience functions. It also handles the different drawSymbol and
32   * fillSymbol methods and print colors. The drawing of framed strings is
33   * broken down to lower level methods.
34   * 
35   * @author Simon Fischer
36   * @author Mark Donszelmann
37   * @author Steffen Greiffenberg
38   * @version $Id: AbstractVectorGraphics.java 10516 2007-02-06 21:11:19Z duns $
39   */
40  public abstract class AbstractVectorGraphics extends VectorGraphics {
41  
42      private UserProperties properties;
43  
44      private String creator;
45  
46      private boolean isDeviceIndependent;
47  
48      private SymbolShape cachedShape;
49  
50      private int colorMode;
51  
52      private Color backgroundColor;
53  
54      private Color currentColor;
55  
56      private Paint currentPaint;
57  
58      private Font currentFont;
59  
60      public AbstractVectorGraphics() {
61          properties = new UserProperties();
62          creator = "FreeHEP Graphics2D Driver";
63          isDeviceIndependent = false;
64          cachedShape = new SymbolShape();
65          colorMode = PrintColor.COLOR;
66  
67          // all of these have to be set in the subclasses
68          currentFont = null;
69          backgroundColor = null;
70          currentColor = null;
71          currentPaint = null;
72      }
73  
74      protected AbstractVectorGraphics(AbstractVectorGraphics graphics) {
75          super();
76          properties = graphics.properties;
77          creator = graphics.creator;
78          isDeviceIndependent = graphics.isDeviceIndependent;
79          cachedShape = graphics.cachedShape;
80  
81          backgroundColor = graphics.backgroundColor;
82          currentColor = graphics.currentColor;
83          currentPaint = graphics.currentPaint;
84          colorMode = graphics.colorMode;
85          currentFont = graphics.currentFont;
86      }
87  
88      public void setProperties(Properties newProperties) {
89          if (newProperties == null)
90              return;
91          properties.setProperties(newProperties);
92      }
93  
94      protected void initProperties(Properties defaults) {
95          properties = new UserProperties();
96          properties.setProperties(defaults);
97      }
98  
99      protected Properties getProperties() {
100         return properties;
101     }
102 
103     public String getProperty(String key) {
104         return properties.getProperty(key);
105     }
106 
107     public Color getPropertyColor(String key) {
108         return properties.getPropertyColor(key);
109     }
110 
111     public Rectangle getPropertyRectangle(String key) {
112         return properties.getPropertyRectangle(key);
113     }
114 
115     public Insets getPropertyInsets(String key) {
116         return properties.getPropertyInsets(key);
117     }
118 
119     public Dimension getPropertyDimension(String key) {
120         return properties.getPropertyDimension(key);
121     }
122 
123     public int getPropertyInt(String key) {
124         return properties.getPropertyInt(key);
125     }
126 
127     public double getPropertyDouble(String key) {
128         return properties.getPropertyDouble(key);
129     }
130 
131     public boolean isProperty(String key) {
132         return properties.isProperty(key);
133     }
134 
135     public String getCreator() {
136         return creator;
137     }
138 
139     public void setCreator(String creator) {
140         if (creator != null) {
141             this.creator = creator;
142         }
143     }
144 
145     public boolean isDeviceIndependent() {
146         return isDeviceIndependent;
147     }
148 
149     public void setDeviceIndependent(boolean isDeviceIndependent) {
150         this.isDeviceIndependent = isDeviceIndependent;
151     }
152 
153     /**
154      * Gets the current font.
155      * 
156      * @return current font
157      */
158     public Font getFont() {
159         return currentFont;
160     }
161 
162     /**
163      * Sets the current font.
164      * 
165      * @param font to be set
166      */
167     public void setFont(Font font) {
168     	if (font == null) return;
169     	
170         // FIXME: maybe add delayed setting
171         currentFont = font;
172     }
173 
174     public void drawSymbol(int x, int y, int size, int symbol) {
175 	drawSymbol((double) x, (double) y, (double) size, symbol);
176     }
177 
178     public void fillSymbol(int x, int y, int size, int symbol) {
179         fillSymbol((double) x, (double) y, (double) size, symbol);
180     }
181 
182     public void fillAndDrawSymbol(int x, int y, int size, int symbol,
183             Color fillColor) {
184         fillAndDrawSymbol((double) x, (double) y, (double) size, symbol,
185                 fillColor);
186     }
187 
188     public void drawSymbol(double x, double y, double size, int symbol) {
189         if (size <= 0)
190             return;
191         drawSymbol(this, x, y, size, symbol);
192     }
193 
194     protected void drawSymbol(VectorGraphics g, double x, double y,
195             double size, int symbol) {
196         switch (symbol) {
197         case SYMBOL_VLINE:
198         case SYMBOL_STAR:
199         case SYMBOL_HLINE:
200         case SYMBOL_PLUS:
201         case SYMBOL_CROSS:
202         case SYMBOL_BOX:
203         case SYMBOL_UP_TRIANGLE:
204         case SYMBOL_DN_TRIANGLE:
205         case SYMBOL_DIAMOND:
206             cachedShape.create(symbol, x, y, size);
207             g.draw(cachedShape);
208             break;
209 
210         case SYMBOL_CIRCLE: {
211             double diameter = Math.max(1, size);
212             diameter += (diameter % 2);
213             g.drawOval(x - diameter / 2, y - diameter / 2, diameter, diameter);
214             break;
215         }
216         }
217     }
218 
219     public void fillSymbol(double x, double y, double size, int symbol) {
220         if (size <= 0)
221             return;
222         fillSymbol(this, x, y, size, symbol);
223     }
224 
225     protected void fillSymbol(VectorGraphics g, double x, double y,
226             double size, int symbol) {
227         switch (symbol) {
228         case SYMBOL_VLINE:
229         case SYMBOL_STAR:
230         case SYMBOL_HLINE:
231         case SYMBOL_PLUS:
232         case SYMBOL_CROSS:
233             cachedShape.create(symbol, x, y, size);
234             g.draw(cachedShape);
235             break;
236 
237         case SYMBOL_BOX:
238         case SYMBOL_UP_TRIANGLE:
239         case SYMBOL_DN_TRIANGLE:
240         case SYMBOL_DIAMOND:
241             cachedShape.create(symbol, x, y, size);
242             g.fill(cachedShape);
243             break;
244 
245         case SYMBOL_CIRCLE: {
246             double diameter = Math.max(1, size);
247             diameter += (diameter % 2);
248             g.fillOval(x - diameter / 2, y - diameter / 2, diameter, diameter);
249             break;
250         }
251         }
252     }
253 
254     public void fillAndDrawSymbol(double x, double y, double size, int symbol,
255             Color fillColor) {
256         Color color = getColor();
257         setColor(fillColor);
258         fillSymbol(x, y, size, symbol);
259         setColor(color);
260         drawSymbol(x, y, size, symbol);
261     }
262 
263     public void fillAndDraw(Shape s, Color fillColor) {
264         Color color = getColor();
265         setColor(fillColor);
266         fill(s);
267         setColor(color);
268         draw(s);
269     }
270 
271     // ---------------------------------------------------------
272     // -------------------- WRAPPER METHODS --------------------
273     // -------------------- int -> double --------------------
274     // needs a bias in some cases
275     // ---------------------------------------------------------
276 
277     private static final double bias = 0.5;
278     
279     public void clearRect(int x, int y, int width, int height) {
280         clearRect((double) x + bias, (double) y + bias, (double) width, (double) height);
281     }
282 
283     public void drawLine(int x1, int y1, int x2, int y2) {
284         drawLine((double) x1 + bias, (double) y1 + bias, (double) x2 + bias, (double) y2 + bias);
285     }
286 
287     public void drawRect(int x, int y, int width, int height) {
288         drawRect((double) x + bias, (double) y + bias, (double) width, (double) height);
289     }
290 
291     public void fillRect(int x, int y, int width, int height) {
292         fillRect((double) x, (double) y, (double) width, (double) height);
293     }
294 
295     public void drawArc(int x, int y, int width, int height, int startAngle,
296             int arcAngle) {
297         drawArc((double) x + bias, (double) y + bias, (double) width, (double) height,
298                 (double) startAngle, (double) arcAngle);
299     }
300 
301     public void fillArc(int x, int y, int width, int height, int startAngle,
302             int arcAngle) {
303         fillArc((double) x, (double) y, (double) width, (double) height,
304                 (double) startAngle, (double) arcAngle);
305     }
306 
307     public void drawOval(int x, int y, int width, int height) {
308         drawOval((double) x + bias, (double) y + bias, (double) width, (double) height);
309     }
310 
311     public void fillOval(int x, int y, int width, int height) {
312         fillOval((double) x, (double) y, (double) width, (double) height);
313     }
314 
315     public void drawRoundRect(int x, int y, int width, int height,
316             int arcWidth, int arcHeight) {
317         drawRoundRect((double)x + bias, (double)y + bias, (double) width, (double) height, (double) arcWidth,
318                 (double) arcHeight);
319     }
320 
321     public void fillRoundRect(int x, int y, int width, int height,
322             int arcWidth, int arcHeight) {
323         fillRoundRect((double) x, (double) y, (double) width, (double) height,
324                 (double) arcWidth, (double) arcHeight);
325     }
326 
327     public void translate(int x, int y) {
328         translate((double) x, (double) y);
329     }
330 
331     /*--------------------------------------------------------------------------------
332      | 8.1. stroke/linewidth
333      *--------------------------------------------------------------------------------*/
334     public void setLineWidth(int width) {
335         setLineWidth((double) width);
336     }
337 
338     public void setLineWidth(double width) {
339         Stroke stroke = getStroke();
340         if (stroke instanceof BasicStroke) {
341             BasicStroke cs = (BasicStroke) stroke;
342             if (cs.getLineWidth() != width) {
343                 stroke = new BasicStroke((float) width, cs.getEndCap(), cs
344                         .getLineJoin(), cs.getMiterLimit(), cs.getDashArray(),
345                         cs.getDashPhase());
346                 setStroke(stroke);
347             }
348         } else {
349             stroke = new BasicStroke((float) width);
350             setStroke(stroke);
351         }
352     }
353 
354     public void drawString(String str, int x, int y) {
355         drawString(str, (double) x, (double) y);
356     }
357 
358     public void drawString(String s, float x, float y) {
359         drawString(s, (double) x, (double) y);
360     }
361 
362     public void drawString(AttributedCharacterIterator iterator, int x, int y) {
363         drawString(iterator, (float) x, (float) y);
364     }
365 
366     /**
367      * Draws frame and banner for a TextLayout, which is used for
368      * calculation auf ajustment
369      *
370      * @param tl TextLayout for frame calculation
371      * @param x coordinate to draw string
372      * @param y coordinate to draw string
373      * @param horizontal alignment of the text
374      * @param vertical alignment of the text
375      * @param framed true if text is surrounded by a frame
376      * @param frameColor color of the frame
377      * @param frameWidth witdh of the frame
378      * @param banner true if the frame is filled by a banner
379      * @param bannerColor color of the banner
380      * @return Offset for the string inside the frame
381      */
382     private Point2D drawFrameAndBanner(TextLayout tl, double x, double y, int horizontal,
383             int vertical, boolean framed, Color frameColor, double frameWidth,
384             boolean banner, Color bannerColor) {
385 
386         // calculate string bounds for alignment
387         Rectangle2D bounds = tl.getBounds();
388 
389         // calculate real bounds
390         bounds.setRect(
391             bounds.getX(),
392             bounds.getY(),
393             // care for Italic fonts too
394             Math.max(tl.getAdvance(), bounds.getWidth()),
395             bounds.getHeight());
396 
397         // add x and y
398         AffineTransform at = AffineTransform.getTranslateInstance(x, y);
399 
400         // horizontal alignment
401         if (horizontal == TEXT_RIGHT) {
402             at.translate(- bounds.getWidth(), 0);
403         } else if (horizontal == TEXT_CENTER) {
404             at.translate(- bounds.getWidth() / 2, 0);
405         }
406 
407         // vertical alignment
408         if (vertical == TEXT_BASELINE) {
409             // no translation needed
410         } else if (vertical == TEXT_TOP) {
411             at.translate(0, - bounds.getY());
412         } else if (vertical == TEXT_CENTER) {
413             // the following adds supersript ascent too,
414             // so it does not work
415             // at.translate(0, tl.getAscent() / 2);
416             // this is nearly the same
417             at.translate(0, tl.getDescent());
418         } else if (vertical == TEXT_BOTTOM) {
419             at.translate(0, - bounds.getHeight() - bounds.getY());
420         }
421 
422         // transform the bounds
423         bounds = at.createTransformedShape(bounds).getBounds2D();
424         // create the result with the same transformation
425         Point2D result = at.transform(new Point2D.Double(0, 0), new Point2D.Double());
426 
427         // space between string and border
428         double adjustment = (getFont().getSize2D() * 2) / 10;
429 
430         // add the adjustment
431         bounds.setRect(
432             bounds.getX() - adjustment,
433             bounds.getY() - adjustment,
434             bounds.getWidth() + 2 * adjustment,
435             bounds.getHeight() + 2 * adjustment);
436 
437         if (banner) {
438             Paint paint = getPaint();
439             setColor(bannerColor);
440             fill(bounds);
441             setPaint(paint);
442         }
443         if (framed) {
444             Paint paint = getPaint();
445             Stroke stroke = getStroke();
446             setColor(frameColor);
447             setLineWidth(frameWidth);
448             draw(bounds);
449             setPaint(paint);
450             setStroke(stroke);
451         }
452 
453         return result;
454     }
455 
456     /**
457      * Draws frame, banner and aligned text inside
458      *
459      * @param str text to be drawn
460      * @param x coordinate to draw string
461      * @param y coordinate to draw string
462      * @param horizontal alignment of the text
463      * @param vertical alignment of the text
464      * @param framed true if text is surrounded by a frame
465      * @param frameColor color of the frame
466      * @param frameWidth witdh of the frame
467      * @param banner true if the frame is filled by a banner
468      * @param bannerColor color of the banner
469      */
470     public void drawString(String str, double x, double y, int horizontal,
471             int vertical, boolean framed, Color frameColor, double frameWidth,
472             boolean banner, Color bannerColor) {
473 
474         // change the x offset for the next drawing
475         // FIXME: change y offset for vertical text
476         TextLayout tl = new TextLayout(
477             str,
478             FontUtilities.getAttributes(getFont()),
479             getFontRenderContext());
480 
481         // draw the frame
482         Point2D offset = drawFrameAndBanner(
483             tl, x, y, horizontal, vertical,
484             framed, frameColor, frameWidth, banner, bannerColor);
485 
486         // draw the string
487         drawString(str, offset.getX(), offset.getY());
488     }
489 
490     /**
491      * Draws the tagged string parsed by a {@link TagHandler} and adds a
492      * border specified by the parameters
493      *
494      * @param str Tagged text to be drawn
495      * @param x coordinate to draw string
496      * @param y coordinate to draw string
497      * @param horizontal alignment of the text
498      * @param vertical alignment of the text
499      * @param framed true if text is surrounded by a frame
500      * @param frameColor color of the frame
501      * @param frameWidth witdh of the frame
502      * @param banner true if the frame is filled by a banner
503      * @param bannerColor color of the banner
504      */
505     public void drawString(TagString str, double x, double y, int horizontal,
506             int vertical, boolean framed, Color frameColor, double frameWidth,
507             boolean banner, Color bannerColor) {
508 
509 		GenericTagHandler tagHandler = new GenericTagHandler(this);
510 		TextLayout tl = tagHandler.createTextLayout(str, getFont().getSize2D() / 7.5);
511 
512         // draw the frame
513         Point2D offset = drawFrameAndBanner(
514             tl, x, y, horizontal, vertical,
515             framed, frameColor, frameWidth, banner, bannerColor);
516 
517         // FIXME: not quite clear why correction is needed
518         // see {@link GenericTagHandler#superscriptCorrection
519         tagHandler.print(str, offset.getX(), offset.getY(), getFont().getSize2D() / 7.5);
520     }
521 
522     // ------------------ other wrapper methods ----------------
523 
524     public void drawString(String str, double x, double y, int horizontal,
525             int vertical) {
526         drawString(str, x, y, horizontal, vertical, false, null, 0, false, null);
527     }
528 
529     public void drawString(TagString str, double x, double y) {
530         drawString(str, x, y, TEXT_LEFT, TEXT_BASELINE);
531     }
532 
533     public void drawString(TagString str, double x, double y, int horizontal,
534             int vertical) {
535         drawString(str, x, y, horizontal, vertical, false, null, 0, false, null);
536     }
537 
538     /* 8.2. paint/color */
539     public int getColorMode() {
540         return colorMode;
541     }
542 
543     public void setColorMode(int colorMode) {
544         this.colorMode = colorMode;
545     }
546 
547     /**
548      * Gets the background color.
549      * 
550      * @return background color
551      */
552     public Color getBackground() {
553         return backgroundColor;
554     }
555 
556     /**
557      * Sets the background color.
558      * 
559      * @param color background color to be set
560      */
561     public void setBackground(Color color) {
562         backgroundColor = color;
563     }
564 
565     /**
566      * Sets the current color and the current paint. Calls writePaint(Color).
567      * 
568      * @param color to be set
569      */
570     public void setColor(Color color) {
571     	if (color == null) return;
572     	
573         currentColor = color;
574         currentPaint = color;
575     }
576 
577     /**
578      * Gets the current color.
579      * 
580      * @return the current color
581      */
582     public Color getColor() {
583         return currentColor;
584     }
585 
586     /**
587      * Sets the current paint.
588      * 
589      * @param paint to be set
590      */
591     public void setPaint(Paint paint) {
592     	if (paint == null) return;
593     	
594         if (!(paint instanceof Color))
595             currentColor = null;
596         currentPaint = paint;
597     }
598 
599     /**
600      * Gets the current paint.
601      * 
602      * @return paint current paint
603      */
604     public Paint getPaint() {
605         return currentPaint;
606     }
607 
608     /**
609      * Returns a printColor created from the original printColor, based on the
610      * ColorMode. If you run getPrintColor on it again you still get the same
611      * color, so that it does not matter if you convert it more than once.
612      */
613     protected Color getPrintColor(Color color) {
614         // shortcut if mode is COLOR for speed
615         if (colorMode == PrintColor.COLOR)
616             return color;
617 
618         // otherwise...
619         PrintColor printColor = PrintColor.createPrintColor(color);
620         return printColor.getColor(colorMode);
621     }
622 
623     public void rotate(double theta, double x, double y) {
624         translate(x, y);
625         rotate(theta);
626         translate(-x, -y);
627     }
628 
629     public void drawArc(double x, double y, double width, double height,
630             double startAngle, double arcAngle) {
631         draw(new Arc2D.Double(x, y, width, height, startAngle, arcAngle,
632                 Arc2D.OPEN));
633     }
634 
635     public void drawLine(double x1, double y1, double x2, double y2) {
636         draw(new Line2D.Double(x1, y1, x2, y2));
637     }
638 
639     public void drawOval(double x, double y, double width, double height) {
640         draw(new Ellipse2D.Double(x, y, width, height));
641     }
642 
643     public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {
644         draw(createShape(xPoints, yPoints, nPoints, false, true));
645     }
646 
647     public void drawPolyline(double[] xPoints, double[] yPoints, int nPoints) {
648         draw(createShape(xPoints, yPoints, nPoints, false));
649     }
650 
651     public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {
652         draw(createShape(xPoints, yPoints, nPoints, true, true));
653     }
654 
655     public void drawPolygon(double[] xPoints, double[] yPoints, int nPoints) {
656         draw(createShape(xPoints, yPoints, nPoints, true));
657     }
658 
659     public void drawRect(double x, double y, double width, double height) {
660         draw(new Rectangle2D.Double(x, y, width, height));
661     }
662 
663     public void drawRoundRect(double x, double y, double width, double height,
664             double arcWidth, double arcHeight) {
665         draw(new RoundRectangle2D.Double(x, y, width, height, arcWidth,
666                 arcHeight));
667     }
668 
669     public void fillArc(double x, double y, double width, double height,
670             double startAngle, double arcAngle) {
671         fill(new Arc2D.Double(x, y, width, height, startAngle, arcAngle,
672                 Arc2D.PIE));
673     }
674 
675     public void fillOval(double x, double y, double width, double height) {
676         fill(new Ellipse2D.Double(x, y, width, height));
677     }
678 
679     public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
680         fill(createShape(xPoints, yPoints, nPoints, true, false));
681     }
682 
683     public void fillPolygon(double[] xPoints, double[] yPoints, int nPoints) {
684         fill(createShape(xPoints, yPoints, nPoints, true));
685     }
686 
687     public void fillRect(double x, double y, double width, double height) {
688         fill(new Rectangle2D.Double(x, y, width, height));
689     }
690 
691     public void fillRoundRect(double x, double y, double width, double height,
692             double arcWidth, double arcHeight) {
693         fill(new RoundRectangle2D.Double(x, y, width, height, arcWidth,
694                 arcHeight));
695     }
696 
697     /**
698      * Creates a polyline/polygon shape from a set of points. Needs to be
699      * defined in subclass because its implementations could be device specific
700      * 
701      * @param xPoints X coordinates of the polyline.
702      * @param yPoints Y coordinates of the polyline.
703      * @param nPoints number of points of the polyline.
704      * @param close is shape closed
705      */
706     protected abstract Shape createShape(double[] xPoints, double[] yPoints,
707             int nPoints, boolean close);
708 
709     /**
710      * Creates a polyline/polygon shape from a set of points.
711      * Needs a bias!
712      * 
713      * @param xPoints X coordinates of the polyline.
714      * @param yPoints Y coordinates of the polyline.
715      * @param nPoints number of points of the polyline.
716      * @param close is shape closed
717      */
718     protected Shape createShape(int[] xPoints, int[] yPoints, int nPoints,
719             boolean close, boolean biased) {
720         
721         float offset = biased ? (float)bias : 0.0f;
722         GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
723         if (nPoints > 0) {
724             path.moveTo(xPoints[0] + offset, yPoints[0] + offset);
725             int lastX = xPoints[0];
726             int lastY = yPoints[0];
727             if (close && (Math.abs(xPoints[nPoints - 1] - lastX) < 1)
728                     && (Math.abs(yPoints[nPoints - 1] - lastY) < 1)) {
729                 nPoints--;
730             }
731             for (int i = 1; i < nPoints; i++) {
732                 if ((Math.abs(xPoints[i] - lastX) > 1)
733                         || (Math.abs(yPoints[i] - lastY) > 1)) {
734                     path.lineTo(xPoints[i] + offset, yPoints[i] + offset);
735                     lastX = xPoints[i];
736                     lastY = yPoints[i];
737                 }
738             }
739             if (close)
740                 path.closePath();
741         }
742         return path;
743     }
744 
745     /**
746      * Checks whether or not the specified <code>Shape</code> intersects
747      * the specified {@link Rectangle}, which is in device
748      * space.
749      *
750      * @param rect the area in device space to check for a hit
751      * @param s the <code>Shape</code> to check for a hit
752      * @param onStroke flag used to choose between testing the stroked or the filled shape.
753      * @see java.awt.Graphics2D#hit(Rectangle, Shape, boolean)
754      */
755     public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
756         if (onStroke && getStroke() != null) {
757             s = getStroke().createStrokedShape(s);
758         }
759 
760         if (getTransform() != null) {
761             s = getTransform().createTransformedShape(s);
762         }
763 
764         Area area = new Area(s);
765         if (getClip() != null) {
766             area.intersect(new Area(getClip()));
767         }
768 
769         return area.intersects(rect);
770     }
771 }