Source Code Cross Referenced for SVGCanvas.java in  » 6.0-JDK-Modules » j2me » com » sun » perseus » midp » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » j2me » com.sun.perseus.midp 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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:
027:        package com.sun.perseus.midp;
028:
029:        import com.sun.perseus.builder.ModelBuilder;
030:
031:        import com.sun.perseus.model.SimpleCanvasManager;
032:        import com.sun.perseus.model.CanvasUpdateListener;
033:        import com.sun.perseus.model.DocumentNode;
034:        import com.sun.perseus.model.ModelEvent;
035:        import com.sun.perseus.model.ModelNode;
036:        import com.sun.perseus.model.SMILSample;
037:        import com.sun.perseus.model.Time;
038:
039:        import com.sun.perseus.j2d.RenderGraphics;
040:
041:        import com.sun.perseus.util.SVGConstants;
042:        import com.sun.perseus.util.RunnableQueue;
043:
044:        import org.w3c.dom.events.Event;
045:        import org.w3c.dom.events.EventListener;
046:
047:        import javax.microedition.m2g.SVGEventListener;
048:
049:        import javax.microedition.lcdui.Canvas;
050:        import javax.microedition.lcdui.Graphics;
051:
052:        import com.sun.pisces.PiscesRenderer;
053:        import com.sun.pisces.RendererBase;
054:        import com.sun.pisces.NativeSurface;
055:        import com.sun.pisces.GraphicsSurfaceDestination;
056:
057:        /**
058:         * This class provides support for an LCDUI Canvas extension which can display
059:         * an SVG Document.
060:         *
061:         * @version $Id: SVGCanvas.java,v 1.16 2006/04/21 06:40:56 st125089 Exp $
062:         */
063:        class SVGCanvas extends Canvas implements  CanvasUpdateListener {
064:            /**
065:             * Color used to clear the canvas' background.
066:             */
067:            public static final int CLEAR_COLOR = 0xffffffff;
068:
069:            /**
070:             * Initial state.
071:             */
072:            public final static int STATE_STOPPED = 1;
073:
074:            /**
075:             * Playing state, i.e., playing animations and repainting buffer.
076:             */
077:            public final static int STATE_PLAYING = 2;
078:
079:            /**
080:             * Paused state, i.e., repainting buffer but no longer advancing the 
081:             * time.
082:             */
083:            public final static int STATE_PAUSED = 3;
084:
085:            /**
086:             * SMIL Animation's frame length, in milliseconds
087:             */
088:            public static final int SMIL_ANIMATION_FRAME_LENGTH = 1000;
089:
090:            /**
091:             * Last x position on a pointer pressed event.
092:             */
093:            protected int lastX;
094:
095:            /**
096:             * Last y position on a pointer pressed event.
097:             */
098:            protected int lastY;
099:
100:            /**
101:             * True if the last pointer event was a pointer pressed event.
102:             */
103:            protected boolean lastWasPressed;
104:
105:            /**
106:             * The current player state.
107:             */
108:            protected int state = STATE_STOPPED;
109:
110:            /**
111:             * The <code>SimpleCanvasManager</code> manages the area where the SVG
112:             * content is rendered.
113:             */
114:            protected SimpleCanvasManager canvasManager;
115:
116:            /**
117:             * This component displays a DocumentNode object, which
118:             * is built from the URI
119:             */
120:            protected DocumentNode documentNode;
121:
122:            /**
123:             * Offscreen image
124:             */
125:            protected NativeSurface offscreen;
126:
127:            /**
128:             * Used to blit the offscreen onto the graphics destination.
129:             */
130:            protected GraphicsSurfaceDestination gsd;
131:
132:            /**
133:             * Offscreen width
134:             */
135:            protected int offscreenWidth;
136:
137:            /**
138:             * Offscreen height
139:             */
140:            protected int offscreenHeight;
141:
142:            /**
143:             * The PiscesRenderer associated with the offscreen.
144:             */
145:            protected PiscesRenderer pr;
146:
147:            /**
148:             * RenderGraphics used to draw into the current offscreen
149:             */
150:            protected RenderGraphics rg;
151:
152:            /**
153:             * The associated SVGEventListener.
154:             */
155:            protected SVGEventListener svgEventListener;
156:
157:            /**
158:             * The RunnableQueue is the _only_ valid way to access the
159:             * model tree. No access to the model should be done other
160:             * than from the RunnableQueue thread.
161:             */
162:            protected RunnableQueue updateQueue = null;
163:
164:            /**
165:             * The animation sampler, which runs animations in the update thread.
166:             */
167:            protected SMILSample smilSample = null;
168:
169:            /**
170:             * The animation clock.
171:             */
172:            protected SMILSample.DocumentWallClock clock = null;
173:
174:            /**
175:             * The time increment for the animation.
176:             */
177:            protected float timeIncrement = 0.1f;
178:
179:            /**
180:             * The last mouse event target.
181:             */
182:            protected ModelNode lastMouseTarget = null;
183:
184:            /**
185:             * Boolean flag used to control when the SVGCanvas ignores a 
186:             * canvas manager update because it asked for a a full paint
187:             * in response to a prior repaint. This avoid queuing an extra
188:             * initial repaint() when building a new offscreen buffer.
189:             */
190:            private boolean ignoreCanvasUpdate = false;
191:
192:            /**
193:             * @param documentNode the documentNode this component will render. The input
194:             *        DocumentNode must be fully loaded before this method is called.
195:             *        Note: if the DocumentNode already has an associated RunnableQueue,
196:             *        it is simply replaced. It is the responsibility of the caller to 
197:             *        stop that RunnableQueue if need be.
198:             * @throws IllegalArgumentException see {@link #setURI setURI}.
199:             */
200:            public SVGCanvas(final DocumentNode documentNode) {
201:                if (documentNode == null) {
202:                    throw new NullPointerException();
203:                }
204:
205:                if (!documentNode.isLoaded()) {
206:                    throw new IllegalStateException();
207:                }
208:
209:                this .documentNode = documentNode;
210:
211:                // Set-up RunnableQueue
212:                updateQueue = RunnableQueue.getDefault();
213:                documentNode.setUpdateQueue(updateQueue);
214:
215:                // Hook in the SimpleCanvasManager after creating the offscreen buffer.
216:                buildOffscreen(1, 1);
217:                canvasManager = new SimpleCanvasManager(rg, documentNode, this );
218:                canvasManager.turnOff(); // disabled until we call play or pause.
219:                documentNode.setRunnableHandler(canvasManager);
220:
221:                // Create a SMILSample instance that will be scheduled with the 
222:                // RunnableQueue whenever the component plays.
223:                clock = new SMILSample.DocumentWallClock(documentNode);
224:                smilSample = new SMILSample(documentNode, clock);
225:
226:                // Initialize the timing engine.
227:                documentNode.initializeTimingEngine();
228:
229:                // Apply animations at time 0
230:                documentNode.sample(new Time(0));
231:                documentNode.applyAnimations();
232:            }
233:
234:            /**
235:             * @see javax.microedition.lcdui.Canvas#paint
236:             */
237:            protected void paint(final Graphics g) {
238:                checkOffscreen();
239:                int x = g.getClipX();
240:                int y = g.getClipY();
241:                int w = g.getClipWidth();
242:                int h = g.getClipHeight();
243:
244:                synchronized (canvasManager.lock) {
245:                    if (x != 0 || y != 0 || w != documentNode.getWidth()
246:                            || h != documentNode.getHeight()) {
247:                        // The repaint area is not exactly the same as the viewport area
248:                        // so we need to clear the background first.
249:                        g.setColor(CLEAR_COLOR);
250:                        g.fillRect(x, y, w, h);
251:                    }
252:
253:                    if (gsd == null) {
254:                        gsd = new GraphicsSurfaceDestination(g);
255:                    }
256:                    gsd.drawSurface(offscreen, 0, 0, 0, 0, offscreenWidth,
257:                            offscreenHeight, 1);
258:                    canvasManager.consume();
259:                }
260:            }
261:
262:            /**
263:             * Checks if the offscreen buffer needs to be built or rebuilt.
264:             */
265:            protected void checkOffscreen() {
266:                if (offscreen == null) {
267:                    // This is the very first time we build an offscreen.
268:                    buildOffscreen(getWidth(), getHeight());
269:                } else {
270:                    // Check that the offscreen is large enough for the current size.
271:                    int width = getWidth();
272:                    int height = getHeight();
273:
274:                    // We use an offscreen size with is the smallest of the viewport
275:                    // size and the canvas size. 
276:                    if (width > documentNode.getWidth()) {
277:                        width = documentNode.getWidth();
278:                    }
279:
280:                    if (height > documentNode.getHeight()) {
281:                        height = documentNode.getHeight();
282:                    }
283:
284:                    if (width != offscreenWidth || height != offscreenHeight) {
285:                        buildOffscreen(width, height);
286:                    }
287:                }
288:            }
289:
290:            /**
291:             * The offscreen buffer has the size of the component. This method
292:             * is called in the MIDP painting thread.
293:             *
294:             * @param width the requested minimum buffer width
295:             * @param height the requested minimum buffer height
296:             */
297:            protected void buildOffscreen(final int width, final int height) {
298:                if (width > 0 && height > 0) {
299:                    // We build an offscreen of the requested size.
300:                    offscreen = new NativeSurface(width, height);
301:                    offscreenWidth = width;
302:                    offscreenHeight = height;
303:                } else {
304:                    // This is a degenerate case, just build with 1x1 offscreen
305:                    if (offscreenWidth == 1 && offscreenHeight == 1) {
306:                        return;
307:                    }
308:
309:                    offscreen = new NativeSurface(1, 1);
310:                    offscreenWidth = 1;
311:                    offscreenHeight = 1;
312:                }
313:
314:                // Build a new PiscesRenderer for the new rendering surface.
315:                pr = new PiscesRenderer(offscreen, offscreenWidth,
316:                        offscreenHeight, 0, offscreenWidth, 1,
317:                        RendererBase.TYPE_INT_ARGB);
318:
319:                // Build a corresponding RenderGraphics
320:                rg = new RenderGraphics(pr, offscreenWidth, offscreenHeight);
321:
322:                if (canvasManager != null) {
323:                    // We need to force painting the offscreen buffer.
324:                    // Offscreen buffer rendering happens in the update 
325:                    // thread.
326:                    try {
327:                        updateQueue.invokeAndWait(new Runnable() {
328:                            public void run() {
329:                                synchronized (canvasManager.lock) {
330:                                    // Automatically adjust the SVG image's viewport size.
331:                                    documentNode.setSize(width, height);
332:
333:                                    // Switch the SimpleCanvasManager to the new RenderGraphics
334:                                    canvasManager.setRenderGraphics(rg);
335:
336:                                    // Set the consumed flag to true to force painting 
337:                                    // immediately.
338:                                    canvasManager.consume();
339:                                }
340:
341:                                // Now, update the new canvas.
342:                                // We set the ignoreCanvasUpdate flag to true so that the 
343:                                // canvas update does not trigger a repaint() request.
344:                                ignoreCanvasUpdate = true;
345:                                canvasManager.updateCanvas();
346:                                ignoreCanvasUpdate = false;
347:                            }
348:                        }, null);
349:                    } catch (InterruptedException ie) {
350:                        // This is a serious error, because it means the 
351:                        // default Runnable Queue thread has been 
352:                        // interrupted.                    
353:                        ie.printStackTrace();
354:                    }
355:                } else {
356:                    pr.setColor(255, 255, 255);
357:                    pr.clearRect(0, 0, offscreenWidth, offscreenHeight);
358:                }
359:            }
360:
361:            // ========================================================================
362:            // CanvasUpdateListener implementation
363:            // ========================================================================
364:
365:            /**
366:             * Invoked by the <code>SimpleCanvasManager</code> when it is done updating the
367:             * canvas. This is used during the progressive rendering loading phase and
368:             * when a Runnable has been invoked on the RunnableQueue associated with the
369:             * SVG image. This method is called in the RunnableQueue thread.
370:             *
371:             * @param canvasManager the <code>SimpleCanvasManager</code> which is reporting
372:             *        the update.
373:             */
374:            public void updateComplete(final Object canvasManager) {
375:                if (!ignoreCanvasUpdate) {
376:                    repaint(0, 0, documentNode.getWidth(), documentNode
377:                            .getHeight());
378:                }
379:            }
380:
381:            /**
382:             * Called by the <code>SimpleCanvasManager</code> when the initial load is
383:             * complete. This method is called in the RunnableQueue thread.
384:             *
385:             * @param e if not null, it means that the initial load failed due to
386:             *          this exception.
387:             */
388:            public void initialLoadComplete(final Exception e) {
389:                if (e != null) {
390:                    e.printStackTrace();
391:                }
392:            }
393:
394:            // ========================================================================
395:
396:            /**
397:             * Event Listeners used to turn MIDP Events into DOM Events. It also
398:             * switches between the MIDP event thread and the document's update
399:             * thread (i.e., the <code>RunnableQueue</code>'s thread.
400:             */
401:
402:            /**
403:             * Invoked when a mouse button has been pressed on a component.
404:             * @param x the x-axis coordinate of the pointer event
405:             * @param y the y-axis coordinate of the pointer event
406:             */
407:            protected void pointerPressed(final int x, final int y) {
408:                if (svgEventListener != null) {
409:                    svgEventListener.pointerPressed(x, y);
410:                }
411:
412:                lastX = x;
413:                lastY = y;
414:                lastWasPressed = true;
415:
416:                float[] pt = { x, y };
417:                dispatchPointerEvent(SVGConstants.SVG_MOUSEDOWN_EVENT_TYPE, pt);
418:            }
419:
420:            /**
421:             * Invoked when a mouse button has been released on a component.
422:             * @param x the x-axis coordinate of the pointer event
423:             * @param y the y-axis coordinate of the pointer event
424:             */
425:            protected void pointerReleased(final int x, final int y) {
426:                if (svgEventListener != null) {
427:                    svgEventListener.pointerReleased(x, y);
428:                }
429:
430:                float[] pt = { x, y };
431:                dispatchPointerEvent(SVGConstants.SVG_MOUSEUP_EVENT_TYPE, pt);
432:
433:                if (lastWasPressed && lastX == x && lastY == y) {
434:                    dispatchPointerEvent(SVGConstants.SVG_CLICK_EVENT_TYPE, pt);
435:                }
436:
437:                lastWasPressed = false;
438:            }
439:
440:            /**
441:             * Dispatches a mouse event to the DOM tree.
442:             *
443:             * @param eventType the DOM event type.
444:             * @param pt the mouse event coordinates.
445:             */
446:            protected void dispatchPointerEvent(final String eventType,
447:                    final float[] pt) {
448:                if (state == STATE_STOPPED) {
449:                    return;
450:                }
451:
452:                invokeLater(new Runnable() {
453:                    public void run() {
454:                        ModelNode target = documentNode.nodeHitAt(pt);
455:                        if (target == null) {
456:                            target = documentNode;
457:                        }
458:
459:                        // If the target is different from the lastMouseTarget
460:                        // dispatch a 'mouseout' event to the lastMouseTarget
461:                        // and dispatch a 'mouseover' to the new target
462:                        if (lastMouseTarget != target) {
463:                            if (lastMouseTarget != null
464:                                    && lastMouseTarget != documentNode) {
465:                                ModelEvent e = new ModelEvent(
466:                                        SVGConstants.SVG_MOUSEOUT_EVENT_TYPE,
467:                                        lastMouseTarget);
468:                                documentNode.dispatchEvent(e);
469:                            }
470:                            ModelEvent e = new ModelEvent(
471:                                    SVGConstants.SVG_MOUSEOVER_EVENT_TYPE,
472:                                    target);
473:                            documentNode.dispatchEvent(e);
474:                            lastMouseTarget = target;
475:                        }
476:
477:                        // Map the event type
478:                        // Build the DOM Event
479:                        ModelEvent evt = new ModelEvent(eventType, target);
480:
481:                        // Dispatch to the target tree
482:                        documentNode.dispatchEvent(evt);
483:                    }
484:                });
485:            }
486:
487:            /**
488:             * Invoked when a key has been pressed.
489:             * @param keyCode the code of the event key
490:             */
491:            protected void keyPressed(int keyCode) {
492:                if (svgEventListener != null) {
493:                    svgEventListener.keyPressed(keyCode);
494:                }
495:                dispatchKeyEvent(SVGConstants.SVG_KEYDOWN_EVENT_TYPE, keyCode);
496:            }
497:
498:            /**
499:             * Dispatches a key event to the DOM tree.
500:             *
501:             * @param eventType the DOM event type.
502:             * @param keyCode the key code.
503:             */
504:            protected void dispatchKeyEvent(final String eventType,
505:                    final int keyCode) {
506:                Runnable r = new Runnable() {
507:                    public void run() {
508:                        documentNode.dispatchEvent(new ModelEvent(eventType,
509:                                documentNode, (char) keyCode));
510:                    }
511:                };
512:
513:                if (state != STATE_STOPPED) {
514:                    invokeLater(r);
515:                }
516:            }
517:
518:            /**
519:             * Invoked when a key has been released.
520:             * @param keyCode the code of the event key
521:             */
522:            protected void keyReleased(int keyCode) {
523:                if (svgEventListener != null) {
524:                    svgEventListener.keyReleased(keyCode);
525:                }
526:                dispatchKeyEvent(SVGConstants.SVG_KEYUP_EVENT_TYPE, keyCode);
527:            }
528:
529:            /**
530:             * Invoked when the component's size changes.
531:             *
532:             * @param w the new width
533:             * @param h the new height
534:             */
535:            protected void sizeChanged(final int w, final int h) {
536:                if (svgEventListener != null) {
537:                    svgEventListener.sizeChanged(w, h);
538:                }
539:            }
540:
541:            /**
542:             * Invoked when the component is hidden.
543:             */
544:            protected void hideNotify() {
545:                if (svgEventListener != null) {
546:                    svgEventListener.hideNotify();
547:                }
548:            }
549:
550:            /**
551:             * Invoked when the component is shown.
552:             */
553:            protected void showNotify() {
554:                if (svgEventListener != null) {
555:                    svgEventListener.showNotify();
556:                }
557:            }
558:
559:            // ========================================================================
560:
561:            /**
562:             * Associate the specified <code>SVGEventListener</code> with this
563:             * <code>SVGAnimator</code>.
564:             *
565:             * @param svgEventListener the SVGEventListener that will receive
566:             *        events forwarded by this <code>SVGAnimator</code>. If null,
567:             *        events will not be forwarded by the <code>SVGAnimator</code>.
568:             */
569:            public void setSVGEventListener(SVGEventListener svgEventListener) {
570:                this .svgEventListener = svgEventListener;
571:            }
572:
573:            /**
574:             * Set the time increment to be used for animation rendering.
575:             *
576:             * @param timeIncrement the minimal period of time, in seconds, that
577:             *         should elapse between frame. Must be greater than zero.
578:             * @throws IllegalArgumentException if timeIncrement is less than or equal to
579:             *         zero.
580:             * @see #getTimeIncrement
581:             */
582:            public void setTimeIncrement(float timeIncrement) {
583:                if (timeIncrement <= 0) {
584:                    throw new IllegalArgumentException();
585:                }
586:
587:                this .timeIncrement = timeIncrement;
588:
589:                if (state == STATE_PLAYING) {
590:                    updateQueue.unschedule(smilSample);
591:                    updateQueue.scheduleAtFixedRate(smilSample, canvasManager,
592:                            (long) (1000 * timeIncrement));
593:                }
594:            }
595:
596:            /**
597:             * Get the current time increment for animation rendering. The
598:             * SVGAnimator increments the SVG document's current time by this amount
599:             * upon each rendering. The default value is 0.1 (100 milliseconds).
600:             *
601:             * @return the current time increment, in seconds, used for animation
602:             *         rendering.
603:             * @see #setTimeIncrement
604:             */
605:            public float getTimeIncrement() {
606:                return timeIncrement;
607:            }
608:
609:            /**
610:             * Transition this <code>SVGAnimator</code> to the <i>playing</i>
611:             * state. In the <i>playing</i> state, both Animation and SVGImage
612:             * updates cause rendering updates. Note that in the playing state,
613:             * when the document's current time changes, the animator will seek
614:             * to the new time, and continue to play animations from this place.
615:             *
616:             * @throws IllegalStateException if the animator is not currently in
617:             *         the <i>stopped</i> or <i>paused</i> state.
618:             */
619:            public void play() {
620:                if (state == STATE_PLAYING) {
621:                    throw new IllegalStateException(Messages.formatMessage(
622:                            Messages.ERROR_INVALID_STATE, new Object[] {
623:                                    getClass().getName(), stateToString(),
624:                                    "play()", "stopped, paused" }));
625:                }
626:
627:                // Mark the document as playing.
628:                updateQueue.preemptLater(new Runnable() {
629:                    public void run() {
630:                        documentNode.setPlaying(true);
631:                    }
632:                }, canvasManager);
633:
634:                // Now, schedule the SMILSampler
635:                clock.start();
636:                updateQueue.scheduleAtFixedRate(smilSample, canvasManager,
637:                        (long) (1000 * timeIncrement));
638:
639:                state = STATE_PLAYING;
640:
641:                // Turn on any updates to the offscreen canvas.
642:                canvasManager.turnOn();
643:            }
644:
645:            /**
646:             * Transition this <code>SVGAnimator</code> to the <i>paused</i> state.
647:             * The <code>SVGAnimator</code> stops advancing the document's current time
648:             * automatically (see the SVGDocument's setCurrentTime method). In consequence,
649:             * animation playback will be paused until another call to the <code>play</code> method
650:             * is made, at which points animations will resume from the document's current
651:             * time. SVGImage updates (through API calls) cause a rendering update
652:             * while the <code>SVGAnimator</code> is in the <i>paused</i> state.
653:             *
654:             * @throws IllegalStateException if the animator is not in the <i>playing</i>
655:             *         state.
656:             */
657:            public void pause() {
658:                if (state != STATE_PLAYING) {
659:                    throw new IllegalStateException(Messages.formatMessage(
660:                            Messages.ERROR_INVALID_STATE, new Object[] {
661:                                    getClass().getName(), stateToString(),
662:                                    "pause()", "playing" }));
663:                }
664:
665:                state = STATE_PAUSED;
666:
667:                // Mark the document as _not_ playing.
668:                updateQueue.preemptLater(new Runnable() {
669:                    public void run() {
670:                        documentNode.setPlaying(false);
671:                    }
672:                }, canvasManager);
673:
674:                // Remove the SMILSampler
675:                updateQueue.unschedule(smilSample);
676:
677:                // Turn on any updates to the offscreen canvas.
678:                canvasManager.turnOn();
679:
680:            }
681:
682:            /**
683:             * Transition this <code>SVGAnimator</code> to the <i>stopped</i> state.
684:             * In this state, no rendering updates are performed.
685:             *
686:             * @throws IllegalStateException if the animator is not in the <i>playing</i>
687:             *         or <i>paused</i> state.
688:             */
689:            public void stop() {
690:                if (state == STATE_STOPPED) {
691:                    throw new IllegalStateException(Messages.formatMessage(
692:                            Messages.ERROR_INVALID_STATE, new Object[] {
693:                                    getClass().getName(), stateToString(),
694:                                    "stop()", "paused, playing" }));
695:                }
696:
697:                state = STATE_STOPPED;
698:
699:                // Remove the SMILSampler
700:                updateQueue.unschedule(smilSample);
701:
702:                // Mark the document as _not_ playing.
703:                documentNode.setPlaying(false);
704:
705:                // To unlock the canvasManager if it is waiting on the 
706:                // consumed flag.
707:                canvasManager.consume();
708:
709:                // Turn off any updates to the offscreen canvas.
710:                canvasManager.turnOff();
711:            }
712:
713:            /**
714:             * Invoke the Runnable in the Document update thread and 
715:             * return only after this Runnable has finished.
716:             *
717:             * @param runnable the new Runnable to invoke.
718:             * @throws InterruptedException if the current thread is waiting,
719:             * sleeping, or otherwise paused for a long time and another thread
720:             * interrupts it.
721:             * @throws NullPointerException if <code>runnable</code> is null.
722:             * @throws IllegalStateException if the animator is in the <i>stopped</i> state.
723:             */
724:            void invokeAndWait(Runnable runnable) throws InterruptedException {
725:                if (runnable == null) {
726:                    throw new NullPointerException();
727:                }
728:
729:                if (state == STATE_STOPPED) {
730:                    throw new IllegalStateException(Messages.formatMessage(
731:                            Messages.ERROR_INVALID_STATE, new Object[] {
732:                                    getClass().getName(), stateToString(),
733:                                    "invokeAndWait()", "paused, playing" }));
734:                }
735:
736:                updateQueue.invokeAndWait(runnable, canvasManager);
737:            }
738:
739:            /**
740:             * Schedule execution of the input Runnable in the update thread at a later time.
741:             *
742:             * @param runnable the new Runnable to execute in the Document's update
743:             * thread when time permits.
744:             * @throws NullPointerException if <code>runnable</code> is null.
745:             * @throws IllegalStateException if the animator is in the <i>stopped</i> state.
746:             */
747:            void invokeLater(Runnable runnable) {
748:                if (runnable == null) {
749:                    throw new NullPointerException();
750:                }
751:
752:                if (state == STATE_STOPPED) {
753:                    throw new IllegalStateException(Messages.formatMessage(
754:                            Messages.ERROR_INVALID_STATE, new Object[] {
755:                                    getClass().getName(), stateToString(),
756:                                    "invokeLater()", "paused, playing" }));
757:                }
758:
759:                updateQueue.invokeLater(runnable, canvasManager);
760:            }
761:
762:            /**
763:             * Helper method. Converts the current state to a String.
764:             */
765:            String stateToString() {
766:                switch (state) {
767:                case STATE_PLAYING:
768:                    return "playing";
769:                case STATE_PAUSED:
770:                    return "paused";
771:                case STATE_STOPPED:
772:                default:
773:                    return "stopped";
774:                }
775:            }
776:
777:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.