857 }
858
859 public FontMetrics getFontMetrics(Font font) {
860 if ((this.fontMetrics != null) && (font == this.font)) {
861 return this.fontMetrics;
862 }
863 FontMetrics fm =
864 FontDesignMetrics.getMetrics(font, getFontRenderContext());
865
866 if (this.font == font) {
867 this.fontMetrics = fm;
868 }
869 return fm;
870 }
871
872 /**
873 * Checks to see if a Path intersects the specified Rectangle in device
874 * space. The rendering attributes taken into account include the
875 * clip, transform, and stroke attributes.
876 * @param rect The area in device space to check for a hit.
877 * @param p The path to check for a hit.
878 * @param onStroke Flag to choose between testing the stroked or
879 * the filled path.
880 * @return True if there is a hit, false otherwise.
881 * @see #setStroke
882 * @see #fillPath
883 * @see #drawPath
884 * @see #transform
885 * @see #setTransform
886 * @see #clip
887 * @see #setClip
888 */
889 public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
890 if (onStroke) {
891 s = stroke.createStrokedShape(s);
892 }
893
894 s = transformShape(s);
895 if ((constrainX|constrainY) != 0) {
896 rect = new Rectangle(rect);
897 rect.translate(constrainX, constrainY);
898 }
899
900 return s.intersects(rect);
901 }
902
903 /**
1278 validFontInfo = false;
1279 this.glyphVectorFontInfo = null;
1280 }
1281 }
1282 if (hints != null) {
1283 hints.put(hintKey, hintValue);
1284 }
1285 return;
1286 }
1287 }
1288 // Nothing we recognize so none of "our state" has changed
1289 if (hints == null) {
1290 hints = makeHints(null);
1291 }
1292 hints.put(hintKey, hintValue);
1293 }
1294
1295
1296 /**
1297 * Returns the preferences for the rendering algorithms.
1298 * @param hintCategory The category of hint to be set. The strings
1299 * are defined in the RenderingHints class.
1300 * @return The preferences for rendering algorithms. The strings
1301 * are defined in the RenderingHints class.
1302 * @see RenderingHints
1303 */
1304 public Object getRenderingHint(Key hintKey) {
1305 if (hints != null) {
1306 return hints.get(hintKey);
1307 }
1308 if (!(hintKey instanceof SunHints.Key)) {
1309 return null;
1310 }
1311 int keyindex = ((SunHints.Key)hintKey).getIndex();
1312 switch (keyindex) {
1313 case SunHints.INTKEY_RENDERING:
1314 return SunHints.Value.get(SunHints.INTKEY_RENDERING,
1315 renderHint);
1316 case SunHints.INTKEY_ANTIALIASING:
1317 return SunHints.Value.get(SunHints.INTKEY_ANTIALIASING,
1318 antialiasHint);
1560 * @param shy The factor by which coordinates are shifted towards the
1561 * positive Y axis direction according to their X coordinate
1562 */
1563 public void shear(double shx, double shy) {
1564 transform.shear(shx, shy);
1565 invalidateTransform();
1566 }
1567
1568 /**
1569 * Composes a Transform object with the transform in this
1570 * Graphics2D according to the rule last-specified-first-applied.
1571 * If the currrent transform is Cx, the result of composition
1572 * with Tx is a new transform Cx'. Cx' becomes the current
1573 * transform for this Graphics2D.
1574 * Transforming a point p by the updated transform Cx' is
1575 * equivalent to first transforming p by Tx and then transforming
1576 * the result by the original transform Cx. In other words,
1577 * Cx'(p) = Cx(Tx(p)).
1578 * A copy of the Tx is made, if necessary, so further
1579 * modifications to Tx do not affect rendering.
1580 * @param Tx The Transform object to be composed with the current
1581 * transform.
1582 * @see #setTransform
1583 * @see AffineTransform
1584 */
1585 public void transform(AffineTransform xform) {
1586 this.transform.concatenate(xform);
1587 invalidateTransform();
1588 }
1589
1590 /**
1591 * Translate
1592 */
1593 public void translate(int x, int y) {
1594 transform.translate(x, y);
1595 if (transformState <= TRANSFORM_INT_TRANSLATE) {
1596 transX += x;
1597 transY += y;
1598 transformState = (((transX | transY) == 0) ?
1599 TRANSFORM_ISIDENT : TRANSFORM_INT_TRANSLATE);
1600 } else {
1601 invalidateTransform();
1602 }
1603 }
1604
1605 /**
1606 * Sets the Transform in the current graphics state.
1607 * @param Tx The Transform object to be used in the rendering process.
1608 * @see #transform
1609 * @see TransformChain
1610 * @see AffineTransform
1611 */
1612 @Override
1613 public void setTransform(AffineTransform Tx) {
1614 if ((constrainX | constrainY) == 0) {
1615 transform.setTransform(Tx);
1616 } else {
1617 transform.setToTranslation(constrainX, constrainY);
1618 transform.concatenate(Tx);
1619 }
1620 invalidateTransform();
1621 }
1622
1623 protected void invalidateTransform() {
1624 int type = transform.getType();
1625 int origTransformState = transformState;
1626 if (type == AffineTransform.TYPE_IDENTITY) {
1627 transformState = TRANSFORM_ISIDENT;
1628 transX = transY = 0;
1629 } else if (type == AffineTransform.TYPE_TRANSLATION) {
1772 }
1773 paintState = PAINT_ALPHACOLOR;
1774 if (imageComp == CompositeType.SrcOverNoEa) {
1775 // special case where compState depends on opacity of paint
1776 compositeState = COMP_ALPHA;
1777 }
1778 }
1779 validFontInfo = false;
1780 invalidatePipe();
1781 }
1782
1783 /**
1784 * Sets the background color in this context used for clearing a region.
1785 * When Graphics2D is constructed for a component, the backgroung color is
1786 * inherited from the component. Setting the background color in the
1787 * Graphics2D context only affects the subsequent clearRect() calls and
1788 * not the background color of the component. To change the background
1789 * of the component, use appropriate methods of the component.
1790 * @param color The background color that should be used in
1791 * subsequent calls to clearRect().
1792 * @see getBackground
1793 * @see Graphics.clearRect()
1794 */
1795 public void setBackground(Color color) {
1796 backgroundColor = color;
1797 }
1798
1799 /**
1800 * Returns the background color used for clearing a region.
1801 * @see setBackground
1802 */
1803 public Color getBackground() {
1804 return backgroundColor;
1805 }
1806
1807 /**
1808 * Returns the current Stroke in the Graphics2D state.
1809 * @see setStroke
1810 */
1811 public Stroke getStroke() {
1812 return stroke;
1813 }
1814
1815 public Rectangle getClipBounds() {
1816 if (clipState == CLIP_DEVICE) {
1817 return null;
1818 }
1819 return getClipBounds(new Rectangle());
1820 }
1821
1822 public Rectangle getClipBounds(Rectangle r) {
1823 if (clipState != CLIP_DEVICE) {
1824 if (transformState <= TRANSFORM_INT_TRANSLATE) {
1825 if (usrClip instanceof Rectangle) {
1826 r.setBounds((Rectangle) usrClip);
1827 } else {
1828 r.setFrame(usrClip.getBounds2D());
1829 }
2039
2040 public void setClip(int x, int y, int w, int h) {
2041 setClip(new Rectangle(x, y, w, h));
2042 }
2043
2044 public Shape getClip() {
2045 return untransformShape(usrClip);
2046 }
2047
2048 public void setClip(Shape sh) {
2049 usrClip = transformShape(sh);
2050 validateCompClip();
2051 }
2052
2053 /**
2054 * Intersects the current clip with the specified Path and sets the
2055 * current clip to the resulting intersection. The clip is transformed
2056 * with the current transform in the Graphics2D state before being
2057 * intersected with the current clip. This method is used to make the
2058 * current clip smaller. To make the clip larger, use any setClip method.
2059 * @param p The Path to be intersected with the current clip.
2060 */
2061 public void clip(Shape s) {
2062 s = transformShape(s);
2063 if (usrClip != null) {
2064 s = intersectShapes(usrClip, s, true, true);
2065 }
2066 usrClip = s;
2067 validateCompClip();
2068 }
2069
2070 public void setPaintMode() {
2071 setComposite(AlphaComposite.SrcOver);
2072 }
2073
2074 public void setXORMode(Color c) {
2075 if (c == null) {
2076 throw new IllegalArgumentException("null XORColor");
2077 }
2078 setComposite(new XORComposite(c, surfaceData));
2079 }
2466 // surfaceData.unlock();
2467 }
2468 }
2469
2470 public void clearRect(int x, int y, int w, int h) {
2471 // REMIND: has some "interesting" consequences if threads are
2472 // not synchronized
2473 Composite c = composite;
2474 Paint p = paint;
2475 setComposite(AlphaComposite.Src);
2476 setColor(getBackground());
2477 fillRect(x, y, w, h);
2478 setPaint(p);
2479 setComposite(c);
2480 }
2481
2482 /**
2483 * Strokes the outline of a Path using the settings of the current
2484 * graphics state. The rendering attributes applied include the
2485 * clip, transform, paint or color, composite and stroke attributes.
2486 * @param p The path to be drawn.
2487 * @see #setStroke
2488 * @see #setPaint
2489 * @see java.awt.Graphics#setColor
2490 * @see #transform
2491 * @see #setTransform
2492 * @see #clip
2493 * @see #setClip
2494 * @see #setComposite
2495 */
2496 public void draw(Shape s) {
2497 try {
2498 shapepipe.draw(this, s);
2499 } catch (InvalidPipeException e) {
2500 try {
2501 revalidateAll();
2502 shapepipe.draw(this, s);
2503 } catch (InvalidPipeException e2) {
2504 // Still catching the exception; we are not yet ready to
2505 // validate the surfaceData correctly. Fail for now and
2506 // try again next time around.
|
857 }
858
859 public FontMetrics getFontMetrics(Font font) {
860 if ((this.fontMetrics != null) && (font == this.font)) {
861 return this.fontMetrics;
862 }
863 FontMetrics fm =
864 FontDesignMetrics.getMetrics(font, getFontRenderContext());
865
866 if (this.font == font) {
867 this.fontMetrics = fm;
868 }
869 return fm;
870 }
871
872 /**
873 * Checks to see if a Path intersects the specified Rectangle in device
874 * space. The rendering attributes taken into account include the
875 * clip, transform, and stroke attributes.
876 * @param rect The area in device space to check for a hit.
877 * @param s The path to check for a hit.
878 * @param onStroke Flag to choose between testing the stroked or
879 * the filled path.
880 * @return True if there is a hit, false otherwise.
881 * @see #setStroke
882 * @see #fill(Shape)
883 * @see #draw(Shape)
884 * @see #transform
885 * @see #setTransform
886 * @see #clip
887 * @see #setClip
888 */
889 public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
890 if (onStroke) {
891 s = stroke.createStrokedShape(s);
892 }
893
894 s = transformShape(s);
895 if ((constrainX|constrainY) != 0) {
896 rect = new Rectangle(rect);
897 rect.translate(constrainX, constrainY);
898 }
899
900 return s.intersects(rect);
901 }
902
903 /**
1278 validFontInfo = false;
1279 this.glyphVectorFontInfo = null;
1280 }
1281 }
1282 if (hints != null) {
1283 hints.put(hintKey, hintValue);
1284 }
1285 return;
1286 }
1287 }
1288 // Nothing we recognize so none of "our state" has changed
1289 if (hints == null) {
1290 hints = makeHints(null);
1291 }
1292 hints.put(hintKey, hintValue);
1293 }
1294
1295
1296 /**
1297 * Returns the preferences for the rendering algorithms.
1298 * @param hintKey The category of hint to be set. The strings
1299 * are defined in the RenderingHints class.
1300 * @return The preferences for rendering algorithms. The strings
1301 * are defined in the RenderingHints class.
1302 * @see RenderingHints
1303 */
1304 public Object getRenderingHint(Key hintKey) {
1305 if (hints != null) {
1306 return hints.get(hintKey);
1307 }
1308 if (!(hintKey instanceof SunHints.Key)) {
1309 return null;
1310 }
1311 int keyindex = ((SunHints.Key)hintKey).getIndex();
1312 switch (keyindex) {
1313 case SunHints.INTKEY_RENDERING:
1314 return SunHints.Value.get(SunHints.INTKEY_RENDERING,
1315 renderHint);
1316 case SunHints.INTKEY_ANTIALIASING:
1317 return SunHints.Value.get(SunHints.INTKEY_ANTIALIASING,
1318 antialiasHint);
1560 * @param shy The factor by which coordinates are shifted towards the
1561 * positive Y axis direction according to their X coordinate
1562 */
1563 public void shear(double shx, double shy) {
1564 transform.shear(shx, shy);
1565 invalidateTransform();
1566 }
1567
1568 /**
1569 * Composes a Transform object with the transform in this
1570 * Graphics2D according to the rule last-specified-first-applied.
1571 * If the currrent transform is Cx, the result of composition
1572 * with Tx is a new transform Cx'. Cx' becomes the current
1573 * transform for this Graphics2D.
1574 * Transforming a point p by the updated transform Cx' is
1575 * equivalent to first transforming p by Tx and then transforming
1576 * the result by the original transform Cx. In other words,
1577 * Cx'(p) = Cx(Tx(p)).
1578 * A copy of the Tx is made, if necessary, so further
1579 * modifications to Tx do not affect rendering.
1580 * @param xform The Transform object to be composed with the current
1581 * transform.
1582 * @see #setTransform
1583 * @see AffineTransform
1584 */
1585 public void transform(AffineTransform xform) {
1586 this.transform.concatenate(xform);
1587 invalidateTransform();
1588 }
1589
1590 /**
1591 * Translate
1592 */
1593 public void translate(int x, int y) {
1594 transform.translate(x, y);
1595 if (transformState <= TRANSFORM_INT_TRANSLATE) {
1596 transX += x;
1597 transY += y;
1598 transformState = (((transX | transY) == 0) ?
1599 TRANSFORM_ISIDENT : TRANSFORM_INT_TRANSLATE);
1600 } else {
1601 invalidateTransform();
1602 }
1603 }
1604
1605 /**
1606 * Sets the Transform in the current graphics state.
1607 * @param Tx The Transform object to be used in the rendering process.
1608 * @see #transform
1609 * @see AffineTransform
1610 */
1611 @Override
1612 public void setTransform(AffineTransform Tx) {
1613 if ((constrainX | constrainY) == 0) {
1614 transform.setTransform(Tx);
1615 } else {
1616 transform.setToTranslation(constrainX, constrainY);
1617 transform.concatenate(Tx);
1618 }
1619 invalidateTransform();
1620 }
1621
1622 protected void invalidateTransform() {
1623 int type = transform.getType();
1624 int origTransformState = transformState;
1625 if (type == AffineTransform.TYPE_IDENTITY) {
1626 transformState = TRANSFORM_ISIDENT;
1627 transX = transY = 0;
1628 } else if (type == AffineTransform.TYPE_TRANSLATION) {
1771 }
1772 paintState = PAINT_ALPHACOLOR;
1773 if (imageComp == CompositeType.SrcOverNoEa) {
1774 // special case where compState depends on opacity of paint
1775 compositeState = COMP_ALPHA;
1776 }
1777 }
1778 validFontInfo = false;
1779 invalidatePipe();
1780 }
1781
1782 /**
1783 * Sets the background color in this context used for clearing a region.
1784 * When Graphics2D is constructed for a component, the backgroung color is
1785 * inherited from the component. Setting the background color in the
1786 * Graphics2D context only affects the subsequent clearRect() calls and
1787 * not the background color of the component. To change the background
1788 * of the component, use appropriate methods of the component.
1789 * @param color The background color that should be used in
1790 * subsequent calls to clearRect().
1791 * @see #getBackground
1792 * @see Graphics#clearRect
1793 */
1794 public void setBackground(Color color) {
1795 backgroundColor = color;
1796 }
1797
1798 /**
1799 * Returns the background color used for clearing a region.
1800 * @see #setBackground
1801 */
1802 public Color getBackground() {
1803 return backgroundColor;
1804 }
1805
1806 /**
1807 * Returns the current Stroke in the Graphics2D state.
1808 * @see #setStroke
1809 */
1810 public Stroke getStroke() {
1811 return stroke;
1812 }
1813
1814 public Rectangle getClipBounds() {
1815 if (clipState == CLIP_DEVICE) {
1816 return null;
1817 }
1818 return getClipBounds(new Rectangle());
1819 }
1820
1821 public Rectangle getClipBounds(Rectangle r) {
1822 if (clipState != CLIP_DEVICE) {
1823 if (transformState <= TRANSFORM_INT_TRANSLATE) {
1824 if (usrClip instanceof Rectangle) {
1825 r.setBounds((Rectangle) usrClip);
1826 } else {
1827 r.setFrame(usrClip.getBounds2D());
1828 }
2038
2039 public void setClip(int x, int y, int w, int h) {
2040 setClip(new Rectangle(x, y, w, h));
2041 }
2042
2043 public Shape getClip() {
2044 return untransformShape(usrClip);
2045 }
2046
2047 public void setClip(Shape sh) {
2048 usrClip = transformShape(sh);
2049 validateCompClip();
2050 }
2051
2052 /**
2053 * Intersects the current clip with the specified Path and sets the
2054 * current clip to the resulting intersection. The clip is transformed
2055 * with the current transform in the Graphics2D state before being
2056 * intersected with the current clip. This method is used to make the
2057 * current clip smaller. To make the clip larger, use any setClip method.
2058 * @param s The Path to be intersected with the current clip.
2059 */
2060 public void clip(Shape s) {
2061 s = transformShape(s);
2062 if (usrClip != null) {
2063 s = intersectShapes(usrClip, s, true, true);
2064 }
2065 usrClip = s;
2066 validateCompClip();
2067 }
2068
2069 public void setPaintMode() {
2070 setComposite(AlphaComposite.SrcOver);
2071 }
2072
2073 public void setXORMode(Color c) {
2074 if (c == null) {
2075 throw new IllegalArgumentException("null XORColor");
2076 }
2077 setComposite(new XORComposite(c, surfaceData));
2078 }
2465 // surfaceData.unlock();
2466 }
2467 }
2468
2469 public void clearRect(int x, int y, int w, int h) {
2470 // REMIND: has some "interesting" consequences if threads are
2471 // not synchronized
2472 Composite c = composite;
2473 Paint p = paint;
2474 setComposite(AlphaComposite.Src);
2475 setColor(getBackground());
2476 fillRect(x, y, w, h);
2477 setPaint(p);
2478 setComposite(c);
2479 }
2480
2481 /**
2482 * Strokes the outline of a Path using the settings of the current
2483 * graphics state. The rendering attributes applied include the
2484 * clip, transform, paint or color, composite and stroke attributes.
2485 * @param s The path to be drawn.
2486 * @see #setStroke
2487 * @see #setPaint
2488 * @see java.awt.Graphics#setColor
2489 * @see #transform
2490 * @see #setTransform
2491 * @see #clip
2492 * @see #setClip
2493 * @see #setComposite
2494 */
2495 public void draw(Shape s) {
2496 try {
2497 shapepipe.draw(this, s);
2498 } catch (InvalidPipeException e) {
2499 try {
2500 revalidateAll();
2501 shapepipe.draw(this, s);
2502 } catch (InvalidPipeException e2) {
2503 // Still catching the exception; we are not yet ready to
2504 // validate the surfaceData correctly. Fail for now and
2505 // try again next time around.
|