KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > lobobrowser > html > renderer > RBlockViewport


1 /*
2     GNU LESSER GENERAL PUBLIC LICENSE
3     Copyright (C) 2006 The Lobo Project
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13     Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19     Contact info: xamjadmin@users.sourceforge.net
20 */

21 /*
22  * Created on Apr 16, 2005
23  */

24 package org.lobobrowser.html.renderer;
25
26 import java.awt.*;
27 import java.awt.event.MouseEvent JavaDoc;
28 import java.util.*;
29
30 import org.lobobrowser.html.*;
31 import org.lobobrowser.html.style.CSS2PropertiesImpl;
32 import org.lobobrowser.html.style.HtmlValues;
33 import org.lobobrowser.html.style.RenderState;
34 import org.lobobrowser.html.domimpl.*;
35 import org.w3c.dom.*;
36 import java.util.logging.*;
37
38 /**
39  * A substantial portion of the HTML rendering logic of the package can
40  * be found in this class.
41  * This class is in charge of laying out the DOM subtree of a node,
42  * usually on behalf of an RBlock.
43  * It creates a renderer subtree consisting of RLine's or RBlock's. RLine's in
44  * turn contain RWord's and so on.
45  * This class also happens to be used as an RBlock scrollable viewport.
46  * @author J. H. S.
47  */

