KickJava   Java API By Example, From Geeks To Geeks.

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


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 package org.lobobrowser.html.renderer;
23
24 import java.awt.Color JavaDoc;
25 import java.awt.Component JavaDoc;
26 import java.awt.Graphics JavaDoc;
27 import java.awt.Image JavaDoc;
28 import java.awt.Insets JavaDoc;
29 import java.awt.Rectangle JavaDoc;
30 import java.awt.image.ImageObserver JavaDoc;
31 import java.net.MalformedURLException JavaDoc;
32 import java.net.URL JavaDoc;
33 import java.security.AccessController JavaDoc;
34 import java.security.PrivilegedAction JavaDoc;
35 import java.util.Collection JavaDoc;
36 import java.util.HashSet JavaDoc;
37 import java.util.Iterator JavaDoc;
38 import java.util.logging.Level JavaDoc;
39
40 import org.lobobrowser.html.HttpRequest;
41 import org.lobobrowser.html.ReadyStateChangeListener;
42 import org.lobobrowser.html.UserAgentContext;
43 import org.lobobrowser.html.domimpl.*;
44 import org.lobobrowser.html.style.BackgroundInfo;
45 import org.lobobrowser.html.style.CSS2PropertiesImpl;
46 import org.lobobrowser.html.style.HtmlValues;
47 import org.lobobrowser.html.style.RenderState;
48 import org.lobobrowser.util.gui.ColorFactory;
49 import org.w3c.dom.css.CSS2Properties;
50
51 abstract class BaseElementRenderable extends BaseRCollection implements RElement, RenderableContainer, java.awt.image.ImageObserver JavaDoc {
52     public static final int OVERFLOW_NONE = 0;
53     public static final int OVERFLOW_SCROLL = 1;
54     public static final int OVERFLOW_AUTO = 2;
55     public static final int OVERFLOW_HIDDEN = 3;
56     public static final int OVERFLOW_VISIBLE = 4;
57     public static final int OVERFLOW_VERTICAL = 5;
58     
59     /**
60      * A collection of all GUI components
61      * added by descendents.
62      */

63     private Collection JavaDoc guiComponents = null;
64
65     /**
66      * A list of absolute positioned or
67      * float parent-child pairs.
68      */

69     protected Collection JavaDoc delayedPairs = null;
70
71     // protected boolean renderStyleCanBeInvalidated = true;
72

73     /**
74      * Background color which may be different to
75      * that from RenderState in the case of a Document node.
76      */

77     protected Color JavaDoc backgroundColor;
78     protected volatile Image JavaDoc backgroundImage;
79     protected int zIndex;
80     protected Color JavaDoc borderTopColor;
81     protected Color JavaDoc borderLeftColor;
82     protected Color JavaDoc borderBottomColor;
83     protected Color JavaDoc borderRightColor;
84     protected Insets JavaDoc borderInsets;
85     protected String JavaDoc lastBackgroundImageUri;
86     protected Insets JavaDoc defaultMarginInsets;
87     private int cachedOverflow = -1;
88     
89     protected final UserAgentContext userAgentContext;
90     
91     public BaseElementRenderable(RenderableContainer container, ModelNode modelNode, UserAgentContext ucontext) {
92         super(container, modelNode);
93         this.userAgentContext = ucontext;
94     }
95
96     public float getAlignmentX() {
97         return 0.0f;
98     }
99
100     public float getAlignmentY() {
101         return 0.0f;
102     }
103     
104 // /**
105
// * Invalidates RenderState in all descendents. Should
106
// * be overridden to invalidate RenderState of current node, if any.
107
// */
108
// public void invalidateRenderStyle() {
109
// if(this.renderStyleCanBeInvalidated) {
110
// Iterator renderables = this.getRenderables();
111
// if(renderables != null) {
112
// while(renderables.hasNext()) {
113
// Object r = renderables.next();
114
// if(r instanceof RCollection) {
115
// ((RCollection) r).invalidateRenderStyle();
116
// }
117
// else if(r instanceof RStyleChanger) {
118
// ((RStyleChanger) r).getRenderState().invalidate();
119
// }
120
// }
121
// }
122
// this.renderStyleCanBeInvalidated = false;
123
// }
124
// }
125

126     protected boolean layoutDeepCanBeInvalidated = false;
127     
128     /**
129      * Invalidates this Renderable and all
130      * descendents. This is only used in special
131      * cases, such as when a new style sheet is
132      * added.
133      */

134     public final void invalidateLayoutDeep() {
135         if(this.layoutDeepCanBeInvalidated) {
136             this.layoutDeepCanBeInvalidated = false;
137             this.invalidateLayoutLocal();
138             Iterator JavaDoc i = this.getRenderables();
139             if(i != null) {
140                 while(i.hasNext()) {
141                     Object JavaDoc r = i.next();
142                     if(r instanceof RCollection) {
143                         ((RCollection) r).invalidateLayoutDeep();
144                     }
145                 }
146             }
147         }
148     }
149
150     protected void invalidateLayoutLocal() {
151         this.cachedOverflow = -1;
152     }
153
154     protected int getDeclaredWidth(RenderState renderState, int availWidth) {
155         Object JavaDoc rootNode = this.modelNode;
156         if(rootNode instanceof HTMLElementImpl) {
157             HTMLElementImpl element = (HTMLElementImpl) rootNode;
158             CSS2Properties props = element.getCurrentStyle();
159             if(props == null) {
160                 return -1;
161             }
162             String JavaDoc widthText = props.getWidth();
163             if(widthText == null || "".equals(widthText)) {
164                 return -1;
165             }
166             return HtmlValues.getPixelSize(widthText, renderState, -1, availWidth);
167         }
168         else {
169             return -1;
170         }
171     }
172
173     protected int getDeclaredHeight(RenderState renderState, int availHeight) {
174         Object JavaDoc rootNode = this.modelNode;
175         if(rootNode instanceof HTMLElementImpl) {
176             HTMLElementImpl element = (HTMLElementImpl) rootNode;
177             CSS2Properties props = element.getCurrentStyle();
178             if(props == null) {
179                 return -1;
180             }
181             String JavaDoc heightText = props.getHeight();
182             if(heightText == null || "".equals(heightText)) {
183                 return -1;
184             }
185             return HtmlValues.getPixelSize(heightText, renderState, -1, availHeight);
186         }
187         else {
188             return -1;
189         }
190     }
191         
192     protected int getOverflow() {
193         int co = this.cachedOverflow;
194         if(co != -1) {
195             return co;
196         }
197         Object JavaDoc rootNode = this.modelNode;
198         if(rootNode instanceof HTMLElementImpl) {
199             HTMLElementImpl element = (HTMLElementImpl) rootNode;
200             CSS2Properties props = element.getCurrentStyle();
201             if(props == null) {
202                 co = OVERFLOW_NONE;
203             }
204             else {
205                 String JavaDoc overflowText = props.getOverflow();
206                 if(overflowText == null) {
207                     co = OVERFLOW_NONE;
208                 }
209                 else {
210                     String JavaDoc overflowTextTL = overflowText.toLowerCase();
211                     if("scroll".equals(overflowTextTL)) {
212                         co = OVERFLOW_SCROLL;
213                     }
214                     else if("auto".equals(overflowTextTL)) {
215                         co = OVERFLOW_AUTO;
216                     }
217                     else if("vertical".equals(overflowTextTL)) {
218                         co = OVERFLOW_VERTICAL;
219                     }
220                     else if("hidden".equals(overflowTextTL)) {
221                         co = OVERFLOW_HIDDEN;
222                     }
223                     else if("visible".equals(overflowTextTL)) {
224                         co = OVERFLOW_VISIBLE;
225                     }
226                     else {
227                         co = OVERFLOW_NONE;
228                     }
229                 }
230             }
231         }
232         else {
233             co = OVERFLOW_NONE;
234         }
235         this.cachedOverflow = co;
236         return co;
237     }
238     
239     /**
240      * All overriders should call super implementation.
241      */

242     public void paint(Graphics JavaDoc g) {
243     }
244
245     public final void layout(int availWidth, int availHeight) {
246         this.layout(availWidth, availHeight, false, false);
247     }
248
249     /**
250      * Lays out children, and deals with "valid" state. Override doLayout method
251      * instead of this one.
252      */

253     public final void layout(int availWidth, int availHeight, boolean expandWidth, boolean expandHeight) {
254         // Must call doLayout regardless of validity state.
255
try {
256             this.doLayout(availWidth, availHeight, expandWidth, expandHeight);
257         } finally {
258             this.layoutUpTreeCanBeInvalidated = true;
259             this.layoutDeepCanBeInvalidated = true;
260 // this.renderStyleCanBeInvalidated = true;
261
}
262     }
263     
264     protected abstract void doLayout(int availWidth, int availHeight, boolean expandWidth, boolean expandHeight);
265     
266     protected final void sendGUIComponentsToParent() {
267         // Ensures that parent has all the components
268
// below this renderer node. (Parent expected to have removed them).
269
Collection JavaDoc gc = this.guiComponents;
270         int count = 0;
271         if(gc != null) {
272             RenderableContainer rc = this.container;
273             Iterator JavaDoc i = gc.iterator();
274             while(i.hasNext()) {
275                 count++;
276                 rc.add((Component JavaDoc) i.next());
277             }
278         }
279     }
280     
281     protected final void clearGUIComponents() {
282         Collection JavaDoc gc = this.guiComponents;
283         if(gc != null) {
284             gc.clear();
285         }
286     }
287     
288     /* (non-Javadoc)
289      * @see org.xamjwg.html.renderer.RenderableContainer#add(java.awt.Component)
290      */

291     public Component JavaDoc add(Component JavaDoc component) {
292         // Expected to be called in GUI thread.
293
// Adds only in local collection.
294
// Does not remove from parent.
295
// Sending components to parent is done
296
// by sendGUIComponentsToParent().
297
Collection JavaDoc gc = this.guiComponents;
298         if(gc == null) {
299             gc = new HashSet JavaDoc(1);
300             this.guiComponents = gc;
301         }
302         gc.add(component);
303         return component;
304     }
305
306     public void updateAllWidgetBounds() {
307         this.container.updateAllWidgetBounds();
308     }
309
310     /**
311      * Updates widget bounds below this node only.
312      * Should not be called during general rendering.
313      */

314     public void updateWidgetBounds() {
315         java.awt.Point JavaDoc guiPoint = this.getGUIPoint(0, 0);
316         this.updateWidgetBounds(guiPoint.x, guiPoint.y);
317     }
318
319     protected void applyStyle() {
320         //TODO: Can be optimized if there's no style?
321
//Note: Overridden by table cell
322
Object JavaDoc rootNode = this.modelNode;
323         HTMLElementImpl rootElement;
324         if(rootNode instanceof HTMLDocumentImpl) {
325             HTMLDocumentImpl doc = (HTMLDocumentImpl) rootNode;
326             // Need to get BODY tag, for bgcolor, etc.
327
rootElement = (HTMLElementImpl) doc.getBody();
328         }
329         else {
330             rootElement = (HTMLElementImpl) rootNode;
331         }
332         if(rootElement == null) {
333             this.clearStyle();
334             this.backgroundColor = null;
335             this.backgroundImage = null;
336             this.lastBackgroundImageUri = null;
337             return;
338         }
339         RenderState rs = rootElement.getRenderState();
340         if(rs == null) {
341             throw new IllegalStateException JavaDoc("Element without render state: " + rootElement + "; parent=" + rootElement.getParentNode());
342         }
343         BackgroundInfo binfo = rs.getBackgroundInfo();
344         this.backgroundColor = binfo == null ? null : binfo.backgroundColor;
345         String JavaDoc backgroundImageUri = binfo == null ? null
346                 : binfo.backgroundImage;
347         if (backgroundImageUri == null) {
348             this.backgroundImage = null;
349             this.lastBackgroundImageUri = null;
350         }
351         else if(!backgroundImageUri.equals(this.lastBackgroundImageUri)) {
352             this.lastBackgroundImageUri = backgroundImageUri;
353             this.loadBackgroundImage(backgroundImageUri);
354         }
355         CSS2PropertiesImpl props = rootElement.getCurrentStyle();
356         if(props == null) {
357             this.clearStyle();
358         }
359         else {
360             this.borderInsets = null;
361             this.borderTopColor = null;
362             this.borderLeftColor = null;
363             this.borderBottomColor = null;
364             this.borderRightColor = null;
365             String JavaDoc border = props.getBorder();
366             if(border != null) {
367                 this.applyBorder(rs, border);
368             }
369             this.borderInsets = HtmlValues.getBorderInsets(this.borderInsets, props, rs);
370             String JavaDoc borderColorText = props.getBorderColor();
371             if(borderColorText != null) {
372                 Color JavaDoc[] colorsArray = HtmlValues.getColors(borderColorText);
373                 this.borderTopColor = colorsArray[0];
374                 this.borderLeftColor = colorsArray[1];
375                 this.borderBottomColor = colorsArray[2];
376                 this.borderRightColor = colorsArray[3];
377             }
378             String JavaDoc borderTopColorText = props.getBorderTopColor();
379             if(borderTopColorText != null) {
380                 this.borderTopColor = ColorFactory.getInstance().getColor(borderTopColorText);
381             }
382             String JavaDoc borderLeftColorText = props.getBorderLeftColor();
383             if(borderLeftColorText != null) {
384                 this.borderLeftColor = ColorFactory.getInstance().getColor(borderLeftColorText);
385             }
386             String JavaDoc borderBottomColorText = props.getBorderBottomColor();
387             if(borderBottomColorText != null) {
388                 this.borderBottomColor = ColorFactory.getInstance().getColor(borderBottomColorText);
389             }
390             String JavaDoc borderRightColorText = props.getBorderRightColor();
391             if(borderRightColorText != null) {
392                 this.borderRightColor = ColorFactory.getInstance().getColor(borderRightColorText);
393             }
394             String JavaDoc zIndex = props.getZIndex();
395             if(zIndex != null) {
396                 try {
397                     this.zIndex = Integer.parseInt(zIndex);
398                 } catch(NumberFormatException JavaDoc err) {
399                     logger.log(Level.WARNING, "Unable to parse z-index [" + zIndex + "] in element " + this.modelNode + ".", err);
400                     this.zIndex = 0;
401                 }
402             }
403             else {
404                 this.zIndex = 0;
405             }
406         }
407
408         // Check if background image needs to be loaded
409
}
410
411     protected void loadBackgroundImage(final String JavaDoc uri) {
412         ModelNode rc = this.modelNode;
413         UserAgentContext ctx = this.userAgentContext;
414         if(ctx != null) {
415             final HttpRequest request = ctx.createHttpRequest();
416             request.addReadyStateChangeListener(new ReadyStateChangeListener() {
417                 public void readyStateChanged() {
418                     int readyState = request.getReadyState();
419                     if(readyState == HttpRequest.STATE_COMPLETE) {
420                         int status = request.getStatus();
421                         if(status == 200 || status == 0) {
422                             Image JavaDoc img = request.getResponseImage();
423                             BaseElementRenderable.this.backgroundImage = img;
424                             // Cause observer to be called
425
int w = img.getWidth(BaseElementRenderable.this);
426                             int h = img.getHeight(BaseElementRenderable.this);
427                             // Maybe image already done...
428
if(w != -1 && h != -1) {
429                                 BaseElementRenderable.this.repaint();
430                             }
431                         }
432                     }
433                 }
434             });
435             try {
436                 final URL JavaDoc fullUrl = rc.getFullURL(uri);
437                 SecurityManager JavaDoc sm = System.getSecurityManager();
438                 if(sm == null) {
439                     request.open("GET", fullUrl);
440                 }
441                 else {
442                     AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
443                         public Object JavaDoc run() {
444                             // Code might have restrictions on accessing
445
// items from elsewhere.
446
request.open("GET", fullUrl);
447                             return null;
448                         }
449                     });
450                 }
451             } catch(MalformedURLException JavaDoc mfu) {
452                 rc.warn("Bad image URI: [" + uri + "]", mfu);
453             }
454         }
455     }
456
457     public int getZIndex() {
458         return this.zIndex;
459     }
460
461     void applyBorder(RenderState renderState, String JavaDoc border) {
462         String JavaDoc[] tokens = HtmlValues.splitCssValue(border);
463         for(int i = 0; i < tokens.length; i++) {
464             String JavaDoc token = tokens[i];
465             if(HtmlValues.isLength(token)) {
466                 int pixelSize = HtmlValues.getPixelSize(token, renderState, 0);
467                 Insets JavaDoc bi = new Insets JavaDoc(pixelSize, pixelSize, pixelSize, pixelSize);
468                 this.borderInsets = bi;
469             }
470             else if(ColorFactory.getInstance().isColor(token)) {
471                 Color JavaDoc color = ColorFactory.getInstance().getColor(token);
472                 this.borderLeftColor = color;
473                 this.borderRightColor = color;
474                 this.borderTopColor = color;
475                 this.borderBottomColor = color;
476             }
477             else if(HtmlValues.isBorderStyle(token)) {
478                 //TODO: dashed and so forth.
479
if("solid".equalsIgnoreCase(token) || "dashed".equalsIgnoreCase(token)) {
480                     Insets JavaDoc bi = this.borderInsets;
481                     if(bi == null) {
482                         bi = new Insets JavaDoc(4, 4, 4, 4);
483                         this.borderInsets = bi;
484                     }
485                 }
486             }
487         }
488     }
489
490     private Color JavaDoc getBorderTopColor() {
491         Color JavaDoc c = this.borderTopColor;
492         return c == null ? Color.black : c;
493     }
494
495     private Color JavaDoc getBorderLeftColor() {
496         Color JavaDoc c = this.borderLeftColor;
497         return c == null ? Color.black : c;
498     }
499
500     private Color JavaDoc getBorderBottomColor() {
501         Color JavaDoc c = this.borderBottomColor;
502         return c == null ? Color.black : c;
503     }
504
505     private Color JavaDoc getBorderRightColor() {
506         Color JavaDoc c = this.borderRightColor;
507         return c == null ? Color.black : c;
508     }
509
510     protected void prePaint(java.awt.Graphics JavaDoc g) {
511         int startWidth = this.width;
512         int startHeight = this.height;
513         int totalWidth = startWidth;
514         int totalHeight = startHeight;
515         int startX = 0;
516         int startY = 0;
517         ModelNode node = this.modelNode;
518         RenderState rs = node.getRenderState();
519         Insets JavaDoc marginInsets = this.getMarginInsets(rs);
520         if(marginInsets != null) {
521             totalWidth -= (marginInsets.left + marginInsets.right);
522             totalHeight -= (marginInsets.top + marginInsets.bottom);
523             startX += marginInsets.left;
524             startY += marginInsets.top;
525         }
526         Insets JavaDoc borderInsets = this.borderInsets;
527         if(borderInsets != null) {
528             int btop = borderInsets.top;
529             int bleft = borderInsets.left;
530             int bright = borderInsets.right;
531             int bbottom = borderInsets.bottom;
532     
533             int newTotalWidth = totalWidth - (bleft + bright);
534             int newTotalHeight = totalHeight - (btop + bbottom);
535             int newStartX = startX + bleft;
536             int newStartY = startY + btop;
537             Rectangle JavaDoc clientRegion = new Rectangle JavaDoc(newStartX, newStartY, newTotalWidth, newTotalHeight);
538     
539             // Paint borders if the clip bounds are not contained
540
// by the content area.
541
Rectangle JavaDoc clipBounds = g.getClipBounds();
542             if(!clientRegion.contains(clipBounds)) {
543                 // Paint top border
544
if(btop > 0) {
545                     g.setColor(this.getBorderTopColor());
546                     for(int i = 0; i < btop; i++) {
547                         int leftOffset = (i * bleft) / btop;
548                         int rightOffset = (i * bright) / btop;
549                         g.drawLine(startX + leftOffset, startY + i, startX + totalWidth - rightOffset - 1, startY + i);
550                     }
551                 }
552                 if(bright > 0) {
553                     g.setColor(this.getBorderRightColor());
554                     int lastX = startX + totalWidth - 1;
555                     for(int i = 0; i < bright; i++) {
556                         int topOffset = (i * btop) / bright;
557                         int bottomOffset = (i * bbottom) / bright;
558                         g.drawLine(lastX - i, startY + topOffset, lastX - i, startY + totalHeight - bottomOffset - 1);
559                     }
560                 }
561                 if(bleft > 0) {
562                     g.setColor(this.getBorderLeftColor());
563                     for(int i = 0; i < bleft; i++) {
564                         int topOffset = (i * btop) / bleft;
565                         int bottomOffset = (i * bbottom) / bleft;
566                         g.drawLine(startX + i, startY + topOffset, startX + i, startY + totalHeight - bottomOffset - 1);
567                     }
568                 }
569                 if(bbottom > 0) {
570                     g.setColor(this.getBorderBottomColor());
571                     int lastY = startY + totalHeight - 1;
572                     for(int i = 0; i < bbottom; i++) {
573                         int leftOffset = (i * bleft) / bbottom;
574                         int rightOffset = (i * bright) / bbottom;
575                         g.drawLine(startX + leftOffset, lastY - i, startX + totalWidth - rightOffset - 1, lastY - i);
576                     }
577                 }
578             }
579     
580             // Adjust client area border
581
totalWidth = newTotalWidth;
582             totalHeight = newTotalHeight;
583             startX = newStartX;
584             startY = newStartY;
585     
586         }
587         // Using clientG (clipped below) beyond this point.
588
Graphics JavaDoc clientG = g.create(startX, startY, totalWidth, totalHeight);
589         try {
590             Rectangle JavaDoc bkgBounds = null;
591             if(node != null) {
592                 Color JavaDoc bkg = this.backgroundColor;
593                 if(bkg != null && bkg.getAlpha() > 0) {
594                     clientG.setColor(bkg);
595                     bkgBounds = clientG.getClipBounds();
596                     clientG.fillRect(bkgBounds.x, bkgBounds.y, bkgBounds.width, bkgBounds.height);
597                 }
598                 BackgroundInfo binfo = rs == null ? null : rs.getBackgroundInfo();
599                 Image JavaDoc image = this.backgroundImage;
600                 if(image != null) {
601                     if(bkgBounds == null) {
602                         bkgBounds = clientG.getClipBounds();
603                     }
604                     int w = image.getWidth(this);
605                     int h = image.getHeight(this);
606                     if(w != -1 && h != -1) {
607                         switch(binfo == null ? BackgroundInfo.BR_REPEAT : binfo.backgroundRepeat) {
608                         case BackgroundInfo.BR_NO_REPEAT: {
609                             int imageX;
610                             if(binfo.backgroundXPositionAbsolute) {
611                                 imageX = binfo.backgroundXPosition;
612                             }
613                             else {
614                                 imageX = (binfo.backgroundXPosition * (totalWidth - w)) / 100;
615                             }
616                             int imageY;
617                             if(binfo.backgroundYPositionAbsolute) {
618                                 imageY = binfo.backgroundYPosition;
619                             }
620                             else {
621                                 imageY =(binfo.backgroundYPosition * (totalHeight - h)) / 100;
622                             }
623                             clientG.drawImage(image, imageX, imageY, w, h, this);
624                             break;
625                         }
626                         case BackgroundInfo.BR_REPEAT_X: {
627                             int imageY;
628                             if(binfo.backgroundYPositionAbsolute) {
629                                 imageY = binfo.backgroundYPosition;
630                             }
631                             else {
632                                 imageY = (binfo.backgroundYPosition * (totalHeight - h)) / 100;
633                             }
634                             // Modulate starting x.
635
int x = (bkgBounds.x / w) * w;
636                             int topX = bkgBounds.x + bkgBounds.width;
637                             for(; x < topX; x += w) {
638                                 clientG.drawImage(image, x, imageY, w, h, this);
639                             }
640                             break;
641                         }
642                         case BackgroundInfo.BR_REPEAT_Y: {
643                             int imageX;
644                             if(binfo.backgroundXPositionAbsolute) {
645                                 imageX = binfo.backgroundXPosition;
646                             }
647                             else {
648                                 imageX = (binfo.backgroundXPosition * (totalWidth - w)) / 100;
649                             }
650                             // Modulate starting y.
651
int y = (bkgBounds.y / h) * h;
652                             int topY = bkgBounds.y + bkgBounds.height;
653                             for(; y < topY; y += h) {
654                                 clientG.drawImage(image, imageX, y, w, h, this);
655                             }
656                             break;
657                         }
658                         default: {
659                             // Modulate starting x and y.
660
int baseX = (bkgBounds.x / w) * w;
661                             int baseY = (bkgBounds.y / h) * h;
662                             int topX = bkgBounds.x + bkgBounds.width;
663                             int topY = bkgBounds.y + bkgBounds.height;
664                             // Replacing this:
665
for(int x = baseX; x < topX; x += w) {
666                                 for(int y = baseY; y < topY; y += h) {
667                                     clientG.drawImage(image, x, y, w, h, this);
668                                 }
669                             }
670                             break;
671                         }
672                         }
673                     }
674                 }
675             }
676         } finally {
677             clientG.dispose();
678         }
679     }
680
681     void clearStyle() {
682         this.borderInsets = null;
683         this.borderTopColor = null;
684         this.borderLeftColor = null;
685         this.borderBottomColor = null;
686         this.borderRightColor = null;
687         this.zIndex = 0;
688     }
689
690     protected final Insets JavaDoc getMarginInsets(RenderState rs) {
691         Insets JavaDoc mi = rs.getMarginInsets();
692         if(mi == null) {
693             return this.defaultMarginInsets;
694         }
695         return mi;
696     }
697     
698     public boolean imageUpdate(Image JavaDoc img, int infoflags, int x, int y, int w, int h) {
699         // This is so that a loading image doesn't cause
700
// too many repaint events.
701
if((infoflags & ImageObserver.ALLBITS) != 0 || (infoflags & ImageObserver.FRAMEBITS) != 0) {
702             this.repaint();
703         }
704         return true;
705     }
706     
707     protected static final int SCROLL_BAR_THICKNESS = 16;
708     
709     /**
710      * Gets insets of content area. It includes margin, borders
711      * and scrollbars, but not padding.
712      */

