/* * $RCSfile: UseProxy.java,v $ * * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package com.sun.perseus.model; import org.w3c.dom.svg.SVGRect; import com.sun.perseus.j2d.Transform; /** * A <code>UseProxy</code> proxies a <code>Use</code> node and * computes the expanded content from the proxied use's children * and its proxy expanded child. * * <p>A <code>UseProxy</code> has a first expanded child corresponding * to the proxied <code>Use</code>'s proxy content. Follow on expanded * children come from the <code>Use</code>'s children.</p> * * @version $Id: UseProxy.java,v 1.6 2006/06/29 10:47:36 ln156897 Exp $ */ public class UseProxy extends StructureNodeProxy { /** * @param proxiedUse <code>Use</code> node to proxy */ UseProxy(final Use proxiedUse) { super(proxiedUse); } /** * Called by the proxied node when the given property's computed value has * changed. * * @param propertyIndex index for the property whose value is changing. * @param proxiedComputedValue computed value for the proxied node. * */ protected void proxiedPropertyStateChange( final int propertyIndex, final Object proxiedComputedValue) { Object inheritValue = proxiedComputedValue; if (!((CompositeGraphicsNode) proxied).isInherited(propertyIndex)) { // The property is specified on the proxied node, update the // state with that specified value. setPropertyState(propertyIndex, proxiedComputedValue); } else { // The property is unspecified on the proxied node. Inherit from // the proxy's parent (and not the proxied's parent). inheritValue = getInheritedPropertyState(propertyIndex); setPropertyState(propertyIndex, inheritValue); } // Propagate to children. ModelNode c = firstExpandedChild; while (c != null) { propagatePropertyState(propertyIndex, inheritValue); c = c.nextSibling; } } /** * Disallow proxying of anything else than <code>Use</code> nodes. * * @param newProxied this node's new proxied node * @throws IllegalArgumentException if the input new proxy is not * a <code>Use</code> node. * @see ElementNodeProxy#setProxied */ protected void setProxied(final ElementNode newProxied) { if (newProxied != null && !(newProxied instanceof Use)) { throw new IllegalArgumentException(); } super.setProxied(newProxied); } /** * @return the tight bounding box in current user coordinate * space. */ public SVGRect getBBox() { Transform t = null; Use proxiedUse = (Use) proxied; if (proxiedUse != null && (proxiedUse.x != 0 || proxiedUse.y != 0)) { t = new Transform(1, 0, 0, 1, proxiedUse.x, proxiedUse.y); } return addBBox(null, t); } /** * Expand the content. For a use node, we create additional expanded * content to account for the use proxy. */ protected void expand() { if (expanded) { return; } if (proxied != null) { // // The first expanded content comes from the proxied <use>'s // proxy. // At the end of this first computation, the firstExpandedChild // points to a proxy for the <use>'s proxy or is null and the // lastExpandedChild is equal to the firstExpandedChild // Use proxiedUse = (Use) proxied; if (proxiedUse.proxy != null) { firstExpandedChild = buildProxiedProxy(); } else { firstExpandedChild = null; } lastExpandedChild = firstExpandedChild; // // Now, do the regular expansion, in case the <use> element // has regular element children. // ElementNodeProxy firstRegularProxies = computeProxiesChain((ElementNode) proxied.getFirstChildNode()); if (firstRegularProxies != null) { lastExpandedChild = firstRegularProxies.prevSibling; if (firstExpandedChild == null) { // The proxied <use> has no proxy firstExpandedChild = firstRegularProxies; firstRegularProxies.prevSibling = null; } else { // The proxied <use> had a proxy firstExpandedChild.nextSibling = firstRegularProxies; firstRegularProxies.prevSibling = firstExpandedChild; } } } expanded = true; } /** * Notifies this proxy that the proxied Use's proxy has just been set. */ void useProxySet() { if (!expanded) { expand(); } else { ElementNodeProxy newFirstExpandedChild = buildProxiedProxy(); newFirstExpandedChild.nextSibling = firstExpandedChild; if (firstExpandedChild != null) { firstExpandedChild.prevSibling = newFirstExpandedChild; } firstExpandedChild = newFirstExpandedChild; if (lastExpandedChild == null) { lastExpandedChild = firstExpandedChild; } } } /** * Implementation helper. This handles getting the proxy from the * proxied <code>Use</code>'s proxy's proxied (see comments in the * code). * * @return an expanded <code>ElementNodeProxy</code> for the proxied * <code>Use</code>'s proxy. */ ElementNodeProxy buildProxiedProxy() { // // Here we are in a situation like: // // + u -> u2 -> rect // // Which we expand into // // + rect // + u2 // +~~> ElementNodeProxy(rect) // + u // +~~> UseProxy(u2) // +~~> ElementNodeProxy(rect) // // To understand the following code, we are building // the equivalent of UseProxy(u2) // // proxied.expandedContent[0] is a reference to // u2's ElementNodeProxy(rect) // Use proxiedUse = (Use) proxied; ElementNodeProxy proxy = proxiedUse.proxy.getProxied().buildExpandedProxy(); proxy.setParentQuiet(this); return proxy; } }