vhardy 2002/11/15 10:44:52 Modified: samples/tests/spec/interactivity cursor4.svg sources/org/apache/batik/bridge CSSUtilities.java CursorManager.java Log: No longers shows a broken image if an image referenced by a cursor cannot be retrieved. Instead, use the follow on <cursor> element or use the built-in cursor at the end of the list (thanks Thomas for pointing out the BROKEN_IMAGE property). Moved all of cursor code to CursorManager except the high-level conversion methods still available through CSSUtilities. Revision Changes Path 1.2 +6 -5 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.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- cursor4.svg 14 Nov 2002 14:57:25 -0000 1.1 +++ cursor4.svg 15 Nov 2002 18:44:52 -0000 1.2 @@ -15,7 +15,8 @@ <!-- This test shows that JPEG, PNG and TIF formats are supported. It also --> <!-- shows that SVG images are not supported for cursors and that BMP images --> <!-- are not either. Unsupported image formats result in the same bahavior as --> -<!-- 'broken images'. The cursor displays a broken image. --> +<!-- 'broken images'. The cursor falls back to the built in cursor specified --> +<!-- at the end of the cursor list values. --> <!-- --> <!-- @author [EMAIL PROTECTED] --> <!-- @version $Id$ --> @@ -103,7 +104,7 @@ <g transform="translate(337.5, 394)" visibility="hidden" > <g id="refbrokenImage" visibility="visible"> - <text class="label" text-anchor="middle" y="40">Broken Image</text> + <text class="label" text-anchor="middle" y="40">Broken Image<tspan dy="1.5em" x="0">defaults to crosshair</tspan></text> <use xlink:href="#brokenImage" /> </g> <g id="reftiffImage"> @@ -119,11 +120,11 @@ <use xlink:href="#jpegImage" /> </g> <g id="refunsupportedImage"> - <text class="label" text-anchor="middle" y="40">Unsupported Image (BMP)</text> + <text class="label" text-anchor="middle" y="40">Unsupported Image (BMP)<tspan dy="1.5em" x="0">defaults to crosshair</tspan></text> <use xlink:href="#unsupportedImage" /> </g> <g id="refsvgImage"> - <text class="label" text-anchor="middle" y="40">SVG Image</text> + <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> 1.40 +2 -138 xml-batik/sources/org/apache/batik/bridge/CSSUtilities.java Index: CSSUtilities.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/CSSUtilities.java,v retrieving revision 1.39 retrieving revision 1.40 diff -u -r1.39 -r1.40 --- CSSUtilities.java 14 Nov 2002 14:57:13 -0000 1.39 +++ CSSUtilities.java 15 Nov 2002 18:44:52 -0000 1.40 @@ -269,145 +269,9 @@ */ public static Cursor convertCursor(Element e, BridgeContext ctx) { - Value cursorValue - = CSSUtilities.getComputedStyle(e, - SVGCSSEngine.CURSOR_INDEX); - String cursorStr = SVGConstants.SVG_AUTO_VALUE; - Cursor cursor = null; - Element cursorElement = null; - - if (cursorValue != null) { - if (cursorValue.getCssValueType() == CSSValue.CSS_PRIMITIVE_VALUE - && - cursorValue.getPrimitiveType() == CSSPrimitiveValue.CSS_IDENT) { - // Single Value : should be one of the predefined cursors or - // 'inherit' - cursorStr = cursorValue.getStringValue(); - } else if (cursorValue.getCssValueType() == CSSValue.CSS_VALUE_LIST) { - ListValue l = (ListValue)cursorValue; - int nValues = l.getLength(); - if (nValues == 1) { - cursorValue = l.item(nValues-1); - if (cursorValue.getPrimitiveType() == CSSPrimitiveValue.CSS_IDENT) { - cursorStr = cursorValue.getStringValue(); - } - } else { - // - // Look for the first cursor url we can handle. - // That would be a reference to a <cursor> element. - // - cursorElement = null; - for (int i=0; i<nValues-1; i++) { - cursorValue = l.item(i); - if (cursorValue.getPrimitiveType() == CSSPrimitiveValue.CSS_URI) { - String uri = cursorValue.getStringValue(); - - // If the uri does not resolve to a cursor element, - // then, this is not a type of cursor uri we can handle: - // go to the next or default to logical cursor - try { - cursorElement = ctx.getReferencedElement(e, uri); - } catch (BridgeException be) { - // Be only silent if this is a case where the target - // could not be found. Do not catch other errors (e.g, - // malformed URIs) - if (!ERR_URI_BAD_TARGET.equals(be.getCode())) { - throw be; - } - } - - if (cursorElement != null) { - // We go an element, check it is of type cursor - String cursorNS = cursorElement.getNamespaceURI(); - if (SVGConstants.SVG_NAMESPACE_URI.equals(cursorNS) - && - SVGConstants.SVG_CURSOR_TAG.equals(cursorElement.getNodeName())) { - break; - } - } - cursorElement = null; - } - } - - if (cursorElement == null) { - if (nValues > 0) { - cursorValue = l.item(nValues-1); - if (cursorValue.getPrimitiveType() == CSSPrimitiveValue.CSS_IDENT) { - cursorStr = cursorValue.getStringValue(); - } - } - } - } - } - } - - if (cursorElement != null) { - return ctx.getCursorManager().convertSVGCursor(cursorElement); - } - - return convertBuiltInCursor(e, cursorStr); - } - - - public static final Cursor convertBuiltInCursor(Element e, String cursorStr) { - Cursor cursor = null; - - // The CSS engine guarantees an non null, non empty string - // as the computed value for cursor. Therefore, the following - // test is safe. - if (cursorStr.charAt(0) == 'a') { - // - // Handle 'auto' value. - // - // - <a> The following sets the cursor for <a> element enclosing - // text nodes. Setting the proper cursor (i.e., depending on the - // children's 'cursor' property, is handled in the SVGAElementBridge - // so as to avoid going up the tree on mouseover events (looking for - // an anchor ancestor. - // - // - <image> The following does not change the cursor if the - // element's cursor property is set to 'auto'. Otherwise, it takes - // precedence over any child (in case of SVG content) cursor setting. - // This means that for images referencing SVG content, a cursor - // property set to 'auto' on the <image> element will not override - // the cursor settings inside the SVG image. Any other cursor property - // will take precedence. - // - // - <use> Same behavior as for <image> except that the behavior - // is controlled from the <use> element bridge (SVGUseElementBridge). - // - // - <text>, <tref> and <tspan> : a cursor value of auto will cause the - // cursor to be set to a text cursor. Note that text content with an - // 'auto' cursor and descendant of an anchor will have its cursor - // set to the anchor cursor through the SVGAElementBridge. - // - String nameSpaceURI = e.getNamespaceURI(); - String tag = e.getNodeName(); - if (SVGConstants.SVG_NAMESPACE_URI.equals(nameSpaceURI)) { - if (SVGConstants.SVG_A_TAG.equals(tag)) { - cursor = CursorManager.ANCHOR_CURSOR; - } else if (SVGConstants.SVG_TEXT_TAG.equals(tag) || - SVGConstants.SVG_TSPAN_TAG.equals(tag) || - SVGConstants.SVG_TREF_TAG.equals(tag) ) { - cursor = CursorManager.TEXT_CURSOR; - } else if (SVGConstants.SVG_IMAGE_TAG.equals(tag)) { - // Do not change the cursor - return null; - } else { - cursor = CursorManager.DEFAULT_CURSOR; - } - } else { - cursor = CursorManager.DEFAULT_CURSOR; - } - } else { - // Specific, logical cursor - cursor = CursorManager.getPredefinedCursor(cursorStr); - } - - return cursor; + return ctx.getCursorManager().convertCursor(e); } - //////////////////////////////////////////////////////////////////////// // 'color-rendering', 'text-rendering', 'image-rendering', // 'shape-rendering' 1.5 +191 -11 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.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- CursorManager.java 14 Nov 2002 19:44:49 -0000 1.4 +++ CursorManager.java 15 Nov 2002 18:44:52 -0000 1.5 @@ -30,6 +30,11 @@ import org.apache.batik.ext.awt.image.spi.ImageTagRegistry; import org.apache.batik.ext.awt.image.renderable.Filter; +import org.apache.batik.css.engine.SVGCSSEngine; +import org.apache.batik.css.engine.value.ListValue; +import org.apache.batik.css.engine.value.StringValue; +import org.apache.batik.css.engine.value.Value; + import org.apache.batik.dom.util.XLinkSupport; import org.apache.batik.dom.svg.XMLBaseSupport; import org.apache.batik.util.SVGConstants; @@ -37,6 +42,9 @@ import org.apache.batik.util.SoftReferenceCache; import org.w3c.dom.Element; +import org.w3c.dom.css.CSSPrimitiveValue; +import org.w3c.dom.css.CSSValue; + /** * The CursorManager class is a helper class which preloads the cursors @@ -45,7 +53,7 @@ * @author <a href="mailto:vincent.hardy@;sun.com">Vincent Hardy</a> * @version $Id$ */ -public class CursorManager implements SVGConstants { +public class CursorManager implements SVGConstants, ErrorConstants { /** * Maps SVG Cursor Values to Java Cursors */ @@ -134,11 +142,168 @@ public static Cursor getPredefinedCursor(String cursorName){ return (Cursor)cursorMap.get(cursorName); } + + /** + * Returns the Cursor corresponding to the input element's cursor property + * + * @param e the element on which the cursor property is set + */ + public Cursor convertCursor(Element e) { + Value cursorValue + = CSSUtilities.getComputedStyle(e, + SVGCSSEngine.CURSOR_INDEX); + + String cursorStr = SVGConstants.SVG_AUTO_VALUE; + + if (cursorValue != null) { + if (cursorValue.getCssValueType() == CSSValue.CSS_PRIMITIVE_VALUE + && + cursorValue.getPrimitiveType() == CSSPrimitiveValue.CSS_IDENT) { + // Single Value : should be one of the predefined cursors or + // 'inherit' + cursorStr = cursorValue.getStringValue(); + return convertBuiltInCursor(e, cursorStr); + } else if (cursorValue.getCssValueType() == CSSValue.CSS_VALUE_LIST) { + ListValue l = (ListValue)cursorValue; + int nValues = l.getLength(); + if (nValues == 1) { + cursorValue = l.item(nValues-1); + if (cursorValue.getPrimitiveType() == CSSPrimitiveValue.CSS_IDENT) { + cursorStr = cursorValue.getStringValue(); + return convertBuiltInCursor(e, cursorStr); + } + } else if (nValues > 1) { + // + // Look for the first cursor url we can handle. + // That would be a reference to a <cursor> element. + // + return convertSVGCursor(e, l); + } + } + } + + return convertBuiltInCursor(e, cursorStr); + } + public Cursor convertBuiltInCursor(Element e, String cursorStr) { + Cursor cursor = null; + + // The CSS engine guarantees an non null, non empty string + // as the computed value for cursor. Therefore, the following + // test is safe. + if (cursorStr.charAt(0) == 'a') { + // + // Handle 'auto' value. + // + // - <a> The following sets the cursor for <a> element enclosing + // text nodes. Setting the proper cursor (i.e., depending on the + // children's 'cursor' property, is handled in the SVGAElementBridge + // so as to avoid going up the tree on mouseover events (looking for + // an anchor ancestor. + // + // - <image> The following does not change the cursor if the + // element's cursor property is set to 'auto'. Otherwise, it takes + // precedence over any child (in case of SVG content) cursor setting. + // This means that for images referencing SVG content, a cursor + // property set to 'auto' on the <image> element will not override + // the cursor settings inside the SVG image. Any other cursor property + // will take precedence. + // + // - <use> Same behavior as for <image> except that the behavior + // is controlled from the <use> element bridge (SVGUseElementBridge). + // + // - <text>, <tref> and <tspan> : a cursor value of auto will cause the + // cursor to be set to a text cursor. Note that text content with an + // 'auto' cursor and descendant of an anchor will have its cursor + // set to the anchor cursor through the SVGAElementBridge. + // + String nameSpaceURI = e.getNamespaceURI(); + String tag = e.getNodeName(); + if (SVGConstants.SVG_NAMESPACE_URI.equals(nameSpaceURI)) { + if (SVGConstants.SVG_A_TAG.equals(tag)) { + cursor = CursorManager.ANCHOR_CURSOR; + } else if (SVGConstants.SVG_TEXT_TAG.equals(tag) || + SVGConstants.SVG_TSPAN_TAG.equals(tag) || + SVGConstants.SVG_TREF_TAG.equals(tag) ) { + cursor = CursorManager.TEXT_CURSOR; + } else if (SVGConstants.SVG_IMAGE_TAG.equals(tag)) { + // Do not change the cursor + return null; + } else { + cursor = CursorManager.DEFAULT_CURSOR; + } + } else { + cursor = CursorManager.DEFAULT_CURSOR; + } + } else { + // Specific, logical cursor + cursor = CursorManager.getPredefinedCursor(cursorStr); + } + + return cursor; + } + + /** - * Returns a cursor for the given cursorElement + * Returns a cursor for the given value list. Note that the + * code assumes that the input value has at least two entries. + * So the caller should check that before calling the method. + * For example, CSSUtilities.convertCursor performs that check. + */ + public Cursor convertSVGCursor(Element e, ListValue l) { + int nValues = l.getLength(); + Element cursorElement = null; + for (int i=0; i<nValues-1; i++) { + Value cursorValue = l.item(i); + if (cursorValue.getPrimitiveType() == CSSPrimitiveValue.CSS_URI) { + String uri = cursorValue.getStringValue(); + + // If the uri does not resolve to a cursor element, + // then, this is not a type of cursor uri we can handle: + // go to the next or default to logical cursor + try { + cursorElement = ctx.getReferencedElement(e, uri); + } catch (BridgeException be) { + // Be only silent if this is a case where the target + // could not be found. Do not catch other errors (e.g, + // malformed URIs) + if (!ERR_URI_BAD_TARGET.equals(be.getCode())) { + throw be; + } + } + + if (cursorElement != null) { + // We go an element, check it is of type cursor + String cursorNS = cursorElement.getNamespaceURI(); + if (SVGConstants.SVG_NAMESPACE_URI.equals(cursorNS) + && + SVGConstants.SVG_CURSOR_TAG.equals(cursorElement.getNodeName())) { + Cursor c = convertSVGCursorElement(cursorElement); + if (c != null) { + return c; + } + } + } + } + } + + // If we got to that point, it means that no cursorElement + // produced a valid cursor, i.e., either a format we support + // or a valid referenced image (no broken image). + // Fallback on the built in cursor property. + Value cursorValue = l.item(nValues-1); + String cursorStr = SVGConstants.SVG_AUTO_VALUE; + if (cursorValue.getPrimitiveType() == CSSPrimitiveValue.CSS_IDENT) { + cursorStr = cursorValue.getStringValue(); + } + + return convertBuiltInCursor(e, cursorStr); + } + + /** + * Returns a cursor for a given element */ - public Cursor convertSVGCursor(Element cursorElement) { + public Cursor convertSVGCursorElement(Element cursorElement) { // One of the cursor url resolved to a <cursor> element // Try to handle its image. String uriStr = XLinkSupport.getXLinkHref(cursorElement); @@ -182,12 +347,23 @@ 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 // Rectangle preferredSize = f.getBounds2D().getBounds(); if (preferredSize == null || preferredSize.width <=0 || preferredSize.height <=0 ) { + cursorCache.clearCursor(desc); return null; } @@ -215,14 +391,14 @@ rh = cursorSize.height; } - RenderedImage img = f.createScaledRendering((int)Math.round(rw), - (int)Math.round(rh), - null); + RenderedImage ri = f.createScaledRendering((int)Math.round(rw), + (int)Math.round(rh), + null); - if (img instanceof Image) { - bi = (Image)img; + if (ri instanceof Image) { + bi = (Image)ri; } else { - bi = renderedImageToImage(img); + bi = renderedImageToImage(ri); } // Apply the scale transform that is applied to the image @@ -252,7 +428,7 @@ y = y > (cursorSize.height-1) ? cursorSize.height - 1: y; // - // The cursor image is not into the bi image + // The cursor image is now into the bi image // Cursor c = Toolkit.getDefaultToolkit() .createCustomCursor(bi, @@ -349,6 +525,10 @@ public void putCursor(CursorDescriptor desc, Cursor cursor) { putImpl(desc, cursor); + } + + public void clearCursor(CursorDescriptor desc) { + clearImpl(desc); } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]