713     public Insets JavaDoc getInsets(boolean hscroll, boolean vscroll) {
714         RenderState rs = this.modelNode.getRenderState();
715         Insets JavaDoc mi = this.getMarginInsets(rs);
716         Insets JavaDoc bi = this.borderInsets;
717         int top = 0;
718         int bottom = 0;
719         int left = 0;
720         int right = 0;
721         if(mi != null) {
722             top += mi.top;
723             left += mi.left;
724             bottom += mi.bottom;
725             right += mi.right;
726         }
727 // if(pi != null) {
728
// top += pi.top;
729
// left += pi.left;
730
// bottom += pi.bottom;
731
// right += pi.right;
732
// }
733
if(bi != null) {
734             top += bi.top;
735             left += bi.left;
736             bottom += bi.bottom;
737             right += bi.right;
738         }
739         if(hscroll) {
740             bottom += SCROLL_BAR_THICKNESS;
741         }
742         if(vscroll) {
743             right += SCROLL_BAR_THICKNESS;
744         }
745         return new Insets JavaDoc(top, left, bottom, right);
746     }
747     
748     protected final void sendDelayedPairsToParent() {
749         // Ensures that parent has all the components
750
// below this renderer node. (Parent expected to have removed them).
751
Collection JavaDoc gc = this.delayedPairs;
752         if(gc != null) {
753             RenderableContainer rc = this.container;
754             Iterator JavaDoc i = gc.iterator();
755             while(i.hasNext()) {
756                 DelayedPair pair = (DelayedPair) i.next();
757                 if(pair.targetParent != this) {
758                     rc.addDelayedPair(pair);
759                 }
760             }
761         }
762     }
763     
764     public final void clearDelayedPairs() {
765         Collection JavaDoc gc = this.delayedPairs;
766         if(gc != null) {
767             gc.clear();
768         }
769     }
770     
771     public final Collection JavaDoc getDelayedPairs() {
772         return this.delayedPairs;
773     }
774     
775     /* (non-Javadoc)
776      * @see org.xamjwg.html.renderer.RenderableContainer#add(java.awt.Component)
777      */

778     public void addDelayedPair(DelayedPair pair) {
779         // Expected to be called in GUI thread.
780
// Adds only in local collection.
781
// Does not remove from parent.
782
// Sending components to parent is done
783
// by sendDelayedPairsToParent().
784
Collection JavaDoc gc = this.delayedPairs;
785         if(gc == null) {
786             // Sequence is important.
787
//TODO: But possibly added multiple
788
//times in table layout?
789
gc = new java.util.LinkedList JavaDoc();
790             this.delayedPairs = gc;
791         }
792         gc.add(pair);
793     }
794
795     public RenderableContainer getParentContainer() {
796         return this.container;
797     }
798 }
799
Popular Tags