001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026: package com.sun.perseus.model;
027:
028: import com.sun.perseus.j2d.Transform;
029:
030: /**
031: * A <code>Viewport</code> describes a <code>ModelNode</code> into which
032: * rendering may happen.
033: *
034: * <p>A <code>ViewportNode</code> has a width and height
035: * which a child <code>SVG</code> uses to compute the viewbox to viewport
036: * transform.</p>
037: *
038: * <p>In addition, a <code>Viewport</code> has a user transform limited to
039: * its scale and translation components.</p>
040: *
041: * <p>The <code>Viewport</code> is the root of any SVG fragment hierarchy.
042: * </p>
043: *
044: * @version $Id: Viewport.java,v 1.9 2006/06/29 10:47:36 ln156897 Exp $
045: */
046: public abstract class Viewport extends CompositeNode implements
047: Transformable {
048: /**
049: * Default width for viewports.
050: */
051: public static final int DEFAULT_VIEWPORT_WIDTH = 100;
052:
053: /**
054: * Default height for viewports
055: */
056: public static final int DEFAULT_VIEWPORT_HEIGHT = 100;
057:
058: /**
059: * As in the SVG 1.1 specification
060: */
061: public static final int ZOOM_PAN_MAGNIFY = 0;
062:
063: /**
064: * As in the SVG 1.1 specification
065: */
066: public static final int ZOOM_PAN_DISABLE = 1;
067:
068: /**
069: * As in the SVG 1.1 specification
070: */
071: public static final int ZOOM_PAN_UNKNOWN = 2;
072:
073: /**
074: * Viewport width
075: */
076: protected int width = DEFAULT_VIEWPORT_WIDTH;
077:
078: /**
079: * Viewport height
080: */
081: protected int height = DEFAULT_VIEWPORT_HEIGHT;
082:
083: /**
084: * The Transform applied to this node.
085: */
086: protected Transform transform = new Transform(null);
087:
088: /**
089: * The inverse of the Transform applied to this node.
090: */
091: protected Transform inverseTxf = new Transform(null);
092:
093: /**
094: * The zoomAndPan setting
095: */
096: protected int zoomAndPan = ZOOM_PAN_MAGNIFY;
097:
098: /**
099: * Default constructor
100: */
101: public Viewport() {
102: }
103:
104: /**
105: * Returns the <code>ModelNode</code>, if any, hit by the
106: * point at coordinate x/y.
107: *
108: * @param pt the x/y coordinate. Should never be null and be
109: * of size two. If not, the behavior is unspecified.
110: * The coordinates are in viewport space.
111: * @return the <tt>ModelNode</tt> hit at the given point or null
112: * if none was hit.
113: */
114: public ModelNode nodeHitAt(final float[] pt) {
115: // Check for a hit on children
116: return nodeHitAt(getLastChildNode(), pt);
117: }
118:
119: /**
120: * @return The zoomAndPan setting for this viewport (read-only)
121: */
122: public int getZoomAndPan() {
123: return zoomAndPan;
124: }
125:
126: /**
127: * @param newZoomAndPan the new value for the zoom and pan setting
128: */
129: public void setZoomAndPan(final int newZoomAndPan) {
130: if (newZoomAndPan != ZOOM_PAN_MAGNIFY
131: && newZoomAndPan != ZOOM_PAN_DISABLE
132: && newZoomAndPan != ZOOM_PAN_UNKNOWN) {
133: throw new IllegalArgumentException();
134: }
135:
136: if (newZoomAndPan == zoomAndPan) {
137: return;
138: }
139: modifyingNode();
140: this .zoomAndPan = newZoomAndPan;
141: modifiedNode();
142: }
143:
144: /////////////////////
145:
146: /**
147: * @return the viewport width
148: */
149: public int getWidth() {
150: return this .width;
151: }
152:
153: /**
154: * @return the viewport height
155: */
156: public int getHeight() {
157: return this .height;
158: }
159:
160: /**
161: * Sets the viewport size
162: *
163: * @param newWidth the new viewport width. Should be greater than 0
164: * @param newHeight the new viewport height. Should be greater than 0.
165: */
166: public void setSize(final int newWidth, final int newHeight) {
167: if (newWidth < 0 || newHeight < 0) {
168: throw new IllegalArgumentException();
169: }
170:
171: if (newWidth == width && newHeight == height) {
172: return;
173: }
174:
175: modifyingNode();
176: this .width = newWidth;
177: this .height = newHeight;
178: recomputeTransformState(null);
179: computeCanRenderWidthBit(width);
180: computeCanRenderHeightBit(height);
181: modifiedNode();
182: }
183:
184: /**
185: * @return this node's cached transform.
186: */
187: public Transform getTransformState() {
188: return transform;
189: }
190:
191: /**
192: * @return this node's cached inverse transform.
193: */
194: public Transform getInverseTransformState() {
195: if (((canRenderState & CAN_RENDER_NON_INVERTIBLE_TXF_BIT) == 0)) {
196: if (inverseTxf == null) {
197: inverseTxf = new Transform(null);
198: try {
199: inverseTxf = (Transform) transform
200: .inverse(inverseTxf);
201: } catch (Exception e) {
202: // If we get an exception, then we have a real error
203: // condition, because we just checked that the
204: // transform was invertible.
205: throw new Error();
206: }
207: }
208: } else {
209: inverseTxf = null;
210: }
211: return inverseTxf;
212: }
213:
214: /**
215: * Recomputes the transform cache, if one exists. This should recursively
216: * call recomputeTransformState on children node or expanded content, if
217: * any.
218: *
219: * By default, because a ModelNode has no transform and no cached transform,
220: * this only does a pass down.
221: *
222: * @param parentTransform the Transform applied to this node's parent.
223: */
224: protected void recomputeTransformState(
225: final Transform parentTransform) {
226: if (parentTransform != null) {
227: throw new IllegalArgumentException();
228: }
229:
230: computeCanRenderTransformBit(transform);
231: inverseTxf = null;
232: recomputeTransformState(transform, getFirstChildNode());
233: }
234:
235: /**
236: * @param newTransform The new <code>Transformable</code>'s transform.
237: */
238: public void setTransform(final Transform newTransform) {
239: if (ElementNode.equal(newTransform, this .transform)) {
240: return;
241: }
242:
243: modifyingNode();
244: this .transform = newTransform;
245: recomputeTransformState(null);
246: modifiedNode();
247: }
248:
249: /**
250: * @return This <code>Transformable</code>'s transform.
251: */
252: public Transform getTransform() {
253: return transform;
254: }
255:
256: /**
257: * Appends this node's transform, if it is not null.
258: *
259: * @param tx the <code>Transform</code> to apply additional node
260: * transforms to. This may be null.
261: * @param workTx a <code>Transform</code> which can be re-used if a
262: * new <code>Transform</code> needs to be created and workTx
263: * is not the same instance as tx.
264: * @return a transform with this node's transform added.
265: */
266: protected Transform appendTransform(Transform tx,
267: final Transform workTx) {
268: if (transform == null) {
269: return tx;
270: }
271:
272: tx = recycleTransform(tx, workTx);
273: tx.mMultiply(transform);
274:
275: return tx;
276: }
277:
278: /**
279: * Debug helper
280: *
281: * @return a textual description of this viewport object
282: */
283: /*
284: public String toString() {
285: return "[Viewport(zoomPan=" + zoomAndPan + ", width="
286: + width + " height=" + height
287: + " txf=" + transform
288: + "]";
289: }
290: */
291:
292: }
|