CanvasManagerpublic class CanvasManager extends SimpleCanvasManager The CanvasManager class is responsible for
keeping the rendering of a ModelNode tree on a
RenderGraphics current.
Specifically, the CanvasManager listens to
update events in a ModelNode tree and
triggers repaint into the RenderGraphics when
necessary.
The CanvasManager optimizes rendering
of the tree while the document is in loading phase. |
Fields Summary |
---|
protected boolean | loadingTrue while the component is processing a document
which is in the loading phase, i.e., between
the UpdateListener 's loadStarting
and loadComplete calls. | protected ModelNode | progressiveNodeProgressive painting is needed when a node has
started loading and has been inserted into the tree.
This is only used during the loading phase of
a document when doing progressive rendering.
The next node to paint progressively | protected ModelNode | needLoadNodeTracks the highest level node whose load completion
is needed to proceed with progressive rendering.
When loading this node completes, then the node
is painted. | protected SMILSample | samplerThe associated SMILSampler, if animations are run. | protected long | smilRateThe rate for SMIL animation. The smilRate is the minimum time between
SMIL samples. |
Methods Summary |
---|
protected void | fullNodePaint(ModelNode node)Utility method invoked when a node and its children need
to be painted. This is used, for example, when a node
which requires full loading before rendering is finally
fully loaded.
if (node.canRenderState == 0) {
synchronized (lock) {
if (!canvasConsumed) {
try {
lock.wait();
} catch (InterruptedException ie) {
}
}
node.paint(rg);
canvasConsumed = false;
canvasUpdateListener.updateComplete(this);
}
}
| public SMILSample | getSampler()
return sampler;
| boolean | isNeedLoadNodeOrChild(ModelNode node)
ModelNode parent = node;
while (parent != null) {
if (parent == needLoadNode) {
break;
}
parent = parent.parent;
}
if (parent == null) {
return false;
}
return true;
| public void | loadBegun(ModelNode node)Invoked when the input node has started loading
updateCanvas();
| public void | loadComplete(ModelNode node)Invoked when the input node has finished loading.
// System.err.println(">>>>>>>>>>>>>> loadComplete : " + node);
if (node instanceof DocumentNode) {
// We are finished with the loading phase.
// Progressive rendering can stop
loading = false;
canvasUpdateListener.initialLoadComplete(null);
// At this point, we are ready to start the animation loop.
// We set the document's scheduled Runnable.
// IMPL NOTE : We disable animations if there are no initial animations.
// We should really only sample when there are
// active animations, but animations can be added by scripts, so
// we will need a more sophisticated mechanism.
if (documentNode.updateQueue != null
&&
documentNode.timeContainerRootSupport
.timedElementChildren.size() > 0) {
SMILSample.DocumentWallClock clock
= new SMILSample.DocumentWallClock(documentNode);
sampler
= new SMILSample(documentNode,
clock);
documentNode.updateQueue.scheduleAtFixedRate(sampler, this,
smilRate);
documentNode.timeContainerRootSupport.initialize();
clock.start();
}
} else if (node == needLoadNode) {
// We loaded a node fully. We can now display that
// node and its children and proceed with progressive
// rendering
if (progressiveNode != null) {
throw new Error();
}
progressiveNode = node;
needLoadNode = null;
}
updateCanvas();
| public void | loadStarting(DocumentNode documentNode, java.io.InputStream is)Invoked when the document starts loading
loading = true;
| public void | loadingFailed(DocumentNode documentNode, java.lang.Exception error)Invoked when a document error happened before finishing loading.
loading = false;
canvasUpdateListener.initialLoadComplete(error);
| public void | modifiedNode(ModelNode node)Invoked when a node modification completed.
if (!loading) {
if (!needRepaint
&&
(node.hasNodeRendering()
||
node.hasDescendants())) {
needRepaint = true;
}
} else {
// Ignore modifications on nodes which have no
// rendering and no descendants
if (!node.hasNodeRendering() && !node.hasDescendants()) {
return;
}
// We are doing progressive rendering. Check if
// the modified node is the one currently suspended
// or one of its children.
// Modifications will be picked up when we
// paint the node after it has finished
// loading.
if (needLoadNode != null) {
if (node == needLoadNode) {
return;
} else {
ModelNode parent = node.parent;
while (parent != null) {
if (parent == needLoadNode) {
return;
}
parent = parent.parent;
}
needRepaint = true;
}
} else {
if (!needRepaint) {
// We modified a node which did not have node
// rendering.
if (progressiveNode != null && progressiveNode != node) {
needRepaint = true;
}
progressiveNode = node;
}
}
}
| public void | modifyingNode(ModelNode node)Invoked when a node is about to be modified.
if (!isNeedLoadNodeOrChild(node)
&&
((node.hasNodeRendering() || node.hasDescendants())
&& (node.canRenderState == 0))) {
needRepaint = true;
}
| public void | nodeInserted(ModelNode node)Invoked when a node has been inserted into the tree
if (loading) {
if (needLoadNode == null) {
// Progressive rendering is _not_ suspended
// If this node's parent is already loaded,
// it means we are dealing with a node insertion
// resulting from reference resolution. We need
// to repaint the document in its current state.
if (node.parent.loaded) {
fullPaint();
} else {
// Check if this node suspends progressive
// rendering.
if (!node.getPaintNeedsLoad()) {
if (progressiveNode != null) {
needRepaint = true;
} else {
progressiveNode = node;
}
} else {
needLoadNode = node;
}
}
} else {
// Progressive rendering _is_ suspended
// We are loading a document and progressive
// repaint is disabled. However, the newly
// inserted node might be a ElementNodeProxy
// child of a Use element which is referencing
// content under the current needLoadNode.
// In that situation, we need to do a repaint
// of the document up to, but not including
// the needLoadNode.
ModelNode parent = node;
while (parent != null) {
if (parent == needLoadNode) {
// We are under the disabled node, no
// problem
break;
}
parent = parent.parent;
}
if (parent == null) {
// Re-render the document up to the current
// needLoadNode
needRepaint = true;
}
}
} else {
needRepaint = true;
}
| protected void | partialPaint(ModelNode node)Utility method to paint the input tree up to, but not
including the needLoadNode. This is a recursive method
which should be called with the root of the tree to
be painted.
if (node == needLoadNode
||
(node.canRenderState != 0)) {
return;
}
if (node.hasNodeRendering()) {
synchronized (lock) {
node.paint(rg);
}
} else {
ModelNode child = node.getFirstExpandedChild();
while (child != null) {
partialPaint(child);
child = child.nextSibling;
}
child = node.getFirstChildNode();
while (child != null) {
partialPaint(child);
child = child.nextSibling;
}
}
| protected void | progressivePaint(ModelNode node)Utility method invoked when an incremental painting is needed
on a node. This may be invoked when a node was just inserted
into the tree or when a node which required full loading of
its children has been completely loaded.
// If this node already has children, we need to do a fullNodePaint.
// This happens for the <use> element when the <use> references
// an element which appeared before in the document.
if (node.hasDescendants()) {
fullNodePaint(node);
} else if (node.hasNodeRendering()
&& (node.canRenderState == 0)) {
synchronized (lock) {
if (!canvasConsumed) {
try {
lock.wait();
} catch (InterruptedException ie) {
}
}
node.paint(rg);
canvasConsumed = false;
canvasUpdateListener.updateComplete(this);
}
}
| public void | textInserted(ModelNode node)Invoked when a string has been appended, during a load
phase. This is only used when parsing a document and is
used in support of progressive download, like the other
loadXXX methods.
| public void | updateCanvas()Utility method used to update the canvas appropriately
depending on what is needed.
During the loading phase, while we do progressive
rendering, the canvas will only redraw nodes in the
progressiveNodes list, unless a repaint has been
requested.
Important Note: this method should only be called from
the update thread, i.e., the thread that also manages
the model node tree.
if (!loading) {
if (needRepaint) {
if (canvasConsumed) {
fullPaint();
needRepaint = false;
} else {
// There is a request to update the canvas
// (likely after a Runnable was invoked),
// but the last update was not consumed.
// If there is a Runnable in the RunnableQueue,
// we just skip this rendering update. Otherwise,
// schedule a fake Runnable to force a later repaint.
if (documentNode.getUpdateQueue().getSize() == 0) {
documentNode.getUpdateQueue()
.preemptLater(new Runnable() {
public void run() {
}
}, this);
}
}
}
} else {
if (needRepaint) {
// A full repaint was requested. If there is no
// suspended node, just do a full repaint.
// Otherwise, do a partial paint
if (needLoadNode == null) {
fullPaint();
} else {
partialPaint(documentNode);
canvasUpdateListener.updateComplete(this);
}
} else if (progressiveNode != null) {
progressivePaint(progressiveNode);
}
needRepaint = false;
progressiveNode = null;
}
|
|