48 public class RBlockViewport extends BaseRCollection {
49     // NOTES:
50
// - seqRenderables should be "lines" in positional order
51
// to allow binary searches by position.
52

53     public static final Insets ZERO_INSETS = new Insets(0, 0, 0, 0);
54     private static final Logger logger = Logger.getLogger(RBlockViewport.class.getName());
55     
56     private final ArrayList seqRenderables = new ArrayList();
57     //private final ArrayList awtComponents = new ArrayList();
58
private final RenderableContainer container;
59     private final int listNesting;
60     private final UserAgentContext userAgentContext;
61     private final HtmlRendererContext rendererContext;
62     private final FrameContext frameContext;
63     
64     private SortedSet positionedRenderables;
65 // private Collection exportedRenderables;
66
private RLine currentLine;
67     private int maxX;
68     private int maxY;
69     //private int availHeight;
70
private int desiredWidth; // includes insets
71
private int desiredHeight; // includes insets
72
private int availContentHeight; // does not include insets
73
private int availContentWidth; // does not include insets
74
private int yLimit;
75     private int otherOrdinal;
76     private Insets paddingInsets;
77     private boolean overrideNoWrap;
78     
79     //private ModelNode currentRenderableContext;
80
private boolean skipParagraphBreakBefore;
81     //private boolean skipLineBreakBefore;
82
private static final Map elementLayout = new HashMap();
83     
84     static {
85         Map el = elementLayout;
86         EmLayout em = new EmLayout();
87         el.put("I", em);
88         el.put("EM", em);
89         el.put("CITE", em);
90         el.put("H1", new HLayout(24));
91         el.put("H2", new HLayout(18));
92         el.put("H3", new HLayout(15));
93         el.put("H4", new HLayout(12));
94         el.put("H5", new HLayout(10));
95         el.put("H6", new HLayout(8));
96         StrongLayout strong = new StrongLayout();
97         el.put("B", strong);
98         el.put("STRONG", strong);
99         el.put("TH", strong);
100         el.put("U", new ULayout());
101         el.put("STRIKE", new StrikeLayout());
102         el.put("BR", new BrLayout());
103         el.put("P", new PLayout());
104         el.put("NOSCRIPT", new NoScriptLayout());
105         NopLayout nop = new NopLayout();
106         el.put("SCRIPT", nop);
107         el.put("HEAD", nop);
108         el.put("TITLE", nop);
109         el.put("META", nop);
110         el.put("STYLE", nop);
111         el.put("LINK", nop);
112         el.put("IMG", new ImgLayout());
113         el.put("TABLE", new TableLayout());
114         ChildrenLayout children = new ChildrenLayout();
115         el.put("HTML", children);
116         AnchorLayout anchor = new AnchorLayout();
117         el.put("A", anchor);
118         el.put("ANCHOR", anchor);
119         el.put("INPUT", new InputLayout2());
120         el.put("TEXTAREA", new TextAreaLayout2());
121         el.put("SELECT", new SelectLayout());
122         ListItemLayout list = new ListItemLayout();
123         el.put("UL", list);
124         el.put("OL", list);
125         el.put("LI", list);
126         CommonBlockLayout cbl = new CommonBlockLayout();
127         el.put("PRE", cbl);
128         el.put("CENTER", cbl);
129         el.put("CAPTION", cbl);
130         DivLayout div = new DivLayout();
131         el.put("DIV", div);
132         el.put("BODY", div);
133         el.put("DL", div);
134         el.put("DT", div);
135         BlockQuoteLayout bq = new BlockQuoteLayout();
136         el.put("BLOCKQUOTE", bq);
137         el.put("DD", bq);
138         el.put("HR", new HrLayout());
139         el.put("SPAN", new SpanLayout());
140         ObjectLayout ol = new ObjectLayout(false, true);
141         el.put("OBJECT", new ObjectLayout(true, true));
142         el.put("APPLET", ol);
143         el.put("EMBED", ol);
144         el.put("IFRAME", new IFrameLayout());
145     }
146     
147     /**
148      * Constructs an HtmlBlockLayout.
149      * @param container This is usually going to be an RBlock.
150      * @param listNesting The nesting level for lists. This is zero except inside a list.
151      * @param pcontext The HTMLParserContext instance.
152      * @param frameContext This is usually going to be HtmlBlock, an object where text selections are contained.
153      * @param parent This is usually going to be the parent of <code>container</code>.
154      */

155     public RBlockViewport(ModelNode modelNode, RenderableContainer container, int listNesting, UserAgentContext pcontext, HtmlRendererContext rcontext, FrameContext frameContext, RCollection parent) {
156         super(container, modelNode);
157         this.parent = parent;
158         this.userAgentContext = pcontext;
159         this.rendererContext = rcontext;
160         this.frameContext = frameContext;
161         this.container = container;
162         this.listNesting = listNesting;
163         // Layout here can always be "invalidated"
164
this.layoutUpTreeCanBeInvalidated = true;
165     }
166     
167     public void invalidateLayoutLocal() {
168         // Workaround for fact that RBlockViewport does not
169
// get validated or invalidated.
170
this.layoutUpTreeCanBeInvalidated = true;
171     }
172     
173     public int getAvailContentWidth() {
174         return this.availContentWidth;
175     }
176     
177     /**
178      * Builds the layout/renderer tree from scratch.
179      * Note: Returned dimension needs to be actual size needed for rendered content,
180      * not the available container size. This is relied upon by table layout.
181      * @param yLimit If other than -1, <code>layout</code> will throw <code>SizeExceededException</code>
182      * in the event that the layout goes beyond this y-coordinate point.
183      */

184     public void layout(int desiredWidth, int desiredHeight, Insets paddingInsets, NodeImpl rootNode, int yLimit, FloatingBounds floatBounds) {
185         // Expected in GUI thread. It's possible it may be invoked during pack()
186
// outside of the GUI thread.
187
if(!EventQueue.isDispatchThread() && logger.isLoggable(Level.INFO)) {
188             logger.warning("layout(): Invoked outside GUI dispatch thread.");
189         }
190         RenderableContainer container = this.container;
191         this.paddingInsets = paddingInsets;
192         this.yLimit = yLimit;
193         this.desiredHeight = desiredHeight;
194         this.desiredWidth = desiredWidth;
195         this.floatBounds = floatBounds;
196
197         // maxX and maxY should not be reset by layoutPass.
198
this.maxX = paddingInsets.left;
199         this.maxY = paddingInsets.top;
200
201         int availw = desiredWidth - paddingInsets.left - paddingInsets.right;
202         if(availw < 0) {
203             availw = 0;
204         }
205         int availh = desiredHeight - paddingInsets.top - paddingInsets.bottom;
206         if(availh == 0) {
207             availh = 0;
208         }
209         this.availContentHeight = availh;
210         this.availContentWidth = availw;
211         Dimension desiredSize = new Dimension(desiredWidth, desiredHeight);
212
213         // New floating algorithm.
214
this.layoutPass(desiredSize, rootNode);
215         Collection delayedPairs = container.getDelayedPairs();
216         if(delayedPairs != null && delayedPairs.size() > 0) {
217             Collection dpcopy = new LinkedList();
218             dpcopy.addAll(delayedPairs);
219             // First pass - reposition everything based on floats.
220
Iterator i = dpcopy.iterator();
221             while(i.hasNext()) {
222                 DelayedPair pair = (DelayedPair) i.next();
223                 if(pair.targetParent == container) {
224                     if(pair.alignment != 0) {
225                         this.positionFloat(pair);
226                         //OPTIMIZE: Laying out everything again could
227
//be replaced with a repositioning of all
228
//renderables, plus relayout of blocks affected
229
//by floats. Note that relayout is necessary
230
//because repositioning of one float potentially
231
//affects positioning of subsequent floats.
232
this.layoutPass(desiredSize, rootNode);
233                     }
234                 }
235             }
236             // Second pass - add to positioned renderables
237
i = dpcopy.iterator();
238             while(i.hasNext()) {
239                 DelayedPair pair = (DelayedPair) i.next();
240                 if(pair.targetParent == container) {
241                     if(pair.alignment == 0) {
242                         this.importNonFloat(pair);
243                     }
244                     else {
245                         this.addFloat(pair);
246                     }
247                 }
248             }
249         }
250
251         // Compute bounds...
252
RLine lastLine = this.currentLine;
253         Rectangle lastBounds = lastLine.getBounds();
254         int lastTopX = lastBounds.x + lastBounds.width;
255         if(lastTopX > this.maxX) {
256             this.maxX = lastTopX;
257         }
258         int lastTopY = lastBounds.y + lastBounds.height;
259         int maxY = this.maxY;
260         if(lastTopY > maxY) {
261             this.maxY = maxY = lastTopY;
262         }
263         this.width = paddingInsets.right + this.maxX;
264         this.height = paddingInsets.bottom + maxY;
265     }
266
267     private void layoutPass(Dimension desiredSize, NodeImpl rootNode) {
268         RenderableContainer container = this.container;
269         container.clearDelayedPairs();
270         this.otherOrdinal = 0;
271
272         // Remove sequential renderables...
273
ArrayList renderables = this.seqRenderables;
274         renderables.clear();
275
276         // Remove other renderables...
277
this.positionedRenderables = null;
278         
279         // Other initialization...
280
Insets paddingInsets = this.paddingInsets;
281
282         // Call addLine after setting margins
283
this.currentLine = this.addLine(rootNode, paddingInsets, null);
284         this.skipParagraphBreakBefore = true;
285         
286         // Start laying out...
287
// The parent is expected to have set the RenderState already.
288
this.layoutChildren(container, desiredSize, paddingInsets, rootNode);
289         
290 // if(floatingPairs != null) {
291
// Iterator i = floatingPairs.iterator();
292
// while(i.hasNext()) {
293
// DelayedPair pair = (DelayedPair) i.next();
294
// this.addFloat(pair);
295
// }
296
// }
297
}
298     
299     /**
300      * Applies any horizonal or vertical alignment. It may also adjust
301      * width and height if necessary.
302      * @param canvasWidth
303      * @param canvasHeight
304      * @param paddingInsets
305      */

306     public void align(int alignXPercent, int alignYPercent, int canvasWidth, int canvasHeight, Insets paddingInsets) {
307         //TODO: Consider left+right margins due to float/align.
308
int prevMaxX = this.maxX;
309         int prevMaxY = this.maxY;
310         // Horizontal alignment
311
if(alignXPercent > 0) {
312             ArrayList renderables = this.seqRenderables;
313             int availLineWidth = canvasWidth - paddingInsets.left - paddingInsets.right;
314             int numRenderables = renderables.size();
315             for(int i = 0; i < numRenderables; i++) {
316                 Object JavaDoc r = renderables.get(i);
317                 if(r instanceof BoundableRenderable) {
318                     BoundableRenderable line = (BoundableRenderable) r;
319                     int y = line.getY();
320                     int leftOffset = this.fetchLeftOffset(y);
321                     int rightOffset = this.fetchRightOffset(y);
322                     int actualAvailWidth = availLineWidth - leftOffset - rightOffset;
323                     int difference = actualAvailWidth - line.getWidth();
324                     if(difference > 0) {
325                         int shift = (difference * alignXPercent) / 100;
326                         int newX = paddingInsets.left + leftOffset + shift;
327                         line.setX(newX);
328                         if(newX + line.getWidth() > this.maxX) {
329                             this.maxX = newX + line.getWidth();
330                         }
331                     }
332                 }
333             }
334         }
335         
336         // Vertical alignment
337
if(alignYPercent > 0) {
338             int availContentHeight = canvasHeight - paddingInsets.top - paddingInsets.bottom;
339             int usedHeight = this.maxY - paddingInsets.top;
340             int difference = availContentHeight - usedHeight;
341             if(difference > 0) {
342                 int shift = (difference * alignYPercent) / 100;
343                 // Try sequential renderables first.
344
Iterator renderables = this.seqRenderables.iterator();
345                 while(renderables.hasNext()) {
346                     Object JavaDoc r = renderables.next();
347                     if(r instanceof BoundableRenderable) {
348                         BoundableRenderable line = (BoundableRenderable) r;
349                         int newY = line.getY() + shift;
350                         line.setY(newY);
351                         if(newY + line.getHeight() > this.maxY) {
352                             this.maxY = newY + line.getHeight();
353                         }
354                     }
355                 }
356                 
357                 // Now other renderables, but only those that can be
358
// vertically aligned
359
Set others = this.positionedRenderables;
360                 if(others != null) {
361                     Iterator i2 = others.iterator();
362                     while(i2.hasNext()) {
363                         PositionedRenderable pr = (PositionedRenderable) i2.next();
364                         if(pr.verticalAlignable) {
365                             BoundableRenderable br = pr.renderable;
366                             int newY = br.getY() + shift;
367                             br.setY(newY);
368                             if(newY + br.getHeight() > this.maxY) {
369                                 this.maxY = newY + br.getHeight();
370                             }
371                         }
372                     }
373                 }
374             }
375         }
376         if(prevMaxX != this.maxX) {
377             this.width += (this.maxX - prevMaxX);
378         }
379         if(prevMaxY != this.maxY) {
380             this.height += (this.maxY - prevMaxY);
381         }
382     }
383
384 // /**
385
// * Gets the parent RBlockViewport.
386
// * Does not cross tables.
387
// */
388
// private RBlockViewport getContainingViewport() {
389
// Object parent = this.parent;
390
// if(parent instanceof RBlock) {
391
// parent = ((RBlock) parent).parent;
392
// if(parent instanceof RBlockViewport) {
393
// return (RBlockViewport) parent;
394
// }
395
// }
396
// return null;
397
// }
398

399     private RLine addLine(ModelNode startNode, Insets insets, RLine prevLine) {
400         int newLineY = prevLine == null ? insets.top : prevLine.y + prevLine.height;
401         this.checkY(newLineY);
402         int leftOffset = this.fetchLeftOffset(newLineY);
403         int insetsl = insets.left;
404         int newX = insetsl + leftOffset;
405         int newMaxWidth = this.availContentWidth - this.fetchRightOffset(newLineY) - leftOffset;
406         RLine rline;
407         if(prevLine == null) {
408             // Note: Assumes that prevLine == null means it's the first line.
409
RenderState rs = this.modelNode.getRenderState();
410             int textIndent = rs == null ? 0 : rs.getTextIndent(this.availContentWidth);
411             if(textIndent != 0) {
412                 newX += textIndent;
413             }
414             rline = new RLine(startNode, this.container, newX, newLineY, newMaxWidth, 0);
415         }
416         else {
417             if(prevLine.x + prevLine.width > this.maxX) {
418                 this.maxX = prevLine.x + prevLine.width;
419             }
420             rline = new RLine(startNode, this.container, newX, newLineY, newMaxWidth, 0);
421         }
422         rline.setParent(this);
423         this.seqRenderables.add(rline);
424         this.currentLine = rline;
425         return rline;
426     }
427     
428     private void layoutMarkup(RenderableContainer container, Dimension containerSize, Insets insets, NodeImpl node) {
429         // This is the "inline" layout of an element.
430
// The difference with layoutChildren is that this
431
// method checks for padding and margin insets.
432
RenderState rs = node.getRenderState();
433         Insets marginInsets = null;
434         Insets paddingInsets = null;
435         if(rs != null) {
436             marginInsets = rs.getMarginInsets();
437             paddingInsets = rs.getPaddingInsets();
438         }
439         int leftSpacing = 0;
440         int rightSpacing = 0;
441         if(marginInsets != null) {
442             leftSpacing += marginInsets.left;
443             rightSpacing += marginInsets.right;
444         }
445         if(paddingInsets != null) {
446             leftSpacing += paddingInsets.left;
447             rightSpacing += paddingInsets.right;
448         }
449         if(leftSpacing > 0) {
450             RLine line = this.currentLine;
451             line.addSpacing(new RSpacing(node, this.container, leftSpacing, line.height));
452         }
453         this.layoutChildren(container, containerSize, insets, node);
454         if(rightSpacing > 0) {
455             RLine line = this.currentLine;
456             line.addSpacing(new RSpacing(node, this.container, rightSpacing, line.height));
457         }
458     }
459
460     private void layoutChildren(RenderableContainer container, Dimension containerSize, Insets insets, NodeImpl node) {
461         NodeImpl[] childrenArray = node.getChildrenArray();
462         if(childrenArray != null) {
463             int length = childrenArray.length;
464             for(int i = 0; i < length; i++) {
465                 NodeImpl child = childrenArray[i];
466                 short nodeType = child.getNodeType();
467                 if(nodeType == Node.TEXT_NODE) {
468                     this.layoutText(container, containerSize, insets, child);
469                 }
470                 else if(nodeType == Node.ELEMENT_NODE) {
471                     String JavaDoc nodeName = child.getNodeName().toUpperCase();
472                     this.currentLine.addStyleChanger(new RStyleChanger(child));
473                     MarkupLayout ml = (MarkupLayout) elementLayout.get(nodeName);
474                     if(ml != null) {
475                         ml.layoutMarkup(this, container, containerSize, insets, (HTMLElementImpl) child);
476                     }
477                     else {
478                         this.layoutMarkup(container, containerSize, insets, child);
479                     }
480                     this.currentLine.addStyleChanger(new RStyleChanger(node));
481                 }
482                 else if(nodeType == Node.COMMENT_NODE) {
483                     // ignore
484
}
485                 else {
486                     throw new IllegalStateException JavaDoc("Unknown node: " + child);
487                 }
488             }
489         }
490     }
491
492     private final void positionRBlock(RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement, RBlock renderable) {
493         // BlockRenderState gets text background color in a different way.
494
if(!this.addElsewhereIfPositioned(container, containerSize, insets, renderable, markupElement, false, true, false)) {
495             // Block can also define text style.
496
RLine line = this.currentLine;
497             int newY = line.getY() + line.getHeight();
498             // Set tentative block origin, so that float bounds work correctly during layout.
499
Insets paddingInsets = this.paddingInsets;
500             int newX = paddingInsets == null ? 0 : paddingInsets.left;
501             renderable.setOrigin(newX, newY);
502             FloatingBounds currentBounds = this.floatBounds;
503             RBlockViewport targetViewport = renderable.getRBlockViewport();
504             FloatingBounds childBounds = currentBounds == null ? null : new OffsetFloatingBounds(currentBounds, this, this.paddingInsets, targetViewport, targetViewport.paddingInsets);
505             renderable.layout(this.availContentWidth, this.availContentHeight, true, false, childBounds, newY);
506             this.addAsSeqBlock(containerSize, insets, renderable, false, false, 0);
507         }
508     }
509     
510     private final void positionRElement(RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement, RElement renderable, boolean usesAlignAttribute) {
511         if(!this.addElsewhereIfPositioned(container, containerSize, insets, renderable, markupElement, usesAlignAttribute, true, false)) {
512             renderable.layout(this.availContentWidth, this.availContentHeight, false, false);
513             this.addAsSeqBlock(containerSize, insets, renderable, false, false, 0);
514         }
515     }
516
517     private final void layoutRBlock(RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement, Insets defaultMarginInsets) {
518         RBlock renderable = (RBlock) markupElement.getUINode();
519         if(renderable == null) {
520             renderable = new RBlock(markupElement, this.listNesting, this.userAgentContext, this.rendererContext, this.frameContext, this.container, RBlock.OVERFLOW_NONE);
521             markupElement.setUINode(renderable);
522         }
523         renderable.setOriginalParent(this);
524         renderable.setDefaultMarginInsets(defaultMarginInsets);
525         this.positionRBlock(container, containerSize, insets, markupElement, renderable);
526     }
527
528     private final void layoutRTable(RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) {
529         RElement renderable = (RElement) markupElement.getUINode();
530         if(renderable == null) {
531             renderable = new RTable(markupElement, this.userAgentContext, this.rendererContext, this.frameContext, container);
532             markupElement.setUINode((UINode) renderable);
533         }
534         renderable.setOriginalParent(this);
535         renderable.layout(this.availContentWidth, this.availContentHeight, false, false);
536         this.positionRElement(container, containerSize, insets, markupElement, renderable, markupElement instanceof HTMLTableElementImpl);
537     }
538
539     private final void layoutListItem(RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) {
540         RListItem renderable = (RListItem) markupElement.getUINode();
541         if(renderable == null) {
542             renderable = new RListItem(markupElement, this.listNesting, this.userAgentContext, this.rendererContext, this.frameContext, this.container, null);
543             markupElement.setUINode(renderable);
544         }
545         renderable.setOriginalParent(this);
546         this.positionRBlock(container, containerSize, insets, markupElement, renderable);
547     }
548
549     private final void layoutList(RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) {
550         RList renderable = (RList) markupElement.getUINode();
551         if(renderable == null) {
552             renderable = new RList(markupElement, this.listNesting, this.userAgentContext, this.rendererContext, this.frameContext, this.container, null);
553             markupElement.setUINode(renderable);
554         }
555         renderable.setOriginalParent(this);
556         this.positionRBlock(container, containerSize, insets, markupElement, renderable);
557     }
558
559 // final void importRenderable(ExportedRenderable er) {
560
// switch(er.alignment) {
561
// case +1: {
562
// Point point = this.translateDescendentPoint(er.originalTarget, er.x, er.y);
563
// int rightOffset = this.fetchRightOffset(point.y);
564
// this.addToRightMargin(er.renderable, point.x, point.y, rightOffset, false);
565
// break;
566
// }
567
// case -1: {
568
// Point point = this.translateDescendentPoint(er.originalTarget, er.x, er.y);
569
// int leftOffset = this.fetchLeftOffset(point.y);
570
// this.addToLeftMargin(er.renderable, point.x, point.y, leftOffset, false);
571
// break;
572
// }
573
// case 0: {
574
// // In this case the original x and y points are not
575
// // translated.
576
// BoundableRenderable r = er.renderable;
577
// r.setOrigin(er.x, er.y);
578
// this.addPositionedRenderable(r, false);
579
// if(er.x + r.getWidth() > this.maxX) {
580
// this.maxX = er.x + r.getWidth();
581
// }
582
// int topY = er.y + r.getHeight();
583
// if(topY > this.maxY) {
584
// this.maxY = topY;
585
// }
586
// break;
587
// }
588
// }
589
// }
590

591     private void addParagraphBreak(RenderableContainer container, Dimension containerSize, Insets insets, ModelNode startNode) {
592         this.addLineBreak(container, containerSize, insets, startNode);
593         this.addLineBreak(container, containerSize, insets, startNode);
594     }
595     
596     private void addLineBreak(RenderableContainer container, Dimension containerSize, Insets insets, ModelNode startNode) {
597         RLine line = this.currentLine;
598         if(line.getHeight() == 0) {
599             RenderState rs = startNode.getRenderState();
600             int fontHeight = rs.getFontMetrics().getHeight();
601             line.setHeight(fontHeight);
602         }
603         this.currentLine = this.addLine(startNode, insets, this.currentLine);
604     }
605     
606     private boolean addElsewhereIfFloat(RenderableContainer container, Dimension containerSize, Insets insets, RElement renderable, HTMLElementImpl element, boolean usesAlignAttribute, CSS2PropertiesImpl style, boolean layout) {
607         // "static" handled here
608
String JavaDoc align = null;
609         if(style != null) {
610             align = style.getFloat();
611             if(align != null && align.length() == 0) {
612                 align = null;
613             }
614         }
615         if(align == null && usesAlignAttribute) {
616             align = element.getAttribute("align");
617         }
618         if(align != null) {
619             if("left".equalsIgnoreCase(align)) {
620                 this.addToLeftMargin(renderable, layout);
621                 return true;
622             }
623             else if("right".equalsIgnoreCase(align)) {
624                 this.addToRightMargin(renderable, layout);
625                 return true;
626             }
627             else {
628                 // fall through
629
}
630         }
631         return false;
632     }
633     
634     final RBlockViewport getParentViewport(ExportedRenderable er) {
635         if(er.alignment == 0) {
636             return this.getParentViewport();
637         }
638         else {
639             return this.getParentViewportForAlign();
640         }
641     }
642     
643     final boolean isImportable(ExportedRenderable er) {
644         if(er.alignment == 0) {
645             return this.positionsAbsolutes();
646         }
647         else {
648             return this.getParentViewportForAlign() == null;
649         }
650     }
651     
652     final RBlockViewport getParentViewport() {
653         // Use originalParent, which for one, is not going to be null during layout.
654
RCollection parent = this.getOriginalOrCurrentParent();
655         while(parent != null && !(parent instanceof RBlockViewport)) {
656             parent = parent.getOriginalOrCurrentParent();
657         }
658         return (RBlockViewport) parent;
659     }
660
661     final RBlockViewport getParentViewportForAlign() {
662         // Use originalParent, which for one, is not going to be null during layout.
663
Object JavaDoc parent = this.getOriginalOrCurrentParent();
664         if(parent instanceof RBlock) {
665             RBlock block = (RBlock) parent;
666             if(!block.couldBeScrollable()) {
667                 parent = ((BaseElementRenderable) parent).getOriginalOrCurrentParent();
668                 if(parent instanceof RBlockViewport) {
669                     return (RBlockViewport) parent;
670                 }
671             }
672         }
673         return null;
674     }
675
676     /**
677      * Returns true iff this viewport can position boxes that
678      * are absolutely positioned.
679      */

680     final boolean positionsAbsolutes() {
681         ModelNode node = this.getModelNode();
682         if(node instanceof HTMLElementImpl) {
683             HTMLElementImpl element = (HTMLElementImpl) node;
684             CSS2PropertiesImpl style = element.getCurrentStyle();
685             if(style != null) {
686                 String JavaDoc position = style.getPosition();
687                 return position != null && (position.equalsIgnoreCase("absolute") || position.equalsIgnoreCase("fixed") || position.equalsIgnoreCase("relative"));
688             }
689             else {
690                 return false;
691             }
692         }
693         else if(node instanceof HTMLDocumentImpl) {
694             return true;
695         }
696         else {
697             return false;
698         }
699     }
700
701     /**
702      * Checks for position and float attributes.
703      * @param container
704      * @param containerSize
705      * @param insets
706      * @param renderable
707      * @param element
708      * @param usesAlignAttribute
709      * @return True if it was added elsewhere.
710      */

711     private boolean addElsewhereIfPositioned(RenderableContainer container, Dimension containerSize, Insets insets, RElement renderable, HTMLElementImpl element, boolean usesAlignAttribute, boolean layout, boolean obeysMargins) {
712         // At this point block already has bounds.
713
CSS2PropertiesImpl style = element.getCurrentStyle();
714         String JavaDoc position = null;
715         if(style != null) {
716             position = style.getPosition();
717             if(position != null && position.length() == 0) {
718                 position = null;
719             }
720         }
721         boolean absolute = position != null && "absolute".equalsIgnoreCase(position);
722         boolean relative = position != null && "relative".equalsIgnoreCase(position);
723         if(absolute || relative) {
724             if(layout) {
725                 // Presumes the method will return true.
726
if(relative) {
727                     renderable.layout(this.availContentWidth, this.availContentHeight, true, false);
728                 }
729                 else {
730                     renderable.layout(this.availContentWidth, this.availContentHeight, false, false);
731                 }
732             }
733             RenderState rs = element.getRenderState();
734             String JavaDoc leftText = style.getLeft();
735             RLine line = this.currentLine;
736             int lineBottomY = line == null ? 0 : line.getY() + line.getHeight();
737             int newLeft;
738             if(leftText != null) {
739                 newLeft = HtmlValues.getPixelSize(leftText, rs, 0, this.availContentWidth);
740             }
741             else {
742                 String JavaDoc rightText = style.getRight();
743                 if(rightText != null) {
744                     int right = HtmlValues.getPixelSize(rightText, rs, 0, this.availContentWidth);
745                     newLeft = containerSize.width - right - renderable.getWidth();
746                     // If right==0 and renderable.width is larger than the parent's width,
747
// the expected behavior is for newLeft to be negative.
748
}
749                 else {
750                     newLeft = 0;
751                 }
752             }
753             int newTop = relative ? 0 : lineBottomY;
754             String JavaDoc topText = style.getTop();
755             if(topText != null) {
756                 newTop = HtmlValues.getPixelSize(topText, rs, newTop, this.availContentHeight);
757             }
758             else {
759                 String JavaDoc bottomText = style.getBottom();
760                 if(bottomText != null) {
761                     int bottom = HtmlValues.getPixelSize(bottomText, rs, 0, this.availContentHeight);
762                     newTop = containerSize.height - bottom - renderable.getHeight();
763                     if(!relative && newTop < 0) {
764                         newTop = 0;
765                     }
766                 }
767             }
768             if(relative) {
769                 // First, try to add normally.
770
boolean added = false;
771                 if(!this.addElsewhereIfFloat(container, containerSize, insets, renderable, element, usesAlignAttribute, style, false)) {
772                     // This is a fake add as block (should not add to seqRenderables).
773
this.addAsSeqBlock(containerSize, insets, renderable, true, obeysMargins, 0);
774                 }
775                 else {
776                     added = true;
777                 }
778                 // Second, shift origin.
779
renderable.setOrigin(renderable.getX() + newLeft, renderable.getY() + newTop);
780                 // Now really add to other renderables.
781
if(!added) {
782                     this.addPositionedRenderable(renderable, true);
783                 }
784             }
785             else {
786                 // Schedule as delayed pair. Will be positioned after
787
// everything else.
788
this.scheduleAbsDelayedPair(renderable, newLeft, newTop, 0);
789                 // Does not affect bounds of viewport.
790
return true;
791             }
792             int newBottomY = renderable.getY() + renderable.getHeight();
793             this.checkY(newBottomY);
794             if(newBottomY > this.maxY) {
795                 this.maxY = newBottomY;
796             }
797             return true;
798         }
799         else {
800             if(this.addElsewhereIfFloat(container, containerSize, insets, renderable, element, usesAlignAttribute, style, layout)) {
801                 return true;
802             }
803         }
804         return false;
805     }
806
807     private boolean isPositionedElsewhere() {
808         ModelNode node = this.modelNode;
809         if(node instanceof HTMLElementImpl) {
810             CSS2PropertiesImpl style = ((HTMLElementImpl) node).getCurrentStyle();
811             if(style != null) {
812                 String JavaDoc position = style.getPosition();
813                 if(position != null) {
814                     if("absolute".equalsIgnoreCase(position) || "relative".equalsIgnoreCase(position)) {
815                         //TODO: fixed
816
return true;
817                     }
818                 }
819                 String JavaDoc floatText = style.getFloat();
820                 if(floatText != null) {
821                     if("left".equalsIgnoreCase(floatText) || "right".equalsIgnoreCase(floatText)) {
822                         return true;
823                     }
824                 }
825             }
826         }
827         return false;
828     }
829     
830     /**
831      * Checks property 'float' and in some cases attribute 'align'.
832      */

833     private void addRenderableToLineCheckStyle(RenderableContainer container, Dimension containerSize, Insets insets, RElement renderable, HTMLElementImpl element, boolean usesAlignAttribute) {
834         if(this.addElsewhereIfPositioned(container, containerSize, insets, renderable, element, usesAlignAttribute, false, true)) {
835             return;
836         }
837         this.addRenderableToLine(container, insets, renderable);
838     }
839     
840     private void addRenderableToLine(RenderableContainer container, Insets insets, Renderable renderable) {
841         //this.skipLineBreakBefore = false;
842
RenderState rs = renderable.getModelNode().getRenderState();
843         int whiteSpace = this.overrideNoWrap ? RenderState.WS_NOWRAP : rs.getWhiteSpace();
844         boolean allowOverflow = whiteSpace == RenderState.WS_NOWRAP || whiteSpace == RenderState.WS_PRE;
845         this.skipParagraphBreakBefore = false;
846         RLine line = this.currentLine;
847         try {
848             line.add(renderable, allowOverflow);
849         } catch(OverflowException oe) {
850             this.addLine(renderable.getModelNode(), insets, line);
851             Collection renderables = oe.getRenderables();
852             Iterator i = renderables.iterator();
853             while(i.hasNext()) {
854                 Renderable r = (Renderable) i.next();
855                 this.addRenderableToLine(container, insets, r);
856             }
857         }
858         if(renderable instanceof RUIControl) {
859             this.container.add(((RUIControl) renderable).widget.getComponent());
860         }
861     }
862     
863     private void addWordToLine(RenderableContainer container, Insets insets, RWord renderable, boolean allowOverflow) {
864         //this.skipLineBreakBefore = false;
865
this.skipParagraphBreakBefore = false;
866         RLine line = this.currentLine;
867         try {
868             line.addWord(renderable, allowOverflow);
869         } catch(OverflowException oe) {
870             this.addLine(renderable.getModelNode(), insets, line);
871             Collection renderables = oe.getRenderables();
872             Iterator i = renderables.iterator();
873             while(i.hasNext()) {
874                 Renderable r = (Renderable) i.next();
875                 this.addRenderableToLine(container, insets, r);
876             }
877         }
878     }
879
880     private void addAsSeqBlockCheckStyle(Dimension containerSize, Insets insets, RElement block, HTMLElementImpl element, boolean usesAlignAttribute) {
881         if(this.addElsewhereIfPositioned(this.container, containerSize, insets, block, element, usesAlignAttribute, false, true)) {
882             return;
883         }
884         this.addAsSeqBlock(containerSize, insets, block, 0);
885     }
886     
887     private void addAsSeqBlock(Dimension containerSize, Insets insets, BoundableRenderable block, int alignXPercent) {
888         this.addAsSeqBlock(containerSize, insets, block, false, true, alignXPercent);
889     }
890     
891     private void addAsSeqBlock(Dimension containerSize, Insets insets, BoundableRenderable block, boolean fakeAdd, boolean obeysMargins, int alignXPercent) {
892         int insetsl = insets.left;
893         Collection sr = this.seqRenderables;
894         RLine prevLine = this.currentLine;
895         if(prevLine != null) {
896             if(prevLine.x + prevLine.width > this.maxX) {
897                 this.maxX = prevLine.x + prevLine.width;
898             }
899             // Check height only with floats.
900
}
901         int newLineY = prevLine == null ? insets.top : prevLine.y + prevLine.height;
902         int blockX;
903         if(obeysMargins) {
904             int blockOffset = this.fetchLeftOffset(newLineY);
905             blockX = blockOffset + insetsl;
906             if(alignXPercent > 0) {
907                 int offset = (this.availContentWidth - blockOffset - block.getWidth()) * alignXPercent / 100;
908                 if(offset > 0) {
909                     blockX += offset;
910                 }
911             }
912         }
913         else {
914             //Block does not obey alignment margins
915
blockX = insetsl;
916             if(alignXPercent > 0) {
917                 int offset = (this.availContentWidth - block.getWidth()) * alignXPercent / 100;
918                 if(offset > 0) {
919                     blockX += offset;
920                 }
921             }
922         }
923         block.setOrigin(blockX, newLineY);
924         if(!fakeAdd) {
925             sr.add(block);
926             block.setParent(this);
927         }
928         if(blockX + block.getWidth() > this.maxX) {
929             this.maxX = blockX + block.getWidth();
930         }
931         newLineY += block.getHeight();
932         this.checkY(newLineY);
933         int leftOffset = this.fetchLeftOffset(newLineY);
934         int newX = insetsl + leftOffset;
935         int newMaxWidth = containerSize.width - insetsl - insets.right - this.fetchRightOffset(newLineY) - leftOffset;
936         ModelNode lineNode = block.getModelNode().getParentModelNode();
937         RLine newLine = new RLine(lineNode, this.container, newX, newLineY, newMaxWidth, 0);
938         newLine.setParent(this);
939         sr.add(newLine);
940         this.currentLine = newLine;
941         this.skipParagraphBreakBefore = false;
942     }
943             
944     private void layoutText(RenderableContainer container, Dimension containerSize, Insets insets, NodeImpl textNode) {
945         RenderState renderState = textNode.getRenderState();
946         if(renderState == null) {
947             throw new IllegalStateException JavaDoc("RenderState is null for node " + textNode + " with parent " + textNode.getParentNode());
948         }
949         FontMetrics fm = renderState.getFontMetrics();
950         int descent = fm.getDescent();
951         int ascentPlusLeading = fm.getAscent() + fm.getLeading();
952         int wordHeight = fm.getHeight();
953         int blankWidth = fm.charWidth(' ');
954         int whiteSpace = this.overrideNoWrap ? RenderState.WS_NOWRAP : renderState.getWhiteSpace();
955         String JavaDoc text = textNode.getNodeValue();
956         if(whiteSpace != RenderState.WS_PRE) {
957             boolean allowOverflow = whiteSpace == RenderState.WS_NOWRAP;
958             int length = text.length();
959             StringBuffer JavaDoc word = new StringBuffer JavaDoc(12);
960             for(int i = 0; i < length; i++) {
961                 char ch = text.charAt(i);
962                 if(Character.isWhitespace(ch)) {
963                     int wlen = word.length();
964                     if(wlen > 0) {
965                         RWord rword = new RWord(textNode, word.toString(), container, fm, descent, ascentPlusLeading, wordHeight);
966                         this.addWordToLine(container, insets, rword, allowOverflow);
967                         word.delete(0, wlen);
968                     }
969                     RLine line = this.currentLine;
970                     if(line.width > 0) {
971                         RBlank rblank = new RBlank(textNode, fm, container, ascentPlusLeading, blankWidth, wordHeight);
972                         line.addBlank(rblank);
973                     }
974                     for(i++; i < length; i++) {
975                         ch = text.charAt(i);
976                         if(!Character.isWhitespace(ch)) {
977                             word.append(ch);
978                             break;
979                         }
980                     }
981                 }
982                 else {
983                     word.append(ch);
984                 }
985             }
986             if(word.length() > 0) {
987                 RWord rword = new RWord(textNode, word.toString(), container, fm, descent, ascentPlusLeading, wordHeight);
988                 this.addWordToLine(container, insets, rword, allowOverflow);
989             }
990         }
991         else {
992             int length = text.length();
993             boolean lastCharSlashR = false;
994             StringBuffer JavaDoc line = new StringBuffer JavaDoc();
995             for(int i = 0; i < length; i++) {
996                 char ch = text.charAt(i);
997                 switch(ch) {
998                 case '\r':
999                     lastCharSlashR = true;
1000                    break;
1001                case '\n':
1002                    int llen = line.length();
1003                    if(llen > 0) {
1004                        RWord rword = new RWord(textNode, line.toString(), container, fm, descent, ascentPlusLeading, wordHeight);
1005                        this.addWordToLine(container, insets, rword, true);
1006                        line.delete(0, line.length());
1007                    }
1008                    this.addLine(textNode, insets, this.currentLine);
1009                    break;
1010                default:
1011                    if(lastCharSlashR) {
1012                        line.append('\r');
1013                        lastCharSlashR = false;
1014                    }
1015                    line.append(ch);
1016                    break;
1017                }
1018            }
1019            if(line.length() > 0) {
1020                RWord rword = new RWord(textNode, line.toString(), container, fm, descent, ascentPlusLeading, wordHeight);
1021                this.addWordToLine(container, insets, rword, true);
1022            }
1023        }
1024    }
1025
1026    /**
1027     *
1028     * @param others An ordered collection.
1029     * @param seqRenderables
1030     * @param destination
1031     */

1032    private void populateZIndexGroups(Collection others, Collection seqRenderables, ArrayList destination) {
1033        this.populateZIndexGroups(others, seqRenderables.iterator(), destination);
1034    }
1035
1036    /**
1037     *
1038     * @param others An ordered collection.
1039     * @param seqRenderablesIterator
1040     * @param destination
1041     */

1042    private void populateZIndexGroups(Collection others, Iterator seqRenderablesIterator, ArrayList destination) {
1043        // First, others with z-index < 0
1044
Iterator i1 = others.iterator();
1045        Renderable pending = null;
1046        while(i1.hasNext()) {
1047            PositionedRenderable pr = (PositionedRenderable) i1.next();
1048            Renderable r = pr.renderable;
1049            if(r.getZIndex() >= 0) {
1050                pending = r;
1051                break;
1052            }
1053            destination.add(r);
1054        }
1055        // Second, sequential renderables
1056
Iterator i2 = seqRenderablesIterator;
1057        while(i2.hasNext()) {
1058            destination.add(i2.next());
1059        }
1060        
1061        // Third, other renderables with z-index >= 0.
1062
if(pending != null) {
1063            destination.add(pending);
1064            while(i1.hasNext()) {
1065                PositionedRenderable pr = (PositionedRenderable) i1.next();
1066                Renderable r = pr.renderable;
1067                destination.add(r);
1068            }
1069        }
1070    }
1071    
1072    public Renderable[] getRenderablesArray() {
1073        SortedSet others = this.positionedRenderables;
1074        int othersSize = others == null ? 0 : others.size();
1075        if(othersSize == 0) {
1076            return (Renderable[]) this.seqRenderables.toArray(Renderable.EMPTY_ARRAY);
1077        }
1078        else {
1079            ArrayList allRenderables = new ArrayList();
1080            this.populateZIndexGroups(others, this.seqRenderables, allRenderables);
1081            return (Renderable[]) allRenderables.toArray(Renderable.EMPTY_ARRAY);
1082        }
1083    }
1084    
1085    public Iterator getRenderables() {
1086        SortedSet others = this.positionedRenderables;
1087        if(others == null || others.size() == 0) {
1088            return this.seqRenderables.iterator();
1089        }
1090        else {
1091            ArrayList allRenderables = new ArrayList();
1092            this.populateZIndexGroups(others, this.seqRenderables, allRenderables);
1093            return allRenderables.iterator();
1094        }
1095    }
1096
1097    public Iterator getRenderables(Rectangle clipBounds) {
1098        if(!EventQueue.isDispatchThread() && logger.isLoggable(Level.INFO)) {
1099            logger.warning("getRenderables(): Invoked outside GUI dispatch thread.");
1100        }
1101        Renderable[] array = (Renderable[]) this.seqRenderables.toArray(Renderable.EMPTY_ARRAY);
1102        Range range = MarkupUtilities.findRenderables(array, clipBounds, true);
1103        Iterator baseIterator = org.lobobrowser.util.ArrayUtilities.iterator(array, range.offset, range.length);
1104        SortedSet others = this.positionedRenderables;
1105        if(others == null || others.size() == 0) {
1106            return baseIterator;
1107        }
1108        else {
1109            ArrayList matches = new ArrayList();
1110            // ArrayList "matches" keeps the order from "others".
1111
Iterator i = others.iterator();
1112            while(i.hasNext()) {
1113                PositionedRenderable pr = (PositionedRenderable) i.next();
1114                Object JavaDoc r = pr.renderable;
1115                if(r instanceof BoundableRenderable) {
1116                    BoundableRenderable br = (BoundableRenderable) r;
1117                    Rectangle rbounds = br.getBounds();
1118                    if(clipBounds.intersects(rbounds)) {
1119                        matches.add(pr);
1120                    }
1121                }
1122            }
1123            if(matches.size() == 0) {
1124                return baseIterator;
1125            }
1126            else {
1127                ArrayList destination = new ArrayList();
1128                this.populateZIndexGroups(matches, baseIterator, destination);
1129                return destination.iterator();
1130            }
1131        }
1132    }
1133    
1134    public BoundableRenderable getRenderable(java.awt.Point JavaDoc point) {
1135        Iterator i = this.getRenderables(point);
1136        return i == null ? null : (i.hasNext() ? (BoundableRenderable) i.next() : null);
1137    }
1138
1139    public Iterator getRenderables(java.awt.Point JavaDoc point) {
1140        if(!EventQueue.isDispatchThread() && logger.isLoggable(Level.INFO)) {
1141            logger.warning("getRenderable(): Invoked outside GUI dispatch thread.");
1142        }
1143        Collection result = null;
1144        SortedSet others = this.positionedRenderables;
1145        int size = others == null ? 0 : others.size();
1146        PositionedRenderable[] otherArray = size == 0 ? null : (PositionedRenderable[]) others.toArray(PositionedRenderable.EMPTY_ARRAY);
1147        // Try to find in other renderables with z-index >= 0 first.
1148
int index = 0;
1149        if(size != 0) {
1150            int px = point.x;
1151            int py = point.y;
1152            // Must go in reverse order
1153
for(index = size; --index >= 0;) {
1154                PositionedRenderable pr = otherArray[index];
1155                Renderable r = pr.renderable;
1156                if(r.getZIndex() < 0) {
1157                    break;
1158                }
1159                if(r instanceof BoundableRenderable) {
1160                    BoundableRenderable br = (BoundableRenderable) r;
1161                    Rectangle rbounds = br.getBounds();
1162                    if(rbounds.contains(px, py)) {
1163                        if(result == null) {
1164                            result = new LinkedList();
1165                        }
1166                        result.add(br);
1167                    }
1168                }
1169            }
1170        }
1171        // Now do a "binary" search on sequential renderables.
1172
Renderable[] array = (Renderable[]) this.seqRenderables.toArray(Renderable.EMPTY_ARRAY);
1173        BoundableRenderable found = MarkupUtilities.findRenderable(array, point, true);
1174        if(found != null) {
1175            if(result == null) {
1176                result = new LinkedList();
1177            }
1178            result.add(found);
1179        }
1180        // Finally, try to find it in renderables with z-index < 0.
1181
if(size != 0) {
1182            int px = point.x;
1183            int py = point.y;
1184            // Must go in reverse order
1185
for(; index >= 0; index--) {
1186                PositionedRenderable pr = otherArray[index];
1187                Renderable r = pr.renderable;
1188                if(r instanceof BoundableRenderable) {
1189                    BoundableRenderable br = (BoundableRenderable) r;
1190                    Rectangle rbounds = br.getBounds();
1191                    if(rbounds.contains(px, py)) {
1192                        if(result == null) {
1193                            result = new LinkedList();
1194                        }
1195                        result.add(br);
1196                    }
1197                }
1198            }
1199        }
1200        return result == null ? null : result.iterator();
1201    }
1202
1203    private RElement setupNewUIControl(RenderableContainer container, HTMLElementImpl element, UIControl control) {
1204        RElement renderable = new RUIControl(element, control, container, this.frameContext, this.userAgentContext);
1205        element.setUINode((UINode) renderable);
1206        return renderable;
1207    }
1208    
1209    private final void addAlignableAsBlock(RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement, BoundableRenderable renderable) {
1210        // At this point block already has bounds.
1211
boolean regularAdd = false;
1212        String JavaDoc align = markupElement.getAttribute("align");
1213        if(align != null) {
1214            if("left".equalsIgnoreCase(align)) {
1215                this.addToLeftMargin(renderable, false);
1216            }
1217            else if("right".equalsIgnoreCase(align)) {
1218                this.addToRightMargin(renderable, false);
1219            }
1220            else {
1221                regularAdd = true;
1222            }
1223        }
1224        else {
1225            regularAdd = true;
1226        }
1227        if(regularAdd) {
1228            int alignXPercent = 0;
1229            if(align != null) {
1230                if("center".equalsIgnoreCase(align)) {
1231                    alignXPercent = 50;
1232                }
1233            }
1234            this.addAsSeqBlock(containerSize, insets, renderable, alignXPercent);
1235        }
1236    }
1237    
1238    private final void layoutHr(RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) {
1239        RElement renderable = (RElement) markupElement.getUINode();
1240        if(renderable == null) {
1241            renderable = this.setupNewUIControl(container, markupElement, new HrControl(markupElement));
1242        }
1243        renderable.layout(this.availContentWidth, this.availContentHeight, false, false);
1244        this.addAlignableAsBlock(container, containerSize, insets, markupElement, renderable);
1245    }
1246
1247    private final BaseInputControl createInputControl(HTMLBaseInputElement markupElement) {
1248        String JavaDoc type = markupElement.getAttribute("type");
1249        if(type == null) {
1250            return new InputTextControl(markupElement);
1251        }
1252        type = type.toLowerCase();
1253        if("text".equals(type) || type.length() == 0) {
1254            return new InputTextControl(markupElement);
1255        }
1256        else if("hidden".equals(type)) {
1257            return null;
1258        }
1259        else if("submit".equals(type)) {
1260            return new InputButtonControl(markupElement);
1261        }
1262        else if("password".equals(type)) {
1263            return new InputPasswordControl(markupElement);
1264        }
1265        else if("radio".equals(type)) {
1266            return new InputRadioControl(markupElement);
1267        }
1268        else if("checkbox".equals(type)) {
1269            return new InputCheckboxControl(markupElement);
1270        }
1271        else if("image".equals(type)) {
1272            return new InputImageControl(markupElement);
1273        }
1274        else if("reset".equals(type)) {
1275            return new InputButtonControl(markupElement);
1276        }
1277        else if("button".equals(type)) {
1278            return new InputButtonControl(markupElement);
1279        }
1280        else if("file".equals(type)) {
1281            return new InputFileControl(markupElement);
1282        }
1283        else {
1284            return null;
1285        }
1286    }
1287    
1288    //private LineMargin leftMargin = null;
1289
//private LineMargin rightMargin = null;
1290

1291    /**
1292     * Gets offset from the left due to floats. It does
1293     * not count padding.
1294     */

1295    private final int fetchLeftOffset(int newLineY) {
1296        FloatingBounds floatBounds = this.floatBounds;
1297        return floatBounds == null ? 0 : floatBounds.getLeft(newLineY);
1298    }
1299    
1300    private final int fetchRightOffset(int newLineY) {
1301        FloatingBounds floatBounds = this.floatBounds;
1302        return floatBounds == null ? 0 : floatBounds.getRight(newLineY);
1303    }
1304    
1305    private final void checkLineOverflow() {
1306        RLine line = this.currentLine;
1307        int lineY = line.getY();
1308        int leftOffset = this.fetchLeftOffset(lineY);
1309        int rightOffset = this.fetchRightOffset(lineY);
1310        Insets insets = this.paddingInsets;
1311        int newX = insets.left + leftOffset;
1312        int newMaxWidth = this.availContentWidth - rightOffset - leftOffset;
1313        if(newX != line.getX() || newMaxWidth != line.getWidth()) {
1314            try {
1315                line.adjustHorizontalBounds(newX, newMaxWidth);
1316            } catch(OverflowException oe) {
1317                Collection renderables = oe.getRenderables();
1318                Iterator i = renderables.iterator();
1319                RenderableContainer rc = this.container;
1320                boolean first = true;
1321                while(i.hasNext()) {
1322                    Renderable r = (Renderable) i.next();
1323                    if(first) {
1324                        first = false;
1325                        this.addLine(r.getModelNode(), insets, line);
1326                    }
1327                    this.addRenderableToLine(rc, insets, r);
1328                }
1329            }
1330        }
1331    }
1332
1333    private static final SizeExceededException SEE = new SizeExceededException();
1334    
1335    private final void checkY(int y) {
1336        if(this.yLimit != -1 && y > this.yLimit) {
1337            throw SEE;
1338        }
1339    }
1340    
1341    private final void addToRightMargin(BoundableRenderable brenderable, boolean layout) {
1342        brenderable.setOriginalParent(this);
1343        int availWidth = this.availContentWidth;
1344        int availHeight = this.availContentHeight;
1345        if(layout) {
1346            if(brenderable instanceof RElement) {
1347                ((RElement) brenderable).layout(availWidth, availHeight, false, false);
1348            }
1349            else {
1350                throw new IllegalStateException JavaDoc();
1351            }
1352        }
1353        int width = brenderable.getWidth();
1354        int y = this.currentLine.getBounds().y;
1355        int rightOffset = 0;
1356        Insets insets = this.paddingInsets;
1357        int x = insets.left + this.availContentWidth - rightOffset - width;
1358        if(x < 0) {
1359            x = 0;
1360        }
1361        this.scheduleFloatDelayedPair(brenderable, x, y, +1);
1362    }
1363 
1364    private final void addToLeftMargin(BoundableRenderable brenderable, boolean layout) {
1365        brenderable.setOriginalParent(this);
1366        int availWidth = this.availContentWidth;
1367        int availHeight = this.availContentHeight;
1368        if(layout) {
1369            if(brenderable instanceof RElement) {
1370                ((RElement) brenderable).layout(availWidth, availHeight, false, false);
1371            }
1372            else {
1373                throw new IllegalStateException JavaDoc();
1374            }
1375        }
1376        int y = this.currentLine.getBounds().y;
1377        int leftOffset = this.fetchLeftOffset(y);
1378        Insets insets = this.paddingInsets;
1379        int x = insets.left + leftOffset;
1380        this.scheduleFloatDelayedPair(brenderable, x, y, -1);
1381    }
1382
1383// private final void addToRightMargin(BoundableRenderable brenderable, int x, int y, int rightOffset, boolean export) {
1384
// int width = brenderable.getWidth();
1385
// int height = brenderable.getHeight();
1386
// // Update maxY and maxY if necessary
1387
// if(x + width > this.maxX) {
1388
// this.maxX = x + width;
1389
// }
1390
// LineMargin newMargin = new LineMargin(this.rightMargin, y + height, rightOffset + width);
1391
// this.rightMargin = newMargin;
1392
// this.checkLineOverflow();
1393
// if(export && this.scheduleAddInContainingViewport(this, brenderable, x, y, +1)) {
1394
// // Must try parent viewport. Consider an aligned block
1395
// // bigger than the current viewport which must also
1396
// // become a margin for a paragraph in the parent viewport
1397
// // and sibling paragraphs.
1398
// return;
1399
// }
1400
// int newY = y + height;
1401
// this.checkY(newY);
1402
// if(newY > this.maxY) {
1403
// this.maxY = newY;
1404
// }
1405
// //Should only set origin, not size.
1406
// //brenderable.setBounds(x, y, width, height);
1407
// brenderable.setOrigin(x, y);
1408
// this.addPositionedRenderable(brenderable, true);
1409
// }
1410
//
1411
// private final void addToLeftMargin(BoundableRenderable brenderable, int x, int y, int leftOffset, boolean export) {
1412
// int width = brenderable.getWidth();
1413
// int height = brenderable.getHeight();
1414
// // Update maxY and maxY if necessary
1415
// if(x + width > this.maxX) {
1416
// this.maxX = x + width;
1417
// }
1418
// LineMargin newMargin = new LineMargin(this.leftMargin, y + height, leftOffset + width);
1419
// this.leftMargin = newMargin;
1420
// this.checkLineOverflow();
1421
// if(export && this.scheduleAddInContainingViewport(this, brenderable, x, y, -1)) {
1422
// // Must try parent viewport. Consider an aligned block
1423
// // bigger than the current viewport which must also
1424
// // become a margin for a paragraph in the parent viewport
1425
// // and sibling paragraphs.
1426
// return;
1427
// }
1428
// int newY = y + height;
1429
// this.checkY(newY);
1430
// if(newY > this.maxY) {
1431
// this.maxY = newY;
1432
// }
1433
// //Should only set origin, not size.
1434
// //brenderable.setBounds(x, y, width, height);
1435
// brenderable.setOrigin(x, y);
1436
// this.addPositionedRenderable(brenderable, true);
1437
// }
1438

1439    private FloatingBounds floatBounds = null;
1440    
1441    private final void positionFloat(DelayedPair pair) {
1442        BoundableRenderable brenderable = pair.child;
1443        //OPTIMIZE: Point translation done twice.
1444
Point localPoint = brenderable == this ? new Point(pair.x, pair.y) : this.translateDescendentPoint(brenderable.getOriginalOrCurrentParent(), pair.x, pair.y);
1445        int width = brenderable.getWidth();
1446        int height = brenderable.getHeight();
1447        int y = localPoint.y;
1448        int newY = y + height;
1449        this.checkY(newY);
1450        if(newY > this.maxY) {
1451            this.maxY = newY;
1452        }
1453        int alignment = pair.alignment;
1454        FloatingBounds prevFloatBounds = this.floatBounds;
1455        int x;
1456        Insets paddingInsets = this.paddingInsets;
1457        int left = paddingInsets == null ? 0 : paddingInsets.left;
1458        if(prevFloatBounds != null) {
1459            x = alignment > 0 ? left + this.availContentWidth - prevFloatBounds.getRight(y) - width : left + prevFloatBounds.getLeft(y);
1460        }
1461        else {
1462            x = alignment > 0 ? left + this.availContentWidth - width : left;
1463        }
1464        if(x < left) {
1465            x = left;
1466        }
1467        int effectiveWidth = width;
1468        if(alignment > 0) {
1469            if(localPoint.x < x) {
1470                effectiveWidth += (x - localPoint.x);
1471                x = localPoint.x;
1472            }
1473        }
1474        else {
1475            if(localPoint.x > x) {
1476                effectiveWidth += (localPoint.x - x);
1477                x = localPoint.x;
1478            }
1479        }
1480        FloatingViewportBounds newFloatBounds = new FloatingViewportBounds(prevFloatBounds, alignment, y, effectiveWidth, height);
1481        this.floatBounds = newFloatBounds;
1482        brenderable.setOrigin(x, y);
1483        if(x + width > this.maxX) {
1484            this.maxX = x + width;
1485        }
1486    }
1487
1488    private final void addFloat(DelayedPair pair) {
1489        BoundableRenderable brenderable = pair.child;
1490        this.addPositionedRenderable(brenderable, true);
1491    }
1492    
1493    
1494// private boolean scheduleAddInContainingViewport(RBlockViewport originalTarget, BoundableRenderable renderable, int x, int y, int alignment) {
1495
// // Always succeeds. It gets reimported in the local
1496
// // viewport if it turns out it can't be exported up.
1497
// this.addExportedRenderable(originalTarget, renderable, x, y, alignment);
1498
// return true;
1499
// }
1500

1501    private void scheduleAbsDelayedPair(BoundableRenderable renderable, int x, int y, int alignment) {
1502        // It gets reimported in the local
1503
// viewport if it turns out it can't be exported up.
1504
RenderableContainer container = this.container;
1505        for(;;) {
1506            if(container instanceof Renderable) {
1507                Object JavaDoc node = ((Renderable) container).getModelNode();
1508                if(node instanceof HTMLElementImpl) {
1509                    HTMLElementImpl element = (HTMLElementImpl) node;
1510                    CSS2PropertiesImpl style = element.getCurrentStyle();
1511                    if(style != null) {
1512                        String JavaDoc position = style.getPosition();
1513                        if(position != null && (position.equalsIgnoreCase("absolute") || position.equalsIgnoreCase("fixed") || position.equalsIgnoreCase("relative"))) {
1514                            break;
1515                        }
1516                    }
1517                    RenderableContainer newContainer = container.getParentContainer();
1518                    if(newContainer == null) {
1519                        break;
1520                    }
1521                    container = newContainer;
1522                }
1523                else {
1524                    break;
1525                }
1526            }
1527            else {
1528                break;
1529            }
1530        }
1531        DelayedPair pair = new DelayedPair(alignment, container, renderable, x, y);
1532        this.container.addDelayedPair(pair);
1533    }
1534
1535    private void scheduleFloatDelayedPair(BoundableRenderable renderable, int x, int y, int alignment) {
1536        // It gets reimported in the local
1537
// viewport if it turns out it can't be exported up.
1538
RenderableContainer targetContainer = this.container;
1539        RBlockViewport targetViewport = this;
1540        for(;;) {
1541            if(targetViewport.isPositionedElsewhere()) {
1542                break;
1543            }
1544            if(!(targetContainer instanceof RBlock)) {
1545                break;
1546            }
1547            RBlock rblock = (RBlock) targetContainer;
1548            Object JavaDoc parent = rblock.getOriginalOrCurrentParent();
1549            if(!(parent instanceof RBlockViewport)) {
1550                break;
1551            }
1552            targetViewport = (RBlockViewport) parent;
1553            targetContainer = targetViewport.container;
1554        }
1555        DelayedPair pair = new DelayedPair(alignment, targetContainer, renderable, x, y);
1556        this.container.addDelayedPair(pair);
1557    }
1558
1559    void importNonFloat(DelayedPair pair) {
1560        BoundableRenderable r = pair.child;
1561        r.setOrigin(pair.x, pair.y);
1562        this.addPositionedRenderable(r, false);
1563        // Size of block does not change - it's
1564
// set in stone?
1565
}
1566
1567// boolean addToExportedRenderables(ExportedRenderable er) {
1568
// // Always succeeds. It gets reimported in the local
1569
// // viewport if it turns out it can't be exported up.
1570
// this.addExportedRenderable(er);
1571
// return true;
1572
// }
1573

1574// private final void addExportedRenderable(RBlockViewport originalTarget, BoundableRenderable renderable, int x, int y, int align) {
1575
// // Note that exported renderables currently require
1576
// // the parent to be a block contained in a viewport.
1577
// Collection er = this.exportedRenderables;
1578
// if(er == null) {
1579
// er = new LinkedList();
1580
// this.exportedRenderables = er;
1581
// }
1582
// er.add(new ExportedRenderable(originalTarget, renderable, x, y, align));
1583
// }
1584

1585// private final void addExportedRenderable(ExportedRenderable er) {
1586
// // Note that exported renderables currently require
1587
// // the parent to be a block contained in a viewport.
1588
// Collection ers = this.exportedRenderables;
1589
// if(ers == null) {
1590
// ers = new LinkedList();
1591
// this.exportedRenderables = ers;
1592
// }
1593
// ers.add(er);
1594
// }
1595

1596// final Iterator getExportedRenderables() {
1597
// Collection er = this.exportedRenderables;
1598
// return er == null ? null : er.iterator();
1599
// }
1600

1601    private final void addPositionedRenderable(BoundableRenderable renderable, boolean verticalAlignable) {
1602        // Expected to be called only in GUI thread.
1603
SortedSet others = this.positionedRenderables;
1604        if(others == null) {
1605            others = new TreeSet(new ZIndexComparator());
1606            this.positionedRenderables = others;
1607        }
1608        others.add(new PositionedRenderable(renderable, verticalAlignable, this.otherOrdinal++));
1609        renderable.setParent(this);
1610        if(renderable instanceof RUIControl) {
1611            this.container.add(((RUIControl) renderable).widget.getComponent());
1612        }
1613    }
1614    
1615    public int getFirstLineHeight() {
1616        ArrayList renderables = this.seqRenderables;
1617        int size = renderables.size();
1618        if(size == 0) {
1619            return 0;
1620        }
1621        BoundableRenderable br = (BoundableRenderable) renderables.get(0);
1622        return br.getHeight();
1623    }
1624
1625    public int getFirstBaselineOffset() {
1626        ArrayList renderables = this.seqRenderables;
1627        Iterator i = renderables.iterator();
1628        while(i.hasNext()) {
1629            Object JavaDoc r = i.next();
1630            if(r instanceof RLine) {
1631                return ((RLine) r).getBaselineOffset();
1632            }
1633        }
1634        return 0;
1635    }
1636    
1637    //----------------------------------------------------------------
1638

1639    public RenderableSpot getLowestRenderableSpot(int x, int y) {
1640        BoundableRenderable br = this.getRenderable(new Point(x, y));
1641        if(br != null) {
1642            return br.getLowestRenderableSpot(x - br.getX(), y - br.getY());
1643        }
1644        else {
1645            return new RenderableSpot(this, x, y);
1646        }
1647    }
1648
1649    /* (non-Javadoc)
1650     * @see org.xamjwg.html.renderer.BoundableRenderable#onMouseClick(java.awt.event.MouseEvent, int, int)
1651     */

1652    public boolean onMouseClick(MouseEvent JavaDoc event, int x, int y) {
1653        Iterator i = this.getRenderables(new Point(x, y));
1654        if(i != null) {
1655            while(i.hasNext()) {
1656                BoundableRenderable br = (BoundableRenderable) i.next();
1657                if(br != null) {
1658                    Rectangle bounds = br.getBounds();
1659                    if(!br.onMouseClick(event, x - bounds.x, y - bounds.y)) {
1660                        return false;
1661                    }
1662                }
1663            }
1664        }
1665        return true;
1666    }
1667
1668    public boolean onDoubleClick(MouseEvent JavaDoc event, int x, int y) {
1669        Iterator i = this.getRenderables(new Point(x, y));
1670        if(i != null) {
1671            while(i.hasNext()) {
1672                BoundableRenderable br = (BoundableRenderable) i.next();
1673                if(br != null) {
1674                    Rectangle bounds = br.getBounds();
1675                    if(!br.onDoubleClick(event, x - bounds.x, y - bounds.y)) {
1676                        return false;
1677                    }
1678                }
1679            }
1680        }
1681        return true;
1682    }
1683
1684    /* (non-Javadoc)
1685     * @see org.xamjwg.html.renderer.BoundableRenderable#onMouseDisarmed(java.awt.event.MouseEvent)
1686     */

1687    public boolean onMouseDisarmed(MouseEvent JavaDoc event) {
1688        BoundableRenderable br = this.armedRenderable;
1689        if(br != null) {
1690            try {
1691                return br.onMouseDisarmed(event);
1692            } finally {
1693                this.armedRenderable = null;
1694            }
1695        }
1696        else {
1697            return true;
1698        }
1699    }
1700
1701    private BoundableRenderable armedRenderable;
1702    
1703    /* (non-Javadoc)
1704     * @see org.xamjwg.html.renderer.BoundableRenderable#onMousePressed(java.awt.event.MouseEvent, int, int)
1705     */

1706    public boolean onMousePressed(MouseEvent JavaDoc event, int x, int y) {
1707        Iterator i = this.getRenderables(new Point(x, y));
1708        if(i != null) {
1709            while(i.hasNext()) {
1710                BoundableRenderable br = (BoundableRenderable) i.next();
1711                if(br != null) {
1712                    Rectangle bounds = br.getBounds();
1713                    if(!br.onMousePressed(event, x - bounds.x, y - bounds.y)) {
1714                        this.armedRenderable = br;
1715                        return false;
1716                    }
1717                }
1718            }
1719        }
1720        return true;
1721    }
1722
1723    /* (non-Javadoc)
1724     * @see org.xamjwg.html.renderer.BoundableRenderable#onMouseReleased(java.awt.event.MouseEvent, int, int)
1725     */

1726    public boolean onMouseReleased(MouseEvent JavaDoc event, int x, int y) {
1727        Iterator i = this.getRenderables(new Point(x, y));
1728        if(i != null) {
1729            while(i.hasNext()) {
1730                BoundableRenderable br = (BoundableRenderable) i.next();
1731                if(br != null) {
1732                    Rectangle bounds = br.getBounds();
1733                    if(!br.onMouseReleased(event, x - bounds.x, y - bounds.y)) {
1734                        BoundableRenderable oldArmedRenderable = this.armedRenderable;
1735                        if(oldArmedRenderable != null && br != oldArmedRenderable) {
1736                            oldArmedRenderable.onMouseDisarmed(event);
1737                            this.armedRenderable = null;
1738                        }
1739                        return false;
1740                    }
1741                }
1742            }
1743        }
1744        BoundableRenderable oldArmedRenderable = this.armedRenderable;
1745        if(oldArmedRenderable != null) {
1746            oldArmedRenderable.onMouseDisarmed(event);
1747            this.armedRenderable = null;
1748        }
1749        return true;
1750    }
1751
1752    public void paint(Graphics g) {
1753        Rectangle clipBounds = g.getClipBounds();
1754        Iterator i = this.getRenderables(clipBounds);
1755        int renderableCount = 0;
1756        while(i.hasNext()) {
1757            renderableCount++;
1758            Object JavaDoc robj = i.next();
1759            
1760            // The expected behavior in HTML is for boxes
1761
// not to be clipped unless overflow=hidden.
1762

1763// if(robj instanceof RElement) {
1764
// // Ensure RElement's are clipped
1765
// RElement relement = (RElement) robj;
1766
// Graphics newG = g.create(relement.getX(), relement.getY(), relement.getWidth(), relement.getHeight());
1767
// try {
1768
// relement.paint(newG);
1769
// } finally {
1770
// newG.dispose();
1771
// }
1772
// }
1773
if(robj instanceof BoundableRenderable) {
1774                BoundableRenderable renderable = (BoundableRenderable) robj;
1775                renderable.paintTranslated(g);
1776                //numRenderables++;
1777
}
1778            else {
1779                ((Renderable) robj).paint(g);
1780            }
1781        }
1782    }
1783    
1784    //----------------------------------------------------------------
1785

1786    private static class NopLayout implements MarkupLayout {
1787        public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) {
1788        }
1789    }
1790
1791    private static class NoScriptLayout implements MarkupLayout {
1792        public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) {
1793            UserAgentContext ucontext = bodyLayout.userAgentContext;
1794            if(!ucontext.isScriptingEnabled()) {
1795                bodyLayout.layoutMarkup(container, containerSize, insets, markupElement);
1796            }
1797            else {
1798                //NOP
1799
}
1800        }
1801    }
1802
1803    private static class ChildrenLayout implements MarkupLayout {
1804        /* (non-Javadoc)
1805         * @see org.xamjwg.html.renderer.MarkupLayout#layoutMarkup(java.awt.Container, java.awt.Insets, org.xamjwg.html.domimpl.HTMLElementImpl)
1806         */

1807        public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) {
1808            bodyLayout.layoutChildren(container, containerSize, insets, markupElement);
1809        }
1810    }
1811
1812    private static class HLayout extends CommonLayout {
1813        
1814        public HLayout(int fontSize) {
1815            super(DISPLAY_BLOCK);
1816        }
1817        
1818        /* (non-Javadoc)
1819         * @see org.xamjwg.html.renderer.MarkupLayout#layoutMarkup(java.awt.Container, java.awt.Insets, org.xamjwg.html.domimpl.HTMLElementImpl)
1820         */

1821        public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) {
1822            if(!bodyLayout.skipParagraphBreakBefore) {
1823                RLine currentLine = bodyLayout.currentLine;
1824                if(currentLine.width == 0) {
1825                    bodyLayout.addLineBreak(container, containerSize, insets, markupElement);
1826                }
1827                else {
1828                    bodyLayout.addParagraphBreak(container, containerSize, insets, markupElement);
1829                }
1830                bodyLayout.skipParagraphBreakBefore = true;
1831            }
1832            super.layoutMarkup(bodyLayout, container, containerSize, insets, markupElement);
1833            if(markupElement.hasChildNodes()) {
1834                bodyLayout.addLineBreak(container, containerSize, insets, markupElement);
1835                bodyLayout.skipParagraphBreakBefore = true;
1836            }
1837        }
1838    }
1839
1840    private static class PLayout extends CommonLayout {
1841        public PLayout() {
1842            super(DISPLAY_BLOCK);
1843        }
1844        
1845        /* (non-Javadoc)
1846         * @see org.xamjwg.html.renderer.MarkupLayout#layoutMarkup(java.awt.Container, java.awt.Insets, org.xamjwg.html.domimpl.HTMLElementImpl)
1847         */

1848        public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) {
1849            if(!bodyLayout.skipParagraphBreakBefore) {
1850                RLine currentLine = bodyLayout.currentLine;
1851                if(currentLine.width == 0) {
1852                    bodyLayout.addLineBreak(container, containerSize, insets, markupElement);
1853                }
1854                else {
1855                    bodyLayout.addParagraphBreak(container, containerSize, insets, markupElement);
1856                }
1857                bodyLayout.skipParagraphBreakBefore = true;
1858            }
1859            super.layoutMarkup(bodyLayout, container, containerSize, insets, markupElement);
1860            if(markupElement.hasChildNodes()) {
1861                bodyLayout.addLineBreak(container, containerSize, insets, markupElement);
1862                bodyLayout.skipParagraphBreakBefore = true;
1863            }
1864        }
1865    }
1866
1867    private static class ListItemLayout extends CommonLayout {
1868        public ListItemLayout() {
1869            super(DISPLAY_LIST_ITEM);
1870        }
1871    }
1872
1873    private static class BrLayout implements MarkupLayout {
1874        /* (non-Javadoc)
1875         * @see org.xamjwg.html.renderer.MarkupLayout#layoutMarkup(java.awt.Container, java.awt.Insets, org.xamjwg.html.domimpl.HTMLElementImpl)
1876         */

1877        public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) {
1878            bodyLayout.addLineBreak(container, containerSize, insets, markupElement);
1879        }
1880    }
1881
1882    private static class HrLayout implements MarkupLayout {
1883        /* (non-Javadoc)
1884         * @see org.xamjwg.html.renderer.MarkupLayout#layoutMarkup(java.awt.Container, java.awt.Insets, org.xamjwg.html.domimpl.HTMLElementImpl)
1885         */

1886        public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) {
1887            bodyLayout.layoutHr(container, containerSize, insets, markupElement);
1888        }
1889    }
1890
1891    private static class TableLayout extends CommonLayout {
1892        public TableLayout() {
1893            super(DISPLAY_TABLE);
1894        }
1895    }
1896
1897    private static class CommonBlockLayout extends CommonLayout {
1898        public CommonBlockLayout() {
1899            super(DISPLAY_BLOCK);
1900        }
1901    }
1902
1903    //---------------------------------------------------------------------------
1904

