Source Code Cross Referenced for CssBox.java in  » IDE-Netbeans » visualweb.api.designer » org » netbeans » modules » visualweb » css2 » Java Source Code / Java DocumentationJava Source Code and Java Documentation

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


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:        package org.netbeans.modules.visualweb.css2;
0042:
0043:        import org.netbeans.modules.visualweb.api.designer.cssengine.CssComputedValue;
0044:        import org.netbeans.modules.visualweb.api.designer.markup.MarkupService;
0045:        import org.netbeans.modules.visualweb.designer.CssUtilities;
0046:        import org.netbeans.modules.visualweb.api.designer.cssengine.CssListValue;
0047:        import org.netbeans.modules.visualweb.api.designer.cssengine.CssProvider;
0048:        import org.netbeans.modules.visualweb.api.designer.cssengine.CssValue;
0049:        import org.netbeans.modules.visualweb.spi.designer.Decoration;
0050:        import org.netbeans.modules.visualweb.designer.ImageCache;
0051:        import java.awt.AlphaComposite;
0052:        import java.awt.Color;
0053:        import java.awt.Composite;
0054:        import java.awt.Cursor;
0055:        import java.awt.Dimension;
0056:        import java.awt.Font;
0057:        import java.awt.FontMetrics;
0058:        import java.awt.Graphics;
0059:        import java.awt.Graphics2D;
0060:        import java.awt.Image;
0061:        import java.awt.Insets;
0062:        import java.awt.Point;
0063:        import java.awt.Rectangle;
0064:        import java.awt.Stroke;
0065:        import java.awt.geom.AffineTransform;
0066:        import java.io.PrintStream;
0067:        import java.io.PrintWriter;
0068:        import java.net.URL;
0069:        import java.util.ArrayList;
0070:        import java.util.List;
0071:        import java.util.logging.Level;
0072:        import java.util.logging.Logger;
0073:
0074:        import javax.swing.ImageIcon;
0075:        import javax.swing.SwingConstants;
0076:        import javax.swing.UIManager;
0077:        import org.netbeans.modules.visualweb.api.designer.Designer.Box;
0078:
0079:        import org.openide.util.Utilities;
0080:        import org.w3c.dom.Element;
0081:        import org.w3c.dom.Node;
0082:
0083:        import org.netbeans.modules.visualweb.designer.DesignerPane;
0084:        import org.netbeans.modules.visualweb.designer.Interaction;
0085:        import org.netbeans.modules.visualweb.designer.WebForm;
0086:        import org.netbeans.modules.visualweb.api.designer.cssengine.XhtmlCss;
0087:        import org.netbeans.modules.visualweb.designer.html.HtmlTag;
0088:
0089:        /**
0090:         * Represents a CSS2 Box. I chose to call it CssBox instead of Box since
0091:         * that would conflict with a JDK class.
0092:         * <p>
0093:         * See  http://www.w3.org/TR/REC-CSS2/box.html
0094:         *
0095:         * @todo Rename class to just "Box". And factor out the container-related
0096:         *  functionality into a subclass, ContainerBox.
0097:         * @todo Clarify the getX(), getWidth(), etc. methods - possibly rename
0098:         *  them, to clarify which edge they are positioning - the margin,
0099:         *  the border, the padding or the content? Ditto for width - which width
0100:         *  is it returning - the margin box, the padding box, the border box,
0101:         *  the content box?
0102:         * @todo Split computeHorizontalLength up in subportions
0103:         * @author Tor Norbye
0104:         */
0105:        public class CssBox implements  Box {
0106:            /** Grid size for design-time borders. XXX we really should make this dynamic to match the user's chosen grid size! */
0107:            private static final int MINIMUM_BEAN_SIZE = 24;
0108:
0109:            //    public static final int AUTO = Integer.MAX_VALUE - 1;
0110:            public static final int AUTO = CssUtilities.AUTO;
0111:
0112:            //    public static final int UNINITIALIZED = Integer.MAX_VALUE - 2; // debugging
0113:            public static final int UNINITIALIZED = Box.UNINITIALIZED; // debugging
0114:
0115:            /** XXX Very suspicious usage, see PageBox, and try to get rid of it.
0116:              What a name? What it has to do with persistence? */
0117:            //    public static boolean noBoxPersistence = false;
0118:            public static final int X_AXIS = SwingConstants.HORIZONTAL;
0119:            public static final int Y_AXIS = SwingConstants.VERTICAL;
0120:
0121:            // Log info pertaining to box layout
0122:            protected static final boolean DEBUGFORMAT = false;
0123:            private static boolean debugPaint = System
0124:                    .getProperty("rave.debugLayout") != null; // NOI18N
0125:            static boolean paintPositioning = System
0126:                    .getProperty("rave.debugPositioning") != null; // NOI18N
0127:            static boolean paintSpaces = debugPaint;
0128:            static boolean paintText = false; //debugPaint;
0129:
0130:            // XXX TODO Get rid of this too (before it was org.netbeans.modules.visualweb.text.Document here).
0131:            protected final WebForm webform;
0132:            int top = AUTO;
0133:            int left = AUTO;
0134:            int right = AUTO;
0135:            int bottom = AUTO;
0136:            int contentWidth;
0137:            int contentHeight;
0138:
0139:            /** Z stacking order. AUTO means not set */
0140:            int z = AUTO;
0141:
0142:            /** Parent box. */
0143:            private ContainerBox parent;
0144:            // XXX
0145:            CssBox positionedBy;
0146:
0147:            // TODO: update these puppies.
0148:            int extentX;
0149:
0150:            // XXX No - minimum default value should be e.g. Integer.MAX_VALUE
0151:            int extentY;
0152:            int extentX2;
0153:            int extentY2;
0154:
0155:            //    // XXX Get rid of this from here.
0156:            //    private MarkupDesignBean bean;
0157:
0158:            int topMargin; // XXX do I need to do floating point arithmetic on this?
0159:            int bottomMargin;
0160:            int leftMargin;
0161:            int rightMargin;
0162:            int topPadding;
0163:            int bottomPadding;
0164:            int leftPadding;
0165:            int rightPadding;
0166:            int topBorderWidth;
0167:            int bottomBorderWidth;
0168:            int rightBorderWidth;
0169:            int leftBorderWidth;
0170:            CssBorder border;
0171:
0172:            // XXX Get rid of these from here.
0173:            /** Rendered element. */
0174:            private final Element element;
0175:
0176:            //    /** Source element. */
0177:            //    private Element sourceElement;
0178:
0179:            Color bg;
0180:            HtmlTag tag;
0181:            BackgroundImagePainter bgPainter;
0182:            int x = UNINITIALIZED;
0183:            int y = UNINITIALIZED;
0184:            int width = UNINITIALIZED;
0185:            int height = UNINITIALIZED;
0186:            private int parentIndex = -1;
0187:
0188:            /** The containing block extents associated with a box is the
0189:             * size it has been allocated by its parent - in other words, it's
0190:             * NOT the block it exposes to its children! The containing block
0191:             * exposed to its children is the content edge - e.g.
0192:             * x+leftBorderWidth+leftPadding, to x+width-rightBorderWidth-rightPadding.
0193:             */
0194:            int containingBlockX;
0195:            int containingBlockY;
0196:            int containingBlockWidth = -1;
0197:            int containingBlockHeight = -1;
0198:            boolean inline;
0199:            boolean replaced;
0200:            BoxType boxType;
0201:            int effectiveTopMargin = UNINITIALIZED;
0202:            int effectiveBottomMargin = UNINITIALIZED;
0203:            boolean hidden;
0204:
0205:            private final boolean elementFocused;
0206:
0207:            //this field is used by in inline layout by
0208:            //LineBox and LineBoxGrouh classes to store an inline container 
0209:            //where the box originally resided in.
0210:            //This is needed to get css properties from that container
0211:            //There's no other way to access the container, 
0212:            //because in inline layout, boxes are taken out of it
0213:            // and placed in an inline box
0214:            CssBox originalInlineContainer = null;
0215:
0216:            public CssBox(WebForm webform, Element element, BoxType boxType,
0217:                    boolean inline, boolean replaced) {
0218:                // XXX How come it can be null (see ViewportBox), and there is no test
0219:                // against possible NPE in the code.
0220:                this .webform = webform;
0221:                this .boxType = boxType;
0222:
0223:                this .inline = inline;
0224:
0225:                // Make sure all block level boxes are container boxes
0226:                // why is that? spec does not say it, does it?
0227:                // assert inline || this instanceof ContainerBox;
0228:
0229:                //            // Ensure that we pick up the original jsp element, not
0230:                //            // a document fragment copy as is the case for html children
0231:                //            // of a rendered jsf component
0232:                //            this.element = ((XhtmlElement)element).getSourceElement();
0233:                //            // Don't confuse the above getSourceElement with our
0234:                //            // "sourceElement" field; the latter is used to correlate
0235:                //            // a rendered jsf element (such as an "<input>" with its
0236:                //            // source element "h:command_button"). I could in fact
0237:                //            // use the field to mean both, but to do that I'll need to
0238:                //            // go and change a lot of getElement usage, since
0239:                //            // for all html elements I want the source element, and for
0240:                //            // most jsf rendered elements, I want the effective (rendered)
0241:                //            // element.
0242:                this .element = element;
0243:
0244:                this .replaced = replaced;
0245:
0246:                initializeDesignBean();
0247:
0248:                effectiveTopMargin = 0;
0249:                effectiveBottomMargin = 0;
0250:                initializeInvariants();
0251:
0252:                //        this.initialFocus = DesignerActions.isFocus(getDesignBean());
0253:                //        this.initialFocus = isFocus(getDesignBean());
0254:                //        this.initialFocus = isFocus(getMarkupDesignBeanForCssBox(this));
0255:                //        this.elementFocused = WebForm.getDomProviderService().isFocusedElement(element);
0256:                this .elementFocused = webform == null ? false : webform
0257:                        .getDomProviderService().isFocusedElement(element);
0258:                if (this .elementFocused) {
0259:                    // XXX #117371, clear it here.
0260:                    webform.setInitialFocusMarkCssBox(null);
0261:                }
0262:            }
0263:
0264:            // XXX Still suspicious, should be cleaner when and when not to init it.
0265:            protected void initializeDesignBean() {
0266:                if ((element != null) && (boxType != BoxType.LINEBOX)) {
0267:                    // DO THIS ONLY FOR LIVEBEAN-ELEMENTS! putBoxReference(element, this);
0268:                    putBoxReference(element, this ); // TEMPORARY HACK! XXX TODO REMOVEME [PERFORMANCE] Should I just do this in the else clause for bean!=null below?
0269:
0270:                    //            bean = FacesSupport.getDesignBean(element);
0271:                    //
0272:                    ////            if (element.getParentNode() instanceof RaveElement &&
0273:                    ////                    (((RaveElement)element.getParentNode()).getDesignBean() == bean)) {
0274:                    //            if (element.getParentNode() instanceof Element
0275:                    ////            && InSyncService.getProvider().getMarkupDesignBeanForElement((Element)element.getParentNode()) == bean) {
0276:                    //            && WebForm.getDomProviderService().getMarkupDesignBeanForElement((Element)element.getParentNode()) == bean) {
0277:                    //                // Only set the sourceElement if we're a new toplevel
0278:                    //                // element for this bean
0279:                    //                bean = null;
0280:                    //            }
0281:
0282:                    ////            bean = WebForm.getDomProviderService().getMarkupDesignBeanForComponentRootElement(element);
0283:                    //            MarkupDesignBean bean = getMarkupDesignBeanForComponentRootCssBox(this);
0284:                    //            
0285:                    //            if (bean != null) {
0286:                    //                sourceElement = bean.getElement();
0287:                    // XXX Strange check, just keeping it the same like it was before.
0288:                    //            Element renderedElement = getElementForPrincipalCssBox(this);
0289:                    //            if (renderedElement == element) {
0290:                    //                Element sourceElement = MarkupService.getSourceElementForElement(renderedElement);
0291:                    Element sourceElement = findSourceElement();
0292:                    if (sourceElement != null) {
0293:                        //assert bean == ((XhtmlElement)sourceElement).getDesignBean() : "sourceElement " +
0294:                        //sourceElement + " has a designbean (" +
0295:                        //((XhtmlElement)sourceElement).getDesignBean() + ") different from bean " +
0296:                        //bean;
0297:                        putBoxReference(sourceElement, this );
0298:                    }
0299:                    //            }
0300:                }
0301:            }
0302:
0303:            /** Initialize the box - but initialize only the properties that do not depend on
0304:             * layout, e.g. the containing block.
0305:             */
0306:            protected void initializeInvariants() {
0307:                // initializeBorder(); ?
0308:                initializeBackground();
0309:
0310:                if (element != null) {
0311:                    //            Value v = CssLookup.getValue(element, XhtmlCss.VISIBILITY_INDEX);
0312:                    CssValue cssValue = CssProvider.getEngineService()
0313:                            .getComputedValueForElement(element,
0314:                                    XhtmlCss.VISIBILITY_INDEX);
0315:                    //            hidden = (v != CssValueConstants.VISIBLE_VALUE);
0316:                    hidden = (!CssProvider.getValueService().isVisibleValue(
0317:                            cssValue));
0318:                }
0319:            }
0320:
0321:            /**
0322:             * @todo XXX I should have a phase flag here, which indicates
0323:             *  whether I'm creating boxes, or doing layout. Some stuff can/should
0324:             *  be initialized early on (box creation), other stuff must be deferred
0325:             *  (because it might depend on the containing block).
0326:             *  For example, CssContainerBlock's addText() method depends on the
0327:             *  background to be initialized during box creation, but only the
0328:             *  background color - and other parts of initializeBackground
0329:             *  (related to background-position) must be computed later on.
0330:             * XXX update: initializeInvariants is now used for the box creation phase
0331:             * and initialize() should only be called when we have a containing block
0332:             * so margin percentages etc. can be computed
0333:             * @todo Rename this method to initializeLayout
0334:             */
0335:            protected void initialize() {
0336:                if (element != null) {
0337:                    initializeBorder(); // move to initializeInvariants???
0338:                    initializeMargins();
0339:                    initializePadding();
0340:
0341:                    //initializeBackground(); moved to initializeInvariants
0342:                    //initializeZOrder(); // XXX done from BoxList.add because
0343:                    //initialize() is called during -layout-, and the z order is
0344:                    //needed during box creation. (XXX why? I should be able to
0345:                    //delay that!)
0346:                } else {
0347:                    effectiveTopMargin = 0;
0348:                    effectiveBottomMargin = 0;
0349:                }
0350:            }
0351:
0352:            protected void initializeContentSize() {
0353:                //        contentWidth = CssLookup.getLength(element, XhtmlCss.WIDTH_INDEX);
0354:                //        contentHeight = CssLookup.getLength(element, XhtmlCss.HEIGHT_INDEX);
0355:                contentWidth = CssUtilities.getCssLength(element,
0356:                        XhtmlCss.WIDTH_INDEX);
0357:                contentHeight = CssUtilities.getCssLength(element,
0358:                        XhtmlCss.HEIGHT_INDEX);
0359:            }
0360:
0361:            /** Get the BoxType for this box */
0362:            public BoxType getBoxType() {
0363:                return boxType;
0364:            }
0365:
0366:            /** Set the box type for this box */
0367:
0368:            /*
0369:            void setBoxType(BoxType boxType) {
0370:                this.boxType = boxType;
0371:            }
0372:             */
0373:            protected void initializeZOrder() {
0374:                // Look up Z
0375:                //        Value val = CssLookup.getValue(element, XhtmlCss.Z_INDEX);
0376:                CssValue cssValue = CssProvider.getEngineService()
0377:                        .getComputedValueForElement(element, XhtmlCss.Z_INDEX);
0378:
0379:                //        if (val != CssValueConstants.AUTO_VALUE) {
0380:                if (!CssProvider.getValueService().isAutoValue(cssValue)) {
0381:                    //            z = (int)val.getFloatValue();
0382:                    z = (int) cssValue.getFloatValue();
0383:                }
0384:            }
0385:
0386:            protected void initializeBorder() {
0387:                border = CssBorder.getBorder(element);
0388:
0389:                if (border != null) {
0390:                    leftBorderWidth = border.getLeftBorderWidth();
0391:                    topBorderWidth = border.getTopBorderWidth();
0392:                    bottomBorderWidth = border.getBottomBorderWidth();
0393:                    rightBorderWidth = border.getRightBorderWidth();
0394:
0395:                    // XXX contentWidth/contentHeight may not have been initialized yet!
0396:                }
0397:
0398:                considerDesignBorder(); // Important: do AFTER border initialization above
0399:            }
0400:
0401:            /** Border Patrol! Make sure there's a border if one is needed. */
0402:            protected void considerDesignBorder() {
0403:                // Don't add design border for boxes that already have a border
0404:                if (border != null) {
0405:                    return;
0406:                }
0407:
0408:                // Only add design time border for absolutely positioned elements
0409:                if (!boxType.isAbsolutelyPositioned()) {
0410:                    return;
0411:                }
0412:
0413:                //        MarkupDesignBean bean = getMarkupDesignBeanForCssBox(this);
0414:                //        // Only add design borders for boxes that correspond to a live bean
0415:                //        // Gotta do something more here for markup beans
0416:                //        if ((bean == null) || ((
0417:                //            // Deal with the fact that we get design-ids repeated on children
0418:                //            // now, e.g. <table design-id="foo"><tr design-id="foo"> ....
0419:                //            // We only want the outer most box to have the design border
0420:                ////            parent != null) && (parent.getDesignBean() == bean))) {
0421:                //            parent != null) && (getMarkupDesignBeanForCssBox(parent) == bean))) {
0422:                //            return;
0423:                //        }
0424:                Element componentRootElement = getElementForComponentRootCssBox(this );
0425:                if (componentRootElement == null) {
0426:                    return;
0427:                }
0428:
0429:                if (tag == HtmlTag.FORM) {
0430:                    // No design border on the form tag itself
0431:                    return;
0432:                }
0433:
0434:                //        // Special case: the page separator shouldn't have a design border even
0435:                //        // though it renders a block box and may have dimensions set on it!
0436:                //        // TODO: Mark it horizontal resizable only!
0437:                //        if (bean.getInstance() instanceof com.sun.rave.web.ui.component.PageSeparator
0438:                //        || bean.getInstance() instanceof com.sun.webui.jsf.component.PageSeparator) {
0439:                //            return;
0440:                //        }
0441:                //        if(WebForm.getDomProviderService().ignoreDesignBorder(componentRootElement)) {
0442:                if (webform.getDomProviderService().ignoreDesignBorder(
0443:                        componentRootElement)) {
0444:                    return;
0445:                }
0446:
0447:                ////        XhtmlCssEngine engine = webform.getMarkup().getCssEngine();
0448:                //
0449:                //        // Design borders only on block boxes, or boxes that have specified
0450:                //        // a particular size (e.g. non-auto)
0451:                //        if (!isInlineBox() || engine.isInlineValue((RaveElement)element, XhtmlCss.WIDTH_INDEX) ||
0452:                //                engine.isInlineValue((RaveElement)element, XhtmlCss.HEIGHT_INDEX)) {
0453:                if (!isInlineBox()
0454:                        || CssProvider.getEngineService().isInlineStyleValue(
0455:                                element, XhtmlCss.WIDTH_INDEX)
0456:                        || CssProvider.getEngineService().isInlineStyleValue(
0457:                                element, XhtmlCss.HEIGHT_INDEX)) {
0458:                    border = CssBorder.getDesignerBorder();
0459:                    leftBorderWidth = border.getLeftBorderWidth();
0460:                    topBorderWidth = border.getTopBorderWidth();
0461:                    bottomBorderWidth = border.getBottomBorderWidth();
0462:                    rightBorderWidth = border.getRightBorderWidth();
0463:                }
0464:            }
0465:
0466:            protected void initializeBackground() {
0467:                // Note: TableBox.CellBox doesn't call super.initializeBackground,
0468:                // so if you do additional work here, check CellBox too.
0469:                initializeBackgroundColor();
0470:                initializeBackgroundImage();
0471:            }
0472:
0473:            protected void initializeBackgroundColor() {
0474:                //        bg = CssLookup.getColor(element, XhtmlCss.BACKGROUND_COLOR_INDEX);
0475:                bg = CssProvider.getValueService().getColorForElement(element,
0476:                        XhtmlCss.BACKGROUND_COLOR_INDEX);
0477:            }
0478:
0479:            protected void initializeBackgroundImage() {
0480:                //        ImageIcon bgImage = BackgroundImagePainter.getBackgroundImage(webform, element);
0481:                //        MarkupUnit markupUnit = webform.getMarkup();
0482:                //        if (markupUnit == null) {
0483:                //            // #6457856 NPE
0484:                //            return;
0485:                //        }
0486:                //        URL markupUnitBase = markupUnit.getBase();
0487:                URL markupUnitBase = webform.getBaseUrl();
0488:                if (markupUnitBase == null) {
0489:                    // #6457856 NPE.
0490:                    return;
0491:                }
0492:
0493:                //        URL imageUrl = CssBoxUtilities.getBackgroundImageUrl(element, markupUnitBase);
0494:                URL imageUrl = CssProvider.getEngineService()
0495:                        .getBackgroundImageUrlForElement(element,
0496:                                markupUnitBase);
0497:                ImageIcon bgImage;
0498:                if (imageUrl != null) {
0499:                    // XXX Revise this caching impl.
0500:                    //            ImageCache imageCache = webform.getDocument().getImageCache();
0501:                    ImageCache imageCache = webform.getImageCache();
0502:                    bgImage = imageCache.get(imageUrl);
0503:                    if (bgImage == null) {
0504:                        bgImage = new ImageIcon(imageUrl);
0505:                        imageCache.put(imageUrl, bgImage);
0506:                    }
0507:                } else {
0508:                    bgImage = null;
0509:                }
0510:
0511:                if (bgImage != null) {
0512:                    //            Value repeatValue = CssLookup.getValue(element, XhtmlCss.BACKGROUND_REPEAT_INDEX);
0513:                    CssValue cssRepeatValue = CssProvider.getEngineService()
0514:                            .getComputedValueForElement(element,
0515:                                    XhtmlCss.BACKGROUND_REPEAT_INDEX);
0516:                    //            ListValue positionValue =
0517:                    //                CssLookup.getListValue(CssLookup.getValue(element,
0518:                    //                        XhtmlCss.BACKGROUND_POSITION_INDEX));
0519:                    CssListValue cssPositionValue = CssProvider
0520:                            .getValueService()
0521:                            .getComputedCssListValue(
0522:                                    CssProvider
0523:                                            .getEngineService()
0524:                                            .getComputedValueForElement(
0525:                                                    element,
0526:                                                    XhtmlCss.BACKGROUND_POSITION_INDEX));
0527:                    bgPainter = new BackgroundImagePainter(bgImage,
0528:                            cssRepeatValue, cssPositionValue, element, webform
0529:                                    .getDefaultFontSize());
0530:                }
0531:            }
0532:
0533:            protected void initializeMargins() {
0534:                //        leftMargin = CssLookup.getLength(element, XhtmlCss.MARGIN_LEFT_INDEX);
0535:                //        rightMargin = CssLookup.getLength(element, XhtmlCss.MARGIN_RIGHT_INDEX);
0536:                //        topMargin = CssLookup.getLength(element, XhtmlCss.MARGIN_TOP_INDEX);
0537:                leftMargin = CssUtilities.getCssLength(element,
0538:                        XhtmlCss.MARGIN_LEFT_INDEX);
0539:                rightMargin = CssUtilities.getCssLength(element,
0540:                        XhtmlCss.MARGIN_RIGHT_INDEX);
0541:
0542:                topMargin = CssUtilities.getCssLength(element,
0543:                        XhtmlCss.MARGIN_TOP_INDEX);
0544:                if (topMargin == AUTO) {
0545:                    // XXX #6490331 Now resolve to 0, which covers almost all of the cases.
0546:                    // FIXME See: http://www.w3.org/TR/CSS21/visudet.html#Computing_heights_and_margins.
0547:                    topMargin = 0;
0548:                }
0549:                effectiveTopMargin = topMargin;
0550:
0551:                //        bottomMargin = CssLookup.getLength(element, XhtmlCss.MARGIN_BOTTOM_INDEX);
0552:                bottomMargin = CssUtilities.getCssLength(element,
0553:                        XhtmlCss.MARGIN_BOTTOM_INDEX);
0554:                if (bottomMargin == AUTO) {
0555:                    // XXX #6490331 Now resolve to 0, which covers almost all of the cases.
0556:                    // FIXME See: http://www.w3.org/TR/CSS21/visudet.html#Computing_heights_and_margins.
0557:                    bottomMargin = 0;
0558:                }
0559:
0560:                effectiveBottomMargin = bottomMargin;
0561:            }
0562:
0563:            protected void initializePadding() {
0564:                //        leftPadding = CssLookup.getLength(element, XhtmlCss.PADDING_LEFT_INDEX);
0565:                //        rightPadding = CssLookup.getLength(element, XhtmlCss.PADDING_RIGHT_INDEX);
0566:                leftPadding = CssUtilities.getCssLength(element,
0567:                        XhtmlCss.PADDING_LEFT_INDEX);
0568:                rightPadding = CssUtilities.getCssLength(element,
0569:                        XhtmlCss.PADDING_RIGHT_INDEX);
0570:
0571:                // Unlike margins, padding values are not allowed to be negative!
0572:                if (leftPadding < 0) {
0573:                    leftPadding = 0;
0574:                }
0575:
0576:                if (rightPadding < 0) {
0577:                    rightPadding = 0;
0578:                }
0579:
0580:                //        topPadding = CssLookup.getLength(element, XhtmlCss.PADDING_TOP_INDEX);
0581:                //        bottomPadding = CssLookup.getLength(element, XhtmlCss.PADDING_BOTTOM_INDEX);
0582:                topPadding = CssUtilities.getCssLength(element,
0583:                        XhtmlCss.PADDING_TOP_INDEX);
0584:                bottomPadding = CssUtilities.getCssLength(element,
0585:                        XhtmlCss.PADDING_BOTTOM_INDEX);
0586:
0587:                if (topPadding < 0) {
0588:                    topPadding = 0;
0589:                }
0590:
0591:                if (bottomPadding < 0) {
0592:                    bottomPadding = 0;
0593:                }
0594:            }
0595:
0596:            /** Return the element being rendered by this box; for jsf components
0597:             * this means it will be a rendered html element, not a jsf element */
0598:            public final Element getElement() {
0599:                return element;
0600:            }
0601:
0602:            // XXX TEMP
0603:            private Element findSourceElement() {
0604:                // XXX Strange check, just keeping it the same like it was before.
0605:                Element renderedElement = getElementForPrincipalCssBox(this );
0606:                if (renderedElement == element) {
0607:                    return MarkupService
0608:                            .getSourceElementForElement(renderedElement);
0609:                }
0610:                return null;
0611:            }
0612:
0613:            /** Return the element representing this box in the source; for jsf
0614:             * this will be the actual jsf element, not an html rendered element
0615:             * for it.
0616:             * XXX Heavy hack!! This method cheats, if there is not corresponding source element,
0617:             * it returns its rendered element (#getElement). Get rid of this.
0618:             */
0619:            public final Element getSourceElement() {
0620:                Element sourceElement = findSourceElement();
0621:                if (sourceElement != null) {
0622:                    return sourceElement;
0623:                } else {
0624:                    return getElement();
0625:                }
0626:            }
0627:
0628:            //    // XXX TODO JSF specific, replace with the latter method.
0629:            //    /** Compute a list of rectangles for all the boxes that represent
0630:            //     * the given live bean. Inline spans are added as a single bounding
0631:            //     * rectangle, not as individual rectangles for each inline text, image,
0632:            //     * form or iframe box. */
0633:            //    protected void computeRectangles(DesignBean component, List list) {
0634:            ////        if (getDesignBean() == component) {
0635:            //        if (getMarkupDesignBeanForCssBox(this) == component) {
0636:            //            // allocations get mutated by later
0637:            //            // transformations so I've gotta make a copy
0638:            //            list.add(new Rectangle(getAbsoluteX(), getAbsoluteY(), getWidth(), getHeight()));
0639:            //
0640:            //            return; // No need to do children!
0641:            //        }
0642:            //
0643:            //        for (int i = 0, n = getBoxCount(); i < n; i++) {
0644:            //            CssBox child = getBox(i);
0645:            //            child.computeRectangles(component, list);
0646:            //
0647:            //            if (list.size() >= 1) {
0648:            //                break;
0649:            //            }
0650:            //        }
0651:            //    }
0652:
0653:            // This will replace the above.
0654:            /** Compute a list of rectangles for all the boxes that represent
0655:             * the given live bean. Inline spans are added as a single bounding
0656:             * rectangle, not as individual rectangles for each inline text, image,
0657:             * form or iframe box. */
0658:            protected void computeRectangles(Element componentRootElement,
0659:                    List<Rectangle> list) {
0660:                //        if (getDesignBean() == component) {
0661:                if (getElementForComponentRootCssBox(this ) == componentRootElement
0662:                        || webform.getDomProviderService().areLinkedToSameBean(
0663:                                element, componentRootElement)) {
0664:                    // allocations get mutated by later
0665:                    // transformations so I've gotta make a copy
0666:                    list.add(new Rectangle(getAbsoluteX(), getAbsoluteY(),
0667:                            getWidth(), getHeight()));
0668:
0669:                    return; // No need to do children!
0670:                }
0671:
0672:                for (int i = 0, n = getBoxCount(); i < n; i++) {
0673:                    CssBox child = getBox(i);
0674:                    //            child.computeRectangles(component, list);
0675:                    child.computeRectangles(componentRootElement, list);
0676:
0677:                    if (list.size() >= 1) {
0678:                        break;
0679:                    }
0680:                }
0681:            }
0682:
0683:            //    // XXX TODO JSF specific, replace with the latter method.
0684:            //    protected Rectangle computeBounds(DesignBean component, Rectangle bounds) {
0685:            ////        if (getDesignBean() == component) {
0686:            //        if (getMarkupDesignBeanForCssBox(this) == component) {
0687:            //            Rectangle r = new Rectangle(getAbsoluteX(), getAbsoluteY(), getWidth(), getHeight());
0688:            //
0689:            //            if (bounds == null) {
0690:            //                // allocations get mutated by later
0691:            //                // transformations so I've gotta make a copy
0692:            //                bounds = r;
0693:            //            } else {
0694:            //                bounds.add(r);
0695:            //            }
0696:            //        }
0697:            //
0698:            //        for (int i = 0, n = getBoxCount(); i < n; i++) {
0699:            //            CssBox child = getBox(i);
0700:            //            bounds = child.computeBounds(component, bounds);
0701:            //        }
0702:            //
0703:            //        return bounds;
0704:            //    }
0705:
0706:            // This will replace the above.
0707:            protected Rectangle computeBounds(Element componentRootElement,
0708:                    Rectangle bounds) {
0709:                //        if (getDesignBean() == component) {
0710:                if (getElementForComponentRootCssBox(this ) == componentRootElement
0711:                        || webform.getDomProviderService().areLinkedToSameBean(
0712:                                element, componentRootElement)) {
0713:                    Rectangle r = new Rectangle(getAbsoluteX(), getAbsoluteY(),
0714:                            getWidth(), getHeight());
0715:
0716:                    if (bounds == null) {
0717:                        // allocations get mutated by later
0718:                        // transformations so I've gotta make a copy
0719:                        bounds = r;
0720:                    } else {
0721:                        bounds.add(r);
0722:                    }
0723:                }
0724:
0725:                for (int i = 0, n = getBoxCount(); i < n; i++) {
0726:                    CssBox child = getBox(i);
0727:                    bounds = child.computeBounds(componentRootElement, bounds);
0728:                }
0729:
0730:                return bounds;
0731:            }
0732:
0733:            //    public /*protected*/ final Rectangle computeRegionBounds(MarkupMouseRegion region, Rectangle bounds) {
0734:            public/*protected*/final Rectangle computeRegionBounds(
0735:                    Element regionElement, Rectangle bounds) {
0736:                //        if ((element != null) && (((RaveElement)element).getMarkupMouseRegion() == region)) {
0737:                //        if (element != null && (InSyncService.getProvider().getMarkupMouseRegionForElement(element) == region)) {
0738:                //        if (element != null && (WebForm.getDomProviderService().getMarkupMouseRegionForElement(element) == region)) {
0739:                if (element != null
0740:                        && webform.getDomProviderService()
0741:                                .isSameRegionOfElement(regionElement, element)) {
0742:                    Rectangle r = new Rectangle(getAbsoluteX(), getAbsoluteY(),
0743:                            getWidth(), getHeight());
0744:
0745:                    if (bounds == null) {
0746:                        // allocations get mutated by later
0747:                        // transformations so I've gotta make a copy
0748:                        bounds = r;
0749:                    } else {
0750:                        bounds.add(r);
0751:                    }
0752:                }
0753:
0754:                for (int i = 0, n = getBoxCount(); i < n; i++) {
0755:                    CssBox child = getBox(i);
0756:
0757:                    if ((child.element != null)
0758:                            && (child.element.getParentNode() != element)) {
0759:                        Node curr = child.element.getParentNode();
0760:                        boolean found = false;
0761:
0762:                        //                while (curr instanceof RaveElement && (curr != element)) {
0763:                        //                    RaveElement xel = (RaveElement)curr;
0764:                        while (curr instanceof  Element && (curr != element)) {
0765:                            Element xel = (Element) curr;
0766:
0767:                            //                    if (xel.getMarkupMouseRegion() == region) {
0768:                            //                    if (InSyncService.getProvider().getMarkupMouseRegionForElement(xel) == region) {
0769:                            //                    if (WebForm.getDomProviderService().getMarkupMouseRegionForElement(xel) == region) {
0770:                            if (webform.getDomProviderService()
0771:                                    .isSameRegionOfElement(regionElement, xel)) {
0772:                                found = true;
0773:                            }
0774:
0775:                            curr = curr.getParentNode();
0776:                        }
0777:
0778:                        if (found) {
0779:                            // Yes, use the entire child as part of the region. One of
0780:                            // its invisible parents (such as a <tr>) includes it.
0781:                            Rectangle r = new Rectangle(child.getAbsoluteX(),
0782:                                    child.getAbsoluteY(), child.getWidth(),
0783:                                    child.getHeight());
0784:
0785:                            if (bounds == null) {
0786:                                // allocations get mutated by later
0787:                                // transformations so I've gotta make a copy
0788:                                bounds = r;
0789:                            } else {
0790:                                bounds.add(r);
0791:                            }
0792:
0793:                            continue;
0794:                        }
0795:                    }
0796:
0797:                    //            bounds = child.computeRegionBounds(region, bounds);
0798:                    bounds = child.computeRegionBounds(regionElement, bounds);
0799:                }
0800:
0801:                return bounds;
0802:            }
0803:
0804:            //    /** Returns true if this box represents an inline span.  This is true for
0805:            //      * inline boxes that are not block tags, or are not inline tags that are
0806:            //      * absolutely positioned, or are replaced.
0807:            //     */
0808:            //    protected boolean isSpan() {
0809:            //        return inline && !boxType.isAbsolutelyPositioned() && !replaced &&
0810:            //        this instanceof ContainerBox;
0811:            //    }
0812:
0813:            //    /** Return the first box matching the given DesignBean. */
0814:            //    private static CssBox findCssBoxInTree(DesignBean bean, CssBox cssBox) {
0815:            /** Returns the first box matching the given component root element (rendered element). */
0816:            private static CssBox findCssBoxInTree(
0817:                    Element componentRootElement, CssBox cssBox) {
0818:                if (componentRootElement == null) {
0819:                    return null;
0820:                }
0821:                //        if (bean == cssBox.getDesignBean()) {
0822:                //        if (bean == getMarkupDesignBeanForCssBox(cssBox)) {
0823:                if (componentRootElement == getElementForComponentRootCssBox(cssBox)) {
0824:                    return cssBox;
0825:                }
0826:
0827:                for (int i = 0, n = cssBox.getBoxCount(); i < n; i++) {
0828:                    CssBox box = cssBox.getBox(i);
0829:                    //            CssBox match = findCssBoxInTree(bean, box);
0830:                    CssBox match = findCssBoxInTree(componentRootElement, box);
0831:
0832:                    if (match != null) {
0833:                        return match;
0834:                    }
0835:                }
0836:
0837:                return null;
0838:            }
0839:
0840:            //    /** Return the first box matching the given DesignBean.
0841:            //     * XXX Get rid of this and replace with #findCssBoxForComponentRootElement. */
0842:            //    protected CssBox findCssBox(DesignBean bean) {
0843:            ////        Element e = FacesSupport.getElement(bean);
0844:            ////        Element e = Util.getElement(bean);
0845:            ////        Element e = WebForm.getDomProviderService().getElement(bean);
0846:            //        Element componentRootElement = WebForm.getDomProviderService().getRenderedElement(bean);
0847:            //
0848:            ////        if (e != null) {
0849:            //////            CssBox box = CssBox.getBox(e);
0850:            ////            CssBox box = getWebForm().findCssBoxForElement(e);
0851:            //        if (componentRootElement != null) {
0852:            //            CssBox box = getWebForm().findCssBoxForElement(componentRootElement);
0853:            //
0854:            //            if (box != null) {
0855:            //                return box;
0856:            //            }
0857:            //        }
0858:            //
0859:            ////        return findCssBoxInTree(bean, this);
0860:            //        return findCssBoxInTree(componentRootElement, this);
0861:            //    }
0862:
0863:            /** Gets the first box matching the given component root element. */
0864:            protected CssBox findCssBoxForComponentRootElement(
0865:                    Element componentRootElement) {
0866:                if (componentRootElement == null) {
0867:                    return null;
0868:                }
0869:
0870:                CssBox box = getWebForm().findCssBoxForElement(
0871:                        componentRootElement);
0872:                if (box != null) {
0873:                    return box;
0874:                }
0875:
0876:                return findCssBoxInTree(componentRootElement, this );
0877:            }
0878:
0879:            /** Stash a reference to this box on the element
0880:             * So we can quickly look up a Box for an element
0881:             *
0882:             */
0883:            void putBoxReference(Element element, CssBox box) {
0884:                //        if (noBoxPersistence) {
0885:                //            return;
0886:                //        }
0887:
0888:                getWebForm().setCssBoxForElement(element, box);
0889:                //        if (element instanceof RaveElement) {
0890:                //            ((RaveElement)element).setBox(box);
0891:                //        }
0892:
0893:                /* This doesn't help, since putBoxReference is called from the
0894:                 * box constructor, and the parent has not been initialized (or
0895:                 * even computed) decided yet.
0896:                // Use the topmost box that refers to this element
0897:                if (box.parent != null &&
0898:                    (box.parent.element == element || box.parent.sourceElement == element)) {
0899:                    return;
0900:                }
0901:                 */
0902:            }
0903:
0904:            // XXX Moved to WebForm.
0905:            //    /**
0906:            //     * Locate the box that was created for the given element,
0907:            //     * if any. May return null if the element has not been
0908:            //     * rendered.
0909:            //     */
0910:            //    public CssBox findCssBoxForElement(Element element) {
0911:            ////        RaveElement e = (RaveElement)element;
0912:            ////        CssBox box = (CssBox)e.getBox();
0913:            //        CssBox box = getWebForm().getCssBoxForElement(element);
0914:            //
0915:            //        if (box != null) {
0916:            //            // Work around the problem that children boxes when created may
0917:            //            // overwrite the existing box reference in the element. I can't
0918:            //            // simply at that point go and look to see if a reference already exists
0919:            //            // and if so not point to my new box, since that would break
0920:            //            // incremental layout etc. -- I create multiple generations of
0921:            //            // boxes for each element, and in the box constructor I don't
0922:            //            // know the parentage of the box yet.
0923:            //            while ((box.parent != null) && (box.parent.getElement() == element)) {
0924:            //                box = box.parent;
0925:            //            }
0926:            //
0927:            ////            e.setBox(box);
0928:            //            getWebForm().setCssBoxForElement(element, box);
0929:            //
0930:            //            return box;
0931:            //        }
0932:            //
0933:            //        return null;
0934:            //    }
0935:
0936:            /**
0937:             * Paints the CSS box according to the attributes
0938:             * given.  This should paint the border, padding,
0939:             * and background.
0940:             *
0941:             * @param g the rendering surface.
0942:             * @param x the x coordinate of the allocated area to
0943:             *  render into.
0944:             * @param y the y coordinate of the allocated area to
0945:             *  render into.
0946:             * @param w the width of the allocated area to render into.
0947:             * @param h the height of the allocated area to render into.
0948:             * @param v the view making the request.  This is
0949:             *  used to get the AttributeSet, and may be used to
0950:             *  resolve percentage arguments.
0951:             */
0952:            protected void paintBox(Graphics g, int x, int y, int w, int h) {
0953:                if (hidden) {
0954:                    return;
0955:                }
0956:
0957:                if (border != null) {
0958:                    border.paintBorder(g, x, y, w, h);
0959:                }
0960:
0961:                // NO! Don't do this if a particular border edge is dashed
0962:                // or none - in that case the border should "shine through!
0963:                x += leftBorderWidth;
0964:                y += topBorderWidth;
0965:                w -= leftBorderWidth;
0966:                w -= rightBorderWidth;
0967:                h -= topBorderWidth;
0968:                h -= bottomBorderWidth;
0969:
0970:                if (bg != null) {
0971:                    g.setColor(bg);
0972:                    g.fillRect(x, y, w, h);
0973:                } // I can't do an "else" here to avoid "double painting" the background
0974:
0975:                // (first fillRect, then gradient painting over it) because I don't know
0976:                // that the background painter will fully cover the box.  For example,
0977:                // with background-repeat: repeat-x the full y won't be painted, etc.
0978:                if (bgPainter != null) {
0979:                    // According to the CSS spec section 1.4.21, the background
0980:                    // image covers the padding rectangle
0981:                    bgPainter.paint(g, x, y, w, h);
0982:                }
0983:            }
0984:
0985:            /**
0986:             * <p>
0987:             * Return the horizontal actual position of the visual portion of this box (the
0988:             * border edge in the CSS 2 model) from the outermost viewport.
0989:             * This is the actual screen pixel where the visual part of the component
0990:             * will be painted.
0991:             * </p>
0992:             * <p>
0993:             * Note that the name "getAbsoluteX" has "absolute" in it because unlike
0994:             * getX(), which returns the -relative- position of this box (relative to
0995:             * its parents border edge), this method computes the absolute, or actual,
0996:             * screen coordinate. Note also that it's a recursive call, unlike getX()
0997:             * which is a plain field accessor.
0998:             * </p>
0999:             *
1000:             * @return The actual horizontal position of the beginning of the lefthand side border
1001:             *   of this box (or if no border, the padding edge, and if no padding, the
1002:             *   content edge).
1003:             */
1004:            public int getAbsoluteX() {
1005:                if (positionedBy != parent) {
1006:                    return positionedBy.getAbsoluteX() + getX() + leftMargin;
1007:                }
1008:
1009:                if (parent != null) {
1010:                    return parent.getAbsoluteX() + x + leftMargin;
1011:                } else {
1012:                    return x + leftMargin;
1013:                }
1014:            }
1015:
1016:            /**
1017:             * <p>
1018:             * Return the actual vertical position of the visual portion of this box (the
1019:             * border edge in the CSS 2 model) from the outermost viewport.
1020:             * This is the actual screen pixel where the visual part of the component
1021:             * will be painted.
1022:             * </p>
1023:             * <p>
1024:             * Note that the name "getAbsoluteY" has "absolute" in it because unlike
1025:             * getY(), which returns the -relative- position of this box (relative to
1026:             * its parents border edge), this method computes the absolute, or actual,
1027:             * screen coordinate. Note also that it's a recursive call, unlike getY()
1028:             * which is a plain field accessor.
1029:             * </p>
1030:             * @return The actual vertical position of the beginning of the lefthand side border
1031:             *   of this box (or if no border, the padding edge, and if no padding, the
1032:             *   content edge).
1033:             */
1034:            public int getAbsoluteY() {
1035:                if (positionedBy != parent) {
1036:                    return positionedBy.getAbsoluteY() + getY()
1037:                            + effectiveTopMargin;
1038:                }
1039:
1040:                if (parent != null) {
1041:                    return parent.getAbsoluteY() + y + effectiveTopMargin;
1042:                } else {
1043:                    return y + effectiveTopMargin;
1044:                }
1045:            }
1046:
1047:            /**
1048:             *  Set the computed width of the box - from the left border edge
1049:             *  to the right border edge - in other words, the width of the
1050:             *  content, plus the padding, plus the border widths.
1051:             * <b>For use by the formatter only.</b>
1052:             * @param width the actual width of the box
1053:             */
1054:
1055:            /*
1056:            void setWidth(int width) {
1057:                Log.err.log(
1058:                    "setWidth("
1059:                        + width
1060:                        + ") on "
1061:                        + getElement()
1062:                        + " disabled for now");
1063:                Thread.dumpStack();
1064:                //this.width = width;
1065:            }
1066:             */
1067:
1068:            /**
1069:             *  Set the computed height of the box - from the top border edge
1070:             *  to the bottom border edge - in other words, the height of the
1071:             *  content, plus the padding, plus the border widths.
1072:             * <b>For use by the formatter only.</b>
1073:             * @param height the actual height of the box
1074:             */
1075:
1076:            /*
1077:            void setHeight(int height) {
1078:                Log.err.log(
1079:                    "setHeight("
1080:                        + height
1081:                        + ") on "
1082:                        + getElement()
1083:                        + " disabled for now");
1084:                Thread.dumpStack();
1085:                //this.height = height;
1086:            }
1087:             */
1088:
1089:            /** Return the baseline of this box, if applicable. The baseline is the distance from
1090:             * the top of the box to the baseline of the content in the box. This method has no
1091:             * meaning for block-formatted boxes. For inline boxes, the box will be aligned with
1092:             * the linebox baseline along its own baseline, when the vertical alignment is set to
1093:             * "baseline".
1094:             */
1095:            protected int getBaseline() {
1096:                return getHeight();
1097:            }
1098:
1099:            /** Return the baseline of this box as it contributes to computing the baseline in a
1100:             * linebox. For most boxes, this is the same as their normal baseline. Images however
1101:             * act a bit differently; normally their baseline are at the bottom of the image;
1102:             * thus the image bottom will be aligned in a linebox along with the text baseline.
1103:             * However, a really tall image will NOT push the baseline down like other boxes do.
1104:             * This method captures the baseline that should be used for computing the overall
1105:             * baseline before laying out the boxes along the baseline.
1106:             */
1107:            protected int getContributingBaseline() {
1108:                return getBaseline();
1109:            }
1110:
1111:            /** Report whether this box is a grid positioning container. */
1112:            public boolean isGrid() {
1113:                return false;
1114:            }
1115:
1116:            /**
1117:             * Set the x position of the box. This referers to the location of
1118:             * the border edge - in other words where the box visually begins.
1119:             * <b>For use by the formatter only.</b>
1120:             * @param x the new x coordinate
1121:             */
1122:            void setX(int x) {
1123:                this .x = x;
1124:            }
1125:
1126:            /**
1127:             * Set the y position of the box. This referers to the location of
1128:             * the border edge  - in other words where the box visually begins.
1129:             * <b>For use by the formatter only.</b>
1130:             * @param y the new y coordinate
1131:             */
1132:            void setY(int y) {
1133:                this .y = y;
1134:            }
1135:
1136:            /** Convenience method to set both x and y in one call.
1137:             * @see setX
1138:             * @see setY
1139:             */
1140:            public final void setLocation(int x, int y) {
1141:                this .x = x;
1142:                this .y = y;
1143:            }
1144:
1145:            public final String toString() {
1146:                return super .toString() + "[" + paramString() + "]"; // NOI18N
1147:            }
1148:
1149:            protected String paramString() {
1150:                return "pos=" + x + ":" + y + "," // NOI18N
1151:                        + "element=" + element // NOI18N
1152:                        //                + ", markupDesignBean=" + getMarkupDesignBeanForCssBox(this) // NOI18N
1153:                        //                + ", componentRootElement=" + getElementForComponentRootCssBox(this) // NOI18N
1154:                        + ", size=" + width + ":" + height // NOI18N
1155:                        //                + ", contentWidth=" + contentWidth // NOI18N
1156:                        //                + ", containingBlockWidth=" + containingBlockWidth
1157:                ; // NOI18N
1158:            }
1159:
1160:            public void paint(Graphics g, int px, int py) {
1161:                px += getX();
1162:                py += getY();
1163:
1164:                // Box model quirk: my coordinate system is based on the visual
1165:                // extents of the boxes - e.g. location and size of the border
1166:                // edge.  Because of this, when visually traversing the hierarchy,
1167:                // I need to add in the margins.
1168:                px += leftMargin;
1169:                py += effectiveTopMargin;
1170:
1171:                if ((Math.abs(px) > 50000) || (Math.abs(py) > 50000)
1172:                        || (Math.abs(width) > 50000)
1173:                        || (Math.abs(height) > 50000)) {
1174:                    //            g.setColor(Color.RED);
1175:                    //            g.setFont(g.getFont().deriveFont(8.0f));
1176:
1177:                    CssBox badBox = findBadBox(this );
1178:                    //            g.drawString("Fatal Painting Error: box " + badBox.toString(), 0,
1179:                    //                g.getFontMetrics().getHeight());
1180:                    //
1181:                    //            if (badBox.getParent() != null) {
1182:                    //                g.drawString("Fatal Painting Error: box " + badBox.getParent().toString(), 0,
1183:                    //                    2 * g.getFontMetrics().getHeight());
1184:                    //            }
1185:                    // XXX Improving the above error handling.
1186:                    // TODO Why is actually this state invalid?
1187:                    // XXX FIXME Possibility of this state is wrong.
1188:                    info(new IllegalStateException("Fatal painting error:" // NOI18N
1189:                            + "\nthis box=" + this  // NOI18N
1190:                            + "\nbad box=" + badBox // NOI18N
1191:                            + "\nparent of bad box=" + badBox.getParent())); // NOI18N
1192:
1193:                    return;
1194:                }
1195:
1196:                paintBackground(g, px, py);
1197:
1198:                // XXX #117371.
1199:                if (hasInitialFocus()
1200:                        && webform.getInitialFocusMarkCssBox() == null) {
1201:                    webform.setInitialFocusMarkCssBox(this );
1202:                }
1203:
1204:                // Paint children
1205:                for (int i = 0, n = getBoxCount(); i < n; i++) {
1206:                    CssBox box = getBox(i);
1207:
1208:                    if (DesignerPane.INCREMENTAL_LAYOUT) {
1209:                        if (DesignerPane.isOutsideClip(box.extentX,
1210:                                box.extentY, box.extentX2, box.extentY2)) {
1211:                            //if (PageBox.debugclip)
1212:                            //    System.out.println("CLIPPED BOX " + box);
1213:                            // <decoration>
1214:                            //                    continue;
1215:                            // ====
1216:                            // XXX Check the decoration too.
1217:                            if (isBoxDecorationOutsideClip(box)) {
1218:                                continue;
1219:                            }
1220:                            // </decoration>
1221:                        }
1222:                    }
1223:
1224:                    CssBox positionParent = box.getPositionedBy();
1225:
1226:                    if (positionParent != this ) {
1227:                        // Not positioned by us - need to compute the
1228:                        // positioning parent's absolute position
1229:                        box.paint(g, positionParent.getAbsoluteX(),
1230:                                positionParent.getAbsoluteY());
1231:                    } else {
1232:                        box.paint(g, px, py);
1233:                    }
1234:                }
1235:
1236:                // XXX #117371.
1237:                if (this  == webform.getInitialFocusMarkCssBox()) {
1238:                    paintFocusWaterMark(g, px, py);
1239:                }
1240:
1241:                // XXX Painting decoration if needed.
1242:                paintDecoration(g, px + getWidth(), py);
1243:
1244:                if (paintPositioning) {
1245:                    paintDebugPositioning(g);
1246:                }
1247:
1248:                // Children will do additional stuff
1249:            }
1250:
1251:            private/*static*/boolean isBoxDecorationOutsideClip(CssBox box) {
1252:                //        if (!DesignerSettings.getInstance().isShowDecorations()) {
1253:                if (!webform.isShowDecorations()) {
1254:                    return true;
1255:                }
1256:
1257:                Decoration decoration = box.getDecoration();
1258:                if (decoration != null) {
1259:                    // XXX Where could be the location of the decoration?
1260:                    int x1 = box.extentX2;
1261:                    int y1 = box.extentY;
1262:                    int x2 = x1 + decoration.getWidth();
1263:                    int y2 = y1 + decoration.getHeight();
1264:
1265:                    return DesignerPane.isOutsideClip(x1, y1, x2, y2);
1266:                }
1267:
1268:                return true;
1269:            }
1270:
1271:            protected final boolean hasInitialFocus() {
1272:                return elementFocused /*&& isComponentTopBoxInLayoutHierarchy()*/;
1273:            }
1274:
1275:            //    private final boolean isComponentTopBoxInLayoutHierarchy() {
1276:            //        Element element = getElement();
1277:            //        if (element == null) {
1278:            //            return false;
1279:            //        }
1280:            //        CssBox parentBox = getParent();
1281:            //        if (parentBox == null) {
1282:            //            return false;
1283:            //        }
1284:            //        CssBox grandParent = parentBox.getParent();
1285:            //        if (grandParent == null) {
1286:            //            return true;
1287:            //        }
1288:            //        return element != parentBox.getElement();
1289:            //    }
1290:
1291:            protected final void paintFocusWaterMark(Graphics g, int x, int y) {
1292:                Image image = Utilities
1293:                        .loadImage("org/netbeans/modules/visualweb/designer/resources/focus-watermark.gif"); // NOI18N
1294:                if ((image != null) && (g instanceof  Graphics2D)) {
1295:                    Graphics2D g2d = (Graphics2D) g;
1296:                    AffineTransform t = new AffineTransform(); // XXX keep transform object around?
1297:                    t.translate(x, y);
1298:
1299:                    Composite oldAlpha = g2d.getComposite();
1300:                    g2d.setComposite(AlphaComposite.getInstance(
1301:                            AlphaComposite.SRC_OVER, 0.5f));
1302:                    g2d.drawImage(image, t, null);
1303:                    g2d.setComposite(oldAlpha);
1304:                }
1305:            }
1306:
1307:            protected void paintDecoration(Graphics g, int x, int y) {
1308:                //        if (!DesignerSettings.getInstance().isShowDecorations()) {
1309:                if (!webform.isShowDecorations()) {
1310:                    return;
1311:                }
1312:
1313:                Decoration decoration = getDecoration();
1314:                if (decoration == null) {
1315:                    return;
1316:                }
1317:
1318:                //        Color oldColor = g.getColor();
1319:                //        Color color = new Color(255, 255, 0, 150); // TEMP
1320:                //        g.setColor(color);
1321:                //        g.fillRect(x, y, decoration.getWidth(), decoration.getHeight());
1322:                //        g.setColor(oldColor);
1323:                //
1324:                ////                g.drawImage(image, x, y, null);
1325:                Image image = decoration.getImage();
1326:                if (image != null) {
1327:                    ImageIcon imageIcon = new ImageIcon(image);
1328:                    imageIcon.paintIcon(null, g, x, y);
1329:                }
1330:            }
1331:
1332:            protected void paintDebugPositioning(Graphics g) {
1333:                //        MarkupDesignBean bean = getMarkupDesignBeanForCssBox(this);
1334:                ////        if ((bean == null) || !boxType.isPositioned() || (FacesSupport.getFacesBean(bean) == null) ||
1335:                ////                FacesSupport.isFormBean(webform, bean)) {
1336:                //        if ((bean == null) || !boxType.isPositioned()
1337:                ////        || (Util.getFacesBean(bean) == null) || Util.isFormBean(webform.getModel(), bean)) {
1338:                //        || !WebForm.getDomProviderService().isFacesBean(bean)
1339:                //        || webform.isFormBean(bean)) {
1340:                //            return;
1341:                //        }
1342:                Element componentRootElement = getElementForComponentRootCssBox(this );
1343:                //        if ((bean == null) || !boxType.isPositioned() || (FacesSupport.getFacesBean(bean) == null) ||
1344:                //                FacesSupport.isFormBean(webform, bean)) {
1345:                if ((componentRootElement == null)
1346:                        || !boxType.isPositioned()
1347:                        //        || (Util.getFacesBean(bean) == null) || Util.isFormBean(webform.getModel(), bean)) {
1348:                        || !webform.getDomProviderService().isFacesComponent(
1349:                                componentRootElement)
1350:                        || webform.isFormComponent(componentRootElement)) {
1351:                    return;
1352:                }
1353:
1354:                // TODO -- paint bottom, right, etc.?
1355:                CssBox positionParent = getPositionedBy();
1356:
1357:                if (positionParent == null) {
1358:                    return;
1359:                }
1360:
1361:                int rx = positionParent.getAbsoluteX();
1362:                int ry = positionParent.getAbsoluteY();
1363:
1364:                int px = getAbsoluteX();
1365:                int py = getAbsoluteY();
1366:
1367:                Graphics2D g2d = (Graphics2D) g;
1368:                Stroke oldStroke = g2d.getStroke();
1369:
1370:                //int width = 1;
1371:                //BasicStroke s =
1372:                //    new BasicStroke((float)width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER,
1373:                //        10.0f, new float[] { 5 * width, (5 * width) + width }, 0.0f);
1374:                //
1375:                //g2d.setStroke(s);
1376:                g.setColor(Color.LIGHT_GRAY);
1377:
1378:                String xStr = Integer.toString(x);
1379:                String yStr = Integer.toString(y);
1380:                Font font = UIManager.getFont("Label.font");
1381:                g2d.setFont(font);
1382:
1383:                FontMetrics metrics = g2d.getFontMetrics();
1384:                int xWidth = metrics.stringWidth(xStr);
1385:                int yWidth = metrics.getAscent() + metrics.getDescent();
1386:
1387:                // First segment
1388:                int len = ((px - rx) / 2) - (xWidth / 2) - 2;
1389:
1390:                if (len > 0) {
1391:                    g.drawLine(rx, py, rx + len, py);
1392:                    g.drawLine(px - len, py, px, py);
1393:                }
1394:
1395:                g
1396:                        .drawString(xStr, rx + len + 1, (py + (metrics
1397:                                .getHeight() / 2))
1398:                                - metrics.getDescent());
1399:
1400:                len = ((py - ry) / 2) - (yWidth / 2) - 2;
1401:
1402:                if (len > 0) {
1403:                    g.drawLine(px, ry, px, ry + len);
1404:                    g.drawLine(px, py - len, px, py);
1405:                }
1406:
1407:                g2d.setStroke(oldStroke);
1408:                g.drawString(yStr, px - (xWidth / 2), py - len
1409:                        - metrics.getDescent() + 1);
1410:            }
1411:
1412:            /** Find the deepest box that has invalid dimensions. This must be called on a bad
1413:             * box to begin with since it will return self if nothing deeper is found.
1414:             */
1415:            private static CssBox findBadBox(CssBox box) {
1416:                for (int i = 0, n = box.getBoxCount(); i < n; i++) {
1417:                    CssBox child = box.getBox(i);
1418:
1419:                    if ((Math.abs(child.extentX) > 50000)
1420:                            || (Math.abs(child.extentX2) > 50000)
1421:                            || (Math.abs(child.extentY) > 50000)
1422:                            || (Math.abs(child.extentY2) > 50000)) {
1423:                        return findBadBox(child);
1424:                    } else if ((Math.abs(child.getX()) > 50000)
1425:                            || (Math.abs(child.getY()) > 50000)
1426:                            || (Math.abs(child.width) > 50000)
1427:                            || (Math.abs(child.height) > 50000)
1428:                            || (Math.abs(child.leftMargin) > 50000)
1429:                            || ((Math.abs(child.effectiveTopMargin)) > 50000)) {
1430:                        return findBadBox(child);
1431:                    }
1432:                }
1433:
1434:                return box;
1435:            }
1436:
1437:            protected void paintBackground(Graphics g, int x, int y) {
1438:                if (hidden) {
1439:                    return;
1440:                }
1441:
1442:                paintBox(g, x, y, getWidth(), getHeight());
1443:            }
1444:
1445:            /**
1446:             *  If this box supports internal resizing, return the Cursor to be
1447:             *  shown over the given coordinate
1448:             */
1449:            public int getInternalResizeDirection(int x, int y) {
1450:                return Cursor.DEFAULT_CURSOR;
1451:            }
1452:
1453:            public Interaction getInternalResizer(int x, int y) {
1454:                return null;
1455:            }
1456:
1457:            //    /** Return a DesignBean associated with this box, if any.
1458:            //     * @deprecated Use {@link #getMarkupDesignBean} instead. */
1459:            //    public MarkupDesignBean getDesignBean() {
1460:            //        return bean;
1461:            //    }
1462:
1463:            //    /** XXX This is JSF specific. Move away from here.
1464:            //     * Gets associated markup design bean for the css box. It is associated only
1465:            //     * for the css box represents component top level elements except lines, texts and spaces. */
1466:            //    public static MarkupDesignBean getMarkupDesignBeanForCssBox(CssBox cssBox) {
1467:            ////        if (cssBox == null) {
1468:            ////            return null;
1469:            ////        }
1470:            ////        
1471:            ////        Element element = cssBox.getElement();
1472:            ////        BoxType boxType = cssBox.getBoxType();
1473:            ////        if (element == null
1474:            ////        || boxType == BoxType.LINEBOX
1475:            ////        || boxType == BoxType.TEXT
1476:            ////        || boxType == BoxType.SPACE) {
1477:            ////            // XXX As before no assigned MarkupDesignBean for the above cases.
1478:            ////            return null;
1479:            ////        }
1480:            ////        return getMarkupDesignBeanForComponentRootCssBox(cssBox);
1481:            //        return WebForm.getDomProviderService().getMarkupDesignBeanForElement(
1482:            //                getElementForComponentRootCssBox(cssBox));
1483:            //    }
1484:
1485:            //    private static MarkupDesignBean getMarkupDesignBeanForComponentRootCssBox(CssBox cssBox) {
1486:            //        if (cssBox == null) {
1487:            //            return null;
1488:            //        }
1489:            //        Element element = cssBox.getElement();
1490:            //        ContainerBox parentBox = cssBox.getParent();
1491:            //        Element parentBoxElement = parentBox == null ? null : parentBox.getElement();
1492:            //        return WebForm.getDomProviderService().getMarkupDesignBeanForComponentRootElement(element, parentBoxElement);
1493:            //    }
1494:
1495:            /** XXX #113773 Find component root element for specified box. */
1496:            public static Element getComponentRootElementForCssBox(CssBox cssBox) {
1497:                WebForm webForm = cssBox == null ? null : cssBox.getWebForm();
1498:                if (webForm == null) {
1499:                    return null;
1500:                }
1501:                while (cssBox != null) {
1502:                    Element element = cssBox.getElement();
1503:                    //            if (WebForm.getDomProviderService().isPrincipalElement(element, null)) {
1504:                    if (webForm.getDomProviderService().isPrincipalElement(
1505:                            element, null)) {
1506:                        return element;
1507:                    }
1508:                    cssBox = cssBox.getParent();
1509:                }
1510:
1511:                return null;
1512:            }
1513:
1514:            /** XXX This will replace the JSF specific above methods.
1515:             * Gets associated element for the css box. It returns the element only if the specified box
1516:             * represents component top level element except lines, texts and spaces. */
1517:            public static Element getElementForComponentRootCssBox(CssBox cssBox) {
1518:                if (cssBox == null) {
1519:                    return null;
1520:                }
1521:
1522:                Element element = cssBox.getElement();
1523:                BoxType boxType = cssBox.getBoxType();
1524:                if (element == null || boxType == BoxType.LINEBOX
1525:                        || boxType == BoxType.TEXT || boxType == BoxType.SPACE) {
1526:                    // XXX As before no assigned MarkupDesignBean for the above cases.
1527:                    return null;
1528:                }
1529:                return getElementForPrincipalCssBox(cssBox);
1530:            }
1531:
1532:            private static Element getElementForPrincipalCssBox(CssBox cssBox) {
1533:                if (cssBox == null) {
1534:                    return null;
1535:                }
1536:                WebForm webForm = cssBox.getWebForm();
1537:                if (webForm == null) {
1538:                    return null;
1539:                }
1540:                Element element = cssBox.getElement();
1541:                ContainerBox parentBox = cssBox.getParent();
1542:                Element parentBoxElement = parentBox == null ? null : parentBox
1543:                        .getElement();
1544:                //        return WebForm.getDomProviderService().isPrincipalElement(element, parentBoxElement) ? element : null;
1545:                return webForm.getDomProviderService().isPrincipalElement(
1546:                        element, parentBoxElement) ? element : null;
1547:            }
1548:
1549:            /** Return the deepest box containing the given point. */
1550:            protected CssBox findCssBox(int x, int y, int px, int py, int depth) {
1551:                // TODO - get rid of px/py
1552:                // Reverse order: list is ordered back to front
1553:                for (int i = getBoxCount() - 1; i >= 0; i--) {
1554:                    CssBox box = getBox(i);
1555:
1556:                    // Is the coordinate in an absolute child of this box?
1557:                    boolean absChild = (x >= box.getExtentX())
1558:                            && (x <= box.getExtentX2())
1559:                            && (y >= box.getExtentY())
1560:                            && (y <= box.getExtentY2());
1561:
1562:                    // XXX Check decoration too.
1563:                    boolean absChildDecoration = isInsideBoxDecoration(x, y,
1564:                            box);
1565:
1566:                    //            if (absChild) {
1567:                    if (absChild || absChildDecoration) {
1568:                        CssBox match = box.findCssBox(x, y, px, py, depth + 1);
1569:
1570:                        if (match != null) {
1571:                            // TODO: we may have multiple matches (overlapping);
1572:                            // should select all and compare best match based on
1573:                            // Z-order!  (A flag to the method could indicate if we
1574:                            // needed best match or any-match behavior. For mouse
1575:                            // motion feedback for example, we don't care if we have
1576:                            // the best match, only that we have a match.
1577:                            // TODO - I can for example have a match field in this
1578:                            // method, and if I find -two- matches, I pick the best
1579:                            // fit, then continue.
1580:                            return match;
1581:                        }
1582:                    }
1583:                }
1584:
1585:                // See if this match is okay.
1586:                // This is necesary because we investigate children whose
1587:                // extents include absolutely positioned views
1588:
1589:                /*
1590:                boolean match = x >=getExtentX()
1591:                            && x <= getExtentX2()
1592:                            && y >= getExtentY()
1593:                            && y <= getExtentY2();
1594:                 */
1595:                int ax = getAbsoluteX();
1596:                int ay = getAbsoluteY();
1597:                boolean match = (x >= ax) && (x <= (ax + getWidth()))
1598:                        && (y >= ay) && (y <= (ay + getHeight()));
1599:
1600:                // XXX Check decoration too.
1601:                boolean matchDecoration = isInsideDecoration(x, y, ax, ay);
1602:
1603:                if (match || matchDecoration) {
1604:                    //        if (match) {
1605:                    return this ;
1606:                } else {
1607:                    return null;
1608:                }
1609:            }
1610:
1611:            private/*static*/boolean isInsideBoxDecoration(int x, int y,
1612:                    CssBox box) {
1613:                //        if (!DesignerSettings.getInstance().isShowDecorations()) {
1614:                if (!webform.isShowDecorations()) {
1615:                    return false;
1616:                }
1617:
1618:                Decoration decoration = box.getDecoration();
1619:                if (decoration != null) {
1620:                    return (x >= box.getExtentX2())
1621:                            && (x <= box.getExtentX2() + decoration.getWidth())
1622:                            && (y >= box.getExtentY())
1623:                            && (y <= box.getExtentY() + decoration.getHeight());
1624:                }
1625:
1626:                return false;
1627:            }
1628:
1629:            private boolean isInsideDecoration(int x, int y, int ax, int ay) {
1630:                //        if (!DesignerSettings.getInstance().isShowDecorations()) {
1631:                if (!webform.isShowDecorations()) {
1632:                    return false;
1633:                }
1634:
1635:                Decoration decoration = getDecoration();
1636:                if (decoration != null) {
1637:                    return (x >= ax + getWidth())
1638:                            && (x <= (ax + getWidth() + decoration.getWidth()))
1639:                            && (y >= ay)
1640:                            && (y <= (ay + decoration.getHeight()));
1641:                }
1642:
1643:                return false;
1644:            }
1645:
1646:            /**
1647:             * Return the smallest x coordinate of any children boxes (only for
1648:             * absolutely positioned boxes) in this box hiearchy.
1649:             * @return the absolute x coordinate in pixels
1650:             * @todo Consider returning a relative coordinate here - relative
1651:             *  to the current box' coordinate system that is! See
1652:             *  ContainerBox.updateExtents.
1653:             */
1654:            protected int getExtentX() {
1655:                // Later, I may have a separate extent from x,y,w,h:
1656:                // This incorporates absolute positions in any descendant children,
1657:                // not just directly managed width/height.
1658:                return extentX;
1659:
1660:                // For now, just implement it to return our position
1661:                //return getX();
1662:            }
1663:
1664:            /**
1665:             * Return the largest x coordinate of any children boxes (only for
1666:             * absolutely positioned boxes) in this box hiearchy.
1667:             * @return the x coordinate in pixels
1668:             */
1669:            protected int getExtentX2() {
1670:                // See comment under getExtentX()
1671:                return extentX2;
1672:
1673:                //return getX() + getWidth();
1674:            }
1675:
1676:            /**
1677:             * Return the smallest y coordinate of any children boxes (only for
1678:             * absolutely positioned boxes) in this box hiearchy.
1679:             * @return the y coordinate in pixels
1680:             */
1681:            protected int getExtentY() {
1682:                // See comment under getExtentX()
1683:                return extentY;
1684:
1685:                //return getY();
1686:            }
1687:
1688:            /**
1689:             * Return the largest y coordinate of any children boxes (only for
1690:             * absolutely positioned boxes) in this box hiearchy.
1691:             * @return the y coordinate in pixels
1692:             */
1693:            protected int getExtentY2() {
1694:                // See comment under getExtentX()
1695:                return extentY2;
1696:
1697:                //return getY() + getHeight();
1698:            }
1699:
1700:            /** Update the extents to include the given position */
1701:
1702:            /*
1703:            protected void updateExtents(int x, int y, int x2, int y2) {
1704:                if (x < extentX) {
1705:                    extentX = x;
1706:                }
1707:                if (x2 > extentX2) {
1708:                    extentX2 = x2;
1709:                }
1710:                if (y < extentY) {
1711:                    extentY = y;
1712:                }
1713:                if (y2 > extentY2) {
1714:                    extentY2 = y2;
1715:                }
1716:            }
1717:             */
1718:
1719:            /** Update the extents for this box (which involves the extents
1720:             * of any of its children)
1721:             */
1722:            protected void updateExtents(int px, int py, int depth) {
1723:                /*
1724:                TODO: Currently this code produces ABSOLUTE coordinates for the
1725:                extents. That will make document mutation updates trickier, since
1726:                I will have to update all the boxes to adjust absolute coordinates
1727:                when for example a newline is inserted near the top.
1728:
1729:                Instead, why don't have I coordinates relative to the current box?
1730:                Thus, when looking at the body box, I see coordinates relative to
1731:                0,0 - e.g. absolute coordinates. When I go down to a particular
1732:                child, I see extents relative to that box' x,y coordinate.
1733:                This has the advantage that I can make local modifications,
1734:                and only have to walk up the direct parent chain and adjust extents.
1735:                 */
1736:                if (positionedBy != parent) {
1737:                    px = positionedBy.getAbsoluteX();
1738:                    py = positionedBy.getAbsoluteY();
1739:                }
1740:
1741:                px += getX();
1742:                py += getY();
1743:
1744:                // Box model quirk: my coordinate system is based on the visual
1745:                // extents of the boxes - e.g. location and size of the border
1746:                // edge.  Because of this, when visually traversing the hierarchy,
1747:                // I need to add in the margins.
1748:                px += leftMargin;
1749:                py += effectiveTopMargin;
1750:
1751:                if (DEBUGFORMAT) {
1752:                    // Look for problematic children
1753:                    if ((Math.abs(px) > 50000) || (Math.abs(py) > 50000)
1754:                            || (Math.abs(width) > 50000)
1755:                            || (Math.abs(height) > 50000)) {
1756:                        fine("Size wrong for " + this );
1757:                    }
1758:                }
1759:
1760:                extentX = px;
1761:                extentY = py;
1762:                extentX2 = px + width;
1763:                extentY2 = py + height;
1764:
1765:                // Check children
1766:                for (int i = 0, n = getBoxCount(); i < n; i++) {
1767:                    CssBox child = getBox(i);
1768:                    child.updateExtents(px, py, depth + 1);
1769:
1770:                    if (child.extentX < extentX) {
1771:                        extentX = child.extentX;
1772:                    }
1773:
1774:                    if (child.extentY < extentY) {
1775:                        extentY = child.extentY;
1776:                    }
1777:
1778:                    if (child.extentX2 > extentX2) {
1779:                        extentX2 = child.extentX2;
1780:                    }
1781:
1782:                    if (child.extentY2 > extentY2) {
1783:                        extentY2 = child.extentY2;
1784:                    }
1785:                }
1786:            }
1787:
1788:            /**
1789:             * Return the parent or "container" for this box.
1790:             */
1791:            public final ContainerBox getParent() {
1792:                return parent;
1793:            }
1794:
1795:            /**
1796:             * Return the parent responsible for positioning this box.
1797:             * This is typically the same as the container parent, but
1798:             * in the case of "positioned" elements such as absolutely
1799:             * positioned boxes, it will be some other ancestor.
1800:             * The important aspect of this is that the coordinates
1801:             * will be relative to this positioned-by parent, not
1802:             * the container parent!
1803:             */
1804:            public CssBox getPositionedBy() {
1805:                return positionedBy;
1806:            }
1807:
1808:            final void setParent(ContainerBox parent) {
1809:                this .parent = parent;
1810:            }
1811:
1812:            void setPositionedBy(CssBox positionedBy) {
1813:                this .positionedBy = positionedBy;
1814:            }
1815:
1816:            /**
1817:             * Return the list of boxes "managed" by this box.  Managed simply
1818:             * means that the coordinates in the boxes are all relative to this
1819:             * one.
1820:             */
1821:            public int getBoxCount() {
1822:                return 0;
1823:            }
1824:
1825:            /**
1826:             * Return the box with the given index. There is no particular
1827:             * significance to the index other than identifying a box; in particular
1828:             * boxes with adjacent indices may not be adjacent visually.
1829:             */
1830:            public CssBox getBox(int index) {
1831:                // Should only be called on ContainerBox-es, and these will
1832:                // override this method
1833:                throw new IllegalArgumentException();
1834:            }
1835:
1836:            /**
1837:             * Set the containing block for this box.
1838:             */
1839:            protected void setContainingBlock(int x, int y, int width,
1840:                    int height) {
1841:                containingBlockX = x;
1842:                containingBlockY = y;
1843:                containingBlockWidth = width;
1844:                containingBlockHeight = height;
1845:            }
1846:
1847:            /*
1848:             * Is this a clear box ("clear" CSS property is "left", "right", "both".
1849:             */
1850:            public boolean isClearBox() {
1851:                CssValue cssClear = CssProvider.getEngineService()
1852:                        .getComputedValueForElement(getElement(),
1853:                                XhtmlCss.CLEAR_INDEX);
1854:                return CssProvider.getValueService().isLeftValue(cssClear)
1855:                        || CssProvider.getValueService().isBothValue(cssClear)
1856:                        || CssProvider.getValueService().isRightValue(cssClear);
1857:            }
1858:
1859:            /** Is this box inline-level? If this method returns true, the box
1860:             * is inline level, otherwise it is block level.
1861:             */
1862:            public boolean isInlineBox() {
1863:                return inline;
1864:            }
1865:
1866:            public boolean isBlockLevel() {
1867:                return !inline;
1868:            }
1869:
1870:            /**
1871:             * Is this box replaced?
1872:             */
1873:            public boolean isReplacedBox() {
1874:                return replaced;
1875:            }
1876:
1877:            public HtmlTag getTag() {
1878:                return tag;
1879:            }
1880:
1881:            /** Return the <code>WebForm</code> this box is associated with.
1882:             * @todo get rid of it from CSS box rendering */
1883:            public WebForm getWebForm() {
1884:                return webform;
1885:            }
1886:
1887:            // BOX MODEL stuff
1888:
1889:            /** Return the -preferred- minimum width; this is the smallest
1890:             * width that will avoid breaking up content beyond word boundaries,
1891:             * or clipping images, etc.
1892:             * @todo XXX Figure out if I should include the padding and border
1893:             *  (and margins?) here - or just the content width? Certainly
1894:             *  when it takes children into consideration, it needs to add in
1895:             *  their margins, padding and borders - but what about itself?
1896:             *  Look at the uses of this method and adjust. For example, in
1897:             *  TableBox I add margins in afterwards - that's not good.
1898:             */
1899:            protected int getPrefMinWidth() {
1900:                // contentWidth should be computed already
1901:                int result;
1902:
1903:                if ((contentWidth != AUTO) && (contentWidth != UNINITIALIZED)) {
1904:                    result = contentWidth;
1905:                } else {
1906:                    result = getIntrinsicWidth();
1907:                }
1908:
1909:                result += (leftBorderWidth + leftPadding + rightPadding + rightBorderWidth);
1910:
1911:                if (leftMargin != AUTO) {
1912:                    result += leftMargin;
1913:                }
1914:
1915:                if (rightMargin != AUTO) {
1916:                    result += rightMargin;
1917:                }
1918:
1919:                return result;
1920:            }
1921:
1922:            /**
1923:             * Return the -preferred- width; this is the largest
1924:             * width that the box can occupy.
1925:             */
1926:            protected int getPrefWidth() {
1927:                // contentWidth should be computed already
1928:                int result;
1929:
1930:                if ((contentWidth != AUTO) && (contentWidth != UNINITIALIZED)) {
1931:                    result = contentWidth;
1932:                } else {
1933:                    result = getIntrinsicWidth();
1934:                }
1935:
1936:                // XXX #124104 There are some hacking their border sizes into contentHeight.
1937:                // see FormComponentBox.
1938:                if (!isBorderSizeIncluded()) {
1939:                    result += (leftBorderWidth + leftPadding + rightPadding + rightBorderWidth);
1940:                }
1941:
1942:                if (leftMargin != AUTO) {
1943:                    result += leftMargin;
1944:                }
1945:
1946:                if (rightMargin != AUTO) {
1947:                    result += rightMargin;
1948:                }
1949:
1950:                return result;
1951:            }
1952:
1953:            /**
1954:             * Return the width of the content - the distance between the
1955:             * content edges. This can be set by the "width" CSS2 property.
1956:             * This width, plus the left and right padding, constitutes the
1957:             * width of the containing block established by this box for its
1958:             * descendants.
1959:             */
1960:            protected int getContentWidth() {
1961:                return width - leftPadding - rightPadding;
1962:            }
1963:
1964:            /**
1965:             * Return the height of the content - the distance between the
1966:             * content edges. This can be set by the "height" CSS2 property.
1967:             * This height, plus the top and bottom padding, constitutes the
1968:             * height of the containing block established by this box for its
1969:             * descendants.
1970:             */
1971:            protected int getContentHeight() {
1972:                return height - topPadding - bottomPadding;
1973:            }
1974:
1975:            /**
1976:             * Return the x position of the content box, relative to the parent box
1977:             */
1978:            protected int getContentX() {
1979:                return x + leftMargin + leftBorderWidth + leftPadding;
1980:            }
1981:
1982:            /**
1983:             * Return the y position of the content box, relative to the parent box
1984:             */
1985:            protected int getContentY() {
1986:                return y + topMargin + topBorderWidth + topPadding;
1987:            }
1988:
1989:            /**
1990:             * Return the horizontal position of the box <b>relative</b> to its parent.
1991:             * This points to the -border edge- of the box - not the margin edge,
1992:             * not the padding edge (aka the containing block edge).
1993:             * In other words, the x attribute tells you where visually the box
1994:             * begins, relative to where its parent's border edge is located.
1995:             *
1996:             * @return the border x position of the box
1997:             */
1998:            public int getX() {
1999:                return x;
2000:            }
2001:
2002:            /**
2003:             * Return the vertical position of the box <b>relative</b> to its parent.
2004:             * This points to the -border edge- of the box - not the margin edge,
2005:             * not the padding edge (aka the containing block edge).
2006:             * In other words, the y attribute tells you where visually the box
2007:             * begins, relative to where its parent's border edge is located.
2008:             *
2009:             * @return the border y position of the box
2010:             */
2011:            public int getY() {
2012:                return y;
2013:            }
2014:
2015:            /**
2016:             * Return the z index of the box for the current stacking context.
2017:             * Will be AUTO if not set using the z-index CSS property.
2018:             *
2019:             * @return the z index of the box.
2020:             */
2021:            public int getZ() {
2022:                return z;
2023:            }
2024:
2025:            /**
2026:             *  Return the actual width (in pixels) of the box.
2027:             *  This refers to the distance between the left and right
2028:             *  border edges - in other words the "visual" width of
2029:             *  the box, since it includes padding, borders and content,
2030:             *  and is therefore different than the containing block's
2031:             *  width.
2032:             *  (See CSS2 spec section 8.1).
2033:             *
2034:             *  @return the actual width of the box
2035:             */
2036:            public int getWidth() {
2037:                return width;
2038:            }
2039:
2040:            /**
2041:             *  Return the actual height (in pixels) of the box.
2042:             *  This refers to the distance between the top and bottom
2043:             *  border edges - in other words the "visual" height of
2044:             *  the box, since it includes padding, borders and content,
2045:             *  and is therefore different than the containing block's
2046:             *  height.
2047:             *  (See CSS2 spec section 8.1).
2048:             *
2049:             *  @return the actual width of the box
2050:             */
2051:            public int getHeight() {
2052:                return height;
2053:            }
2054:
2055:            /**
2056:             * Get the intrinsic width of the box. This is only defined for boxes
2057:             * representing replaced elements as well as text boxes
2058:             */
2059:            protected int getIntrinsicWidth() {
2060:                return 0; // XXX override in ImageBox, FormComponentBox, etc.
2061:            }
2062:
2063:            /**
2064:             * Get the intrinsic width of the box. This is only defined for boxes
2065:             * representing replaced elements as well as text boxes
2066:             */
2067:            protected int getIntrinsicHeight() {
2068:                return 0; // XXX override in ImageBox, FormComponentBox, etc.
2069:            }
2070:
2071:            /**
2072:             * Get the left margin of the box.
2073:             * @return The left side margin of the box
2074:             */
2075:            public int getLeftMargin() {
2076:                return leftMargin;
2077:            }
2078:
2079:            /**
2080:             * Get the right margin of the box
2081:             * @return The right side margin of the box
2082:             */
2083:            public int getRightMargin() {
2084:                return rightMargin;
2085:            }
2086:
2087:            /**
2088:             * Get the effective top margin of the box. This is
2089:             * the collapsed margin of this box (e.g. the max of its margin
2090:             * and any first children, modulo some scenarios with negative margins.)
2091:             * @return The top margin of the box
2092:             */
2093:            public int getEffectiveTopMargin() {
2094:                return effectiveTopMargin;
2095:            }
2096:
2097:            /**
2098:             * Get the effective bottom margin of the box. This is
2099:             * the collapsed margin of this box (e.g. the max of its margin
2100:             * and any last children, modulo some scenarios with negative margins.)
2101:             * @return The bottom margin of the box
2102:             */
2103:            protected int getEffectiveBottomMargin() {
2104:                return effectiveBottomMargin;
2105:            }
2106:
2107:            /**
2108:             * Set the left margin and effective top margin.
2109:             * @param leftMargin The new left margin
2110:             * @param effectiveTopMargin The new effective top margin
2111:             */
2112:            public void setMargins(int leftMargin, int effectiveTopMargin) {
2113:                this .leftMargin = leftMargin;
2114:                this .effectiveTopMargin = effectiveTopMargin;
2115:            }
2116:
2117:            /**
2118:             * Return true for boxes where the size of border and padding is included
2119:             * in the width assigned the element.
2120:             * For example, if you have {@code <div style="width: 100px; border: 20px solid gray"></div>}
2121:             * then the actual visual size of the box (not including the invisible margins) is going
2122:             * to be 140 pixels. On the other hand, if you have
2123:             * {@code <table style="width: 100px; border: 20px solid gray">...</table>} then
2124:             * the actual width is 100 pixels. Thus, to distinguish the different kinds of
2125:             * formatting behaviors (I haven't found details in the CSS spec regarding
2126:             * this, but I'm sure it's there) this method lets you query what kind of
2127:             * border/padding computation this box is performing.  For the normal case (div
2128:             * in the above example), this method will return false. For table, and buttons,
2129:             * it will return true.
2130:             * @return True iff this box will subtract the border and padding widths from the
2131:             *  assigned content width and content height to make the component fit in exactly
2132:             *  the allocated size
2133:             * @see getContentInsets
2134:             */
2135:            protected boolean isBorderSizeIncluded() {
2136:                return false;
2137:            }
2138:
2139:            /**
2140:             * <p>
2141:             * Return the insets from the border box to the actual content area of the box.
2142:             * This is normally the border width plus the padding, but for boxes like
2143:             * buttons (which include their own borders, see {@link #isBorderSizeIncluded})
2144:             * and tables (which may include a caption) it will be something different.
2145:             * You can also think of this method as returning the difference in size between
2146:             * the visual size of the box (the border box) and the content box (e.g. the
2147:             * CSS width and height).
2148:             * </p>
2149:             * <p>
2150:             * <b>Note</b>: to be more accurate, this method should return the insets from
2151:             * the outermost box generated for the element for this box, to the area covered
2152:             * by the CSS width and height dimensions.
2153:             * Thus, in the case of a captioned table, where the caption is above the table,
2154:             * the offset will be the size of the caption (and for the table, NOT the border
2155:             * or padding since tables include their borders in the CSS width size.
2156:             * </p>
2157:             *
2158:             * @return The insets from outside the borders of the box to the box covered by
2159:             *   the CSS width and height properties for this element
2160:             */
2161:            public Insets getCssSizeInsets() {
2162:                return new Insets(topBorderWidth + topPadding, leftBorderWidth
2163:                        + leftPadding, bottomBorderWidth + bottomPadding,
2164:                        rightBorderWidth + rightPadding);
2165:            }
2166:
2167:            /**
2168:             * Recompute the layout. Once the layout routine gets to a point
2169:             * where the child layout matches the computed layout, it will leave
2170:             * that tree alone.  Thus, only the portions of the layout below
2171:             * this box that need to be recomputed are updated
2172:             */
2173:            protected void relayout(FormatContext context) {
2174:                // Nothing to do - no children
2175:            }
2176:
2177:            /** Very similar to relayout(context) but does not compute
2178:             * vertical dimensions, and does not position the boxes.
2179:             * Used to initialize box dimensions for computation
2180:             * of minimum widths when we're computing minimum widths
2181:             * for table cells, etc.
2182:             * <p>
2183:             * NOTE: It's very important for CSS computations of values that
2184:             * are percentages to be "cleared" if we "pre-compute" them using
2185:             * getPrefWidth and getPrefMinWidth before a containing block
2186:             * has been computed (as is the case when we're calling getPrefWidth
2187:             * to compute dimensions for table layout), since otherwise the
2188:             * computed width value is cached for later, even when a real containing
2189:             * block is available. If you put a table widht a div inside it, and
2190:             * set the width of the div to 100%, the div will show up with zero
2191:             * width without this caveat since otherwise during the outer table
2192:             * layout, we're calling initializeHorizontalWidths and getPrefMinWidth
2193:             * on the div, with a 0 containing block, so the computed value for
2194:             * the div is 0*100%=0, and when we subsequently lay out the table,
2195:             * even though the containing block may now be 600px the CSS lookup
2196:             * for the width attribute will return the previously computed 0-value
2197:             * rather than 600.
2198:             */
2199:            protected void initializeHorizontalWidths(FormatContext context) {
2200:                if (element == null) {
2201:                    fine("Unexpected null element in initialize horizontal widths");
2202:
2203:                    return; // why does this happen?
2204:                }
2205:
2206:                //        // No containing block for children - 100% etc. should
2207:                //        // evaluate to 0.
2208:                //        containingBlockX = 0;
2209:                //        containingBlockY = 0;
2210:                //        containingBlockWidth = 0;
2211:                //        containingBlockHeight = 0;
2212:                // XXX #6504407 Incorrectly rendered table component when dealt with percentage width values.
2213:                // see also http://www.w3.org/TR/CSS21/tables.html#auto-table-layout
2214:                initializeContainingBlock();
2215:
2216:                initialize();
2217:
2218:                /* OLD: this gets us into trouble! For example, when called on
2219:                   an absolutely positioned div to initialize its children, it
2220:                   will call shrinkToFit, which winds up calling
2221:                   initializeHorizontalWidths, which again calls shrinkToFit ->
2222:                   stack overflow.
2223:                computeHorizontalLengths(context);
2224:                if (contentWidth != AUTO) {
2225:                    width = leftBorderWidth + leftPadding
2226:                        + contentWidth + rightPadding
2227:                        + rightBorderWidth;
2228:                } else {
2229:                    width = UNINITIALIZED;
2230:                }
2231:                 */
2232:
2233:                // All we really care about is having margins, padding
2234:                // and content width initialized... as a bonus, this
2235:                // is cheaper than computeHorizontalLengths() too!
2236:                // Set parent width to 0 to force percentages to evaluate to 0
2237:                //        Value val = CssLookup.getValue(element, XhtmlCss.WIDTH_INDEX);
2238:                //        CssValue cssValue = CssProvider.getEngineService().getComputedValueForElement(element, XhtmlCss.WIDTH_INDEX);
2239:                CssValue cssValue = computeWidthCssValue();
2240:
2241:                //boolean uncompute = false;
2242:                //        if (val == CssValueConstants.AUTO_VALUE) {
2243:                if (cssValue == null // XXX #6460007 Possible NPE.
2244:                        || CssProvider.getValueService().isAutoValue(cssValue)) {
2245:                    if (replaced) {
2246:                        contentWidth = getIntrinsicWidth();
2247:                    } else {
2248:                        contentWidth = 0;
2249:                        //uncompute = true;
2250:                    }
2251:                } else {
2252:                    //            contentWidth = (int)val.getFloatValue();
2253:                    contentWidth = (int) cssValue.getFloatValue();
2254:                    //uncompute = cssValue instanceof CssComputedValue &&
2255:                    //    CssProvider.getValueService().
2256:                    //    isOfPrimitivePercentageType(((CssComputedValue)cssValue).getCascadedValue());
2257:                }
2258:
2259:                //if (uncompute) {
2260:                // We have now initialized the width value for the element,
2261:                // possibly using wrong containing block widths (they
2262:                // are often not set when doing a width prescan via
2263:                // getPrefMinWidth etc.)   The problem is that when we're
2264:                // doing a "real" layout the old computed value is cached.
2265:                // So we want to "recompute" this value.
2266:                if (cssValue instanceof  CssComputedValue) {
2267:                    uncomputeWidthCssValue();
2268:                }
2269:                //}
2270:            }
2271:
2272:            private void initializeContainingBlock() {
2273:                // No containing block for children - 100% etc. should
2274:                // evaluate to 0.
2275:
2276:                // XXX That seems to be incorrect, see #6504407.
2277:                //        containingBlockX = 0;
2278:                //        containingBlockY = 0;
2279:                //        containingBlockWidth = 0;
2280:                //        containingBlockHeight = 0;
2281:                // XXX Overriding the default behavior, initing to 0.
2282:                containingBlockX = 0;
2283:                containingBlockY = 0;
2284:
2285:                int containerWidth = getParentContainerLength(this ,
2286:                        XhtmlCss.WIDTH_INDEX);
2287:                int containerHeight = getParentContainerLength(this ,
2288:                        XhtmlCss.HEIGHT_INDEX);
2289:
2290:                int componentWidth = getIntrinsicWidth();
2291:                int componentHeight = getIntrinsicHeight();
2292:                containingBlockWidth = componentWidth > containerWidth ? containerWidth
2293:                        : componentWidth;
2294:                containingBlockHeight = componentHeight > containerHeight ? containerHeight
2295:                        : componentHeight;
2296:            }
2297:
2298:            private static int getParentContainerLength(CssBox cssBox,
2299:                    int propIndex) {
2300:                ContainerBox parent = cssBox.getParent();
2301:                while (parent != null) {
2302:                    Element element = parent.getElement();
2303:                    if (element != null) {
2304:                        //                int length = CssUtilities.getCssLength(element, propIndex);
2305:                        //                if (length != AUTO) {
2306:                        //                    return length;
2307:                        //                }
2308:                        CssValue cssValue = parent.computeWidthCssValue();
2309:                        if (!CssProvider.getValueService()
2310:                                .isAutoValue(cssValue)) {
2311:                            int length;
2312:                            if (cssValue == null) {
2313:                                // XXX #6460007 Possible NPE.
2314:                                length = 0;
2315:                            } else {
2316:                                length = (int) cssValue.getFloatValue();
2317:                            }
2318:
2319:                            // XXX #108602 The percentages might still not be inited correctly.
2320:                            if (cssValue instanceof  CssComputedValue) {
2321:                                parent.uncomputeWidthCssValue();
2322:                            }
2323:                            return length;
2324:                        }
2325:                    }
2326:                    parent = parent.getParent();
2327:                }
2328:                return 0;
2329:            }
2330:
2331:            // XXX See overriding in JspIncludeBox.
2332:            protected CssValue computeWidthCssValue() {
2333:                return CssProvider.getEngineService()
2334:                        .getComputedValueForElement(element,
2335:                                XhtmlCss.WIDTH_INDEX);
2336:            }
2337:
2338:            // XXX See overriding in JspIncludeBox.
2339:            protected void uncomputeWidthCssValue() {
2340:                CssProvider.getEngineService().uncomputeValueForElement(
2341:                        element, XhtmlCss.WIDTH_INDEX);
2342:            }
2343:
2344:            /** Set the index of this box in the parent's box list */
2345:            void setParentIndex(int idx) {
2346:                parentIndex = idx;
2347:            }
2348:
2349:            /** Get the index of this box in the parent's box list */
2350:            protected int getParentIndex() {
2351:                return parentIndex;
2352:            }
2353:
2354:            // CSS Formatting related routines
2355:
2356:            /**
2357:             * Compute widths and margins, as discussed in section
2358:             * 10.3 of the CSS2 spec:
2359:             * http://www.w3.org/TR/CSS21/visudet.html#Computing_widths_and_margins
2360:             * <p>
2361:             * NOTE: This may have the side effect of setting
2362:             * contentHEIGHT for replaced elements. This is because
2363:             * the spec calls for special treatment of width and height
2364:             * for replaced elements, in order to preserve the aspect ratio
2365:             * of the intrinsic size of the replaced elements. If we first
2366:             * solve the content width without looking at the height, we end
2367:             * up having to compute the aspect ratio in the vertical computation
2368:             * method since it will no longer be the case that both width and
2369:             * height are auto (which initially tells us that we should use
2370:             * the intrinsic size for both).
2371:             * <p>
2372:             * <b>Note</b>: While this method computes horizontal dimensions,
2373:             * it also initializes box.contentHeight from its css property!
2374:             * It may not compute the value (and will happily leave it AUTO)
2375:             * but it is properly initialized for use by computeVerticalLengths.
2376:             * <p>
2377:             * <b>Note</b>: I changed the implementation of 10.3.8 since the
2378:             * rules seemed a bit incorrect; see details in the relevant method.
2379:             *
2380:             * @param parentWidth the width of the containing block established
2381:             *   by the parent.
2382:             * @todo I don't think I'm computing it right for absolute boxes
2383:             *   positioned via right/bottom. I end up setting left=staticLeft
2384:             *   even when I have everything else computed - then I end up discovering
2385:             *   I'm overconstrained, and I throw away the right value (the one that's
2386:             *   set correctly!) instead of left, which is the one I "invented" using
2387:             *   getStaticLeft.  Ditto for vertical computations. Look back at the
2388:             *   rules and fix this.
2389:             */
2390:            void computeHorizontalLengths(FormatContext context) {
2391:                int parentWidth = containingBlockWidth;
2392:
2393:                assert boxType != BoxType.LINEBOX : this ;
2394:
2395:                // Initialize width
2396:                Element element = getElement();
2397:
2398:                if (element != null) {
2399:                    // This will initialize the height too.
2400:                    // We have to initialize this early, since in case of replaced elements,
2401:                    // we want to maintain the aspect ratio if only one of content width
2402:                    // and height are set to auto. The only way we can check that is if we
2403:                    // initialize both now.
2404:                    initializeContentSize();
2405:
2406:                    // Initialize left/right - only defined for positioned elements
2407:                    if (boxType.isPositioned()) {
2408:                        //                left = CssLookup.getLength(element, XhtmlCss.LEFT_INDEX);
2409:                        //                right = CssLookup.getLength(element, XhtmlCss.RIGHT_INDEX);
2410:                        left = CssUtilities.getCssLength(element,
2411:                                XhtmlCss.LEFT_INDEX);
2412:                        right = CssUtilities.getCssLength(element,
2413:                                XhtmlCss.RIGHT_INDEX);
2414:                    }
2415:
2416:                    if (isBorderSizeIncluded()) {
2417:                        // These boxes (like <input>, <select>, etc.) behave in the standard
2418:                        // box model way, but widths and heights specified for them refer to the
2419:                        // border box, not the content box, so adjust the specified width to the
2420:                        // standard notation before computing.  NOTE: I have not found where in the
2421:                        // spec this is described, this is only observed empirically -- browsers
2422:                        // treat these tags differently. Please insert spec reference here if
2423:                        // anyone knows where this is spec'ed.
2424:                        if (contentWidth != AUTO) {
2425:                            contentWidth -= (leftBorderWidth + leftPadding
2426:                                    + rightPadding + rightBorderWidth);
2427:                        }
2428:
2429:                        if (contentHeight != AUTO) {
2430:                            contentHeight -= (topBorderWidth + topPadding
2431:                                    + bottomPadding + bottomBorderWidth);
2432:                        }
2433:                    }
2434:                } else {
2435:                    contentWidth = AUTO;
2436:                    contentHeight = AUTO;
2437:
2438:                    // XXX what about the others?
2439:                }
2440:
2441:                if (boxType == BoxType.FLOAT) {
2442:                    computeHorizontalFloat(context, parentWidth);
2443:                } else if (!replaced && boxType.isAbsolutelyPositioned()) {
2444:                    computeHorizontalNonReplacedAbsPos(context, parentWidth);
2445:                } else if (replaced && boxType.isAbsolutelyPositioned()) {
2446:                    computeHorizontalReplacedAbsPos(context, parentWidth);
2447:                } else if (inline) {
2448:                    computeHorizInlineNormal();
2449:                } else if (!inline && boxType.isNormalFlow()) {
2450:                    computeHorizNonInlineNormalFlow(context, parentWidth);
2451:                } else {
2452:                    // how did we get here?
2453:                    assert false : this  + ";" + boxType + ";" + inline + ";"
2454:                            + replaced;
2455:                }
2456:
2457:                if (boxType == BoxType.RELATIVE) {
2458:                    // Same as normal above, but normal flow computations don't
2459:                    // consider the left and right values so fix them up here
2460:                    // as described in section 9.4.3 of the CSS2.1 spec
2461:                    if ((left == AUTO) && (right == AUTO)) {
2462:                        left = 0;
2463:                        right = 0;
2464:                    } else if (left == AUTO) {
2465:                        left = -right;
2466:                    } else if (right == AUTO) {
2467:                        right = -left;
2468:                    } else { // overconstrained
2469:                        right = -left; // LTR assumption
2470:                    }
2471:                }
2472:            }
2473:
2474:            private void computeHorizontalFloat(FormatContext context,
2475:                    int parentWidth) {
2476:                // Left and right don't apply, do they?
2477:                if (left == AUTO) {
2478:                    left = 0;
2479:                }
2480:
2481:                if (right == AUTO) {
2482:                    right = 0;
2483:                }
2484:
2485:                if (leftMargin == AUTO) {
2486:                    leftMargin = 0;
2487:                }
2488:
2489:                if (rightMargin == AUTO) {
2490:                    rightMargin = 0;
2491:                }
2492:
2493:                if (replaced) {
2494:                    // 10.3.6: floating replaced elements
2495:                    updateAutoContentSize();
2496:                } else {
2497:                    // 10.3.5: floating non-replaced elements
2498:                    if (contentWidth == AUTO) {
2499:                        // This was revised in CSS2.1: Should use shrink to fit.
2500:                        int availableWidth = parentWidth - leftMargin - left
2501:                                - leftBorderWidth - leftPadding - rightPadding
2502:                                - rightBorderWidth - rightMargin - right;
2503:                        contentWidth = shrinkToFit(availableWidth, context);
2504:                    }
2505:                }
2506:            }
2507:
2508:            private void computeHorizontalNonReplacedAbsPos(
2509:                    FormatContext context, int parentWidth) {
2510:                // Section 10.3.7: Absolutely positioned, non-replaced elements
2511:                // For BoxType.FIXED, the containing block is the
2512:                // initial containing block instead of the viewport
2513:                // (for the purpose of computing widths, margins, etc.)
2514:                if (boxType == BoxType.FIXED) {
2515:                    parentWidth = getInitialWidth(context);
2516:                }
2517:
2518:                if ((left == AUTO) && (right == AUTO) && (contentWidth == AUTO)) {
2519:                    if (leftMargin == AUTO) {
2520:                        leftMargin = 0;
2521:                    }
2522:
2523:                    if (rightMargin == AUTO) {
2524:                        rightMargin = 0;
2525:                    }
2526:
2527:                    left = getStaticLeft(context);
2528:
2529:                    // Apply CSS21 section 10.3.7's rule 3:
2530:                    int availableWidth = parentWidth - leftMargin
2531:                            - 0 //right=0
2532:                            - leftBorderWidth - leftPadding - rightPadding
2533:                            - rightBorderWidth - rightMargin - left;
2534:                    contentWidth = shrinkToFit(availableWidth, context);
2535:                    right = parentWidth - left - leftMargin - leftBorderWidth
2536:                            - leftPadding - contentWidth - rightPadding
2537:                            - rightBorderWidth - rightMargin;
2538:                } else if ((left != AUTO) && (right != AUTO)
2539:                        && (contentWidth != AUTO)) {
2540:                    if ((leftMargin == AUTO) && (rightMargin == AUTO)) {
2541:                        int leftOver = parentWidth - left - leftBorderWidth
2542:                                - leftPadding - contentWidth - rightPadding
2543:                                - rightBorderWidth;
2544:                        int margin = leftOver / 2;
2545:                        int remainder = leftOver % 2;
2546:                        leftMargin = margin;
2547:                        rightMargin = margin + remainder;
2548:                    } else if ((leftMargin != AUTO) && (rightMargin == AUTO)) {
2549:                        rightMargin = parentWidth - left - leftMargin
2550:                                - leftBorderWidth - leftPadding - contentWidth
2551:                                - rightPadding - rightBorderWidth - right;
2552:                    } else if ((leftMargin == AUTO) && (rightMargin != AUTO)) {
2553:                        leftMargin = parentWidth - left - leftBorderWidth
2554:                                - leftPadding - contentWidth - rightPadding
2555:                                - rightBorderWidth - rightMargin - right;
2556:                    } else { // Overconstrained
2557:
2558:                        // Ignore value for right and solve for that value
2559:                        right = parentWidth - left - leftMargin
2560:                                - leftBorderWidth - leftPadding - contentWidth
2561:                                - rightPadding - rightBorderWidth - rightMargin;
2562:                    }
2563:                } else {
2564:                    if (leftMargin == AUTO) {
2565:                        leftMargin = 0;
2566:                    }
2567:
2568:                    if (rightMargin == AUTO) {
2569:                        rightMargin = 0;
2570:                    }
2571:
2572:                    // Perform one of rules 1-6 in section 10.3.7
2573:                    if ((left == AUTO) && (contentWidth == AUTO) && // (1)
2574:                            (right != AUTO)) {
2575:                        // calculate the available width: this is found by
2576:                        // solving for 'width' after setting 'left' (in
2577:                        // case 1) or 'right' (in case 3) to 0.
2578:                        int availableWidth = parentWidth - leftMargin
2579:                                - 0 //left=0
2580:                                - leftBorderWidth - leftPadding - rightPadding
2581:                                - rightBorderWidth - rightMargin - right;
2582:                        contentWidth = shrinkToFit(availableWidth, context);
2583:                        left = parentWidth - leftMargin - leftBorderWidth
2584:                                - leftPadding - contentWidth - rightPadding
2585:                                - rightBorderWidth - rightMargin - right;
2586:                    } else if ((left == AUTO) && (right == AUTO)
2587:                            && (contentWidth != AUTO)) { // (2)
2588:
2589:                        // Since we're ltr
2590:                        left = getStaticLeft(context);
2591:                        right = parentWidth - left - leftMargin
2592:                                - leftBorderWidth - leftPadding - contentWidth
2593:                                - rightPadding - rightBorderWidth - rightMargin;
2594:                    } else if ((contentWidth == AUTO) && (right == AUTO)
2595:                            && (left != AUTO)) { // (3)
2596:
2597:                        // calculate the available width: this is found by
2598:                        // solving for 'width' after setting 'left' (in
2599:                        // case 1) or 'right' (in case 3) to 0.
2600:                        int availableWidth = parentWidth - leftMargin
2601:                                - 0 //right=0
2602:                                - leftBorderWidth - leftPadding - rightPadding
2603:                                - rightBorderWidth - rightMargin - left;
2604:                        contentWidth = shrinkToFit(availableWidth, context);
2605:                        right = parentWidth - left - leftMargin
2606:                                - leftBorderWidth - leftPadding - contentWidth
2607:                                - rightPadding - rightBorderWidth - rightMargin;
2608:                    } else if ((left == AUTO) && (contentWidth != AUTO)
2609:                            && (right != AUTO)) { // (4)
2610:                        left = parentWidth - leftMargin - leftBorderWidth
2611:                                - leftPadding - contentWidth - rightPadding
2612:                                - rightBorderWidth - rightMargin - right;
2613:                    } else if ((left != AUTO) && (contentWidth == AUTO)
2614:                            && (right != AUTO)) { // (5)
2615:                        contentWidth = parentWidth - left - leftMargin
2616:                                - leftBorderWidth - leftPadding - rightPadding
2617:                                - rightBorderWidth - rightMargin - right;
2618:                    } else if ( // This is a common case - move it up
2619:                    (left != AUTO) && (contentWidth != AUTO) && (right == AUTO)) { // (6)
2620:                        right = parentWidth - left - leftMargin
2621:                                - leftBorderWidth - leftPadding - contentWidth
2622:                                - rightPadding - rightBorderWidth - rightMargin;
2623:                    }
2624:                }
2625:
2626:                // Check that we made it:
2627:                assert (left + leftMargin + leftBorderWidth + leftPadding
2628:                        + contentWidth + rightPadding + rightBorderWidth
2629:                        + rightMargin + right) == parentWidth;
2630:            }
2631:
2632:            private void computeHorizontalReplacedAbsPos(FormatContext context,
2633:                    int parentWidth) {
2634:                // Section 10.3.8: Absolutely positioned, replaced elements
2635:                // For BoxType.FIXED, the containing block is the
2636:                // initial containing block instead of the viewport
2637:                // (for the purpose of computing widths, margins, etc.)
2638:                if (boxType == BoxType.FIXED) {
2639:                    parentWidth = getInitialWidth(context);
2640:                }
2641:
2642:                updateAutoContentSize();
2643:
2644:                if (leftMargin == AUTO) {
2645:                    leftMargin = 0;
2646:                }
2647:
2648:                if (rightMargin == AUTO) {
2649:                    rightMargin = 0;
2650:                }
2651:
2652:                // XXX The following is not in the rule substitution list
2653:                // for 10.3.8 in CSS21, but probably what was intended
2654:                if ((left != AUTO) && (right == AUTO)) {
2655:                    right = parentWidth - left - leftMargin - leftBorderWidth
2656:                            - leftPadding - contentWidth - rightPadding
2657:                            - rightBorderWidth - rightMargin;
2658:                } else if ((left == AUTO) && (right != AUTO)) {
2659:                    left = parentWidth - right - leftMargin - leftBorderWidth
2660:                            - leftPadding - contentWidth - rightPadding
2661:                            - rightBorderWidth - rightMargin;
2662:                } else
2663:                // .... now back to your regular programming, courtesy
2664:                // of channel 10.3.8 on the CSS21 network
2665:                if (left == AUTO) { // (2)
2666:                    left = getStaticLeft(context); // ltr
2667:                }
2668:
2669:                // skipping 10.3.8's step 3 since we're not in ltr
2670:                if (right == AUTO) { // (4)
2671:
2672:                    if (leftMargin == AUTO) {
2673:                        leftMargin = 0;
2674:                    }
2675:
2676:                    if (rightMargin == AUTO) {
2677:                        rightMargin = 0;
2678:                    }
2679:                }
2680:
2681:                if ((leftMargin == AUTO) && (rightMargin == AUTO)) { // (5)
2682:
2683:                    int leftOver = parentWidth - left - leftBorderWidth
2684:                            - leftPadding - contentWidth - rightPadding
2685:                            - rightBorderWidth - right;
2686:                    int margin = leftOver / 2;
2687:                    int remainder = leftOver % 2;
2688:                    leftMargin = margin;
2689:                    rightMargin = margin + remainder;
2690:                }
2691:
2692:                int numAuto = 0;
2693:
2694:                if (contentWidth == AUTO) {
2695:                    numAuto++;
2696:                }
2697:
2698:                if (leftMargin == AUTO) {
2699:                    numAuto++;
2700:                }
2701:
2702:                if (rightMargin == AUTO) {
2703:                    numAuto++;
2704:                }
2705:
2706:                if (right == AUTO) {
2707:                    numAuto++;
2708:                }
2709:
2710:                // left can't be auto (in ltr) since we've applied
2711:                // rule 2
2712:                if (numAuto == 1) { // (6)
2713:
2714:                    int total = parentWidth - left - leftBorderWidth
2715:                            - rightBorderWidth - leftPadding - rightPadding;
2716:                    Equation equation = new Equation(total, new int[] {
2717:                            leftMargin, rightMargin, contentWidth, right });
2718:                    equation.solve();
2719:
2720:                    switch (equation.index) {
2721:                    case 0:
2722:                        leftMargin = equation.value;
2723:
2724:                        break;
2725:
2726:                    case 1:
2727:                        rightMargin = equation.value;
2728:
2729:                        break;
2730:
2731:                    case 2:
2732:                        contentWidth = equation.value;
2733:
2734:                        break;
2735:
2736:                    case 3:
2737:                        right = equation.value;
2738:
2739:                        break;
2740:                    }
2741:                } else { // (7)
2742:                    assert numAuto == 0;
2743:
2744:                    // Overconstrained. Since we're in a ltr context, ignore
2745:                    // the right and recompute it to make the equality
2746:                    // true.
2747:                    right = parentWidth - left - leftMargin - leftBorderWidth
2748:                            - leftPadding - contentWidth - rightPadding
2749:                            - rightBorderWidth - rightMargin;
2750:                }
2751:
2752:                // Check that we made it:
2753:                assert (left + leftMargin + leftBorderWidth + leftPadding
2754:                        + contentWidth + rightPadding + rightBorderWidth
2755:                        + rightMargin + right) == parentWidth;
2756:            }
2757:
2758:            private void computeHorizInlineNormal() {
2759:                // Section 10.3.1, 10.3.2, 10.6.1, 10.6.2:
2760:                // inline replaced or non-replaced elements
2761:                if (replaced) {
2762:                    // 10.3.2, 10.6.2
2763:                    updateAutoContentSize();
2764:                }
2765:
2766:                //        else {
2767:                //            // "width" and "height" does not apply.
2768:                //            // The width is given by the text width; section 10.6.1
2769:                //            // says that the height of the box is given by the
2770:                //            // line-height property, but that seems wrong - how can
2771:                //            // it then be vertically aligned if all the boxes are
2772:                //            // the line-height?
2773:                //        }
2774:                //do not set left, right, top and bottom for relative boxes
2775:                if (getBoxType() != BoxType.RELATIVE) {
2776:                    if (left == AUTO) {
2777:                        left = 0;
2778:                    }
2779:
2780:                    if (right == AUTO) {
2781:                        right = 0;
2782:                    }
2783:
2784:                    if (top == AUTO) {
2785:                        top = 0;
2786:                    }
2787:
2788:                    if (bottom == AUTO) {
2789:                        bottom = 0;
2790:                    }
2791:                }
2792:                if (leftMargin == AUTO) {
2793:                    leftMargin = 0;
2794:                }
2795:
2796:                if (rightMargin == AUTO) {
2797:                    rightMargin = 0;
2798:                }
2799:
2800:                if (topMargin == AUTO) {
2801:                    topMargin = 0;
2802:                }
2803:
2804:                if (bottomMargin == AUTO) {
2805:                    bottomMargin = 0;
2806:                }
2807:            }
2808:
2809:            protected void computeHorizNonInlineNormalFlow(
2810:                    FormatContext context, int parentWidth) {
2811:                // Section 10.3.3: block-level, non-replaced elements, normal flow
2812:                // Section 10.3.4: block-level, replaced elements in normal flow
2813:                if (left == AUTO) {
2814:                    left = 0;
2815:                }
2816:
2817:                if (right == AUTO) {
2818:                    right = 0;
2819:                }
2820:
2821:                if (replaced && (contentWidth == AUTO)) {
2822:                    updateAutoContentSize();
2823:                }
2824:
2825:                // Count the number of "auto"'s we're dealing with
2826:                int numAuto = 0;
2827:
2828:                if (contentWidth == AUTO) {
2829:                    numAuto++;
2830:                }
2831:
2832:                if (leftMargin == AUTO) {
2833:                    numAuto++;
2834:                }
2835:
2836:                if (rightMargin == AUTO) {
2837:                    numAuto++;
2838:                }
2839:
2840:                // This equation must be true:
2841:                // leftMargin+leftWidth+leftPadding+width+rightPadding+rightWidth+rightMargin = parentWidth
2842:                if (numAuto == 0) {
2843:                    // Overconstrained. Since we're in a ltr context, ignore
2844:                    // the rightMargin and recompute it to make the equality
2845:                    // true.
2846:                    rightMargin = parentWidth - contentWidth - leftMargin
2847:                            - leftBorderWidth - leftPadding - rightPadding
2848:                            - rightBorderWidth;
2849:                } else if (numAuto == 1) {
2850:                    // "easy" - just solve this equation for the AUTO parameter:
2851:                    // leftMargin+leftWidth+leftPadding+width+rightPadding+rightWidth+rightMargin=parentWidth
2852:                    int total = parentWidth - leftBorderWidth
2853:                            - rightBorderWidth - leftPadding - rightPadding;
2854:                    Equation equation = new Equation(total, new int[] {
2855:                            leftMargin, rightMargin, contentWidth });
2856:                    equation.solve();
2857:
2858:                    switch (equation.index) {
2859:                    case 0:
2860:                        leftMargin = equation.value;
2861:
2862:                        break;
2863:
2864:                    case 1:
2865:                        rightMargin = equation.value;
2866:
2867:                        break;
2868:
2869:                    case 2:
2870:                        contentWidth = equation.value;
2871:
2872:                        break;
2873:                    }
2874:
2875:                    // XXX I could automate these kinds of computations
2876:                    // if instead of having leftPadding, rightPadding etc.
2877:                    // be direct fields in the CssBox class; they could
2878:                    // instead be fields in an array, e.g.
2879:                    // span[LEFTMARGIN], span[RIGHTMARGIN], span[WIDTH], etc.
2880:                    // Food for thought.
2881:                } else if ((numAuto == 2) && (leftMargin == AUTO)
2882:                        && (rightMargin == AUTO)) {
2883:                    // Same case as above - except here the spec calls for
2884:                    // computing equal values for left and right margins -
2885:                    // thus the equation becomes
2886:                    // 2*margin+leftWidth+leftPadding+width+rightPadding+rightWidth=parentWidth
2887:                    int leftOver = parentWidth - contentWidth - leftBorderWidth
2888:                            - leftPadding - rightPadding - rightBorderWidth;
2889:
2890:                    // XXX #113437 If the viewport is smaller, we can't push the box to the left.
2891:                    if (leftOver < 0) {
2892:                        if (context.initialWidth < (contentWidth
2893:                                - leftBorderWidth - leftPadding - rightPadding - rightBorderWidth)) {
2894:                            leftOver = 0;
2895:                        }
2896:                    }
2897:
2898:                    int margin = leftOver / 2;
2899:                    int remainder = leftOver % 2;
2900:                    leftMargin = margin;
2901:                    rightMargin = margin + remainder;
2902:                } else if (contentWidth == AUTO) {
2903:                    // Set all the other auto values to zero and compute the
2904:                    // width from the equality
2905:                    if (leftMargin == AUTO) {
2906:                        leftMargin = 0;
2907:                    }
2908:
2909:                    if (rightMargin == AUTO) {
2910:                        rightMargin = 0;
2911:                    }
2912:
2913:                    if (leftPadding == AUTO) {
2914:                        leftPadding = 0;
2915:                    }
2916:
2917:                    if (rightPadding == AUTO) {
2918:                        rightPadding = 0;
2919:                    }
2920:
2921:                    if (leftBorderWidth == AUTO) {
2922:                        leftBorderWidth = 0;
2923:                    }
2924:
2925:                    if (rightBorderWidth == AUTO) {
2926:                        rightBorderWidth = 0;
2927:                    }
2928:
2929:                    contentWidth = parentWidth - leftMargin - leftBorderWidth
2930:                            - leftPadding - rightPadding - rightBorderWidth
2931:                            - rightMargin;
2932:                } else {
2933:                    // "underconstrained". We have auto for too many parameters.
2934:                    // The spec does not address this (at least not in
2935:                    // the relevant section, 10.3.)
2936:                    // XXX NO - I just realized padding can't be AUTO!
2937:                    // (Not an option).  So it shouldn't be a
2938:                    // problem. Simplify this by presubtracting the total
2939:                    // and don't include padding in the parameters.
2940:                    // For now, just set them all to 0
2941:                    if (leftMargin == AUTO) {
2942:                        leftMargin = 0;
2943:                    }
2944:
2945:                    if (rightMargin == AUTO) {
2946:                        rightMargin = 0;
2947:                    }
2948:
2949:                    if (leftPadding == AUTO) {
2950:                        leftPadding = 0;
2951:                    }
2952:
2953:                    if (rightPadding == AUTO) {
2954:                        rightPadding = 0;
2955:                    }
2956:
2957:                    if (leftBorderWidth == AUTO) {
2958:                        leftBorderWidth = 0;
2959:                    }
2960:
2961:                    if (rightBorderWidth == AUTO) {
2962:                        rightBorderWidth = 0;
2963:                    }
2964:                }
2965:
2966:                // XXX #113437 This assertion is now incorrect.
2967:                //        // Check that we made it:
2968:                //        assert (leftMargin + leftBorderWidth + leftPadding + contentWidth + rightPadding +
2969:                //        rightBorderWidth + rightMargin) == parentWidth;
2970:            }
2971:
2972:            /** Compute the horizontal "static position" of an element.
2973:             * This is defined in section 10.3.7 of the CSS2.1 spec:
2974:             * <blockquote>
2975:             *  The static position for 'left' is the distance from the left
2976:             *  edge of the containing block to the left margin edge of a
2977:             *  hypothetical box that would have been the first box of the
2978:             *  element if its 'position' property had been 'static'. The
2979:             *  value is negative if the hypothetical box is to the left of
2980:             *  the containing block
2981:             * </blockquote>
2982:             */
2983:            private int getStaticLeft(FormatContext context) {
2984:                /*
2985:                Log.err.log("getStaticLeft computation is bustabazoink -- linebox is bogus in FormatContext");
2986:                CssBox block = getBlockBox();
2987:                return block.getX(); // XXXX This is probably still bogus!
2988:                 */
2989:
2990:                // XXX this isn't right!
2991:                // TODO getStaticLeft computation is bustabazoink -- linebox is bogus in FormatContext
2992:                if (isInlineBox() && (context.lineBox != null)
2993:                        && context.lineBox.canFit(this )) {
2994:                    // XXX what if we have an inline box but it should be right
2995:                    // shifted due to floats???
2996:                    return context.lineBox.getNextX();
2997:                } else {
2998:                    // Block boxes are placed exactly at the containing block
2999:                    // boundary so there's no distance
3000:                    return 0;
3001:                }
3002:            }
3003:
3004:            /** Compute position of the current linebox - even if one hasn't
3005:             * been started yet.
3006:             */
3007:            private int getLineBoxY(FormatContext context) {
3008:                int py;
3009:
3010:                if (context.lineBox != null) {
3011:                    py = context.lineBox.getY();
3012:                } else {
3013:                    // Compute location where the line box should appear.
3014:                    CssBox prevBox = getPrevNormalBox();
3015:
3016:                    if (prevBox != null) {
3017:                        // Attach below bottom of previous block box
3018:                        int margin = prevBox.effectiveBottomMargin;
3019:                        py = prevBox.getY() + prevBox.getHeight() + margin;
3020:                    } else {
3021:                        // Attach at the top of the box
3022:                        //CssBox block = getBlockBox();
3023:                        // The above doesn't work because it aborts at inline parents
3024:                        // that are absolutely positioned; I don't want that here I think
3025:                        CssBox blockBox = this ;
3026:
3027:                        while (blockBox.inline /* && !blockBox.boxType.isAbsolutelyPositioned()*/) {
3028:                            blockBox = blockBox.parent;
3029:                        }
3030:
3031:                        py = blockBox.topPadding + blockBox.topBorderWidth;
3032:                    }
3033:                }
3034:
3035:                return py;
3036:            }
3037:
3038:            //    /** If this is a block-level box, return self, otherwise
3039:            //     * return the nearest block-level ancestor box.
3040:            //     * Note that absolutely positioned inline boxes are considered
3041:            //     * block boxes, and so are replaced inline boxes (e.g. iframe, stringbox).
3042:            //     */
3043:            //    protected ContainerBox getBlockBox() {
3044:            //        // XXX what about floats?
3045:            //        if (!inline || boxType.isAbsolutelyPositioned()) {
3046:            //            return (ContainerBox)this;
3047:            //        } else {
3048:            //            CssBox blockBox = this;
3049:            //
3050:            //            while (blockBox.inline && !blockBox.boxType.isAbsolutelyPositioned() &&
3051:            //                    !blockBox.replaced || !(blockBox instanceof ContainerBox)) {
3052:            //                blockBox = blockBox.parent;
3053:            //            }
3054:            //
3055:            //            return (ContainerBox)blockBox;
3056:            //        }
3057:            //    }
3058:
3059:            /** Get the most recent normal-flow box prior to the current box
3060:             * in the parent's box list */
3061:            protected CssBox getPrevNormalBox() {
3062:                ContainerBox parent = getParent();
3063:                if (parent == null) {
3064:                    return null;
3065:                }
3066:
3067:                // XXX #98826 Workaround of the parentage linkning issue. Incorrect parent assigned.
3068:                if (!parent.containsChild(this )) {
3069:                    return null;
3070:                }
3071:
3072:                for (int i = getParentIndex() - 1; i >= 0; i--) {
3073:                    CssBox prev = parent.getBox(i);
3074:
3075:                    // XXX #6329717 NPE. TODO It seems that the access to the container CssBox children
3076:                    // is done from various threads, and it is not in sync.
3077:                    if (prev == null) {
3078:                        continue;
3079:                    }
3080:
3081:                    ///if this is a linebox group, though, we need to check whether its
3082:                    //container is normal flow or not
3083:                    if (prev.getBoxType() == BoxType.LINEBOX) {
3084:                        if (!prev.getParent().getBoxType().isNormalFlow()) {
3085:                            continue;
3086:                        }
3087:                    }
3088:
3089:                    if (prev.getBoxType().isNormalFlow()) {
3090:                        return prev;
3091:                    }
3092:                }
3093:
3094:                return null;
3095:            }
3096:
3097:            /** Get the next normal-flow box after to the current box
3098:             * in the parent's box list */
3099:            protected CssBox getNextNormalBox() {
3100:                ContainerBox parent = getParent();
3101:                if (parent == null) {
3102:                    return null;
3103:                }
3104:
3105:                // XXX #98826 Workaround of the parentage linkning issue. Incorrect parent assigned.
3106:                if (!parent.containsChild(this )) {
3107:                    return null;
3108:                }
3109:
3110:                int n = parent.getBoxCount();
3111:
3112:                for (int i = getParentIndex() + 1; i < n; i++) {
3113:                    CssBox next = parent.getBox(i);
3114:
3115:                    // XXX #6329717 NPE. TODO It seems that the access to the container CssBox children
3116:                    // is done from various threads, and it is not in sync.
3117:                    if (next == null) {
3118:                        continue;
3119:                    }
3120:
3121:                    if (next.getBoxType().isNormalFlow()) {
3122:                        return next;
3123:                    }
3124:                }
3125:
3126:                return null;
3127:            }
3128:
3129:            /** Get the most recent normal-flow box prior to the current box
3130:             * in the parent's box list that is also a block box. Lineboxes
3131:             * are considered block level for this purpose. Same as getPrevNormalBox
3132:             * except we also include LineBoxes. */
3133:            protected CssBox getPrevNormalBlockBox() {
3134:                ContainerBox parent = getParent();
3135:                if (parent == null) {
3136:                    return null;
3137:                }
3138:
3139:                // XXX #98826 Workaround of the parentage linkning issue. Incorrect parent assigned.
3140:                if (!parent.containsChild(this )) {
3141:                    return null;
3142:                }
3143:
3144:                for (int i = getParentIndex() - 1; i >= 0; i--) {
3145:                    CssBox prev = parent.getBox(i);
3146:
3147:                    // XXX #6329717 NPE. TODO It seems that the access to the container CssBox children
3148:                    // is done from various threads, and it is not in sync.
3149:                    if (prev == null) {
3150:                        continue;
3151:                    }
3152:
3153:                    if (prev.getBoxType().isNormalFlow()
3154:                            && ((prev.getBoxType() == BoxType.LINEBOX) || prev
3155:                                    .isBlockLevel())) {
3156:                        return prev;
3157:                    }
3158:                }
3159:
3160:                return null;
3161:            }
3162:
3163:            /** Get the next normal-flow box after to the current box
3164:             * in the parent's box list that is also a block box. Lineboxes
3165:             * are considered block level for this purpose. Same as getNextNormalBox
3166:             * except we also include LineBoxes. */
3167:            protected CssBox getNextNormalBlockBox() {
3168:                ContainerBox parent = getParent();
3169:                if (parent == null) {
3170:                    return null;
3171:                }
3172:
3173:                // XXX #98826 Workaround of the parentage linkning issue. Incorrect parent assigned.
3174:                if (!parent.containsChild(this )) {
3175:                    return null;
3176:                }
3177:
3178:                int n = parent.getBoxCount();
3179:
3180:                for (int i = getParentIndex() + 1; i < n; i++) {
3181:                    CssBox next = parent.getBox(i);
3182:
3183:                    // XXX #6329717 NPE. TODO It seems that the access to the container CssBox children
3184:                    // is done from various threads, and it is not in sync.
3185:                    if (next == null) {
3186:                        continue;
3187:                    }
3188:
3189:                    if (next.getBoxType().isNormalFlow()
3190:                            && ((next.getBoxType() == BoxType.LINEBOX) || next
3191:                                    .isBlockLevel())) {
3192:                        return next;
3193:                    }
3194:                }
3195:
3196:                return null;
3197:            }
3198:
3199:            /** Get the first normal-flow child box */
3200:            CssBox getFirstNormalBox() {
3201:                int n = getBoxCount();
3202:
3203:                for (int i = 0; i < n; i++) {
3204:                    CssBox first = getBox(i);
3205:
3206:                    if (first.getBoxType().isNormalFlow()) {
3207:                        return first;
3208:                    }
3209:                }
3210:
3211:                return null;
3212:            }
3213:
3214:            /** Get the last normal-flow child box */
3215:            private CssBox getLastNormalBox() {
3216:                for (int i = getBoxCount() - 1; i >= 0; i--) {
3217:                    CssBox last = getBox(i);
3218:
3219:                    if (last.getBoxType().isNormalFlow()) {
3220:                        return last;
3221:                    }
3222:                }
3223:
3224:                return null;
3225:            }
3226:
3227:            //    /** Get the first normal-flow child box that is also a block box.
3228:            //     * Lineboxes are considered block for this purpose.
3229:            //     */
3230:            //    CssBox getFirstNormalBlockBox() {
3231:            //        int n = getBoxCount();
3232:            //
3233:            //        for (int i = 0; i < n; i++) {
3234:            //            CssBox first = getBox(i);
3235:            //
3236:            //            if (first.getBoxType().isNormalFlow() &&
3237:            //                    ((first.getBoxType() == BoxType.LINEBOX) || first.isBlockLevel())) {
3238:            //                return first;
3239:            //            }
3240:            //        }
3241:            //
3242:            //        return null;
3243:            //    }
3244:            //
3245:            //    /** Get the last normal-flow child box that is also a block box.
3246:            //     * Lineboxes are considered block for this purpose.
3247:            //     */
3248:            //    CssBox getLastNormalBlockBox() {
3249:            //        for (int i = getBoxCount() - 1; i >= 0; i--) {
3250:            //            CssBox last = getBox(i);
3251:            //
3252:            //            if (last.getBoxType().isNormalFlow() &&
3253:            //                    ((last.getBoxType() == BoxType.LINEBOX) || last.isBlockLevel())) {
3254:            //                return last;
3255:            //            }
3256:            //        }
3257:            //
3258:            //        return null;
3259:            //    }
3260:
3261:            /** Compute the vertical "static position" of an element.
3262:             * This is defined in section 10.6.4 of the CSS2.1 spec.
3263:             * See also section 10.3.7 and the getStaticLeft() method.
3264:             */
3265:            private int getStaticTop(FormatContext context) {
3266:                return getLineBoxY(context);
3267:            }
3268:
3269:            protected int shrinkToFit(int availableWidth, FormatContext context) {
3270:                // XXX does width refer to the content width, or border
3271:                // width, or what, here?
3272:                // Calculate the preferred width by formatting the content
3273:                // without breaking lines other than where explicit line
3274:                // breaks occur, and also calculate the preferred minimum
3275:                // width, e.g. by trying all possible line breaks. CSS2.1
3276:                // does not define the exact algorithm.
3277:                //
3278:                // Then the shrink-to-fit width is:
3279:                // min(max(preferred minimum width, available width), preferred width).
3280:                // This box has already been width initialized, so only initialize
3281:                // its children
3282:                for (int i = 0, n = getBoxCount(); i < n; i++) {
3283:                    CssBox box = getBox(i);
3284:
3285:                    // We don't care about absolute/fixed children!
3286:                    if (box.getBoxType().isAbsolutelyPositioned()) {
3287:                        continue;
3288:                    }
3289:                    box.uncomputeWidthCssValue();
3290:                    box.initializeHorizontalWidths(context);
3291:                }
3292:
3293:                // XXX #109564 This loop was commented out (from unknown reasons here),
3294:                // it was present in 5.5, and it fixes the mentioned issue.
3295:                //XXX TODO 
3296:                //temporary fix for 6480767. see bug info for more details
3297:                //for all boxes within linebox, if the box width is in %, 
3298:                //uninitialize contentWidth, so that intrinsic width is taken        
3299:                for (int i = 0; i < getBoxCount(); i++) {
3300:                    CssBox box = getBox(i);
3301:                    if (box instanceof  LineBoxGroup) {
3302:                        for (int j = 0; j < ((LineBoxGroup) box)
3303:                                .getManagedBoxes().size(); j++) {
3304:                            CssBox aFloat = ((LineBoxGroup) box)
3305:                                    .getManagedBoxes().get(j);
3306:                            CssValue cssValue = CssProvider.getEngineService()
3307:                                    .getComputedValueForElement(aFloat.element,
3308:                                            XhtmlCss.WIDTH_INDEX);
3309:                            if (cssValue != null
3310:                                    && !CssProvider.getValueService()
3311:                                            .isAutoValue(cssValue)
3312:                                    && cssValue instanceof  CssComputedValue
3313:                                    && CssProvider
3314:                                            .getValueService()
3315:                                            .isOfPrimitivePercentageType(
3316:                                                    ((CssComputedValue) cssValue)
3317:                                                            .getCascadedValue())) {
3318:                                aFloat.contentWidth = UNINITIALIZED;
3319:                                CssProvider.getEngineService()
3320:                                        .uncomputeValueForElement(
3321:                                                aFloat.element,
3322:                                                XhtmlCss.WIDTH_INDEX);
3323:                            }
3324:                        }
3325:                    }
3326:                }
3327:
3328:                int preferred = getPrefWidth();
3329:                int minimum = getPrefMinWidth();
3330:                int shrinkFit = Math.min(Math.max(minimum, availableWidth),
3331:                        preferred);
3332:
3333:                //        MarkupDesignBean bean = getMarkupDesignBeanForCssBox(this);
3334:                Element componentRootElement = getElementForComponentRootCssBox(this );
3335:                //        if ((shrinkFit <= (leftBorderWidth + rightBorderWidth)) && (bean != null)) { // XXX padding too?
3336:                if ((shrinkFit <= (leftBorderWidth + rightBorderWidth))
3337:                        && (componentRootElement != null)) { // XXX padding too?
3338:                    shrinkFit = MINIMUM_BEAN_SIZE;
3339:
3340:                    //            if ((border == null) && ((parent == null) || (parent.getDesignBean() != bean)) &&
3341:                    //            if ((border == null) && ((parent == null) || (getMarkupDesignBeanForCssBox(parent) != bean)) &&
3342:                    if ((border == null)
3343:                            && ((parent == null) || (getElementForComponentRootCssBox(parent) != componentRootElement))
3344:                            && (tag != HtmlTag.FORM)) {
3345:                        border = CssBorder.getDesignerBorder();
3346:                        leftBorderWidth = border.getLeftBorderWidth();
3347:                        topBorderWidth = border.getTopBorderWidth();
3348:                        bottomBorderWidth = border.getBottomBorderWidth();
3349:                        rightBorderWidth = border.getRightBorderWidth();
3350:                    }
3351:                }
3352:
3353:                return shrinkFit;
3354:            }
3355:
3356:            private int computeContentHeight() {
3357:                // CSS21, section 10.6.4 - rule 3 for example:
3358:                // "then the height is based on the content" --
3359:                // what do they mean? Something similar to shrinkToFit?
3360:                // Is it the case that we've already done layout of the
3361:                // children when we call this method, so we can look up the actual
3362:                // width that was required? - but if we've done that, how could
3363:                // the width still say auto? Do I store the computed children
3364:                // height elsewhere?
3365:                // (aha. something similar to the case in 10.6.3 where I look
3366:                // at the children boxes and check their positions?)
3367:                // XXX should I use box.width? Did layout set it?
3368:                // XXX Check contentHeigeht attribute the way I'm doing it
3369:                // in getprefminwidth!
3370:                int result = 0;
3371:                int maxY = 0;
3372:                int n = getBoxCount();
3373:
3374:                for (int i = 0; i < n; i++) {
3375:                    CssBox child = getBox(i);
3376:
3377:                    if (child.getBoxType().isNormalFlow()) {
3378:                        int bottom = child.getY() + child.getHeight();
3379:
3380:                        if (bottom > maxY) {
3381:                            maxY = bottom;
3382:                        }
3383:                    }
3384:                }
3385:
3386:                if ((maxY == topPadding) && (topBorderWidth > 0)) {
3387:                    result = topBorderWidth;
3388:                } else {
3389:                    result = maxY - topPadding - topBorderWidth;
3390:                }
3391:
3392:                //        MarkupDesignBean bean = getMarkupDesignBeanForCssBox(this);
3393:                Element componentRootElement = getElementForComponentRootCssBox(this );
3394:                // XXX TODO - gotta add in margins here?
3395:                // XXX gotta add in min-heights too? Nope, if height has already
3396:                // been computed we should be okay.
3397:                // I suspect the above only works on TextBoxes because their sizes
3398:                // are computed at box creation time... I need to do more initialization
3399:                // to compute additional heights from attributes, margin alignment, etc.
3400:                // Design time borders for 0-sized components
3401:                //        if ((result <= topBorderWidth) && (bean != null) && // XXX add in padding too, not just borderwidth?
3402:                if ((result <= topBorderWidth)
3403:                        && (componentRootElement != null) && // XXX add in padding too, not just borderwidth?
3404:                        !element.getTagName().equals(HtmlTag.HR.name)) { // <hr>'s COULD be 0 sized
3405:                    result = MINIMUM_BEAN_SIZE;
3406:                }
3407:
3408:                return result;
3409:            }
3410:
3411:            /**
3412:             * Compute vertical heights and margins, as discussed in section
3413:             * 10.6 of the CSS2 spec.
3414:             *
3415:             * @todo Revisit section 10.6.3, I'm not implementing that correctly
3416:             *  (I might have implemented it according to the CSS2 spec, and in
3417:             *  CSS21 there are a bunch of additional conditions related to
3418:             *  margin collapsing)
3419:             * @todo Floating box section 10.6.6 is not fully implemented.
3420:             * <p>
3421:             * <b>Note</b>: I changed the implementation of 10.6.5 since the
3422:             * rules seemed a bit incorrect; see details in the relevant method.
3423:             *
3424:             * @param parentHeight the height of the containing block established
3425:             *   by the parent.
3426:             */
3427:            void computeVerticalLengths(FormatContext context) {
3428:                int parentHeight = containingBlockHeight;
3429:                assert boxType != BoxType.LINEBOX : this ;
3430:
3431:                // Initialize height
3432:                Element element = getElement();
3433:
3434:                if (element != null) {
3435:                    // Initialize top/bottom - only defined for positioned elements
3436:                    if (boxType.isPositioned()) {
3437:                        //                top = CssLookup.getLength(element, XhtmlCss.TOP_INDEX);
3438:                        //                bottom = CssLookup.getLength(element, XhtmlCss.BOTTOM_INDEX);
3439:                        top = CssUtilities.getCssLength(element,
3440:                                XhtmlCss.TOP_INDEX);
3441:                        bottom = CssUtilities.getCssLength(element,
3442:                                XhtmlCss.BOTTOM_INDEX);
3443:                    }
3444:                }
3445:
3446:                if ((boxType == BoxType.FLOAT) && !replaced) {
3447:                    computeVerticalNonReplacedFloat();
3448:                } else if (boxType.isAbsolutelyPositioned() && !replaced) {
3449:                    computeVerticalNonReplacedAbsPos(context, parentHeight);
3450:                } else if (boxType.isAbsolutelyPositioned() && replaced) {
3451:                    computeVerticalReplacedAbsPos(context, parentHeight);
3452:                } else if (inline && !replaced) {
3453:                    computeVerticalNonReplacedInline();
3454:                } else if ((inline && replaced)
3455:                        || (replaced && !inline && boxType.isNormalFlow())
3456:                        || (replaced && (boxType == BoxType.FLOAT))) {
3457:                    computeVerticalSec10_6_2();
3458:                } else if (!inline && !replaced && boxType.isNormalFlow()) {
3459:                    computeNonInlineNonReplacedNormal();
3460:                }
3461:
3462:                if (effectiveTopMargin == UNINITIALIZED) {
3463:                    effectiveTopMargin = topMargin;
3464:                }
3465:
3466:                if (effectiveBottomMargin == UNINITIALIZED) {
3467:                    effectiveBottomMargin = bottomMargin;
3468:                }
3469:
3470:                if (boxType == BoxType.RELATIVE) {
3471:                    // Same as normal above, but normal flow computations don't
3472:                    // consider the top and bottom values so fix them up here
3473:                    // as described in section 9.4.3 of the CSS2.1 spec
3474:                    if ((top == AUTO) && (bottom == AUTO)) {
3475:                        top = 0;
3476:                        bottom = 0;
3477:                    } else if (top == AUTO) {
3478:                        top = -bottom;
3479:                    } else if (bottom == AUTO) {
3480:                        bottom = -top;
3481:                    } else { // overconstrained
3482:                        bottom = -top; // always, not ltr dependent like widths
3483:                    }
3484:                }
3485:            }
3486:
3487:            private void computeVerticalNonReplacedFloat() {
3488:                // 10.6.6 Floating, non-replaced elements
3489:                if (topMargin == AUTO) {
3490:                    topMargin = 0;
3491:                }
3492:
3493:                if (bottomMargin == AUTO) {
3494:                    bottomMargin = 0;
3495:                }
3496:
3497:                if (contentHeight == AUTO) {
3498:                    // This is similar to 10.6.3, but with a modification
3499:                    // to the height search where we look for floating
3500:                    // children and adjust the height to accomodate their margin
3501:                    // edges
3502:                    int top = Integer.MAX_VALUE;
3503:                    int bottom = Integer.MIN_VALUE;
3504:
3505:                    if (hasNormalBlockLevelChildren()) {
3506:                        // XXX This gets tricky. Children boxes may be anonymous
3507:                        // block boxes - but I haven't been creating those!
3508:                        // Figure out how to handle this....
3509:                        // XXX This is still not clear. Look at section 10.6.3
3510:                        // in CSS21 again.
3511:                        // distance is the distance between the top border-edge
3512:                        // of the topmost block-level child box that doesn't have
3513:                        // margins collapsed through it, and the bottom border-edge
3514:                        // of the bottommost block-level child box that doesn't
3515:                        // have margins collapsed through it.
3516:                        int distance = 0;
3517:
3518:                        //CssBox topBox = null;
3519:                        //CssBox bottomBox = null;
3520:                        int n = getBoxCount();
3521:
3522:                        for (int i = 0; i < n; i++) {
3523:                            CssBox child = getBox(i);
3524:
3525:                            if (child.getY() < top) {
3526:                                top = child.getY();
3527:
3528:                                //topBox = child;
3529:                            }
3530:
3531:                            if ((child.getY() + child.getHeight()) > bottom) {
3532:                                bottom = child.getY() + child.getHeight();
3533:
3534:                                //bottomBox = child;
3535:                            }
3536:                        }
3537:
3538:                        //if (topBox != null) {
3539:                        if (top != Integer.MAX_VALUE) {
3540:                            distance = bottom - top;
3541:                        }
3542:
3543:                        contentHeight = distance;
3544:                    } else {
3545:                        // distance = distance from the top of the topmost
3546:                        // line box and the bottom most line box
3547:                        int distance = 0;
3548:
3549:                        //LineBoxGroup topBox = null;
3550:                        //LineBoxGroup bottomBox = null;
3551:                        int n = getBoxCount();
3552:
3553:                        for (int i = 0; i < n; i++) {
3554:                            CssBox child = getBox(i);
3555:
3556:                            if (!(child instanceof  LineBoxGroup)) {
3557:                                continue;
3558:                            }
3559:
3560:                            LineBoxGroup lineBox = (LineBoxGroup) child;
3561:
3562:                            if (lineBox.getY() < top) {
3563:                                top = lineBox.getY();
3564:
3565:                                //topBox = lineBox;
3566:                            }
3567:
3568:                            if ((lineBox.getY() + lineBox.getHeight()) > bottom) {
3569:                                bottom = lineBox.getY() + lineBox.getHeight();
3570:
3571:                                //bottomBox = lineBox;
3572:                            }
3573:                        }
3574:
3575:                        if ((top != Integer.MAX_VALUE)
3576:                                && (bottom != Integer.MAX_VALUE)) {
3577:                            //distance = bottomBox.bottom - topBox.top;
3578:                            distance = bottom - top;
3579:                        }
3580:
3581:                        contentHeight = distance;
3582:                    }
3583:
3584:                    // "In addition, if the element has any floating
3585:                    // descendants whose top margin edge is above the top
3586:                    // established above or whose bottom margin edge is
3587:                    // below the bottom, then the height is increased to
3588:                    // include those edges. Only floats that are children of
3589:                    // the element itself or of descendants in the normal
3590:                    // flow are taken into account, i.e., floats inside
3591:                    // absolutely positioned descendants are not."
3592:                    // Adjust top and bottom as necessary
3593:                    for (int i = 0; i < getBoxCount(); i++) {
3594:                        CssBox box = getBox(i);
3595:                        if (box instanceof  LineBoxGroup) {
3596:                            int newSize = ((LineBoxGroup) box)
3597:                                    .getSizeWithFloats();
3598:                            if (newSize > contentHeight) {
3599:                                contentHeight = newSize;
3600:                            }
3601:                        } else if (box != null
3602:                                && box.getBoxType() == BoxType.FLOAT) {
3603:                            // XXX #99707 Counting floats. This is just a hack.
3604:                            int newSize = box.getHeight();
3605:                            if (newSize != UNINITIALIZED && newSize != AUTO
3606:                                    && newSize > contentHeight) {
3607:                                contentHeight = newSize;
3608:                            }
3609:                        }
3610:                    }
3611:                }
3612:            }
3613:
3614:            private void computeVerticalNonReplacedAbsPos(
3615:                    FormatContext context, int parentHeight) {
3616:                // 10.6.4 Absolutely positioned, non-replaced elements
3617:                // For BoxType.FIXED, the containing block is the
3618:                // initial containing block instead of the viewport
3619:                // (for the purpose of computing heights, margins, etc.)
3620:                if (boxType == BoxType.FIXED) {
3621:                    parentHeight = getInitialHeight(context);
3622:                }
3623:
3624:                // XXX #6511830 Heavy hack to avoid fatal painting error,
3625:                // can't deal with value AUTO here. But is using initial height correct?
3626:                if (parentHeight == AUTO) {
3627:                    parentHeight = getInitialHeight(context);
3628:                }
3629:
3630:                // Must satisfy this constraint:
3631:                //top+topMargin+topBorderWidth+topPadding+height+bottomPadding+bottomBorderWidth+bottomMargin+bottom==parentHeight
3632:                if ((top == AUTO) && (bottom == AUTO)
3633:                        && (contentHeight == AUTO)) {
3634:                    top = getStaticTop(context);
3635:
3636:                    if (topMargin == AUTO) {
3637:                        topMargin = 0;
3638:                    }
3639:
3640:                    if (bottomMargin == AUTO) {
3641:                        bottomMargin = 0;
3642:                    }
3643:
3644:                    // 10.6.4, rule 3:
3645:                    // "then the height is based on the content" -- what do they
3646:                    // mean?
3647:                    contentHeight = computeContentHeight();
3648:                    bottom = parentHeight - top - topMargin - topBorderWidth
3649:                            - topPadding - contentHeight - bottomPadding
3650:                            - bottomBorderWidth - bottomMargin;
3651:                } else if ((top != AUTO) && (bottom != AUTO)
3652:                        && (contentHeight != AUTO)) {
3653:                    if ((topMargin == AUTO) && (bottomMargin == AUTO)) {
3654:                        int leftOver = parentHeight - top - topBorderWidth
3655:                                - topPadding - contentHeight - bottomPadding
3656:                                - bottomBorderWidth - bottom;
3657:                        int margin = leftOver / 2;
3658:                        int remainder = leftOver % 2;
3659:                        topMargin = margin;
3660:                        bottomMargin = margin + remainder;
3661:                    } else if ((topMargin != AUTO) && (bottomMargin == AUTO)) {
3662:                        bottomMargin = parentHeight - top - topMargin
3663:                                - topBorderWidth - topPadding - contentHeight
3664:                                - bottomPadding - bottomBorderWidth - bottom;
3665:                    } else if ((topMargin == AUTO) && (bottomMargin != AUTO)) {
3666:                        topMargin = parentHeight - top - topBorderWidth
3667:                                - topPadding - contentHeight - bottomPadding
3668:                                - bottomBorderWidth - bottomMargin - bottom;
3669:                    } else { // Overconstrained
3670:
3671:                        // Ignore value for bottom and solve for that value
3672:                        bottom = parentHeight - top - topMargin
3673:                                - topBorderWidth - topPadding - contentHeight
3674:                                - bottomPadding - bottomBorderWidth
3675:                                - bottomMargin;
3676:                    }
3677:                } else {
3678:                    // Perform one of rules 1-6 in section 10.6.4
3679:                    // The rules didn't pull out the "set auto values
3680:                    // for margin-top and margin-bottom to 0" part, but
3681:                    // included it in each rule; I've done the same (didn't
3682:                    // notice that it's included for all the rules until now).
3683:                    if ((top == AUTO) && (contentHeight == AUTO) && // (1)
3684:                            (bottom != AUTO)) {
3685:                        // "then the height is based on the content" --
3686:                        // what do they mean?
3687:                        contentHeight = computeContentHeight();
3688:
3689:                        if (topMargin == AUTO) {
3690:                            topMargin = 0;
3691:                        }
3692:
3693:                        if (bottomMargin == AUTO) {
3694:                            bottomMargin = 0;
3695:                        }
3696:
3697:                        top = parentHeight - topMargin - topBorderWidth
3698:                                - topPadding - contentHeight - bottomPadding
3699:                                - bottomBorderWidth - bottomMargin - bottom;
3700:                    } else if ((top == AUTO) && (bottom == AUTO)
3701:                            && (contentHeight != AUTO)) { // (2)
3702:                        top = getStaticTop(context); // ltr
3703:
3704:                        if (topMargin == AUTO) {
3705:                            topMargin = 0;
3706:                        }
3707:
3708:                        if (bottomMargin == AUTO) {
3709:                            bottomMargin = 0;
3710:                        }
3711:
3712:                        bottom = parentHeight - top - topMargin
3713:                                - topBorderWidth - topPadding - contentHeight
3714:                                - bottomPadding - bottomBorderWidth
3715:                                - bottomMargin;
3716:                    } else if ((contentHeight == AUTO) && (bottom == AUTO)
3717:                            && (top != AUTO)) { // (3)
3718:
3719:                        // "then the height is based on the content" --
3720:                        // what do they mean?
3721:                        contentHeight = computeContentHeight(); // XXX why would this return 0?
3722:
3723:                        if (topMargin == AUTO) {
3724:                            topMargin = 0;
3725:                        }
3726:
3727:                        if (bottomMargin == AUTO) {
3728:                            bottomMargin = 0;
3729:                        }
3730:
3731:                        bottom = parentHeight - top - topMargin
3732:                                - topBorderWidth - topPadding - contentHeight
3733:                                - bottomPadding - bottomBorderWidth
3734:                                - bottomMargin;
3735:                    } else if ((top == AUTO) && (contentHeight != AUTO)
3736:                            && (bottom != AUTO)) { // (4)
3737:
3738:                        if (topMargin == AUTO) {
3739:                            topMargin = 0;
3740:                        }
3741:
3742:                        if (bottomMargin == AUTO) {
3743:                            bottomMargin = 0;
3744:                        }
3745:
3746:                        top = parentHeight - topMargin - topBorderWidth
3747:                                - topPadding - contentHeight - bottomPadding
3748:                                - bottomBorderWidth - bottomMargin - bottom;
3749:                    } else if ((top != AUTO) && (contentHeight == AUTO)
3750:                            && (bottom != AUTO)) { // (5)
3751:
3752:                        if (topMargin == AUTO) {
3753:                            topMargin = 0;
3754:                        }
3755:
3756:                        if (bottomMargin == AUTO) {
3757:                            bottomMargin = 0;
3758:                        }
3759:
3760:                        contentHeight = parentHeight - top - topMargin
3761:                                - topBorderWidth - topPadding - bottomPadding
3762:                                - bottomBorderWidth - bottomMargin - bottom;
3763:                    } else if ((top != AUTO) && (contentHeight != AUTO)
3764:                            && (bottom == AUTO)) { // (6)
3765:
3766:                        if (topMargin == AUTO) {
3767:                            topMargin = 0;
3768:                        }
3769:
3770:                        if (bottomMargin == AUTO) {
3771:                            bottomMargin = 0;
3772:                        }
3773:
3774:                        bottom = parentHeight - top - topMargin
3775:                                - topBorderWidth - topPadding - contentHeight
3776:                                - bottomPadding - bottomBorderWidth
3777:                                - bottomMargin;
3778:                    }
3779:                }
3780:
3781:                // Check that we made it
3782:                assert (top + topMargin + topBorderWidth + topPadding
3783:                        + contentHeight + bottomPadding + bottomBorderWidth
3784:                        + bottomMargin + bottom) == parentHeight;
3785:            }
3786:
3787:            private void computeVerticalReplacedAbsPos(FormatContext context,
3788:                    int parentHeight) {
3789:                // 10.6.5 Absolutely positioned, replaced elements
3790:                // For BoxType.FIXED, the containing block is the
3791:                // initial containing block instead of the viewport
3792:                // (for the purpose of computing heights, margins, etc.)
3793:                if (boxType == BoxType.FIXED) {
3794:                    parentHeight = getInitialHeight(context);
3795:                }
3796:
3797:                // XXX #6511830 Heavy hack to avoid fatal painting error,
3798:                // can't deal with value AUTO here. But is using initial height correct?
3799:                if (parentHeight == AUTO) {
3800:                    parentHeight = getInitialHeight(context);
3801:                }
3802:
3803:                updateAutoContentSize(); // (1)
3804:
3805:                // XXX The following is not in the rule substitution list
3806:                // for 10.6.5 in CSS21, but probably what was intended
3807:                if ((top == AUTO) && (bottom != AUTO)) {
3808:                    if (topMargin == AUTO) {
3809:                        topMargin = 0;
3810:                    }
3811:
3812:                    if (bottomMargin == AUTO) {
3813:                        bottomMargin = 0;
3814:                    }
3815:
3816:                    top = parentHeight - bottom - topMargin - topBorderWidth
3817:                            - topPadding - contentHeight - bottomPadding
3818:                            - bottomBorderWidth - bottomMargin;
3819:                } else if ((top != AUTO) && (bottom == AUTO)) {
3820:                    if (topMargin == AUTO) {
3821:                        topMargin = 0;
3822:                    }
3823:
3824:                    if (bottomMargin == AUTO) {
3825:                        bottomMargin = 0;
3826:                    }
3827:
3828:                    bottom = parentHeight - top - topMargin - topBorderWidth
3829:                            - topPadding - contentHeight - bottomPadding
3830:                            - bottomBorderWidth - bottomMargin;
3831:                } else
3832:                // .... now back to your regular programming, courtesy
3833:                // of channel 10.3.8 on the CSS21 network
3834:                if (top == AUTO) { // (2)
3835:                    top = getStaticTop(context); // ltr
3836:                }
3837:
3838:                if (bottom == AUTO) { // (3)
3839:
3840:                    if (topMargin == AUTO) {
3841:                        topMargin = 0;
3842:                    }
3843:
3844:                    if (bottomMargin == AUTO) {
3845:                        bottomMargin = 0;
3846:                    }
3847:                }
3848:
3849:                if ((topMargin == AUTO) && (bottomMargin == AUTO)) { // (4)
3850:
3851:                    int leftOver = parentHeight - top - topBorderWidth
3852:                            - topPadding - contentHeight - bottomPadding
3853:                            - bottomBorderWidth - bottom;
3854:                    int margin = leftOver / 2;
3855:                    int remainder = leftOver % 2;
3856:                    topMargin = margin;
3857:                    bottomMargin = margin + remainder;
3858:                }
3859:
3860:                int numAuto = 0;
3861:
3862:                if (contentHeight == AUTO) {
3863:                    numAuto++;
3864:                }
3865:
3866:                if (topMargin == AUTO) {
3867:                    numAuto++;
3868:                }
3869:
3870:                if (bottomMargin == AUTO) {
3871:                    numAuto++;
3872:                }
3873:
3874:                if (bottom == AUTO) {
3875:                    numAuto++;
3876:                }
3877:
3878:                // top can't be auto since we've applied rule 2
3879:                if (numAuto == 1) { // (5)
3880:
3881:                    int total = parentHeight - top - topBorderWidth
3882:                            - bottomBorderWidth - topPadding - bottomPadding;
3883:                    Equation equation = new Equation(total, new int[] {
3884:                            topMargin, bottomMargin, contentHeight, bottom });
3885:                    equation.solve();
3886:
3887:                    switch (equation.index) {
3888:                    case 0:
3889:                        topMargin = equation.value;
3890:
3891:                        break;
3892:
3893:                    case 1:
3894:                        bottomMargin = equation.value;
3895:
3896:                        break;
3897:
3898:                    case 2:
3899:                        contentHeight = equation.value;
3900:
3901:                        break;
3902:
3903:                    case 3:
3904:                        bottom = equation.value;
3905:
3906:                        break;
3907:                    }
3908:                } else { // (6)
3909:                    assert numAuto == 0;
3910:
3911:                    // Overconstrained. Since we're in a ltr context, ignore
3912:                    // the bottomMargin and recompute it to make the equality
3913:                    // true.
3914:                    bottom = parentHeight - top - topMargin - topBorderWidth
3915:                            - topPadding - contentHeight - bottomPadding
3916:                            - bottomBorderWidth - bottomMargin;
3917:                }
3918:
3919:                // Check that we made it:
3920:                assert (top + topMargin + topBorderWidth + topPadding
3921:                        + contentHeight + bottomPadding + bottomBorderWidth
3922:                        + bottomMargin + bottom) == parentHeight;
3923:            }
3924:
3925:            private void computeVerticalNonReplacedInline() {
3926:                if (this  instanceof  TableBox) {
3927:                    // XXX #6494312 For inline tables this algorithm doesn't apply.
3928:                } else {
3929:                    // 10.6.1: Inline, non-replaced elements
3930:                    //        Value heightValue = CssLookup.getValue(element, XhtmlCss.LINE_HEIGHT_INDEX);
3931:                    CssValue cssHeightValue = CssProvider.getEngineService()
3932:                            .getComputedValueForElement(element,
3933:                                    XhtmlCss.LINE_HEIGHT_INDEX);
3934:
3935:                    //        if (heightValue == CssValueConstants.NORMAL_VALUE) {
3936:                    if (CssProvider.getValueService().isNormalValue(
3937:                            cssHeightValue)) {
3938:                        //            contentHeight = (int)(1.1 * CssLookup.getFontSize(element, DesignerSettings.getInstance().getDefaultFontSize()));
3939:                        //                contentHeight = (int)(1.1 * CssProvider.getValueService().getFontSizeForElement(element, DesignerSettings.getInstance().getDefaultFontSize()));
3940:                        contentHeight = (int) (1.1 * CssProvider
3941:                                .getValueService().getFontSizeForElement(
3942:                                        element, webform.getDefaultFontSize()));
3943:                    } else {
3944:                        //            contentHeight = (int)heightValue.getFloatValue();
3945:                        contentHeight = (int) cssHeightValue.getFloatValue();
3946:                    }
3947:                }
3948:
3949:                // XXX this seems wrong!
3950:                // XXX slow. Optimize!
3951:                // Also, it doesn't handle cases where the are multiple differently
3952:                // sized fonts in the line. See the spec for a suggestion on how
3953:                // to calculate it.
3954:                // 10.6.1 says: "The vertical padding, border and margin
3955:                // of an inline, non-replaced box start at the top and
3956:                // bottom of the content area, not the 'line-height'.
3957:                // XXX Does this mean that vertical padding, borders and
3958:                // margins should be zero for non-replaced inline
3959:                // elements?
3960:                topPadding = 0;
3961:                bottomPadding = 0;
3962:                topBorderWidth = 0;
3963:                bottomBorderWidth = 0;
3964:                topMargin = 0;
3965:                bottomMargin = 0;
3966:
3967:                // XXX Really unsure that the above is okay
3968:            }
3969:
3970:            private void computeVerticalSec10_6_2() {
3971:                // 10.6.2 Inline replaced elements, block-level replaced elements
3972:                // in normal flow, and floating replaced elements
3973:                if (topMargin == AUTO) {
3974:                    topMargin = 0;
3975:                }
3976:
3977:                if (bottomMargin == AUTO) {
3978:                    bottomMargin = 0;
3979:                }
3980:
3981:                updateAutoContentSize();
3982:            }
3983:
3984:            private void computeNonInlineNonReplacedNormal() {
3985:                // 10.6.3 Block-level, non-replaced elements in normal flow
3986:                if (topMargin == AUTO) {
3987:                    topMargin = 0;
3988:                }
3989:
3990:                if (bottomMargin == AUTO) {
3991:                    bottomMargin = 0;
3992:                }
3993:
3994:                if (contentHeight == AUTO) {
3995:                    if (hasNormalBlockLevelChildren()) {
3996:                        // XXX This gets tricky. Children boxes may be anonymous
3997:                        // block boxes - but I haven't been creating those!
3998:                        // Figure out how to handle this....
3999:                        // XXX This is still not clear. Look at section 10.6.3
4000:                        // in CSS21 again.
4001:                        // distance is the distance between the top border-edge
4002:                        // of the topmost block-level child box that doesn't have
4003:                        // margins collapsed through it, and the bottom border-edge
4004:                        // of the bottommost block-level child box that doesn't
4005:                        // have margins collapsed through it.
4006:                        int distance = 0;
4007:                        int top = Integer.MAX_VALUE;
4008:                        int bottom = Integer.MIN_VALUE;
4009:
4010:                        //CssBox topBox = null;
4011:                        //CssBox bottomBox = null;
4012:                        int n = getBoxCount();
4013:
4014:                        for (int i = 0; i < n; i++) {
4015:                            CssBox child = getBox(i);
4016:
4017:                            if (!child.getBoxType().isNormalFlow()) {
4018:                                continue;
4019:                            }
4020:
4021:                            if (child.getY() < top) {
4022:                                top = child.getY();
4023:
4024:                                //topBox = child;
4025:                            }
4026:
4027:                            if ((child.getY() + child.getHeight()) > bottom) {
4028:                                bottom = child.getY() + child.getHeight();
4029:
4030:                                //bottomBox = child;
4031:                            }
4032:                        }
4033:
4034:                        //if (topBox != null) {
4035:                        if (top != Integer.MAX_VALUE) {
4036:                            distance = bottom - top;
4037:                        }
4038:
4039:                        contentHeight = distance;
4040:                    } else {
4041:                        // distance = distance from the top of the topmost
4042:                        // line box and the bottom most line box
4043:                        int distance = 0;
4044:                        int top = Integer.MAX_VALUE;
4045:                        int bottom = Integer.MIN_VALUE;
4046:
4047:                        //LineBoxGroup topBox = null;
4048:                        //LineBoxGroup bottomBox = null;
4049:                        int n = getBoxCount();
4050:
4051:                        for (int i = 0; i < n; i++) {
4052:                            CssBox child = getBox(i);
4053:
4054:                            if (!child.getBoxType().isNormalFlow()) {
4055:                                continue;
4056:                            }
4057:
4058:                            if (!(child instanceof  LineBoxGroup)) {
4059:                                continue;
4060:                            }
4061:
4062:                            LineBoxGroup lineBox = (LineBoxGroup) child;
4063:
4064:                            if (lineBox.getY() < top) {
4065:                                top = lineBox.getY();
4066:
4067:                                //topBox = lineBox;
4068:                            }
4069:
4070:                            if ((lineBox.getY() + lineBox.getHeight()) > bottom) {
4071:                                bottom = lineBox.getY() + lineBox.getHeight();
4072:
4073:                                //bottomBox = lineBox;
4074:                            }
4075:                        }
4076:
4077:                        if ((top != Integer.MAX_VALUE)
4078:                                && (bottom != Integer.MAX_VALUE)) {
4079:                            //distance = bottomBox.bottom - topBox.top;
4080:                            distance = bottom - top;
4081:                        } else {
4082:                            distance = getIntrinsicHeight();
4083:                        }
4084:
4085:                        contentHeight = distance;
4086:                    }
4087:                }
4088:            }
4089:
4090:            /**
4091:             * Clear previous boxes such that this box is positioned below the
4092:             * clear area.
4093:             */
4094:            protected void clearTop(FormatContext context, CssValue cssSide) {
4095:                int cleared = context.clear(cssSide, this );
4096:
4097:                if (cleared > Integer.MIN_VALUE) {
4098:                    int clearance = cleared - getAbsoluteY();
4099:
4100:                    if (clearance > 0) {
4101:                        y += clearance;
4102:                    }
4103:                }
4104:            }
4105:
4106:            /**
4107:             * Adjust height and contentHeight to clear floating
4108:             * boxes on either (or both) sides within this box.
4109:             */
4110:            protected void clearBottom(FormatContext context, CssValue cssSide) {
4111:                int cleared = context.clear(cssSide, null);
4112:
4113:                if (cleared > Integer.MIN_VALUE) {
4114:                    int clearance = cleared - (getAbsoluteY() + getHeight());
4115:
4116:                    if (clearance > 0) {
4117:                        contentHeight += clearance;
4118:                        height += clearance;
4119:                    }
4120:                }
4121:            }
4122:
4123:            /**
4124:             * Check whether the given box has any block level children that
4125:             * participate in normal flow (e.g. not floating boxes or
4126:             * absolutely positioned boxes).
4127:             *
4128:             * @todo Gotta add positioning type to CssBox!
4129:             *
4130:             */
4131:            protected boolean hasNormalBlockLevelChildren() {
4132:                return false;
4133:            }
4134:
4135:            /** Return the width of the initial containing block */
4136:            private int getInitialWidth(FormatContext context) {
4137:                return context.initialWidth;
4138:            }
4139:
4140:            /** Return the height of the initial containing block */
4141:            private int getInitialHeight(FormatContext context) {
4142:                return context.initialHeight;
4143:            }
4144:
4145:            /**
4146:             * Compute the content width/height settings for a replaced
4147:             *  This will do nothing if the content width or height are
4148:             * already set to something other than AUTO; however, if set to
4149:             * AUTO it will compute a size which preserves the aspect
4150:             * ratio. If both width and height are set to auto, it returns the
4151:             * intrinsic size.  <p> See the errata since this was incorrect in
4152:             * the spec.
4153:             * http://www.w3.org/Style/css2-updates/REC-CSS2-19980512-errata.html
4154:             * specifically section 10.3.2 (which also applies to 10.3.4,
4155:             * 10.3.6, and 10.3.8).
4156:             */
4157:            protected void updateAutoContentSize() {
4158:                if ((contentWidth == AUTO) && (contentHeight == AUTO)) {
4159:                    if (contentWidth == AUTO) {
4160:                        contentWidth = getIntrinsicWidth();
4161:                    }
4162:
4163:                    if (contentHeight == AUTO) {
4164:                        contentHeight = getIntrinsicHeight();
4165:                    }
4166:                } else if ((contentWidth == AUTO) && (contentHeight != AUTO)) {
4167:                    if (getIntrinsicHeight() == 0) {
4168:                        contentWidth = getIntrinsicWidth();
4169:                    } else {
4170:                        contentWidth = (getIntrinsicWidth() * contentHeight)
4171:                                / getIntrinsicHeight();
4172:                    }
4173:                } else if ((contentWidth != AUTO) && (contentHeight == AUTO)) {
4174:                    if (getIntrinsicWidth() == 0) {
4175:                        contentHeight = getIntrinsicHeight();
4176:                    } else {
4177:                        contentHeight = (getIntrinsicHeight() * contentWidth)
4178:                                / getIntrinsicWidth();
4179:                    }
4180:
4181:                    //} else if (contentWidth != AUTO &&
4182:                    //         contentHeight != AUTO) {
4183:                    //    // Do nothing
4184:                }
4185:            }
4186:
4187:            /** Compute the effective top margin for this box.
4188:             * Collapsing vertical margins: specified in 8.3.1
4189:             * @todo I don't quite understand the "collapsed through" discussion
4190:             *  in 8.3.1. Revisit and make sure it's supported correctly.
4191:             */
4192:            protected int getCollapsedTopMargin() {
4193:                int max = (topMargin > 0) ? topMargin : 0; // largest positive margin
4194:                int min = (topMargin > 0) ? 0 : (-topMargin); // abs(largest negative margin)
4195:
4196:                if (getBoxCount() > 0) {
4197:                    CssBox child = getFirstNormalBox();
4198:
4199:                    while (child != null) {
4200:                        if (child.topMargin > 0) {
4201:                            if (child.topMargin > max) {
4202:                                max = child.topMargin;
4203:                            }
4204:                        } else {
4205:                            if (-child.topMargin > min) {
4206:                                min = -child.topMargin;
4207:                            }
4208:                        }
4209:
4210:                        // TODO: also abort collapse search if the child has clearance
4211:                        if ((child.topBorderWidth == 0)
4212:                                && (child.topPadding == 0)
4213:                                && (child.getBoxCount() > 0)) {
4214:                            child = child.getFirstNormalBox();
4215:                        } else {
4216:                            break;
4217:                        }
4218:                    }
4219:                }
4220:
4221:                return max - min;
4222:            }
4223:
4224:            /** Compute the effective bottom margins for this box.
4225:             * Collapsing vertical margins: specified in 8.3.1.
4226:             * @todo I don't quite understand the "collapsed through" discussion
4227:             *  in 8.3.1. Revisit and make sure it's supported correctly.
4228:             */
4229:            protected int getCollapsedBottomMargin() {
4230:                int max = (bottomMargin > 0) ? bottomMargin : 0; // largest positive margin
4231:                int min = (bottomMargin > 0) ? 0 : (-bottomMargin); // abs(largest negative margin)
4232:
4233:                if (getBoxCount() > 0) {
4234:                    CssBox child = getLastNormalBox();
4235:
4236:                    while (child != null) {
4237:                        if (child.bottomMargin > 0) {
4238:                            if (child.bottomMargin > max) {
4239:                                max = child.bottomMargin;
4240:                            }
4241:                        } else {
4242:                            if (-child.bottomMargin > min) {
4243:                                min = -child.bottomMargin;
4244:                            }
4245:                        }
4246:
4247:                        // TODO: also abort collapse search if the child has clearance
4248:                        if ((child.bottomBorderWidth == 0)
4249:                                && (child.bottomPadding == 0)
4250:                                && (child.getBoxCount() > 0)) {
4251:                            child = child.getLastNormalBox();
4252:                        } else {
4253:                            break;
4254:                        }
4255:                    }
4256:                }
4257:
4258:                return max - min;
4259:            }
4260:
4261:            // Implements ContainingBlock
4262:            public int getBlockWidth() {
4263:                return containingBlockWidth;
4264:            }
4265:
4266:            // Implements ContainingBlock
4267:            public int getBlockHeight() {
4268:                return containingBlockHeight;
4269:            }
4270:
4271:            //    /** XXX For testsuite only */
4272:            //    public String getUnitializedField() {
4273:            //        if (x == UNINITIALIZED) {
4274:            //            return "x";
4275:            //        }
4276:            //
4277:            //        if (y == UNINITIALIZED) {
4278:            //            return "y";
4279:            //        }
4280:            //
4281:            //        if (width == UNINITIALIZED) {
4282:            //            return "width";
4283:            //        }
4284:            //
4285:            //        if (height == UNINITIALIZED) {
4286:            //            return "height";
4287:            //        }
4288:            //
4289:            //        if (this instanceof ContainerBox) {
4290:            //            if (containingBlockWidth == -1) {
4291:            //                return "containingBlockWidth";
4292:            //            }
4293:            //
4294:            //            if (containingBlockHeight == -1) {
4295:            //                return "containingBlockHeight";
4296:            //            }
4297:            //
4298:            //            if (contentWidth == AUTO) {
4299:            //                return "contentWidth";
4300:            //            }
4301:            //
4302:            //            if (contentHeight == AUTO) {
4303:            //                return "contentHeight";
4304:            //            }
4305:            //
4306:            //            if (leftMargin == AUTO) {
4307:            //                return "leftMargin";
4308:            //            }
4309:            //
4310:            //            if (rightMargin == AUTO) {
4311:            //                return "rightMargin";
4312:            //            }
4313:            //        }
4314:            //
4315:            //        if (!(this instanceof PageBox)) {
4316:            //            if (positionedBy == null) {
4317:            //                return "positionedBy";
4318:            //            }
4319:            //
4320:            //            if (parent == null) {
4321:            //                return "parent";
4322:            //            }
4323:            //        }
4324:            //
4325:            //        return null;
4326:            //    }
4327:
4328:            // -------------------------------------------------------------------------------------------------
4329:            // Stuff for debugging purposes (DOM inspector BoxNode)
4330:
4331:            // TODO Only DomInspector, get rid of it (do not create new pulbic methods here).
4332:            public Rectangle getCBRectangle() {
4333:                return new Rectangle(containingBlockX, containingBlockY,
4334:                        containingBlockWidth, containingBlockHeight);
4335:            }
4336:
4337:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4338:            public Rectangle getExtentsRectangle() {
4339:                return new Rectangle(extentX, extentY, extentX2 - extentX,
4340:                        extentY2 - extentY);
4341:            }
4342:
4343:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4344:            public Point getPosition() {
4345:                return new Point(getAbsoluteX(), getAbsoluteY());
4346:            }
4347:
4348:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4349:            public Point getRelPosition() {
4350:                return new Point(getX(), getY());
4351:            }
4352:
4353:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4354:            public Rectangle getPositionRect() {
4355:                if (boxType.isPositioned()) {
4356:                    return new Rectangle(left, top, bottom, right);
4357:                } else {
4358:                    return null;
4359:                }
4360:            }
4361:
4362:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4363:            public String getBoxTypeName() {
4364:                return boxType.getDescription();
4365:            }
4366:
4367:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4368:            public Dimension getSize() {
4369:                return new Dimension(getWidth(), getHeight());
4370:            }
4371:
4372:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4373:            public Dimension getContentSize() {
4374:                return new Dimension(contentWidth, contentHeight);
4375:            }
4376:
4377:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4378:            public Rectangle getMarginRectangle() {
4379:                return new Rectangle(leftMargin, topMargin, rightMargin,
4380:                        bottomMargin);
4381:            }
4382:
4383:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4384:            public Rectangle getPaddingRectangle() {
4385:                return new Rectangle(leftPadding, topPadding, rightPadding,
4386:                        bottomPadding);
4387:            }
4388:
4389:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4390:            public Rectangle getBorderWidthRectangle() {
4391:                return new Rectangle(leftBorderWidth, topBorderWidth,
4392:                        rightBorderWidth, bottomBorderWidth);
4393:            }
4394:
4395:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4396:            public Color getBg() {
4397:                return bg;
4398:            }
4399:
4400:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4401:            public String getStyles() {
4402:                if (element != null) {
4403:                    //            String styles = CssLookup.getAllStyles(element);
4404:                    String styles = CssProvider.getEngineService()
4405:                            .getAllStylesForElement(element);
4406:
4407:                    if (styles == null) {
4408:                        return "";
4409:                    } else {
4410:                        return styles;
4411:                    }
4412:                } else if ((this .getBoxType() == BoxType.TEXT)
4413:                        || (this .getBoxType() == BoxType.SPACE)) {
4414:                    return parent.getStyles();
4415:                } else { // e.g. anonymous box such as a CaptionedTable
4416:
4417:                    return "";
4418:                }
4419:            }
4420:
4421:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4422:            public String getRules() {
4423:                if (element != null) {
4424:                    //            String styles = CssLookup.getAllRules(element);
4425:                    String styles = CssProvider.getEngineService()
4426:                            .getAllRulesForElement(element);
4427:
4428:                    if (styles == null) {
4429:                        return "";
4430:                    } else {
4431:                        return styles;
4432:                    }
4433:                } else if ((this .getBoxType() == BoxType.TEXT)
4434:                        || (this .getBoxType() == BoxType.SPACE)) {
4435:                    return parent.getRules();
4436:                } else {
4437:                    return "";
4438:                }
4439:            }
4440:
4441:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4442:            public String getComputedStyles() {
4443:                if (element != null) {
4444:                    //            String styles = CssLookup.getAllComputedStyles(element);
4445:                    String styles = CssProvider.getEngineService()
4446:                            .getAllComputedStylesForElement(element);
4447:
4448:                    if (styles == null) {
4449:                        return "";
4450:                    } else {
4451:                        return styles;
4452:                    }
4453:                } else if ((this .getBoxType() == BoxType.TEXT)
4454:                        || (this .getBoxType() == BoxType.SPACE)) {
4455:                    return parent.getComputedStyles();
4456:                } else { // e.g. anonymous box such as a CaptionedTable
4457:
4458:                    return "";
4459:                }
4460:            }
4461:
4462:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4463:            public boolean getPaintSpaces() {
4464:                return paintSpaces;
4465:            }
4466:
4467:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4468:            public void setPaintSpaces(boolean paintSpaces) {
4469:                this .paintSpaces = paintSpaces;
4470:                webform.getPane().repaint();
4471:            }
4472:
4473:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4474:            public boolean getPaintText() {
4475:                return paintText;
4476:            }
4477:
4478:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4479:            public void setPaintText(boolean paintText) {
4480:                this .paintText = paintText;
4481:                webform.getPane().repaint();
4482:            }
4483:
4484:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4485:            public boolean getPaintPositions() {
4486:                return paintPositioning;
4487:            }
4488:
4489:            // TODO Only DomInspector, get rid of it (do not create new public methods here).
4490:            public void setPaintPositions(boolean paintPositioning) {
4491:                this .paintPositioning = paintPositioning;
4492:                webform.getPane().repaint();
4493:            }
4494:
4495:            protected boolean isPlaceHolder() {
4496:                return false;
4497:            }
4498:
4499:            /** Prints out the this box. 
4500:             * @see java.awt.Component#list(java.io.PrintStream, int) */
4501:            public void list(PrintStream out, int indent) {
4502:                for (int i = 0; i < indent; i++) {
4503:                    out.print("    "); // NOI18N
4504:                }
4505:                out.println("*" + this ); // NOI18N
4506:            }
4507:
4508:            /** Prints out the this box. 
4509:             * @see java.awt.Component#list(java.io.PrintWriter, int) */
4510:            public void list(PrintWriter out, int indent) {
4511:                for (int i = 0; i < indent; i++) {
4512:                    out.print("    "); // NOI18N
4513:                }
4514:                out.println("*" + this ); // NOI18N
4515:            }
4516:
4517:            /** Gets <code>Decoration</code> associated with this box.
4518:             * @return gets the associated <code>Decoration</code> or null if there is none. */
4519:            public Decoration getDecoration() {
4520:                //        return DecorationManager.getDefault().getDecoration(element);
4521:                return webform.getDecoration(element);
4522:            }
4523:
4524:            /**
4525:             * Class used to solve equations involving containing blocks where
4526:             * one of the parameters (margin, content width, etc.) are unknown.
4527:             */
4528:            private static class Equation {
4529:                /** List of integers, where exactly one can have the value
4530:                 * of AUTO. The other variables plus the AUTO field's value
4531:                 * should equal total, so solve for AUTO.
4532:                 */
4533:                private final int[] variables;
4534:
4535:                /** When a solution has been found, index points to the
4536:                 * variable that we solved for - e.g. the variable that
4537:                 * was originally AUTO.
4538:                 */
4539:                private int index;
4540:
4541:                /** When a solution has been found, this is the value of
4542:                 * the variable we solved for.
4543:                 */
4544:                private int value;
4545:
4546:                /** All the integers in variables, plus the AUTO one,
4547:                 * should total this amount.
4548:                 */
4549:                private final int total;
4550:
4551:                /** */
4552:                private Equation(int total, int[] variables) {
4553:                    this .total = total;
4554:                    this .variables = variables;
4555:                }
4556:
4557:                /**
4558:                 * Given a list of integers, of which exactly one might be AUTO,
4559:                 * return the total minus all the other parameters: in other words
4560:                 * solve the equation sum(params)=total.  Return the answer as a
4561:                 * 2-element integer array: the first element is the index of the
4562:                 * parameter which was AUTO (e.g. the one we solved the equation
4563:                 * for), and the second element is the new value of that parameter.
4564:                 *
4565:                 * XXX NO - I just realized padding can't be AUTO! (Not an option).
4566:                 * So it shouldn't be a problem. Simplify this by presubtracting
4567:                 * the total and don't include padding in the parameters.
4568:                 */
4569:                private void solve() {
4570:                    index = -1;
4571:
4572:                    for (int i = 0; i < variables.length; i++) {
4573:                        if (variables[i] == AUTO) {
4574:                            index = i;
4575:
4576:                            break;
4577:                        }
4578:                    }
4579:
4580:                    // we should only be called when number-of-auto==1
4581:                    assert index != -1;
4582:
4583:                    int remaining = total;
4584:
4585:                    for (int i = 0; i < variables.length; i++) {
4586:                        if (i != index) {
4587:                            remaining -= variables[i];
4588:                        }
4589:                    }
4590:
4591:                    value = remaining;
4592:                }
4593:            }
4594:
4595:            public Element getComponentRootElement() {
4596:                return getElementForComponentRootCssBox(this );
4597:            }
4598:
4599:            public Box[] getChildren() {
4600:                List<Box> boxes = new ArrayList<Box>();
4601:                for (int i = 0, n = getBoxCount(); i < n; i++) {
4602:                    CssBox box = getBox(i);
4603:                    boxes.add(box);
4604:                }
4605:                return boxes.toArray(new Box[boxes.size()]);
4606:            }
4607:
4608:            public boolean isPositioned() {
4609:                return getBoxType().isPositioned();
4610:            }
4611:
4612:            public boolean isAbsolutelyPositioned() {
4613:                return getBoxType().isAbsolutelyPositioned();
4614:            }
4615:
4616:            //    /** Gets the width of the block which directly contains the
4617:            //     * given element. */
4618:            //    public float getBlockWidth(Element element) {
4619:            //        CssBox box = getWebForm().getCssBoxForElement(element);
4620:            ////        if (element instanceof RaveElement) {
4621:            ////            RaveElement e = (RaveElement)element;
4622:            ////            block = e.getBox();
4623:            ////        }
4624:            //        if (box != null) {
4625:            //            return box.getBlockWidth();
4626:            //        }
4627:            //        ErrorManager.getDefault().log("No containing block available for element " + element); // NOI18N
4628:            //        return 0.0f; // if no available containing block, just use 0
4629:            //    }
4630:            //    
4631:            //    /** Gets the height of the block which directly contains the
4632:            //     * given element. */
4633:            //    public float getBlockHeight(Element element) {
4634:            //        CssBox box = getWebForm().getCssBoxForElement(element);
4635:            ////        if (element instanceof RaveElement) {
4636:            ////            block = ((RaveElement)element).getBox();
4637:            ////        }
4638:            //        if (box != null) {
4639:            //            return box.getBlockHeight();
4640:            //        }
4641:            //        ErrorManager.getDefault().log("No containing block available for element " + element); // NOI18N
4642:            //        return 0.0f; // if no available containing block, just use 0
4643:            //    }
4644:
4645:            //    // XXX TODO Temporary. There should be a cleaner mechanism managing the links
4646:            //    // between the elements and the corresponding boxes.
4647:            //    private static final Map elementToBox = new WeakHashMap(200);
4648:            //    
4649:            //    private static void setCssBoxForElement(Element element, CssBox box) {
4650:            //        // XXX Copied from the original impl (in RaveElement).
4651:            //        org.w3c.dom.Node parent = element.getParentNode();
4652:            //        if ((parent instanceof Element) && getCssBoxForElement((Element)parent) == box) {
4653:            //            return; // Don't duplicate a bean reference on all the children!
4654:            //        }
4655:            //        
4656:            //        synchronized (elementToBox) {
4657:            //            elementToBox.put(element, box);
4658:            //        }
4659:            //    }
4660:            //    
4661:            //    private static CssBox getCssBoxForElement(Element element) {
4662:            //        synchronized (elementToBox) {
4663:            //            return (CssBox)elementToBox.get(element);
4664:            //        }
4665:            //    }
4666:            //    
4667:            //    // XXX Temporary, see DesignerService.copyBoxForElement.
4668:            //    public static void copyBoxForElement(Element fromElement, Element toElement) {
4669:            //        CssBox box = getCssBoxForElement(fromElement);
4670:            //        setCssBoxForElement(toElement, box);
4671:            //    }
4672:
4673:            //    /** XXX Copy also in insync/FacesDnDSupport.
4674:            //     * XXX Provides the auto value as <code>AUTO</code>, revise that, it looks very dangerous. */
4675:            //    public static int getCssLength(Element element, int property) {
4676:            ////        Value val = getValue(element, property);
4677:            //        CssValue cssValue = CssProvider.getEngineService().getComputedValueForElement(element, property);
4678:            //        
4679:            //        // XXX #6460007 Possible NPE.
4680:            //        if (cssValue == null) {
4681:            //            // XXX What value to return?
4682:            //            return 0;
4683:            //        }
4684:            //        
4685:            ////        if (val == CssValueConstants.AUTO_VALUE) {
4686:            //        if (CssProvider.getValueService().isAutoValue(cssValue)) {
4687:            //            return CssBox.AUTO;
4688:            //        }
4689:            //        
4690:            ////        return (int)val.getFloatValue();
4691:            //        return (int)cssValue.getFloatValue();
4692:            //    }
4693:
4694:            //    /** XXX Moved from DesignerActions.
4695:            //     * Returns whether or not this component is the initial focus.
4696:            //     * @param bean The bean associated with the component
4697:            //     * @return whether or not that component is the initial focus
4698:            //     */
4699:            //    private static boolean isFocus(DesignBean bean) {
4700:            //        if (bean == null) {
4701:            //            return false;
4702:            //        }
4703:            //
4704:            //        DesignBean body = getWebuiBody(bean);
4705:            //
4706:            //        if (body == null) {
4707:            //            return false;
4708:            //        }
4709:            //
4710:            //        DesignProperty prop = body.getProperty("focus");  // NOI18N
4711:            //
4712:            //        if ((prop != null) && (prop.getValue() != null)) {
4713:            //            // The property points to the client id, not the instance name!
4714:            //            return prop.getValue().equals(getClientId(bean));
4715:            //        } else {
4716:            //            return false;
4717:            //        }
4718:            //    }
4719:            //
4720:            //    // XXX Moved from DesignerActions.
4721:            //    /** Find the Body component of the page containing the given bean, if any */
4722:            //    private static DesignBean getWebuiBody(DesignBean bean) {
4723:            //        DesignBean parent = bean.getBeanParent();
4724:            //
4725:            //        while (parent != null) {
4726:            //            if (parent.getInstance() instanceof com.sun.rave.web.ui.component.Body
4727:            //            || parent.getInstance() instanceof com.sun.webui.jsf.component.Body) {
4728:            //                return parent;
4729:            //            }
4730:            //
4731:            //            parent = parent.getBeanParent();
4732:            //        }
4733:            //
4734:            //        return null;
4735:            //    }
4736:            //    
4737:            //    // XXX Moved from DesignerActions.
4738:            //    /** Get the client id for the given DesignBean */
4739:            //    private static String getClientId(DesignBean bean) {
4740:            //        Object instance = bean.getInstance();
4741:            //
4742:            //        if (!(instance instanceof UIComponent)) {
4743:            //            return null;
4744:            //        }
4745:            //
4746:            //        UIComponent uic = (UIComponent)instance;
4747:            //        DesignContext dcontext = bean.getDesignContext();
4748:            //        FacesContext fcontext = ((FacesDesignContext)dcontext).getFacesContext();
4749:            //
4750:            //        return uic.getClientId(fcontext);
4751:            //    }
4752:
4753:            private static void info(Exception ex) {
4754:                getLogger().log(Level.INFO, null, ex);
4755:            }
4756:
4757:            private static void fine(String message) {
4758:                getLogger().fine(message);
4759:            }
4760:
4761:            private static Logger getLogger() {
4762:                return Logger.getLogger(CssBox.class.getName());
4763:            }
4764:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.