// regular widgets.
int childInsertionIndex = 0;
// iterate all child widgets
for (int childIndex = 0; childIndex < children.size(); childIndex++) {
Widget child = (Widget) children.elementAt(childIndex);
Style childStyle;
int childPosition;
int childWidth;
if (child instanceof TextFragmentWidget) {
TextFragmentWidget fragment = (TextFragmentWidget) child;
addChild(childInsertionIndex, fragment);
childStyle = fragment.element.getComputedStyle();
childPosition = childStyle.getEnum(Style.POSITION);
fragment.setX(left);
fragment.setY(top + layoutContext.getCurrentY());
fragment.setWidth(innerMaxWidth);
// line-break and size the fragment
breakPosition = fragment.doLayout(childIndex, layoutContext,
breakPosition, lineStartIndex, childInsertionIndex);
// update position and status accordingly
if (fragment.getLineCount() > 1) {
lineStartIndex = childInsertionIndex;
}
childInsertionIndex++;
childWidth = fragment.getWidth();
} else {
// break positions are valid only for sequences of TextFragmentWidget
breakPosition = -1;
BlockWidget block = (BlockWidget) child;
childStyle = block.element.getComputedStyle();
int childDisplay = childStyle.getEnum(Style.DISPLAY);
childPosition = childStyle.getEnum(Style.POSITION);
int floating = childStyle.getEnum(Style.FLOAT);
if (childPosition == Style.ABSOLUTE || childPosition == Style.FIXED){
// absolute or fixed position: move block to its position; leave
// anything else unaffected (in particular the layout context).
addChild(block);
block.doLayout(innerMaxWidth, viewportWidth, null, true);
int left1 = marginLeft + borderLeft;
int right1 = marginRight + borderRight;
int top1 = marginTop + borderTop;
int bottom1 = marginBottom + borderBottom;
int iw = boxWidth - left1 - right1;
if (childStyle.getEnum(Style.RIGHT) != Style.AUTO) {
block.setX(boxWidth - block.boxX - right1 - block.boxWidth -
childStyle.getPx(Style.RIGHT, iw));
} else if (childStyle.getEnum(Style.LEFT) != Style.AUTO) {
block.setX(left1 + childStyle.getPx(Style.LEFT, iw) - block.boxX);
} else {
block.setX(left1 - block.boxX);
}
if (childStyle.getEnum(Style.TOP) != Style.AUTO) {
block.setY(top1 - block.boxY +
childStyle.getPx(Style.TOP, getHeight() - top1 - bottom1));
} else if (childStyle.getEnum(Style.BOTTOM) != Style.AUTO) {
block.setY(top1 - block.boxY + boxHeight -
childStyle.getPx(Style.TOP, getHeight() - top1 - bottom1));
} else {
block.setY(top + layoutContext.getCurrentY() - block.boxY);
}
} else if (floating == Style.LEFT || floating == Style.RIGHT){
// float: easy. just call layout for the block and place it.
// the block is added to the layout context, but the current
// y-position remains unchanged (advance() is not called)
addChild(block);
block.doLayout(innerMaxWidth, viewportWidth, null, true);
layoutContext.placeBox(block.boxWidth, block.boxHeight,
floating, childStyle.getEnum(Style.CLEAR));
block.setX(left + layoutContext.getBoxX() - block.boxX);
block.setY(top + layoutContext.getBoxY() - block.boxY);
} else if (childDisplay == Style.BLOCK ||
childDisplay == Style.LIST_ITEM) {
// Blocks and list items always start a new paragraph (implying a new
// line.
// if there is a pending line, adjust the alignement for it
if (layoutContext.getLineHeight() > 0) {
if (lineStartIndex != childInsertionIndex) {
adjustLine(lineStartIndex, childInsertionIndex, layoutContext);
}
layoutContext.advance(layoutContext.getLineHeight());
previousBlock = null;
}
// if the position is relative, the widget is inserted on top of
// others. Other adjustments for relative layout are made at the end
if (childPosition == Style.RELATIVE) {
addChild(block);
} else {
addChild(childInsertionIndex++, block);
}
if (layoutContext.clear(childStyle.getEnum(Style.CLEAR))) {
previousBlock = null;
}
// check whether we can collapse margins with the previous block
if (previousBlock != null) {
int m1 = previousBlock.getElement().getComputedStyle().getPx(
Style.MARGIN_BOTTOM, outerMaxWidth);
int m2 = childStyle.getPx(Style.MARGIN_TOP, outerMaxWidth);
// m1 has been applied already, the difference between m1 and m2
// still needs to be applied
int delta;
if (m1 < 0) {
if (m2 < 0) {
delta = -(m1 + m2);
} else {
delta = -m1;
}
} else if (m2 < 0) {
delta = -m2;
} else {
delta = -Math.min(m1, m2);
}
layoutContext.advance(delta);
}
int saveY = layoutContext.getCurrentY();
block.doLayout(innerMaxWidth, viewportWidth, layoutContext, false);
block.setX(left - block.boxX);
block.setY(top + saveY - block.boxY);
lineStartIndex = childInsertionIndex;
previousBlock = block;
} else {
// inline-block, needs to be inserted in the regular text flow
// similar to text fragments.
addChild(childInsertionIndex, block);
previousBlock = null;
block.doLayout(innerMaxWidth, viewportWidth, null, childDisplay != Style.TABLE);
int avail = layoutContext.getHorizontalSpace(block.boxHeight);
if (avail >= block.boxWidth) {
layoutContext.placeBox(
block.boxWidth, block.boxHeight, Style.NONE, 0);
} else {
// line break necessary
adjustLine(lineStartIndex, childInsertionIndex, layoutContext);
lineStartIndex = childInsertionIndex;
layoutContext.advance(layoutContext.getLineHeight());
layoutContext.placeBox(
block.boxWidth, block.boxHeight, Style.NONE, 0);
layoutContext.advance(layoutContext.getBoxY() -
layoutContext.getCurrentY());
layoutContext.setLineHeight(block.boxHeight);
}
block.setX(left + layoutContext.getBoxX() - block.boxX);
block.setY(top + layoutContext.getCurrentY() - block.boxY);
childInsertionIndex++;
}
childWidth = block.boxWidth;
}
// Make adjustments for relative positioning
if (childPosition == Style.RELATIVE) {
if (childStyle.isSet(Style.RIGHT)) {
child.setX(child.getX() + boxWidth - childWidth -
childStyle.getPx(Style.RIGHT, getWidth()));
} else {
child.setX(child.getX() + childStyle.getPx(Style.LEFT, getWidth()));
}
child.setY(child.getY() + childStyle.getPx(Style.TOP, getHeight()));
}
}
// Still need to adjust alignment if there is a pending line.
if (lineStartIndex != childInsertionIndex &&