1905    private static class DivLayout extends CommonLayout {
1906        public DivLayout() {
1907            super(DISPLAY_BLOCK);
1908        }
1909    }
1910    
1911    private static class BlockQuoteLayout extends CommonLayout {
1912        public java.awt.Insets JavaDoc getDefaultMarginInsets() {
1913            return new Insets(0, 36, 0, 0);
1914        }
1915
1916        public BlockQuoteLayout() {
1917            super(DISPLAY_BLOCK);
1918        }
1919    }
1920
1921    private static class SpanLayout extends CommonLayout {
1922        public SpanLayout() {
1923            super(DISPLAY_INLINE);
1924        }
1925    }
1926
1927    private static class EmLayout extends CommonLayout {
1928        public EmLayout() {
1929            super(DISPLAY_INLINE);
1930        }
1931        
1932        /* (non-Javadoc)
1933         * @see org.xamjwg.html.renderer.MarkupLayout#layoutMarkup(java.awt.Container, java.awt.Insets, org.xamjwg.html.domimpl.HTMLElementImpl)
1934         */

1935        public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) {
1936            super.layoutMarkup(bodyLayout, container, containerSize, insets, markupElement);
1937        }
1938    }
1939    
1940    private static class ULayout extends CommonLayout {
1941        public ULayout() {
1942            super(DISPLAY_INLINE);
1943        }
1944        
1945        /* (non-Javadoc)
1946         * @see org.xamjwg.html.renderer.MarkupLayout#layoutMarkup(java.awt.Container, java.awt.Insets, org.xamjwg.html.domimpl.HTMLElementImpl)
1947         */

1948        public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) {
1949            super.layoutMarkup(bodyLayout, container, containerSize, insets, markupElement);
1950        }
1951    }
1952
1953    private static class StrikeLayout extends CommonLayout {
1954        public StrikeLayout() {
1955            super(DISPLAY_INLINE);
1956        }
1957    }
1958
1959    private static class StrongLayout extends CommonLayout {
1960        public StrongLayout() {
1961            super(DISPLAY_INLINE);
1962        }
1963    }
1964    
1965    private static class AnchorLayout extends CommonLayout {
1966        public AnchorLayout() {
1967            super(DISPLAY_INLINE);
1968        }
1969    }
1970    
1971    private static class ObjectLayout extends CommonWidgetLayout {
1972        private boolean tryToRenderContent;
1973        
1974        /**
1975         * @param tryToRenderContent If the object is unknown, content is rendered as HTML.
1976         * @param usesAlignAttribute
1977         */

1978        public ObjectLayout(boolean tryToRenderContent, boolean usesAlignAttribute) {
1979            super(ADD_INLINE, usesAlignAttribute);
1980            this.tryToRenderContent = tryToRenderContent;
1981        }
1982        
1983        /**
1984         * Must use this ThreadLocal because
1985         * an ObjectLayout instance is shared
1986         * across renderers.
1987         */

1988        private final ThreadLocal JavaDoc htmlObject = new ThreadLocal JavaDoc();
1989
1990        public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) {
1991            HtmlObject ho = bodyLayout.rendererContext.getHtmlObject(markupElement);
1992            if(ho == null && this.tryToRenderContent) {
1993                // Don't know what to do with it - render contents.
1994
bodyLayout.layoutMarkup(container, containerSize, insets, markupElement);
1995            }
1996            else if (ho != null) {
1997                this.htmlObject.set(ho);
1998                super.layoutMarkup(bodyLayout, container, containerSize, insets, markupElement);
1999            }
2000        }
2001
2002        protected RElement createRenderable(RBlockViewport bodyLayout, HTMLElementImpl markupElement) {
2003            HtmlObject ho = (HtmlObject) this.htmlObject.get();
2004            UIControl uiControl = new UIControlWrapper(ho);
2005            RUIControl ruiControl = new RUIControl(markupElement, uiControl, bodyLayout.container, bodyLayout.frameContext, bodyLayout.userAgentContext);
2006            return ruiControl;
2007        }
2008    }
2009    
2010    private static class ImgLayout extends CommonWidgetLayout {
2011        public ImgLayout() {
2012            super(ADD_INLINE, true);
2013        }
2014
2015        protected RElement createRenderable(RBlockViewport bodyLayout, HTMLElementImpl markupElement) {
2016            UIControl control = new ImgControl((HTMLImageElementImpl) markupElement);
2017            return new RUIControl(markupElement, control, bodyLayout.container, bodyLayout.frameContext, bodyLayout.userAgentContext);
2018        }
2019    }
2020    
2021    private static class InputLayout2 extends CommonWidgetLayout {
2022        public InputLayout2() {
2023            super(ADD_INLINE, true);
2024        }
2025
2026        protected RElement createRenderable(RBlockViewport bodyLayout, HTMLElementImpl markupElement) {
2027            HTMLBaseInputElement bie = (HTMLBaseInputElement) markupElement;
2028            BaseInputControl uiControl = bodyLayout.createInputControl(bie);
2029            if(uiControl == null) {
2030                return null;
2031            }
2032            bie.setInputContext(uiControl);
2033            return new RUIControl(markupElement, uiControl, bodyLayout.container, bodyLayout.frameContext, bodyLayout.userAgentContext);
2034        }
2035    }
2036
2037    private static class SelectLayout extends CommonWidgetLayout {
2038        public SelectLayout() {
2039            super(ADD_INLINE, true);
2040        }
2041        
2042        protected RElement createRenderable(RBlockViewport bodyLayout, HTMLElementImpl markupElement) {
2043            HTMLBaseInputElement bie = (HTMLBaseInputElement) markupElement;
2044            BaseInputControl uiControl = new InputSelectControl(bie);
2045            bie.setInputContext(uiControl);
2046            return new RUIControl(markupElement, uiControl, bodyLayout.container, bodyLayout.frameContext, bodyLayout.userAgentContext);
2047        }
2048    }
2049
2050    private static class TextAreaLayout2 extends CommonWidgetLayout {
2051        public TextAreaLayout2() {
2052            super(ADD_INLINE, true);
2053        }
2054        
2055        protected RElement createRenderable(RBlockViewport bodyLayout, HTMLElementImpl markupElement) {
2056            HTMLBaseInputElement bie = (HTMLBaseInputElement) markupElement;
2057            BaseInputControl control = new InputTextAreaControl(bie);
2058            bie.setInputContext(control);
2059            return new RUIControl(markupElement, control, bodyLayout.container, bodyLayout.frameContext, bodyLayout.userAgentContext);
2060        }
2061    }
2062
2063    private static class IFrameLayout extends CommonWidgetLayout {
2064        public IFrameLayout() {
2065            super(ADD_INLINE, true);
2066        }
2067        
2068        protected RElement createRenderable(RBlockViewport bodyLayout, HTMLElementImpl markupElement) {
2069            BrowserFrame frame = bodyLayout.rendererContext.createBrowserFrame();
2070            ((HTMLIFrameElementImpl) markupElement).setBrowserFrame(frame);
2071            UIControl control = new BrowserFrameUIControl(markupElement, frame);
2072            return new RUIControl(markupElement, control, bodyLayout.container, bodyLayout.frameContext, bodyLayout.userAgentContext);
2073        }
2074    }
2075
2076    //------------------------------------------------------------------------
2077

