blob: 8a77346f309ff4517c6ea1a45ce085385a254b6d [file] [log] [blame]
/*
* Copyright (C) 2018 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
namespace Layout {
class Box {
public:
Layout::Container& parent();
Layout::Box* nextSibling();
Layout::Box* nextInFlowSibling();
Layout::Box* nextInFlowOrFloatSibling();
Layout::Box* previousSibling();
Layout::Box* previousInFlowSibling();
void setParent(Layout::Container&);
void setNextSibling(Layout::Box&);
void setPreviousSibling(Layout::Box&);
bool isContainer();
bool isInlineContainer();
bool isInlineBox();
bool isBlockLevelBox();
bool isBlockContainerBox();
bool isInlineBlockBox();
bool isInlineLevelBox();
void setIsAnonymous(bool);
bool isAnonymous();
bool establishesFormattingContext();
bool establishesBlockFormattingContext();
bool establishesInlineFormattingContext();
bool isPositioned();
bool isRelativelyPositioned();
bool isAbsolutelyPositioned();
bool isFixedPositioned();
bool isInFlow();
bool isOutOfFlowPositioned();
bool isInFlowPositioned();
bool isFloatingPositioned();
bool isFloatingOrOutOfFlowPositioned();
bool isRootBox();
Layout::Container* containingBlock();
bool isDescendantOf(Layout::Container&);
};
}
*/
var Layout = { }
Layout.Box = class Box {
constructor(node, id) {
this.m_id = id;
this.m_rendererName = null;
this.m_node = node;
this.m_parent = null;
this.m_nextSibling = null;
this.m_previousSibling = null;
this.m_isAnonymous = false;
this.m_displayBox = null;
}
id() {
return this.m_id;
}
setRendererName(name) {
this.m_rendererName = name;
}
name() {
return this.m_rendererName;
}
node() {
return this.m_node;
}
parent() {
return this.m_parent;
}
nextSibling() {
return this.m_nextSibling;
}
nextInFlowSibling() {
let nextInFlowSibling = this.nextSibling();
while (nextInFlowSibling) {
if (nextInFlowSibling.isInFlow())
return nextInFlowSibling;
nextInFlowSibling = nextInFlowSibling.nextSibling();
}
return null;
}
nextInFlowOrFloatSibling() {
let nextInFlowSibling = this.nextSibling();
while (nextInFlowSibling) {
if (nextInFlowSibling.isInFlow() || nextInFlowSibling.isFloatingPositioned())
return nextInFlowSibling;
nextInFlowSibling = nextInFlowSibling.nextSibling();
}
return null;
}
previousSibling() {
return this.m_previousSibling;
}
previousInFlowSibling() {
let previousInFlowSibling = this.previousSibling();
while (previousInFlowSibling) {
if (previousInFlowSibling.isInFlow())
return previousInFlowSibling;
previousInFlowSibling = previousInFlowSibling.previousSibling();
}
return null;
}
setParent(parent) {
this.m_parent = parent;
}
setNextSibling(nextSibling) {
this.m_nextSibling = nextSibling;
}
setPreviousSibling(previousSibling) {
this.m_previousSibling = previousSibling;
}
isContainer() {
return this instanceof Layout.Container
}
isInlineContainer() {
return this instanceof Layout.InlineContainer
}
isInlineBox() {
return this instanceof Layout.InlineBox;
}
isBlockLevelBox() {
return Utils.isBlockLevelElement(this.node());
}
isBlockContainerBox() {
return Utils.isBlockContainerElement(this.node());
}
isInlineBlockBox() {
return Utils.isInlineBlockElement(this.node());
}
isInlineLevelBox() {
return Utils.isInlineLevelElement(this.node());
}
setIsAnonymous() {
this.m_isAnonymous = true;
}
isAnonymous() {
return this.m_isAnonymous;
}
establishesFormattingContext() {
if (this.isAnonymous())
return false;
return this.establishesBlockFormattingContext() || this.establishesInlineFormattingContext();
}
establishesBlockFormattingContext() {
// Initial Containing Block always creates a new (inital) block formatting context.
if (!this.parent())
return true;
// 9.4.1 Block formatting contexts
// Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions)
// that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport)
// establish new block formatting contexts for their contents.
return this.isFloatingPositioned() || this.isAbsolutelyPositioned() || (this.isBlockContainerBox() && !this.isBlockLevelBox())
|| (this.isBlockLevelBox() && !Utils.isOverflowVisible(this));
}
establishesInlineFormattingContext() {
return false;
}
isPositioned() {
return this.isOutOfFlowPositioned() || this.isRelativelyPositioned();
}
isRelativelyPositioned() {
return Utils.isRelativelyPositioned(this);
}
isAbsolutelyPositioned() {
return Utils.isAbsolutelyPositioned(this) || this.isFixedPositioned();
}
isFixedPositioned() {
return Utils.isFixedPositioned(this);
}
isInFlow() {
if (this.isAnonymous())
return true;
return !this.isFloatingOrOutOfFlowPositioned();
}
isOutOfFlowPositioned() {
return this.isAbsolutelyPositioned();
}
isInFlowPositioned() {
return this.isPositioned() && !this.isOutOfFlowPositioned();
}
isFloatingPositioned() {
return Utils.isFloatingPositioned(this);
}
isFloatingOrOutOfFlowPositioned() {
return this.isFloatingPositioned() || this.isOutOfFlowPositioned();
}
isRootBox() {
// FIXME: This should just be a simple instanceof check, but we are in the mainframe while the test document is in an iframe
// Let's just return root for both the RenderView and the <html> element.
return !this.parent() || !this.parent().parent();
}
containingBlock() {
if (!this.parent())
return null;
if (!this.isPositioned() || this.isInFlowPositioned())
return this.parent();
if (this.isOutOfFlowPositioned() && !this.isFixedPositioned()) {
let ascendant = this.parent();
while (ascendant.parent() && !ascendant.isPositioned())
ascendant = ascendant.parent();
return ascendant;
}
if (this.isFixedPositioned()) {
let ascendant = this.parent();
while (ascendant.parent())
ascendant = ascendant.parent();
return ascendant;
}
ASSERT_NOT_REACHED();
return null;
}
isDescendantOf(container) {
ASSERT(container);
let ascendant = this.parent();
while (ascendant && ascendant != container)
ascendant = ascendant.parent();
return !!ascendant;
}
}