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: }
|