* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+// All geometry here is absolute to the formatting context's root.
class FloatingContext {
- constructor(formattingContext) {
- this.m_leftFloatingBoxStack = new Array();
- this.m_rightFloatingBoxStack = new Array();
- this.m_lastFloating = null;
- this.m_formattingContext = formattingContext;
+ constructor(floatingState) {
+ this.m_floatingState = floatingState;
}
computePosition(layoutBox) {
if (layoutBox.isOutOfFlowPositioned())
return;
- let displayBox = this._formattingContext().toDisplayBox(layoutBox);
+ let displayBox = this._formattingState().displayBox(layoutBox);
if (layoutBox.isFloatingPositioned()) {
- let position = this._positionForFloating(layoutBox);
- this._addFloating(layoutBox);
- return displayBox.setTopLeft(position);
+ displayBox.setTopLeft(this._positionForFloating(layoutBox));
+ this._addFloatingBox(layoutBox);
+ return;
}
if (Utils.hasClear(layoutBox))
return displayBox.setTopLeft(this._positionForClear(layoutBox));
}
bottom() {
- let leftBottom = this._bottom(this.m_leftFloatingBoxStack);
- let rightBottom = this._bottom(this.m_rightFloatingBoxStack);
+ let leftBottom = this._bottom(this._leftFloatingStack());
+ let rightBottom = this._bottom(this._rightFloatingStack());
if (Number.isNaN(leftBottom) && Number.isNaN(rightBottom))
return Number.NaN;
if (!Number.isNaN(leftBottom) && !Number.isNaN(rightBottom))
}
_positionForFloating(floatingBox) {
+ let absoluteFloatingBox = this._mapMarginBoxToFormattingRoot(floatingBox);
if (this._isEmpty())
- return this._adjustedFloatingPosition(floatingBox, this._formattingContext().absoluteMarginBox(floatingBox).top());
- let verticalPosition = Math.max(this._formattingContext().absoluteMarginBox(floatingBox).top(), this._formattingContext().absoluteMarginBox(this.m_lastFloating).top());
- let spaceNeeded = this._formattingContext().absoluteMarginBox(floatingBox).width();
+ return this._adjustedFloatingPosition(floatingBox, absoluteFloatingBox.top());
+ let verticalPosition = Math.max(absoluteFloatingBox.top(), this._mapDisplayMarginBoxToFormattingRoot(this._lastFloating()).top());
+ let spaceNeeded = absoluteFloatingBox.width();
while (true) {
let floatingPair = this._findInnerMostLeftAndRight(verticalPosition);
if (this._availableSpace(floatingBox.containingBlock(), floatingPair) >= spaceNeeded)
_positionForClear(layoutBox) {
ASSERT(Utils.hasClear(layoutBox));
- let displayBox = this._formattingContext().toDisplayBox(layoutBox);
+ let displayBox = this._formattingState().displayBox(layoutBox);
if (this._isEmpty())
return displayBox.topLeft();
let leftBottom = Number.NaN;
let rightBottom = Number.NaN;
if (Utils.hasClearLeft(layoutBox) || Utils.hasClearBoth(layoutBox))
- leftBottom = this._bottom(this.m_leftFloatingBoxStack);
+ leftBottom = this._bottom(this._leftFloatingStack());
if (Utils.hasClearRight(layoutBox) || Utils.hasClearBoth(layoutBox))
- rightBottom = this._bottom(this.m_rightFloatingBoxStack);
+ rightBottom = this._bottom(this._rightFloatingStack());
if (!Number.isNaN(leftBottom) && !Number.isNaN(rightBottom))
return new LayoutPoint(Math.max(leftBottom, rightBottom), displayBox.left());
_computePositionToAvoidIntrudingFloats(layoutBox) {
if (!layoutBox.establishesBlockFormattingContext() || this._isEmpty())
- return this._formattingContext().toDisplayBox(layoutBox).topLeft();
+ return this._formattingState().displayBox(layoutBox).topLeft();
// The border box of a table, a block-level replaced element, or an element in the normal flow that establishes
// a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the
// margin box of any floats in the same block formatting context as the element itself.
return this._positionForFloating(layoutBox);
}
- _addFloating(floatingBox) {
- this.m_lastFloating = floatingBox;
- if (Utils.isFloatingLeft(floatingBox)) {
- this.m_leftFloatingBoxStack.push(floatingBox);
- return;
- }
- this.m_rightFloatingBoxStack.push(floatingBox);
- }
-
_findInnerMostLeftAndRight(verticalPosition) {
- let leftFloating = this._findFloatingAtVerticalPosition(verticalPosition, this.m_leftFloatingBoxStack);
- let rightFloating = this._findFloatingAtVerticalPosition(verticalPosition, this.m_rightFloatingBoxStack);
+ let leftFloating = this._findFloatingAtVerticalPosition(verticalPosition, this._leftFloatingStack());
+ let rightFloating = this._findFloatingAtVerticalPosition(verticalPosition, this._rightFloatingStack());
return { left: leftFloating, right: rightFloating };
}
let leftBottom = Number.POSITIVE_INFINITY;
let rightBottom = Number.POSITIVE_INFINITY;
if (floatingPair.left)
- leftBottom = this._formattingContext().absoluteMarginBox(floatingPair.left).bottom();
+ leftBottom = this._mapDisplayMarginBoxToFormattingRoot(floatingPair.left).bottom();
if (floatingPair.right)
- rightBottom = this._formattingContext().absoluteMarginBox(floatingPair.right).bottom();
+ rightBottom = this._mapDisplayMarginBoxToFormattingRoot(floatingPair.right).bottom();
return Math.min(leftBottom, rightBottom);
}
_availableSpace(containingBlock, floatingPair) {
+ let containingBlockContentBox = this._formattingState().displayBox(containingBlock);
if (floatingPair.left && floatingPair.right)
- return this._formattingContext().absoluteMarginBox(floatingPair.right).left() - this._formattingContext().absoluteMarginBox(floatingPair.left).right();
- if (floatingPair.left)
- return containingBlock.contentBox().width() - (this._formattingContext().absoluteMarginBox(floatingPair.left).right() - this._formattingContext().absoluteBorderBox(containingBlock).left());
+ return floatingPair.right.left() - floatingPair.left.right();
+ if (floatingPair.left) {
+ return containingBlockContentBox.width() - (this._mapDisplayMarginBoxToFormattingRoot(floatingPair.left).right() - this._mapBorderBoxToFormattingRoot(containingBlock).left());
+ }
if (floatingPair.right)
- return this._formattingContext().absoluteMarginBox(floatingPair.right).left();
- return containingBlock.contentBox().width();
+ return this._mapDisplayMarginBoxToFormattingRoot(floatingPair.right).left();
+ return containingBlockContentBox.width();
}
_findFloatingAtVerticalPosition(verticalPosition, floatingStack) {
let index = floatingStack.length;
- while (--index >= 0 && this._formattingContext().absoluteMarginBox(floatingStack[index]).bottom() <= verticalPosition);
+ while (--index >= 0 && this._mapDisplayMarginBoxToFormattingRoot(floatingStack[index]).bottom() <= verticalPosition);
return index >= 0 ? floatingStack[index] : null;
}
_isEmpty() {
- return !this.m_leftFloatingBoxStack.length && !this.m_rightFloatingBoxStack.length;
+ return !this._leftFloatingStack().length && !this._rightFloatingStack().length;
}
_adjustedFloatingPosition(floatingBox, verticalPosition, leftRightFloatings) {
let containingBlock = floatingBox.containingBlock();
// Convert all coordinates relative to formatting context's root.
- let left = this._formattingContext().absoluteContentBox(containingBlock).left();
- let right = this._formattingContext().absoluteContentBox(containingBlock).right();
+ let left = this._mapContentBoxToFormattingRoot(containingBlock).left();
+ let right = this._mapContentBoxToFormattingRoot(containingBlock).right();
if (leftRightFloatings) {
if (leftRightFloatings.left) {
- let floatingBoxRight = this._formattingContext().absoluteMarginBox(leftRightFloatings.left).right();
+ let floatingBoxRight = this._mapDisplayMarginBoxToFormattingRoot(leftRightFloatings.left).right();
if (floatingBoxRight > left)
left = floatingBoxRight;
}
if (leftRightFloatings.right) {
- let floatingBoxLeft = this._formattingContext().absoluteMarginBox(leftRightFloatings.right).left();
+ let floatingBoxLeft = this._mapDisplayMarginBoxToFormattingRoot(leftRightFloatings.right).left();
if (floatingBoxLeft < right)
right = floatingBoxLeft;
}
}
- left += this._formattingContext().marginLeft(floatingBox);
- right -= this._formattingContext().marginRight(floatingBox);
- verticalPosition += this._formattingContext().marginTop(floatingBox);
+ let floatingDisplayBox = this._formattingState().displayBox(floatingBox);
+ left += floatingDisplayBox.marginLeft();
+ right -= floatingDisplayBox.marginRight();
+ verticalPosition += floatingDisplayBox.marginTop();
// No convert them back relative to the floatingBox's containing block.
- let containingBlockLeft = this._formattingContext().absoluteBorderBox(containingBlock).left();
- let containingBlockTop = this._formattingContext().absoluteBorderBox(containingBlock).top();
+ let containingBlockLeft = this._mapBorderBoxToFormattingRoot(containingBlock).left();
+ let containingBlockTop = this._mapBorderBoxToFormattingRoot(containingBlock).top();
left -= containingBlockLeft;
right -= containingBlockLeft;
verticalPosition -= containingBlockTop;
if (Utils.isFloatingLeft(floatingBox) || !Utils.isFloatingPositioned(floatingBox))
return new LayoutPoint(verticalPosition, left);
- return new LayoutPoint(verticalPosition, right - this._formattingContext().toDisplayBox(floatingBox).rect().width());
+ return new LayoutPoint(verticalPosition, right - floatingDisplayBox.rect().width());
}
_bottom(floatingStack) {
return Number.NaN;
let max = Number.NEGATIVE_INFINITY;
for (let i = 0; i < floatingStack.length; ++i)
- max = Math.max(this._formattingContext().absoluteMarginBox(floatingStack[i]).bottom(), max);
+ max = Math.max(this._mapDisplayMarginBoxToFormattingRoot(floatingStack[i]).bottom(), max);
return max;
}
- _formattingContext() {
- return this.m_formattingContext;
+ _addFloatingBox(layoutBox) {
+ this._floatingState().addFloating(this._formattingState().displayBox(layoutBox), Utils.isFloatingLeft(layoutBox));
+ }
+
+ _mapMarginBoxToFormattingRoot(layoutBox) {
+ ASSERT(layoutBox instanceof Layout.Box);
+ return this._mapDisplayMarginBoxToFormattingRoot(this._formattingState().displayBox(layoutBox));
+ }
+
+ _mapDisplayMarginBoxToFormattingRoot(displayBox) {
+ ASSERT(displayBox instanceof Display.Box);
+ return Utils.marginBox(displayBox, this._formattingState().displayBox(this._formattingRoot()));
+ }
+
+ _mapBorderBoxToFormattingRoot(layoutBox) {
+ let displayBox = this._formattingState().displayBox(layoutBox);
+ let rootDisplayBox = this._formattingState().displayBox(this._formattingRoot());
+ return Utils.borderBox(displayBox, rootDisplayBox);
+ }
+
+ _mapContentBoxToFormattingRoot(layoutBox) {
+ let displayBox = this._formattingState().displayBox(layoutBox);
+ let rootDisplayBox = this._formattingState().displayBox(this._formattingRoot());
+ return Utils.contentBox(displayBox, rootDisplayBox);
+ }
+
+ _floatingState() {
+ return this.m_floatingState;
+ }
+
+ _formattingRoot() {
+ return this._formattingState().formattingRoot();
+ }
+
+ _formattingState() {
+ return this._floatingState().formattingState();
+ }
+
+ _lastFloating() {
+ return this._floatingState().lastFloating();
+ }
+
+ _leftFloatingStack() {
+ return this._floatingState().leftFloatingStack();
+ }
+
+ _rightFloatingStack() {
+ return this._floatingState().rightFloatingStack();
}
}