/** * Returns a Filter that represents a svg document or element as an image. * * @param ctx the bridge context * @param primitiveRegion the primitive region * @param refElement the referenced element * @param toBBoxNeeded true if there is a need to transform to ObjectBoundingBox space * @param filterElement parent filter element * @param filteredNode node to which the filter applies */ protected static Filter createSVGFeImage( BridgeContext ctx, Rectangle2D primitiveRegion, Element refElement, boolean toBBoxNeeded, Element filterElement, GraphicsNode filteredNode) { // // <!> FIX ME // Unresolved issue on the feImage behavior when referencing an // image (PNG, JPEG or SVG image). // VH & TK, 03/08/2002 // Furthermore, for feImage referencing doc fragment, should act // like a <use>, i.e., CSS cascading and the whole zing bang. // GraphicsNode node = ctx.getGVTBuilder().build(ctx, refElement); Filter filter = node.getGraphicsNodeRable(true); AffineTransform at = new AffineTransform(); if (toBBoxNeeded) { // 'primitiveUnits' attribute - default is userSpaceOnUse short coordSystemType; Element filterDefElement = (Element) (filterElement.getParentNode()); String s = SVGUtilities.getChainableAttributeNS( filterDefElement, null, SVG_PRIMITIVE_UNITS_ATTRIBUTE, ctx); if (s.length() == 0) { coordSystemType = SVGUtilities.USER_SPACE_ON_USE; } else { coordSystemType = SVGUtilities.parseCoordinateSystem( filterDefElement, SVG_PRIMITIVE_UNITS_ATTRIBUTE, s, ctx); } if (coordSystemType == SVGUtilities.OBJECT_BOUNDING_BOX) { at = SVGUtilities.toObjectBBox(at, filteredNode); } Rectangle2D bounds = filteredNode.getGeometryBounds(); at.preConcatenate( AffineTransform.getTranslateInstance( primitiveRegion.getX() - bounds.getX(), primitiveRegion.getY() - bounds.getY())); } else { // Need to translate the image to the x, y coordinate to // have the same behavior as the <use> element at.translate(primitiveRegion.getX(), primitiveRegion.getY()); } return new AffineRable8Bit(filter, at); }
/** Invoked when an MutationEvent of type 'DOMNodeInserted' is fired. */ public void handleDOMNodeInsertedEvent(MutationEvent evt) { if (evt.getTarget() instanceof Element) { Element childElt = (Element) evt.getTarget(); GVTBuilder builder = ctx.getGVTBuilder(); GraphicsNode childNode = builder.build(ctx, childElt); if (childNode == null) { return; } // There can only be one document element. node.add(childNode); } }
/** * Creates a <tt>Filter</tt> primitive according to the specified parameters. * * @param ctx the bridge context to use * @param filterElement the element that defines a filter * @param filteredElement the element that references the filter * @param filteredNode the graphics node to filter * @param inputFilter the <tt>Filter</tt> that represents the current filter input if the filter * chain. * @param filterRegion the filter area defined for the filter chain the new node will be part of. * @param filterMap a map where the mediator can map a name to the <tt>Filter</tt> it creates. * Other <tt>FilterBridge</tt>s can then access a filter node from the filterMap if they know * its name. */ public Filter createFilter( BridgeContext ctx, Element filterElement, Element filteredElement, GraphicsNode filteredNode, Filter inputFilter, Rectangle2D filterRegion, Map filterMap) { // 'xlink:href' attribute String uriStr = XLinkSupport.getXLinkHref(filterElement); if (uriStr.length() == 0) { throw new BridgeException( ctx, filterElement, ERR_ATTRIBUTE_MISSING, new Object[] {"xlink:href"}); } // // According the the SVG specification, feImage behaves like // <image> if it references an SVG document or a raster image // and it behaves like a <use> if it references a document // fragment. // // To provide this behavior, depending on whether the uri // contains a fragment identifier, we create either an // <image> or a <use> element and request the corresponding // bridges to build the corresponding GraphicsNode for us. // // Then, we take care of the possible transformation needed // from objectBoundingBox space to user space. // Document document = filterElement.getOwnerDocument(); boolean isUse = uriStr.indexOf('#') != -1; Element contentElement = null; if (isUse) { contentElement = document.createElementNS(SVG_NAMESPACE_URI, SVG_USE_TAG); } else { contentElement = document.createElementNS(SVG_NAMESPACE_URI, SVG_IMAGE_TAG); } contentElement.setAttributeNS(XLINK_NAMESPACE_URI, XLINK_HREF_QNAME, uriStr); Element proxyElement = document.createElementNS(SVG_NAMESPACE_URI, SVG_G_TAG); proxyElement.appendChild(contentElement); // feImage's default region is that of the filter chain. Rectangle2D defaultRegion = filterRegion; Element filterDefElement = (Element) (filterElement.getParentNode()); Rectangle2D primitiveRegion = SVGUtilities.getBaseFilterPrimitiveRegion( filterElement, filteredElement, filteredNode, defaultRegion, ctx); // System.err.println(">>>>>>>> primitiveRegion : " + primitiveRegion); contentElement.setAttributeNS(null, SVG_X_ATTRIBUTE, String.valueOf(primitiveRegion.getX())); contentElement.setAttributeNS(null, SVG_Y_ATTRIBUTE, String.valueOf(primitiveRegion.getY())); contentElement.setAttributeNS( null, SVG_WIDTH_ATTRIBUTE, String.valueOf(primitiveRegion.getWidth())); contentElement.setAttributeNS( null, SVG_HEIGHT_ATTRIBUTE, String.valueOf(primitiveRegion.getHeight())); GraphicsNode node = ctx.getGVTBuilder().build(ctx, proxyElement); Filter filter = node.getGraphicsNodeRable(true); // 'primitiveUnits' attribute - default is userSpaceOnUse short coordSystemType; String s = SVGUtilities.getChainableAttributeNS( filterDefElement, null, SVG_PRIMITIVE_UNITS_ATTRIBUTE, ctx); if (s.length() == 0) { coordSystemType = SVGUtilities.USER_SPACE_ON_USE; } else { coordSystemType = SVGUtilities.parseCoordinateSystem( filterDefElement, SVG_PRIMITIVE_UNITS_ATTRIBUTE, s, ctx); } // Compute the transform from object bounding box to user // space if needed. AffineTransform at = new AffineTransform(); if (coordSystemType == SVGUtilities.OBJECT_BOUNDING_BOX) { at = SVGUtilities.toObjectBBox(at, filteredNode); } filter = new AffineRable8Bit(filter, at); // handle the 'color-interpolation-filters' property handleColorInterpolationFilters(filter, filterElement); // get filter primitive chain region Rectangle2D primitiveRegionUserSpace = SVGUtilities.convertFilterPrimitiveRegion( filterElement, filteredElement, filteredNode, defaultRegion, filterRegion, ctx); filter = new PadRable8Bit(filter, primitiveRegionUserSpace, PadMode.ZERO_PAD); // update the filter Map updateFilterMap(filterElement, filter, filterMap); return filter; }