2078    /**
2079     * This is layout common to elements that render themselves,
2080     * except RBlock, RTable and RList.
2081     */

2082    private static abstract class CommonWidgetLayout implements MarkupLayout {
2083        protected static final int ADD_INLINE = 0;
2084        protected static final int ADD_AS_BLOCK = 1;
2085        private final int method;
2086        private final boolean useAlignAttribute;
2087        
2088        public CommonWidgetLayout(int method, boolean usesAlignAttribute) {
2089            this.method = method;
2090            this.useAlignAttribute = usesAlignAttribute;
2091        }
2092        
2093        public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) {
2094            CSS2PropertiesImpl style = markupElement.getCurrentStyle();
2095            if(style != null) {
2096                String JavaDoc display = style.getDisplay();
2097                if(display != null && "none".equalsIgnoreCase(display)) {
2098                    return;
2099                }
2100            }
2101            UINode node = markupElement.getUINode();
2102            RElement renderable = null;
2103            if(node == null) {
2104                renderable = this.createRenderable(bodyLayout, markupElement);
2105                if(renderable == null) {
2106                    if(logger.isLoggable(Level.INFO)) {
2107                        logger.info("layoutMarkup(): Don't know how to render " + markupElement + ".");
2108                    }
2109                    return;
2110                }
2111                markupElement.setUINode((UINode) renderable);
2112            }
2113            else {
2114                renderable = (RElement) node;
2115            }
2116            int availWidth = bodyLayout.availContentWidth;
2117            int heightAvailToRenderable = bodyLayout.availContentHeight;
2118            renderable.layout(availWidth, heightAvailToRenderable, false, false);
2119            switch(this.method) {
2120            case ADD_INLINE:
2121                bodyLayout.addRenderableToLineCheckStyle(container, containerSize, insets, renderable, markupElement, this.useAlignAttribute);
2122                break;
2123            case ADD_AS_BLOCK:
2124                bodyLayout.addAsSeqBlockCheckStyle(containerSize, insets, renderable, markupElement, this.useAlignAttribute);
2125                break;
2126            }
2127        }
2128
2129        protected abstract RElement createRenderable(RBlockViewport bodyLayout, HTMLElementImpl markupElement);
2130    }
2131    
2132    private static abstract class CommonLayout implements MarkupLayout {
2133        protected static final int DISPLAY_NONE = 0;
2134        protected static final int DISPLAY_INLINE = 1;
2135        protected static final int DISPLAY_BLOCK = 2;
2136        protected static final int DISPLAY_LIST_ITEM = 3;
2137        protected static final int DISPLAY_TABLE_ROW = 4;
2138        protected static final int DISPLAY_TABLE_CELL = 5;
2139        protected static final int DISPLAY_TABLE = 6;
2140        
2141        private final int display;
2142        
2143        public CommonLayout(int defaultDisplay) {
2144            this.display = defaultDisplay;
2145        }
2146
2147        /**
2148         * The default margin insets for a block. Only used
2149         * with DISPLAY_BLOCK.
2150         */

2151        public java.awt.Insets JavaDoc getDefaultMarginInsets() {
2152            return null;
2153        }
2154        
2155        public void layoutMarkup(RBlockViewport bodyLayout, RenderableContainer container, Dimension containerSize, Insets insets, HTMLElementImpl markupElement) {
2156            RenderState rs = markupElement.getRenderState();
2157            int display = rs == null ? this.display : rs.getDisplay();
2158            switch(display) {
2159                case DISPLAY_NONE:
2160                    // skip it completely.
2161
break;
2162                case DISPLAY_BLOCK:
2163                    bodyLayout.layoutRBlock(container, containerSize, insets, markupElement, this.getDefaultMarginInsets());
2164                    break;
2165                case DISPLAY_LIST_ITEM:
2166                    String JavaDoc tagName = markupElement.getTagName();
2167                    if("UL".equalsIgnoreCase(tagName) || "OL".equalsIgnoreCase(tagName)) {
2168                        bodyLayout.layoutList(container, containerSize, insets, markupElement);
2169                    }
2170                    else {
2171                        bodyLayout.layoutListItem(container, containerSize, insets, markupElement);
2172                    }
2173                    break;
2174                case DISPLAY_TABLE:
2175                    bodyLayout.layoutRTable(container, containerSize, insets, markupElement);
2176                    break;
2177                default:
2178                    // Assume INLINE
2179
bodyLayout.layoutMarkup(container, containerSize, insets, markupElement);
2180                    break;
2181                //TODO: tables, lists, etc.
2182
}
2183        }
2184    }
2185    
2186    public String JavaDoc toString() {
2187        return "RBlockViewport[node=" + this.modelNode + "]";
2188    }
2189}
2190
Popular Tags