You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-dev@xmlgraphics.apache.org by vh...@apache.org on 2002/11/18 12:47:14 UTC
cvs commit: xml-batik/samples/tests/spec/interactivity cursor4.svg
vhardy 2002/11/18 03:47:14
Modified: sources/org/apache/batik/bridge CursorManager.java
ViewBox.java
samples/tests/spec/interactivity cursor4.svg
Added: samples/tests/resources/images svgCursor2.svg svgCursor3.svg
svgCursor4.svg
Log:
Added support for SVG cursors. The <cursor> element can now reference
SVG images.
Revision Changes Path
1.6 +180 -77 xml-batik/sources/org/apache/batik/bridge/CursorManager.java
Index: CursorManager.java
===================================================================
RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/CursorManager.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- CursorManager.java 15 Nov 2002 18:44:52 -0000 1.5
+++ CursorManager.java 18 Nov 2002 11:47:14 -0000 1.6
@@ -16,6 +16,7 @@
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.RenderedImage;
@@ -27,8 +28,13 @@
import java.lang.ref.SoftReference;
import org.apache.batik.ext.awt.image.GraphicsUtil;
+import org.apache.batik.ext.awt.image.PadMode;
import org.apache.batik.ext.awt.image.spi.ImageTagRegistry;
import org.apache.batik.ext.awt.image.renderable.Filter;
+import org.apache.batik.ext.awt.image.renderable.AffineRable8Bit;
+import org.apache.batik.ext.awt.image.renderable.PadRable8Bit;
+
+import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.css.engine.SVGCSSEngine;
import org.apache.batik.css.engine.value.ListValue;
@@ -42,8 +48,11 @@
import org.apache.batik.util.SoftReferenceCache;
import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.css.CSSPrimitiveValue;
import org.w3c.dom.css.CSSValue;
+import org.w3c.dom.svg.SVGPreserveAspectRatio;
/**
@@ -78,6 +87,12 @@
= Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR);
/**
+ * Default preferred cursor size, used for SVG images
+ */
+ public static final int DEFAULT_PREFERRED_WIDTH = 32;
+ public static final int DEFAULT_PREFERRED_HEIGHT = 32;
+
+ /**
* Static initialization of the cursorMap
*/
static {
@@ -307,6 +322,11 @@
// One of the cursor url resolved to a <cursor> element
// Try to handle its image.
String uriStr = XLinkSupport.getXLinkHref(cursorElement);
+ if (uriStr.length() == 0) {
+ throw new BridgeException(cursorElement, ERR_ATTRIBUTE_MISSING,
+ new Object[] {"xlink:href"});
+ }
+
String baseURI = XMLBaseSupport.getCascadedXMLBase(cursorElement);
ParsedURL purl;
if (baseURI == null) {
@@ -337,103 +357,56 @@
CursorDescriptor desc = new CursorDescriptor(purl, x, y);
+ //
// Check if there is a cursor in the cache for this url
+ //
Cursor cachedCursor = cursorCache.getCursor(desc);
if (cachedCursor != null) {
return cachedCursor;
}
- ImageTagRegistry reg = ImageTagRegistry.getRegistry();
- Filter f = reg.readURL(purl);
-
-
- //
- // Check if we got a broken image
- //
- if (f.getProperty
- (SVGBrokenLinkProvider.SVG_BROKEN_LINK_DOCUMENT_PROPERTY) != null) {
- cursorCache.clearCursor(desc);
- return null;
- }
-
//
- // Now, get the preferred cursor dimension
+ // Load image into Filter f and transform hotSpot to
+ // cursor space.
//
- Rectangle preferredSize = f.getBounds2D().getBounds();
- if (preferredSize == null || preferredSize.width <=0
- || preferredSize.height <=0 ) {
+ Point2D.Float hotSpot = new Point2D.Float(x, y);
+ Filter f = cursorHrefToFilter(cursorElement,
+ purl,
+ hotSpot);
+ if (f == null) {
cursorCache.clearCursor(desc);
return null;
}
-
- Dimension cursorSize
- = Toolkit.getDefaultToolkit().getBestCursorSize
- (preferredSize.width, preferredSize.height);
-
- //
- // Fit the rendered image into the cursor image
- // size and aspect ratio if it does not fit into
- // the cursorSize area. Otherwise, draw the cursor
- // into an image the size of the preferred cursor
- // size.
- //
- Image bi = null;
-
- if (cursorSize.width < preferredSize.width
- ||
- cursorSize.height < preferredSize.height) {
- float rw = cursorSize.width;
- float rh = (cursorSize.width * preferredSize.height) / (float)preferredSize.width;
-
- if (rh > cursorSize.height) {
- rw *= (cursorSize.height / rh);
- rh = cursorSize.height;
- }
- RenderedImage ri = f.createScaledRendering((int)Math.round(rw),
- (int)Math.round(rh),
- null);
-
- if (ri instanceof Image) {
- bi = (Image)ri;
- } else {
- bi = renderedImageToImage(ri);
- }
-
- // Apply the scale transform that is applied to the image
- x *= rw/preferredSize.width;
- y *= rh/preferredSize.height;
+ // The returned Filter is guaranteed to create a
+ // default rendering of the desired size
+ Rectangle cursorSize = f.getBounds2D().getBounds();
+ RenderedImage ri = f.createScaledRendering(cursorSize.width,
+ cursorSize.height,
+ null);
+ Image img = null;
+ if (ri instanceof Image) {
+ img = (Image)ri;
} else {
- // Preferred size fits into ideal cursor size. No resize,
- // just draw cursor in 0, 0.
- BufferedImage tbi = new BufferedImage(cursorSize.width,
- cursorSize.height,
- BufferedImage.TYPE_INT_ARGB);
- RenderedImage ri = f.createScaledRendering(preferredSize.width,
- preferredSize.height,
- null);
- Graphics2D g = GraphicsUtil.createGraphics(tbi);
- GraphicsUtil.drawImage(g, ri);
- g.dispose();
- bi = tbi;
+ img = renderedImageToImage(ri);
}
// Make sure the not spot does not fall out of the cursor area. If it
// does, then clamp the coordinates to the image space.
- x = x < 0 ? 0 : x;
- y = y < 0 ? 0 : y;
- x = x > (cursorSize.width-1) ? cursorSize.width - 1 : x;
- y = y > (cursorSize.height-1) ? cursorSize.height - 1: y;
+ hotSpot.x = hotSpot.x < 0 ? 0 : hotSpot.x;
+ hotSpot.y = hotSpot.y < 0 ? 0 : hotSpot.y;
+ hotSpot.x = hotSpot.x > (cursorSize.width-1) ? cursorSize.width - 1 : hotSpot.x;
+ hotSpot.y = hotSpot.y > (cursorSize.height-1) ? cursorSize.height - 1: hotSpot.y;
//
- // The cursor image is now into the bi image
+ // The cursor image is now into 'img'
//
Cursor c = Toolkit.getDefaultToolkit()
- .createCustomCursor(bi,
- new Point((int)Math.round(x),
- (int)Math.round(y)),
+ .createCustomCursor(img,
+ new Point((int)Math.round(hotSpot.x),
+ (int)Math.round(hotSpot.y)),
purl.toString());
cursorCache.putCursor(desc, c);
@@ -441,6 +414,138 @@
}
/**
+ * Converts the input ParsedURL into a Filter and transforms the
+ * input hotSpot point (in image space) to cursor space
+ */
+ protected Filter cursorHrefToFilter(Element cursorElement,
+ ParsedURL purl,
+ Point2D hotSpot) {
+
+ AffineRable8Bit f = null;
+ String uriStr = purl.toString();
+ Dimension cursorSize = null;
+
+ // Try to load as an SVG Document
+ DocumentLoader loader = (DocumentLoader)ctx.getDocumentLoader();
+ SVGDocument svgDoc = (SVGDocument)cursorElement.getOwnerDocument();
+ URIResolver resolver = new URIResolver(svgDoc, loader);
+ try {
+ Element rootElement = null;
+ Node n = resolver.getNode(uriStr, cursorElement);
+ if (n.getNodeType() == n.DOCUMENT_NODE) {
+ rootElement = ((SVGDocument)n).getRootElement();
+ } else {
+ throw new BridgeException
+ (cursorElement, ERR_URI_IMAGE_INVALID,
+ new Object[] {uriStr});
+ }
+ GraphicsNode node = ctx.getGVTBuilder().build(ctx, rootElement);
+
+ //
+ // The cursorSize define the viewport into which the
+ // cursor is displayed. That viewport is platform
+ // dependant and is not defined by the SVG content.
+ //
+ float width = DEFAULT_PREFERRED_WIDTH;
+ float height = DEFAULT_PREFERRED_HEIGHT;
+ UnitProcessor.Context uctx
+ = UnitProcessor.createContext(ctx, rootElement);
+
+ String s = rootElement.getAttribute(SVG_WIDTH_ATTRIBUTE);
+ if (s.length() != 0) {
+ width = UnitProcessor.svgHorizontalLengthToUserSpace
+ (s, SVG_WIDTH_ATTRIBUTE, uctx);
+ }
+
+ s = rootElement.getAttribute(SVG_HEIGHT_ATTRIBUTE);
+ if (s.length() != 0) {
+ height = UnitProcessor.svgVerticalLengthToUserSpace
+ (s, SVG_HEIGHT_ATTRIBUTE, uctx);
+ }
+
+ cursorSize
+ = Toolkit.getDefaultToolkit().getBestCursorSize
+ ((int)Math.round(width), (int)Math.round(height));
+
+ // Handle the viewBox transform
+ AffineTransform at
+ = ViewBox.getPreserveAspectRatioTransform(rootElement,
+ cursorSize.width,
+ cursorSize.height);
+ Filter filter = node.getGraphicsNodeRable(true);
+ f = new AffineRable8Bit(filter, at);
+ } catch (BridgeException ex) {
+ throw ex;
+ } catch (SecurityException ex) {
+ throw new BridgeException(cursorElement, ERR_URI_UNSECURE,
+ new Object[] {uriStr});
+ } catch (Exception ex) {
+ /* Nothing to do */
+ }
+
+
+ // If f is null, it means that we are not dealing with
+ // an SVG image. Try as a raster image.
+ if (f == null) {
+ ImageTagRegistry reg = ImageTagRegistry.getRegistry();
+ Filter filter = reg.readURL(purl);
+ if (filter == null) {
+ return null;
+ }
+
+ // Check if we got a broken image
+ if (filter.getProperty
+ (SVGBrokenLinkProvider.SVG_BROKEN_LINK_DOCUMENT_PROPERTY) != null) {
+ return null;
+ }
+
+ Rectangle preferredSize = filter.getBounds2D().getBounds();
+ cursorSize = Toolkit.getDefaultToolkit().getBestCursorSize
+ (preferredSize.width, preferredSize.height);
+
+ if (preferredSize != null && preferredSize.width >0
+ && preferredSize.height > 0 ) {
+ AffineTransform at = new AffineTransform();
+ if (preferredSize.width > cursorSize.width
+ ||
+ preferredSize.height > cursorSize.height) {
+ at = ViewBox.getPreserveAspectRatioTransform
+ (new float[] {0, 0, preferredSize.width, preferredSize.height},
+ SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN,
+ true,
+ cursorSize.width,
+ cursorSize.height);
+ }
+ f = new AffineRable8Bit(filter, at);
+ } else {
+ // Invalid Size
+ return null;
+ }
+ }
+
+
+ //
+ // Transform the hot spot from image space to cursor space
+ //
+ AffineTransform at = f.getAffine();
+ at.transform(hotSpot, hotSpot);
+
+ //
+ // In all cases, clip to the cursor boundaries
+ //
+ Rectangle cursorViewport
+ = new Rectangle(0, 0, cursorSize.width, cursorSize.height);
+
+ PadRable8Bit cursorImage
+ = new PadRable8Bit(f, cursorViewport,
+ PadMode.ZERO_PAD);
+
+ return cursorImage;
+
+ }
+
+
+ /**
* Implementation helper: converts a RenderedImage to an Image
*/
protected Image renderedImageToImage(RenderedImage ri) {
@@ -495,8 +600,6 @@
&&
this.y == desc.y;
- // System.out.println("isEqual : " + isEqual);
- // (new Exception()).printStackTrace();
return isEqual;
}
1.8 +2 -2 xml-batik/sources/org/apache/batik/bridge/ViewBox.java
Index: ViewBox.java
===================================================================
RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/ViewBox.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- ViewBox.java 8 Nov 2001 23:02:43 -0000 1.7
+++ ViewBox.java 18 Nov 2002 11:47:14 -0000 1.8
@@ -285,7 +285,7 @@
* @param w the width of the region in which the document has to fit into
* @param h the height of the region in which the document has to fit into
*/
- private static
+ public static
AffineTransform getPreserveAspectRatioTransform(float [] vb,
short align,
boolean meet,
1.1 xml-batik/samples/tests/resources/images/svgCursor2.svg
Index: svgCursor2.svg
===================================================================
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
id="body" >
<rect x="0%" y="0%" width="200%" height="200%" fill="gold" />
<rect x="0" y="0" width="32" height="32" fill="black" />
<rect x="2" y="2" width="28" height="28" fill="#eeeeee" />
<rect x="15" y="0" width="2" height="32" fill="black" />
<rect y="15" x="0" width="32" height="2" fill="black" />
<rect x="12" y="12" width="8" height="8" fill="crimson" />
<rect x="5" y="20" width="22" height="10" fill="#eeeeee" />
<text x="15.5" y="29" font-family="sans-serif" font-size="8" text-anchor="middle">SVG 2</text>
</svg>
1.1 xml-batik/samples/tests/resources/images/svgCursor3.svg
Index: svgCursor3.svg
===================================================================
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
id="body" viewBox="0 0 32 32" >
<rect x="0%" y="0%" width="200%" height="200%" fill="green" />
<rect x="0" y="0" width="32" height="32" fill="black" />
<rect x="2" y="2" width="28" height="28" fill="#ccccff" />
<rect x="15" y="0" width="2" height="32" fill="black" />
<rect y="15" x="0" width="32" height="2" fill="black" />
<rect x="12" y="12" width="8" height="8" fill="crimson" />
<rect x="5" y="20" width="22" height="10" fill="#ccccff" />
<text x="15.5" y="29" font-family="sans-serif" font-size="8" text-anchor="middle">SVG 3</text>
</svg>
1.1 xml-batik/samples/tests/resources/images/svgCursor4.svg
Index: svgCursor4.svg
===================================================================
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
id="body" width="300" height="300" viewBox="0 0 32 16" preserveAspectRatio="xMidYMid meet">
<rect x="0" y="0" width="32" height="16" fill="black" />
<rect x="2" y="2" width="28" height="12" fill="orange" />
<rect x="15" y="0" width="2" height="16" fill="black" />
<rect y="7" x="0" width="32" height="2" fill="black" />
<rect x="12" y="4" width="8" height="8" fill="crimson" />
</svg>
1.3 +24 -3 xml-batik/samples/tests/spec/interactivity/cursor4.svg
Index: cursor4.svg
===================================================================
RCS file: /home/cvs/xml-batik/samples/tests/spec/interactivity/cursor4.svg,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- cursor4.svg 15 Nov 2002 18:44:52 -0000 1.2
+++ cursor4.svg 18 Nov 2002 11:47:14 -0000 1.3
@@ -77,8 +77,8 @@
<rect x="0" y="0" width="100" height="100" stroke="black"/>
<rect x="44" y="44" width="12" height="12" fill="black"/>
<rect x="45" y="45" width="10" height="10" fill="#eeeeee" />
- <rect x="49" y="40" width="2" height="20" fill="black" />
- <rect y="49" x="40" height="2" width="20" fill="black" />
+ <rect x="49" y="30" width="2" height="40" fill="black" />
+ <rect y="49" x="30" height="2" width="40" fill="black" />
<!-- <line x1="40" y1="50" x2="60" y2="50" stroke="black" />
<line y1="40" x1="50" y2="60" x2="50" stroke="black" /> -->
<rect x="49" y="49" width="2" height="2" fill="black"
@@ -98,6 +98,9 @@
<use xlink:href="#jpegImage" x="0" y="34"/>
<use xlink:href="#unsupportedImage" x="34" y="34"/>
<use xlink:href="#svgImage" x="68" y="34"/>
+ <use xlink:href="#svgImage2" x="0" y="68"/>
+ <use xlink:href="#svgImage3" x="34" y="68"/>
+ <use xlink:href="#svgImage4" x="68" y="68"/>
</g>
<text class="label" text-anchor="middle" x="75%" y="340" >Current Target Area Cursor</text>
@@ -127,6 +130,18 @@
<text class="label" text-anchor="middle" y="40">SVG Image<tspan dy="1.5em" x="0">defaults to crosshair</tspan></text>
<use xlink:href="#svgImage" />
</g>
+ <g id="refsvgImage2">
+ <text class="label" text-anchor="middle" y="40">SVG Image<tspan dy="1.5em" x="0">No viewBox/width/height</tspan></text>
+ <use xlink:href="#svgImage2" />
+ </g>
+ <g id="refsvgImage3">
+ <text class="label" text-anchor="middle" y="40">SVG Image<tspan dy="1.5em" x="0">ViewBox, no width/height</tspan></text>
+ <use xlink:href="#svgImage3" />
+ </g>
+y <g id="refsvgImage4">
+ <text class="label" text-anchor="middle" y="40">SVG Image<tspan dy="1.5em" x="0">ViewBox, different aspect ratio</tspan></text>
+ <use xlink:href="#svgImage4" />
+ </g>
</g>
@@ -137,6 +152,9 @@
<image id="jpegImage" xlink:href="../../resources/images/jpegCursor.jpg" width="32" height="32" x="-16" y="-16"/>
<image id="unsupportedImage" xlink:href="../../resources/images/bmpCursor.bmp" width="32" height="32" x="-16" y="-16"/>
<image id="svgImage" xlink:href="../../resources/images/svgCursor.svg" width="32" height="32" x="-16" y="-16"/>
+ <image id="svgImage2" xlink:href="../../resources/images/svgCursor2.svg" width="32" height="32" x="-16" y="-16"/>
+ <image id="svgImage3" xlink:href="../../resources/images/svgCursor3.svg" width="32" height="32" x="-16" y="-16"/>
+ <image id="svgImage4" xlink:href="../../resources/images/svgCursor4.svg" width="32" height="32" x="-16" y="-16"/>
<cursor id="cursorbrokenImage" xlink:href="../../resources/images/iDontExist.png" x="16" y="16"/>
<cursor id="cursortiffImage" xlink:href="../../resources/images/tiffCursor.tif" x="16" y="16"/>
@@ -144,6 +162,9 @@
<cursor id="cursorjpegImage" xlink:href="../../resources/images/jpegCursor.jpg" x="16" y="16"/>
<cursor id="cursorunsupportedImage" xlink:href="../../resources/images/bmpCursor.bmp" x="16" y="16"/>
<cursor id="cursorsvgImage" xlink:href="../../resources/images/svgCursor.svg" x="16" y="16"/>
+ <cursor id="cursorsvgImage2" xlink:href="../../resources/images/svgCursor2.svg" x="16" y="16"/>
+ <cursor id="cursorsvgImage3" xlink:href="../../resources/images/svgCursor3.svg" x="16" y="16"/>
+ <cursor id="cursorsvgImage4" xlink:href="../../resources/images/svgCursor4.svg" x="16" y="8"/>
</defs>
</svg>
---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-dev-help@xml.apache.org