Diff
Modified: trunk/Source/WebCore/ChangeLog (250489 => 250490)
--- trunk/Source/WebCore/ChangeLog 2019-09-29 08:56:34 UTC (rev 250489)
+++ trunk/Source/WebCore/ChangeLog 2019-09-29 15:08:41 UTC (rev 250490)
@@ -1,3 +1,51 @@
+2019-09-29 Zalan Bujtas <za...@apple.com>
+
+ [LFC][IFC] Remove InlineLayout abstraction layer
+ https://bugs.webkit.org/show_bug.cgi?id=202352
+ <rdar://problem/55811532>
+
+ Reviewed by Antti Koivisto.
+
+ Move InlineLayout functions to InlineFormattingContext. Now inline layout has
+ 1. InlineFormattingContext -high level layout and preferred width computation, collecting inline content, constructing display boxes
+ 2. LineLayout -responsible for placing inline content on the current line (partial inline content handling, line breaking etc)
+ 3. Line -represents an actual line, turns inline content into runs.
+
+ * Sources.txt:
+ * WebCore.xcodeproj/project.pbxproj:
+ * layout/inlineformatting/InlineFormattingContext.cpp:
+ (WebCore::Layout::InlineFormattingContext::layoutInFlowContent):
+ (WebCore::Layout::InlineFormattingContext::lineLayout):
+ (WebCore::Layout::InlineFormattingContext::computedIntrinsicWidthConstraints):
+ (WebCore::Layout::InlineFormattingContext::computedIntrinsicWidthForConstraint const):
+ (WebCore::Layout::InlineFormattingContext::initialConstraintsForLine):
+ (WebCore::Layout::InlineFormattingContext::setDisplayBoxesForLine):
+ * layout/inlineformatting/InlineFormattingContext.h:
+ (WebCore::Layout::InlineFormattingContext::InlineLayout::layoutState const): Deleted.
+ (WebCore::Layout::InlineFormattingContext::InlineLayout::formattingContext const): Deleted.
+ (WebCore::Layout::InlineFormattingContext::InlineLayout::formattingRoot const): Deleted.
+ (WebCore::Layout::InlineFormattingContext::InlineLayout::formattingState): Deleted.
+ (WebCore::Layout::InlineFormattingContext::InlineLayout::widthConstraint const): Deleted.
+ * layout/inlineformatting/InlineFormattingContextLineLayout.cpp: Removed.
+ * layout/inlineformatting/InlineFormattingState.h:
+ (WebCore::Layout::InlineFormattingState::inlineItems const):
+ * layout/inlineformatting/InlineLineLayout.cpp: Added.
+ (WebCore::Layout::inlineItemWidth):
+ (WebCore::Layout::LineLayout::LineInput::LineInput):
+ (WebCore::Layout::LineLayout::UncommittedContent::add):
+ (WebCore::Layout::LineLayout::UncommittedContent::reset):
+ (WebCore::Layout::LineLayout::LineLayout):
+ (WebCore::Layout::LineLayout::commitPendingContent):
+ (WebCore::Layout::LineLayout::close):
+ (WebCore::Layout::LineLayout::placeInlineItem):
+ (WebCore::Layout::LineLayout::layout):
+ * layout/inlineformatting/InlineLineLayout.h: Added.
+ (WebCore::Layout::LineLayout::formattingContext const):
+ (WebCore::Layout::LineLayout::UncommittedContent::runs):
+ (WebCore::Layout::LineLayout::UncommittedContent::isEmpty const):
+ (WebCore::Layout::LineLayout::UncommittedContent::size const):
+ (WebCore::Layout::LineLayout::UncommittedContent::width const):
+
2019-09-29 Zan Dobersek <zdober...@igalia.com>
[Nicosia] Add overflow, overflow proxy node implementations
Modified: trunk/Source/WebCore/Sources.txt (250489 => 250490)
--- trunk/Source/WebCore/Sources.txt 2019-09-29 08:56:34 UTC (rev 250489)
+++ trunk/Source/WebCore/Sources.txt 2019-09-29 15:08:41 UTC (rev 250490)
@@ -1419,12 +1419,12 @@
layout/floats/FloatingState.cpp
layout/inlineformatting/InlineFormattingContext.cpp
layout/inlineformatting/InlineFormattingContextGeometry.cpp
-layout/inlineformatting/InlineFormattingContextLineLayout.cpp
layout/inlineformatting/InlineFormattingContextQuirks.cpp
layout/inlineformatting/InlineFormattingState.cpp
layout/inlineformatting/InlineInvalidation.cpp
layout/inlineformatting/InlineLine.cpp
layout/inlineformatting/InlineLineBreaker.cpp
+layout/inlineformatting/InlineLineLayout.cpp
layout/inlineformatting/InlineTextItem.cpp
layout/inlineformatting/text/TextUtil.cpp
layout/layouttree/LayoutBox.cpp
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (250489 => 250490)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2019-09-29 08:56:34 UTC (rev 250489)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2019-09-29 15:08:41 UTC (rev 250490)
@@ -2003,6 +2003,7 @@
6F0CD695229ED32700C5994E /* InlineLine.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F0CD694229ED32700C5994E /* InlineLine.h */; };
6F1CC1DE225F8B4900720AD2 /* InlineTextItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F1CC1DD225F8B4200720AD2 /* InlineTextItem.h */; settings = {ATTRIBUTES = (Private, ); }; };
6F26BB6C23343E6F002F2BEA /* LayoutContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F26BB6B23343E5B002F2BEA /* LayoutContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 6F26EB48234004A5006906E2 /* InlineLineLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F26EB46234004A5006906E2 /* InlineLineLayout.h */; };
6F3E1F622136142000A65A08 /* FloatBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F3E1F612136141700A65A08 /* FloatBox.h */; settings = {ATTRIBUTES = (Private, ); }; };
6F7CA3C6208C2957002F29AB /* LayoutState.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F7CA3C4208C2956002F29AB /* LayoutState.h */; settings = {ATTRIBUTES = (Private, ); }; };
6F7CA3CA208C2B2E002F29AB /* InlineFormattingContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F7CA3C8208C2B2E002F29AB /* InlineFormattingContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -9159,9 +9160,10 @@
6F1CC1DD225F8B4200720AD2 /* InlineTextItem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InlineTextItem.h; sourceTree = "<group>"; };
6F222B741AB52D640094651A /* WebGLVertexArrayObjectBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebGLVertexArrayObjectBase.h; sourceTree = "<group>"; };
6F222B751AB52D8A0094651A /* WebGLVertexArrayObjectBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebGLVertexArrayObjectBase.cpp; sourceTree = "<group>"; };
- 6F25B200220A85AB0000011B /* InlineFormattingContextLineLayout.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InlineFormattingContextLineLayout.cpp; sourceTree = "<group>"; };
+ 6F25B200220A85AB0000011B /* InlineLineLayout.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InlineLineLayout.cpp; sourceTree = "<group>"; };
6F26BB6923343E5A002F2BEA /* LayoutContext.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutContext.cpp; sourceTree = "<group>"; };
6F26BB6B23343E5B002F2BEA /* LayoutContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LayoutContext.h; sourceTree = "<group>"; };
+ 6F26EB46234004A5006906E2 /* InlineLineLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineLineLayout.h; sourceTree = "<group>"; };
6F35EFAF2187CBD50044E0F4 /* InlineFormattingContextGeometry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InlineFormattingContextGeometry.cpp; sourceTree = "<group>"; };
6F3E1F5F2136141700A65A08 /* FloatBox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FloatBox.cpp; sourceTree = "<group>"; };
6F3E1F612136141700A65A08 /* FloatBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FloatBox.h; sourceTree = "<group>"; };
@@ -16482,7 +16484,6 @@
6F7CA3C9208C2B2E002F29AB /* InlineFormattingContext.cpp */,
6F7CA3C8208C2B2E002F29AB /* InlineFormattingContext.h */,
6F35EFAF2187CBD50044E0F4 /* InlineFormattingContextGeometry.cpp */,
- 6F25B200220A85AB0000011B /* InlineFormattingContextLineLayout.cpp */,
6F10B08622B8568D0090E69C /* InlineFormattingContextQuirks.cpp */,
115CFA7D208B8E10001E6991 /* InlineFormattingState.cpp */,
115CFA7C208B8E10001E6991 /* InlineFormattingState.h */,
@@ -16494,6 +16495,8 @@
6FB47E612277425A00C7BCB0 /* InlineLineBox.h */,
6FE198132178397B00446F08 /* InlineLineBreaker.cpp */,
6FE198152178397C00446F08 /* InlineLineBreaker.h */,
+ 6F25B200220A85AB0000011B /* InlineLineLayout.cpp */,
+ 6F26EB46234004A5006906E2 /* InlineLineLayout.h */,
6F1CC1DC225F8B4100720AD2 /* InlineTextItem.cpp */,
6F1CC1DD225F8B4200720AD2 /* InlineTextItem.h */,
);
@@ -28306,9 +28309,9 @@
FFB698CD1833F17600158A31 /* LineInfo.cpp */,
FFB698CE1833F17600158A31 /* LineInfo.h */,
FFEFAB2D183BCB6F00514534 /* LineInlineHeaders.h */,
+ FFEFAB2918380DA000514534 /* LineLayoutState.h */,
E484A33D23055303009ADE6A /* LineLayoutTraversal.cpp */,
E484A33B23055303009ADE6A /* LineLayoutTraversal.h */,
- FFEFAB2918380DA000514534 /* LineLayoutState.h */,
FFDBC046183D27B700407109 /* LineWidth.cpp */,
FFDBC045183D27B700407109 /* LineWidth.h */,
FFAC30FD184FB145008C4F1E /* TrailingObjects.cpp */,
@@ -29749,6 +29752,7 @@
6F0CD695229ED32700C5994E /* InlineLine.h in Headers */,
6FB47E632277425A00C7BCB0 /* InlineLineBox.h in Headers */,
6FE198172178397C00446F08 /* InlineLineBreaker.h in Headers */,
+ 6F26EB48234004A5006906E2 /* InlineLineLayout.h in Headers */,
AA4C3A770B2B1679002334A2 /* InlineStyleSheetOwner.h in Headers */,
BCEA485A097D93020094C9E4 /* InlineTextBox.h in Headers */,
1C010701192594DF008A4201 /* InlineTextBoxStyle.h in Headers */,
@@ -30744,8 +30748,8 @@
84730D911248F0B300D3A9C9 /* LightSource.h in Headers */,
B22279650D00BF220071B782 /* LinearGradientAttributes.h in Headers */,
AB31C91E10AE1B8E000C7B92 /* LineClampValue.h in Headers */,
+ FFEFAB2A18380DA000514534 /* LineLayoutState.h in Headers */,
E484A33E23055325009ADE6A /* LineLayoutTraversal.h in Headers */,
- FFEFAB2A18380DA000514534 /* LineLayoutState.h in Headers */,
FFDBC047183D27B700407109 /* LineWidth.h in Headers */,
CBA9DC0B1DF44DF40005675C /* LinkHeader.h in Headers */,
5143B2631DDD15200014FAC6 /* LinkIcon.h in Headers */,
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp (250489 => 250490)
--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp 2019-09-29 08:56:34 UTC (rev 250489)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp 2019-09-29 15:08:41 UTC (rev 250490)
@@ -88,10 +88,41 @@
formattingState().inlineRuns().clear();
collectInlineContent();
- InlineLayout(*this, usedHorizontalValues).layout(formattingState().inlineItems());
+ lineLayout(usedHorizontalValues);
LOG_WITH_STREAM(FormattingContextLayout, stream << "[End] -> inline formatting context -> formatting root(" << &root() << ")");
}
+void InlineFormattingContext::lineLayout(UsedHorizontalValues usedHorizontalValues)
+{
+ auto& inlineItems = formattingState().inlineItems();
+ auto lineLogicalTop = geometryForBox(root()).contentBoxTop();
+ LineLayout::IndexAndRange currentInlineItem;
+ while (currentInlineItem.index < inlineItems.size()) {
+ auto lineConstraints = initialConstraintsForLine(usedHorizontalValues, lineLogicalTop);
+ auto lineInput = LineLayout::LineInput { lineConstraints, root().style().textAlign(), currentInlineItem, inlineItems };
+ auto lineLayout = LineLayout { *this, lineInput };
+
+ auto lineContent = lineLayout.layout();
+ setDisplayBoxesForLine(lineContent, usedHorizontalValues);
+
+ if (lineContent.lastCommitted) {
+ currentInlineItem = { lineContent.lastCommitted->index + 1, WTF::nullopt };
+ lineLogicalTop = lineContent.lineBox.logicalBottom();
+ } else {
+ // Floats prevented us placing any content on the line.
+ ASSERT(lineInput.initialConstraints.lineIsConstrainedByFloat);
+ // Move the next line below the intrusive float.
+ auto floatingContext = FloatingContext { root(), *this, formattingState().floatingState() };
+ auto floatConstraints = floatingContext.constraints({ lineLogicalTop });
+ ASSERT(floatConstraints.left || floatConstraints.right);
+ static auto inifitePoint = PointInContextRoot::max();
+ // In case of left and right constraints, we need to pick the one that's closer to the current line.
+ lineLogicalTop = std::min(floatConstraints.left.valueOr(inifitePoint).y, floatConstraints.right.valueOr(inifitePoint).y);
+ ASSERT(lineLogicalTop < inifitePoint.y);
+ }
+ }
+}
+
void InlineFormattingContext::layoutFormattingContextRoot(const Box& formattingContextRoot, UsedHorizontalValues usedHorizontalValues, UsedVerticalValues usedVerticalValues)
{
ASSERT(formattingContextRoot.isFloatingPositioned() || formattingContextRoot.isInlineBlockBox());
@@ -183,7 +214,7 @@
displayBox.setContentBoxWidth(contentWidth);
}
auto usedHorizontalValues = UsedHorizontalValues { UsedHorizontalValues::Constraints { { }, availableWidth } };
- return InlineLayout(*this, usedHorizontalValues).computedIntrinsicWidth(formattingState().inlineItems());
+ return computedIntrinsicWidthForConstraint(usedHorizontalValues);
};
auto constraints = geometry().constrainByMinMaxWidth(root(), { maximumLineWidth(0), maximumLineWidth(LayoutUnit::max()) });
@@ -191,6 +222,27 @@
return constraints;
}
+LayoutUnit InlineFormattingContext::computedIntrinsicWidthForConstraint(UsedHorizontalValues usedHorizontalValues) const
+{
+ auto& inlineItems = formattingState().inlineItems();
+ LayoutUnit maximumLineWidth;
+ LineLayout::IndexAndRange currentInlineItem;
+ while (currentInlineItem.index < inlineItems.size()) {
+ // Only the horiztonal available width is constrained when computing intrinsic width.
+ auto initialLineConstraints = Line::InitialConstraints { { }, usedHorizontalValues.constraints.width, false, { } };
+ auto lineInput = LineLayout::LineInput { initialLineConstraints, currentInlineItem, inlineItems };
+
+ auto lineContent = LineLayout(*this, lineInput).layout();
+
+ currentInlineItem = { lineContent.lastCommitted->index + 1, { } };
+ LayoutUnit floatsWidth;
+ for (auto& floatItem : lineContent.floats)
+ floatsWidth += geometryForBox(floatItem->layoutBox()).marginBoxWidth();
+ maximumLineWidth = std::max(maximumLineWidth, floatsWidth + lineContent.lineBox.logicalWidth());
+ }
+ return maximumLineWidth;
+}
+
void InlineFormattingContext::computeIntrinsicWidthForFormattingRoot(const Box& formattingRoot, UsedHorizontalValues usedHorizontalValues)
{
ASSERT(formattingRoot.establishesFormattingContext());
@@ -311,7 +363,139 @@
}
}
+Line::InitialConstraints InlineFormattingContext::initialConstraintsForLine(UsedHorizontalValues usedHorizontalValues, const LayoutUnit lineLogicalTop)
+{
+ auto lineLogicalLeft = geometryForBox(root()).contentBoxLeft();
+ auto availableWidth = usedHorizontalValues.constraints.width;
+ auto lineIsConstrainedByFloat = false;
+
+ auto floatingContext = FloatingContext { root(), *this, formattingState().floatingState() };
+ // Check for intruding floats and adjust logical left/available width for this line accordingly.
+ if (!floatingContext.isEmpty()) {
+ auto floatConstraints = floatingContext.constraints({ lineLogicalTop });
+ // Check if these constraints actually put limitation on the line.
+ if (floatConstraints.left && floatConstraints.left->x <= lineLogicalLeft)
+ floatConstraints.left = { };
+
+ auto lineLogicalRight = geometryForBox(root()).contentBoxRight();
+ if (floatConstraints.right && floatConstraints.right->x >= lineLogicalRight)
+ floatConstraints.right = { };
+
+ lineIsConstrainedByFloat = floatConstraints.left || floatConstraints.right;
+
+ if (floatConstraints.left && floatConstraints.right) {
+ ASSERT(floatConstraints.left->x <= floatConstraints.right->x);
+ availableWidth = floatConstraints.right->x - floatConstraints.left->x;
+ lineLogicalLeft = floatConstraints.left->x;
+ } else if (floatConstraints.left) {
+ ASSERT(floatConstraints.left->x >= lineLogicalLeft);
+ availableWidth -= (floatConstraints.left->x - lineLogicalLeft);
+ lineLogicalLeft = floatConstraints.left->x;
+ } else if (floatConstraints.right) {
+ ASSERT(floatConstraints.right->x >= lineLogicalLeft);
+ availableWidth = floatConstraints.right->x - lineLogicalLeft;
+ }
+ }
+ return Line::InitialConstraints { { lineLogicalLeft, lineLogicalTop }, availableWidth, lineIsConstrainedByFloat, quirks().lineHeightConstraints(root()) };
}
+
+void InlineFormattingContext::setDisplayBoxesForLine(const LineLayout::LineContent& lineContent, UsedHorizontalValues usedHorizontalValues)
+{
+ auto& formattingState = this->formattingState();
+
+ if (!lineContent.floats.isEmpty()) {
+ auto floatingContext = FloatingContext { root(), *this, formattingState.floatingState() };
+ // Move floats to their final position.
+ for (const auto& floatItem : lineContent.floats) {
+ auto& floatBox = floatItem->layoutBox();
+ auto& displayBox = formattingState.displayBox(floatBox);
+ // Set static position first.
+ auto& lineBox = lineContent.lineBox;
+ displayBox.setTopLeft({ lineBox.logicalLeft(), lineBox.logicalTop() });
+ // Float it.
+ displayBox.setTopLeft(floatingContext.positionForFloat(floatBox));
+ floatingContext.append(floatBox);
+ }
+ }
+
+ // Add final display runs to state.
+ for (auto& lineRun : lineContent.runList) {
+ // Inline level containers (<span>) don't generate inline runs.
+ if (lineRun->isContainerStart() || lineRun->isContainerEnd())
+ continue;
+ // Collapsed line runs don't generate display runs.
+ if (lineRun->isVisuallyEmpty())
+ continue;
+ formattingState.addInlineRun(lineRun->displayRun());
+ }
+
+ // Compute box final geometry.
+ auto& lineRuns = lineContent.runList;
+ for (unsigned index = 0; index < lineRuns.size(); ++index) {
+ auto& lineRun = lineRuns.at(index);
+ auto& logicalRect = lineRun->logicalRect();
+ auto& layoutBox = lineRun->layoutBox();
+ auto& displayBox = formattingState.displayBox(layoutBox);
+
+ if (lineRun->isLineBreak()) {
+ displayBox.setTopLeft(logicalRect.topLeft());
+ displayBox.setContentBoxWidth(logicalRect.width());
+ displayBox.setContentBoxHeight(logicalRect.height());
+ continue;
+ }
+
+ // Inline level box (replaced or inline-block)
+ if (lineRun->isBox()) {
+ auto topLeft = logicalRect.topLeft();
+ if (layoutBox.isInFlowPositioned())
+ topLeft += geometry().inFlowPositionedPositionOffset(layoutBox, usedHorizontalValues);
+ displayBox.setTopLeft(topLeft);
+ continue;
+ }
+
+ // Inline level container start (<span>)
+ if (lineRun->isContainerStart()) {
+ displayBox.setTopLeft(logicalRect.topLeft());
+ continue;
+ }
+
+ // Inline level container end (</span>)
+ if (lineRun->isContainerEnd()) {
+ if (layoutBox.isInFlowPositioned()) {
+ auto inflowOffset = geometry().inFlowPositionedPositionOffset(layoutBox, usedHorizontalValues);
+ displayBox.moveHorizontally(inflowOffset.width());
+ displayBox.moveVertically(inflowOffset.height());
+ }
+ auto marginBoxWidth = logicalRect.left() - displayBox.left();
+ auto contentBoxWidth = marginBoxWidth - (displayBox.marginStart() + displayBox.borderLeft() + displayBox.paddingLeft().valueOr(0));
+ // FIXME fix it for multiline.
+ displayBox.setContentBoxWidth(contentBoxWidth);
+ displayBox.setContentBoxHeight(logicalRect.height());
+ continue;
+ }
+
+ if (lineRun->isText()) {
+ const Line::Run* previousLineRun = !index ? nullptr : lineRuns[index - 1].get();
+ // FIXME take content breaking into account when part of the layout box is on the previous line.
+ auto firstInlineRunForLayoutBox = !previousLineRun || &previousLineRun->layoutBox() != &layoutBox;
+ auto logicalWidth = lineRun->isVisuallyEmpty() ? LayoutUnit() : logicalRect.width();
+ if (firstInlineRunForLayoutBox) {
+ // Setup display box for the associated layout box.
+ displayBox.setTopLeft(logicalRect.topLeft());
+ displayBox.setContentBoxWidth(logicalWidth);
+ displayBox.setContentBoxHeight(logicalRect.height());
+ } else {
+ // FIXME fix it for multirun/multiline.
+ displayBox.setContentBoxWidth(displayBox.contentBoxWidth() + logicalWidth);
+ }
+ continue;
+ }
+ ASSERT_NOT_REACHED();
+ }
+ formattingState.addLineBox(lineContent.lineBox);
}
+}
+}
+
#endif
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h (250489 => 250490)
--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h 2019-09-29 08:56:34 UTC (rev 250489)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h 2019-09-29 15:08:41 UTC (rev 250490)
@@ -31,6 +31,7 @@
#include "FormattingContext.h"
#include "InlineFormattingState.h"
#include "InlineLine.h"
+#include "InlineLineLayout.h"
#include <wtf/IsoMalloc.h>
namespace WebCore {
@@ -51,29 +52,6 @@
private:
IntrinsicWidthConstraints computedIntrinsicWidthConstraints() override;
- class InlineLayout {
- public:
- InlineLayout(InlineFormattingContext&, UsedHorizontalValues);
- void layout(const InlineItems&);
- LayoutUnit computedIntrinsicWidth(const InlineItems&) const;
-
- private:
- Line::InitialConstraints initialConstraintsForLine(const LayoutUnit lineLogicalTop);
-
- LayoutState& layoutState() const { return m_inlineFormattingContext.layoutState(); }
- InlineFormattingContext& formattingContext() const { return m_inlineFormattingContext; }
- const Container& formattingRoot() const { return m_inlineFormattingContext.root(); }
- InlineFormattingState& formattingState() { return m_inlineFormattingContext.formattingState(); }
- LayoutUnit widthConstraint() const { return m_usedHorizontalValues.constraints.width; }
-
- LineContent placeInlineItems(const LineInput&) const;
- void setupDisplayBoxes(const LineContent&);
-
- private:
- InlineFormattingContext& m_inlineFormattingContext;
- UsedHorizontalValues m_usedHorizontalValues;
- };
-
class Quirks : public FormattingContext::Quirks {
public:
bool lineDescentNeedsCollapsing(const Line::RunList&) const;
@@ -102,11 +80,13 @@
};
InlineFormattingContext::Geometry geometry() const { return Geometry(*this); }
+ void lineLayout(UsedHorizontalValues);
void layoutFormattingContextRoot(const Box&, UsedHorizontalValues, UsedVerticalValues);
void computeHorizontalAndVerticalGeometry(const Box&, UsedHorizontalValues, UsedVerticalValues);
void computeIntrinsicWidthForFormattingRoot(const Box&, UsedHorizontalValues);
void computeWidthAndHeightForReplacedInlineBox(const Box&, UsedHorizontalValues, UsedVerticalValues);
+ LayoutUnit computedIntrinsicWidthForConstraint(UsedHorizontalValues) const;
void computeHorizontalMargin(const Box&, UsedHorizontalValues);
void computeHeightAndMargin(const Box&, UsedHorizontalValues, UsedVerticalValues);
@@ -113,12 +93,13 @@
void computeWidthAndMargin(const Box&, UsedHorizontalValues);
void collectInlineContent();
+ Line::InitialConstraints initialConstraintsForLine(UsedHorizontalValues, const LayoutUnit lineLogicalTop);
+ void setDisplayBoxesForLine(const LineLayout::LineContent&, UsedHorizontalValues);
const InlineFormattingState& formattingState() const { return downcast<InlineFormattingState>(FormattingContext::formattingState()); }
InlineFormattingState& formattingState() { return downcast<InlineFormattingState>(FormattingContext::formattingState()); }
// FIXME: Come up with a structure that requires no friending.
friend class Line;
- friend class InlineLayout;
};
inline InlineFormattingContext::Geometry::Geometry(const InlineFormattingContext& inlineFormattingContext)
Deleted: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextLineLayout.cpp (250489 => 250490)
--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextLineLayout.cpp 2019-09-29 08:56:34 UTC (rev 250489)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextLineLayout.cpp 2019-09-29 15:08:41 UTC (rev 250490)
@@ -1,471 +0,0 @@
-/*
- * Copyright (C) 2019 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. AND ITS CONTRIBUTORS ``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 ITS 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.
- */
-
-#include "config.h"
-#include "InlineFormattingContext.h"
-
-#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
-
-#include "FloatingContext.h"
-#include "FloatingState.h"
-#include "InlineFormattingState.h"
-#include "InlineLine.h"
-#include "InlineLineBreaker.h"
-#include "LayoutBox.h"
-#include "LayoutContainer.h"
-#include "LayoutState.h"
-#include "TextUtil.h"
-
-namespace WebCore {
-namespace Layout {
-
-static LayoutUnit inlineItemWidth(const FormattingContext& formattingContext, const InlineItem& inlineItem, LayoutUnit contentLogicalLeft)
-{
- if (inlineItem.isLineBreak())
- return 0;
-
- if (is<InlineTextItem>(inlineItem)) {
- auto& inlineTextItem = downcast<InlineTextItem>(inlineItem);
- auto end = inlineTextItem.isCollapsed() ? inlineTextItem.start() + 1 : inlineTextItem.end();
- return TextUtil::width(inlineTextItem.layoutBox(), inlineTextItem.start(), end, contentLogicalLeft);
- }
-
- auto& layoutBox = inlineItem.layoutBox();
- auto& boxGeometry = formattingContext.geometryForBox(layoutBox);
-
- if (layoutBox.isFloatingPositioned())
- return boxGeometry.marginBoxWidth();
-
- if (layoutBox.replaced())
- return boxGeometry.width();
-
- if (inlineItem.isContainerStart())
- return boxGeometry.marginStart() + boxGeometry.borderLeft() + boxGeometry.paddingLeft().valueOr(0);
-
- if (inlineItem.isContainerEnd())
- return boxGeometry.marginEnd() + boxGeometry.borderRight() + boxGeometry.paddingRight().valueOr(0);
-
- // Non-replaced inline box (e.g. inline-block)
- return boxGeometry.width();
-}
-
-struct IndexAndRange {
- unsigned index { 0 };
- struct Range {
- unsigned start { 0 };
- unsigned length { 0 };
- };
- Optional<Range> partialContext;
-};
-
-struct LineInput {
- LineInput(const Line::InitialConstraints&, TextAlignMode, IndexAndRange firstToProcess, const InlineItems&);
- LineInput(const Line::InitialConstraints&, IndexAndRange firstToProcess, const InlineItems&);
-
- Line::InitialConstraints initialConstraints;
- TextAlignMode horizontalAlignment;
- // FIXME Alternatively we could just have a second pass with vertical positioning (preferred width computation opts out)
- Line::SkipAlignment skipAlignment { Line::SkipAlignment::No };
- IndexAndRange firstInlineItem;
- const InlineItems& inlineItems;
- Optional<LayoutUnit> floatMinimumLogicalBottom;
-};
-
-LineInput::LineInput(const Line::InitialConstraints& initialLineConstraints, TextAlignMode horizontalAlignment, IndexAndRange firstToProcess, const InlineItems& inlineItems)
- : initialConstraints(initialLineConstraints)
- , horizontalAlignment(horizontalAlignment)
- , firstInlineItem(firstToProcess)
- , inlineItems(inlineItems)
-{
-}
-
-LineInput::LineInput(const Line::InitialConstraints& initialLineConstraints, IndexAndRange firstToProcess, const InlineItems& inlineItems)
- : initialConstraints(initialLineConstraints)
- , skipAlignment(Line::SkipAlignment::Yes)
- , firstInlineItem(firstToProcess)
- , inlineItems(inlineItems)
-{
-}
-
-struct LineContent {
- Optional<IndexAndRange> lastCommitted;
- Vector<WeakPtr<InlineItem>> floats;
- const Line::RunList runList;
- const LineBox lineBox;
-};
-
-class LineLayout {
-public:
- LineLayout(const InlineFormattingContext&, const LineInput&);
-
- LineContent layout();
-
-private:
- const InlineFormattingContext& formattingContext() const { return m_inlineFormattingContext; }
- enum class IsEndOfLine { No, Yes };
- IsEndOfLine placeInlineItem(const InlineItem&);
- void commitPendingContent();
- LineContent close();
-
- struct UncommittedContent {
- struct Run {
- const InlineItem& inlineItem;
- LayoutUnit logicalWidth;
- };
- void add(const InlineItem&, LayoutUnit logicalWidth);
- void reset();
-
- Vector<Run> runs() { return m_uncommittedRuns; }
- bool isEmpty() const { return m_uncommittedRuns.isEmpty(); }
- unsigned size() const { return m_uncommittedRuns.size(); }
- LayoutUnit width() const { return m_width; }
-
- private:
- Vector<Run> m_uncommittedRuns;
- LayoutUnit m_width;
- };
-
- const InlineFormattingContext& m_inlineFormattingContext;
- const LineInput& m_lineInput;
- Line m_line;
- LineBreaker m_lineBreaker;
- bool m_lineHasIntrusiveFloat { false };
- UncommittedContent m_uncommittedContent;
- unsigned m_committedInlineItemCount { 0 };
- Vector<WeakPtr<InlineItem>> m_floats;
- std::unique_ptr<InlineTextItem> m_leadingPartialInlineTextItem;
- std::unique_ptr<InlineTextItem> m_trailingPartialInlineTextItem;
-};
-
-void LineLayout::UncommittedContent::add(const InlineItem& inlineItem, LayoutUnit logicalWidth)
-{
- m_uncommittedRuns.append({ inlineItem, logicalWidth });
- m_width += logicalWidth;
-}
-
-void LineLayout::UncommittedContent::reset()
-{
- m_uncommittedRuns.clear();
- m_width = 0;
-}
-
-LineLayout::LineLayout(const InlineFormattingContext& inlineFormattingContext, const LineInput& lineInput)
- : m_inlineFormattingContext(inlineFormattingContext)
- , m_lineInput(lineInput)
- , m_line(inlineFormattingContext, lineInput.initialConstraints, lineInput.horizontalAlignment, lineInput.skipAlignment)
- , m_lineHasIntrusiveFloat(lineInput.initialConstraints.lineIsConstrainedByFloat)
-{
-}
-
-void LineLayout::commitPendingContent()
-{
- if (m_uncommittedContent.isEmpty())
- return;
- m_committedInlineItemCount += m_uncommittedContent.size();
- for (auto& uncommittedRun : m_uncommittedContent.runs())
- m_line.append(uncommittedRun.inlineItem, uncommittedRun.logicalWidth);
- m_uncommittedContent.reset();
-}
-
-LineContent LineLayout::close()
-{
- ASSERT(m_committedInlineItemCount || m_lineHasIntrusiveFloat);
- if (!m_committedInlineItemCount)
- return LineContent { WTF::nullopt, WTFMove(m_floats), m_line.close(), m_line.lineBox() };
-
- auto lastInlineItemIndex = m_lineInput.firstInlineItem.index + m_committedInlineItemCount - 1;
- Optional<IndexAndRange::Range> partialContext;
- if (m_trailingPartialInlineTextItem)
- partialContext = IndexAndRange::Range { m_trailingPartialInlineTextItem->start(), m_trailingPartialInlineTextItem->length() };
-
- auto lastCommitedItem = IndexAndRange { lastInlineItemIndex, partialContext };
- return LineContent { lastCommitedItem, WTFMove(m_floats), m_line.close(), m_line.lineBox() };
-}
-
-LineLayout::IsEndOfLine LineLayout::placeInlineItem(const InlineItem& inlineItem)
-{
- auto availableWidth = m_line.availableWidth() - m_uncommittedContent.width();
- auto currentLogicalRight = m_line.lineBox().logicalRight() + m_uncommittedContent.width();
- auto itemLogicalWidth = inlineItemWidth(formattingContext(), inlineItem, currentLogicalRight);
-
- // FIXME: Ensure LineContext::trimmableWidth includes uncommitted content if needed.
- auto lineIsConsideredEmpty = !m_line.hasContent() && !m_lineHasIntrusiveFloat;
- auto breakingContext = m_lineBreaker.breakingContext(inlineItem, itemLogicalWidth, { availableWidth, currentLogicalRight, m_line.trailingTrimmableWidth(), lineIsConsideredEmpty });
- if (breakingContext.isAtBreakingOpportunity)
- commitPendingContent();
-
- // Content does not fit the current line.
- if (breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Wrap)
- return IsEndOfLine::Yes;
-
- // Partial content stays on the current line.
- if (breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Split) {
- ASSERT(inlineItem.isText());
- auto& inlineTextItem = downcast<InlineTextItem>(inlineItem);
- auto splitData = TextUtil::split(inlineTextItem.layoutBox(), inlineTextItem.start(), inlineTextItem.length(), itemLogicalWidth, availableWidth, currentLogicalRight);
- // Construct a partial trailing inline item.
- ASSERT(!m_trailingPartialInlineTextItem);
- m_trailingPartialInlineTextItem = inlineTextItem.split(splitData.start, splitData.length);
- m_uncommittedContent.add(*m_trailingPartialInlineTextItem, splitData.logicalWidth);
- commitPendingContent();
- return IsEndOfLine::Yes;
- }
-
- ASSERT(breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Keep);
- if (inlineItem.isFloat()) {
- auto& floatBox = inlineItem.layoutBox();
- // Shrink available space for current line and move existing inline runs.
- auto floatBoxWidth = formattingContext().geometryForBox(floatBox).marginBoxWidth();
- floatBox.isLeftFloatingPositioned() ? m_line.moveLogicalLeft(floatBoxWidth) : m_line.moveLogicalRight(floatBoxWidth);
- m_floats.append(makeWeakPtr(inlineItem));
- ++m_committedInlineItemCount;
- m_lineHasIntrusiveFloat = true;
- return IsEndOfLine::No;
- }
-
- m_uncommittedContent.add(inlineItem, itemLogicalWidth);
- if (breakingContext.isAtBreakingOpportunity)
- commitPendingContent();
-
- return inlineItem.isHardLineBreak() ? IsEndOfLine::Yes : IsEndOfLine::No;
-}
-
-LineContent LineLayout::layout()
-{
- // Iterate through the inline content and place the inline boxes on the current line.
- // Start with the partial text from the previous line.
- auto firstInlineItem = m_lineInput.firstInlineItem;
- unsigned firstNonPartialIndex = firstInlineItem.index;
- if (firstInlineItem.partialContext) {
- // Handle partial inline item (split text from the previous line).
- auto& originalTextItem = m_lineInput.inlineItems[firstInlineItem.index];
- RELEASE_ASSERT(originalTextItem->isText());
-
- auto textRange = *firstInlineItem.partialContext;
- // Construct a partial leading inline item.
- ASSERT(!m_leadingPartialInlineTextItem);
- m_leadingPartialInlineTextItem = downcast<InlineTextItem>(*originalTextItem).split(textRange.start, textRange.length);
- if (placeInlineItem(*m_leadingPartialInlineTextItem) == IsEndOfLine::Yes)
- return close();
- ++firstNonPartialIndex;
- }
-
- for (auto inlineItemIndex = firstNonPartialIndex; inlineItemIndex < m_lineInput.inlineItems.size(); ++inlineItemIndex) {
- if (placeInlineItem(*m_lineInput.inlineItems[inlineItemIndex]) == IsEndOfLine::Yes)
- return close();
- }
- commitPendingContent();
- return close();
-}
-
-InlineFormattingContext::InlineLayout::InlineLayout(InlineFormattingContext& inlineFormattingContext, UsedHorizontalValues usedHorizontalValues)
- : m_inlineFormattingContext(inlineFormattingContext)
- , m_usedHorizontalValues(usedHorizontalValues)
-{
-}
-
-void InlineFormattingContext::InlineLayout::layout(const InlineItems& inlineItems)
-{
- auto lineLogicalTop = formattingContext().geometryForBox(formattingRoot()).contentBoxTop();
- IndexAndRange currentInlineItem;
- while (currentInlineItem.index < inlineItems.size()) {
- auto lineInput = LineInput { initialConstraintsForLine(lineLogicalTop), formattingRoot().style().textAlign(), currentInlineItem, inlineItems };
- auto lineLayout = LineLayout { formattingContext(), lineInput };
-
- auto lineContent = lineLayout.layout();
- setupDisplayBoxes(lineContent);
-
- if (lineContent.lastCommitted) {
- currentInlineItem = { lineContent.lastCommitted->index + 1, WTF::nullopt };
- lineLogicalTop = lineContent.lineBox.logicalBottom();
- } else {
- // Floats prevented us placing any content on the line.
- ASSERT(lineInput.initialConstraints.lineIsConstrainedByFloat);
- // Move the next line below the intrusive float.
- auto floatingContext = FloatingContext { formattingRoot(), formattingContext(), formattingState().floatingState() };
- auto floatConstraints = floatingContext.constraints({ lineLogicalTop });
- ASSERT(floatConstraints.left || floatConstraints.right);
- static auto inifitePoint = PointInContextRoot::max();
- // In case of left and right constraints, we need to pick the one that's closer to the current line.
- lineLogicalTop = std::min(floatConstraints.left.valueOr(inifitePoint).y, floatConstraints.right.valueOr(inifitePoint).y);
- ASSERT(lineLogicalTop < inifitePoint.y);
- }
- }
-}
-
-Line::InitialConstraints InlineFormattingContext::InlineLayout::initialConstraintsForLine(const LayoutUnit lineLogicalTop)
-{
- auto lineLogicalLeft = formattingContext().geometryForBox(formattingRoot()).contentBoxLeft();
- auto availableWidth = widthConstraint();
- auto lineIsConstrainedByFloat = false;
-
- auto floatingContext = FloatingContext { formattingRoot(), formattingContext(), formattingState().floatingState() };
- // Check for intruding floats and adjust logical left/available width for this line accordingly.
- if (!floatingContext.isEmpty()) {
- auto floatConstraints = floatingContext.constraints({ lineLogicalTop });
- // Check if these constraints actually put limitation on the line.
- if (floatConstraints.left && floatConstraints.left->x <= lineLogicalLeft)
- floatConstraints.left = { };
-
- auto lineLogicalRight = formattingContext().geometryForBox(formattingRoot()).contentBoxRight();
- if (floatConstraints.right && floatConstraints.right->x >= lineLogicalRight)
- floatConstraints.right = { };
-
- lineIsConstrainedByFloat = floatConstraints.left || floatConstraints.right;
-
- if (floatConstraints.left && floatConstraints.right) {
- ASSERT(floatConstraints.left->x <= floatConstraints.right->x);
- availableWidth = floatConstraints.right->x - floatConstraints.left->x;
- lineLogicalLeft = floatConstraints.left->x;
- } else if (floatConstraints.left) {
- ASSERT(floatConstraints.left->x >= lineLogicalLeft);
- availableWidth -= (floatConstraints.left->x - lineLogicalLeft);
- lineLogicalLeft = floatConstraints.left->x;
- } else if (floatConstraints.right) {
- ASSERT(floatConstraints.right->x >= lineLogicalLeft);
- availableWidth = floatConstraints.right->x - lineLogicalLeft;
- }
- }
- return Line::InitialConstraints { { lineLogicalLeft, lineLogicalTop }, availableWidth, lineIsConstrainedByFloat, formattingContext().quirks().lineHeightConstraints(formattingRoot()) };
-}
-
-LayoutUnit InlineFormattingContext::InlineLayout::computedIntrinsicWidth(const InlineItems& inlineItems) const
-{
- auto& formattingContext = this->formattingContext();
- LayoutUnit maximumLineWidth;
- IndexAndRange currentInlineItem;
- while (currentInlineItem.index < inlineItems.size()) {
- // Only the horiztonal available width is constrained when computing intrinsic width.
- auto initialLineConstraints = Line::InitialConstraints { { }, widthConstraint(), false, { } };
- auto lineInput = LineInput { initialLineConstraints, currentInlineItem, inlineItems };
-
- auto lineContent = LineLayout(formattingContext, lineInput).layout();
-
- currentInlineItem = { lineContent.lastCommitted->index + 1, { } };
- LayoutUnit floatsWidth;
- for (auto& floatItem : lineContent.floats)
- floatsWidth += formattingContext.geometryForBox(floatItem->layoutBox()).marginBoxWidth();
- maximumLineWidth = std::max(maximumLineWidth, floatsWidth + lineContent.lineBox.logicalWidth());
- }
- return maximumLineWidth;
-}
-
-void InlineFormattingContext::InlineLayout::setupDisplayBoxes(const LineContent& lineContent)
-{
- auto& formattingContext = this->formattingContext();
- auto& formattingState = this->formattingState();
- auto floatingContext = FloatingContext { formattingRoot(), formattingContext, formattingState.floatingState() };
-
- // Move floats to their final position.
- for (const auto& floatItem : lineContent.floats) {
- auto& floatBox = floatItem->layoutBox();
- auto& displayBox = formattingState.displayBox(floatBox);
- // Set static position first.
- auto& lineBox = lineContent.lineBox;
- displayBox.setTopLeft({ lineBox.logicalLeft(), lineBox.logicalTop() });
- // Float it.
- displayBox.setTopLeft(floatingContext.positionForFloat(floatBox));
- floatingContext.append(floatBox);
- }
-
- // Add final display runs to state.
- for (auto& lineRun : lineContent.runList) {
- // Inline level containers (<span>) don't generate inline runs.
- if (lineRun->isContainerStart() || lineRun->isContainerEnd())
- continue;
- formattingState.addInlineRun(lineRun->displayRun());
- }
-
- // Compute box final geometry.
- auto geometry = formattingContext.geometry();
- auto& lineRuns = lineContent.runList;
- for (unsigned index = 0; index < lineRuns.size(); ++index) {
- auto& lineRun = lineRuns.at(index);
- auto& logicalRect = lineRun->logicalRect();
- auto& layoutBox = lineRun->layoutBox();
- auto& displayBox = formattingState.displayBox(layoutBox);
-
- if (lineRun->isLineBreak()) {
- displayBox.setTopLeft(logicalRect.topLeft());
- displayBox.setContentBoxWidth(logicalRect.width());
- displayBox.setContentBoxHeight(logicalRect.height());
- continue;
- }
-
- // Inline level box (replaced or inline-block)
- if (lineRun->isBox()) {
- auto topLeft = logicalRect.topLeft();
- if (layoutBox.isInFlowPositioned())
- topLeft += geometry.inFlowPositionedPositionOffset(layoutBox, m_usedHorizontalValues);
- displayBox.setTopLeft(topLeft);
- continue;
- }
-
- // Inline level container start (<span>)
- if (lineRun->isContainerStart()) {
- displayBox.setTopLeft(logicalRect.topLeft());
- continue;
- }
-
- // Inline level container end (</span>)
- if (lineRun->isContainerEnd()) {
- if (layoutBox.isInFlowPositioned()) {
- auto inflowOffset = geometry.inFlowPositionedPositionOffset(layoutBox, m_usedHorizontalValues);
- displayBox.moveHorizontally(inflowOffset.width());
- displayBox.moveVertically(inflowOffset.height());
- }
- auto marginBoxWidth = logicalRect.left() - displayBox.left();
- auto contentBoxWidth = marginBoxWidth - (displayBox.marginStart() + displayBox.borderLeft() + displayBox.paddingLeft().valueOr(0));
- // FIXME fix it for multiline.
- displayBox.setContentBoxWidth(contentBoxWidth);
- displayBox.setContentBoxHeight(logicalRect.height());
- continue;
- }
-
- if (lineRun->isText()) {
- const Line::Run* previousLineRun = !index ? nullptr : lineRuns[index - 1].get();
- // FIXME take content breaking into account when part of the layout box is on the previous line.
- auto firstInlineRunForLayoutBox = !previousLineRun || &previousLineRun->layoutBox() != &layoutBox;
- auto logicalWidth = lineRun->isVisuallyEmpty() ? LayoutUnit() : logicalRect.width();
- if (firstInlineRunForLayoutBox) {
- // Setup display box for the associated layout box.
- displayBox.setTopLeft(logicalRect.topLeft());
- displayBox.setContentBoxWidth(logicalWidth);
- displayBox.setContentBoxHeight(logicalRect.height());
- } else {
- // FIXME fix it for multirun/multiline.
- displayBox.setContentBoxWidth(displayBox.contentBoxWidth() + logicalWidth);
- }
- continue;
- }
- ASSERT_NOT_REACHED();
- }
- formattingState.addLineBox(lineContent.lineBox);
-}
-
-}
-}
-
-#endif
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingState.h (250489 => 250490)
--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingState.h 2019-09-29 08:56:34 UTC (rev 250489)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingState.h 2019-09-29 15:08:41 UTC (rev 250490)
@@ -49,6 +49,7 @@
virtual ~InlineFormattingState();
InlineItems& inlineItems() { return m_inlineItems; }
+ const InlineItems& inlineItems() const { return m_inlineItems; }
void addInlineItem(std::unique_ptr<InlineItem>&& inlineItem) { m_inlineItems.append(WTFMove(inlineItem)); }
InlineRuns& inlineRuns() { return m_inlineRuns; }
Added: trunk/Source/WebCore/layout/inlineformatting/InlineLineLayout.cpp (0 => 250490)
--- trunk/Source/WebCore/layout/inlineformatting/InlineLineLayout.cpp (rev 0)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineLayout.cpp 2019-09-29 15:08:41 UTC (rev 250490)
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2019 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+#include "config.h"
+#include "InlineLineLayout.h"
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "FloatingContext.h"
+#include "FloatingState.h"
+#include "InlineFormattingState.h"
+#include "LayoutBox.h"
+#include "TextUtil.h"
+
+namespace WebCore {
+namespace Layout {
+
+static LayoutUnit inlineItemWidth(const FormattingContext& formattingContext, const InlineItem& inlineItem, LayoutUnit contentLogicalLeft)
+{
+ if (inlineItem.isLineBreak())
+ return 0;
+
+ if (is<InlineTextItem>(inlineItem)) {
+ auto& inlineTextItem = downcast<InlineTextItem>(inlineItem);
+ auto end = inlineTextItem.isCollapsed() ? inlineTextItem.start() + 1 : inlineTextItem.end();
+ return TextUtil::width(inlineTextItem.layoutBox(), inlineTextItem.start(), end, contentLogicalLeft);
+ }
+
+ auto& layoutBox = inlineItem.layoutBox();
+ auto& boxGeometry = formattingContext.geometryForBox(layoutBox);
+
+ if (layoutBox.isFloatingPositioned())
+ return boxGeometry.marginBoxWidth();
+
+ if (layoutBox.replaced())
+ return boxGeometry.width();
+
+ if (inlineItem.isContainerStart())
+ return boxGeometry.marginStart() + boxGeometry.borderLeft() + boxGeometry.paddingLeft().valueOr(0);
+
+ if (inlineItem.isContainerEnd())
+ return boxGeometry.marginEnd() + boxGeometry.borderRight() + boxGeometry.paddingRight().valueOr(0);
+
+ // Non-replaced inline box (e.g. inline-block)
+ return boxGeometry.width();
+}
+
+LineLayout::LineInput::LineInput(const Line::InitialConstraints& initialLineConstraints, TextAlignMode horizontalAlignment, IndexAndRange firstToProcess, const InlineItems& inlineItems)
+ : initialConstraints(initialLineConstraints)
+ , horizontalAlignment(horizontalAlignment)
+ , firstInlineItem(firstToProcess)
+ , inlineItems(inlineItems)
+{
+}
+
+LineLayout::LineInput::LineInput(const Line::InitialConstraints& initialLineConstraints, IndexAndRange firstToProcess, const InlineItems& inlineItems)
+ : initialConstraints(initialLineConstraints)
+ , skipAlignment(Line::SkipAlignment::Yes)
+ , firstInlineItem(firstToProcess)
+ , inlineItems(inlineItems)
+{
+}
+
+void LineLayout::UncommittedContent::add(const InlineItem& inlineItem, LayoutUnit logicalWidth)
+{
+ m_uncommittedRuns.append({ inlineItem, logicalWidth });
+ m_width += logicalWidth;
+}
+
+void LineLayout::UncommittedContent::reset()
+{
+ m_uncommittedRuns.clear();
+ m_width = 0;
+}
+
+LineLayout::LineLayout(const InlineFormattingContext& inlineFormattingContext, const LineInput& lineInput)
+ : m_inlineFormattingContext(inlineFormattingContext)
+ , m_lineInput(lineInput)
+ , m_line(inlineFormattingContext, lineInput.initialConstraints, lineInput.horizontalAlignment, lineInput.skipAlignment)
+ , m_lineHasIntrusiveFloat(lineInput.initialConstraints.lineIsConstrainedByFloat)
+{
+}
+
+LineLayout::LineContent LineLayout::layout()
+{
+ // Iterate through the inline content and place the inline boxes on the current line.
+ // Start with the partial text from the previous line.
+ auto firstInlineItem = m_lineInput.firstInlineItem;
+ unsigned firstNonPartialIndex = firstInlineItem.index;
+ if (firstInlineItem.partialContext) {
+ // Handle partial inline item (split text from the previous line).
+ auto& originalTextItem = m_lineInput.inlineItems[firstInlineItem.index];
+ RELEASE_ASSERT(originalTextItem->isText());
+
+ auto textRange = *firstInlineItem.partialContext;
+ // Construct a partial leading inline item.
+ ASSERT(!m_leadingPartialInlineTextItem);
+ m_leadingPartialInlineTextItem = downcast<InlineTextItem>(*originalTextItem).split(textRange.start, textRange.length);
+ if (placeInlineItem(*m_leadingPartialInlineTextItem) == IsEndOfLine::Yes)
+ return close();
+ ++firstNonPartialIndex;
+ }
+
+ for (auto inlineItemIndex = firstNonPartialIndex; inlineItemIndex < m_lineInput.inlineItems.size(); ++inlineItemIndex) {
+ if (placeInlineItem(*m_lineInput.inlineItems[inlineItemIndex]) == IsEndOfLine::Yes)
+ return close();
+ }
+ commitPendingContent();
+ return close();
+}
+
+void LineLayout::commitPendingContent()
+{
+ if (m_uncommittedContent.isEmpty())
+ return;
+ m_committedInlineItemCount += m_uncommittedContent.size();
+ for (auto& uncommittedRun : m_uncommittedContent.runs())
+ m_line.append(uncommittedRun.inlineItem, uncommittedRun.logicalWidth);
+ m_uncommittedContent.reset();
+}
+
+LineLayout::LineContent LineLayout::close()
+{
+ ASSERT(m_committedInlineItemCount || m_lineHasIntrusiveFloat);
+ if (!m_committedInlineItemCount)
+ return LineContent { WTF::nullopt, WTFMove(m_floats), m_line.close(), m_line.lineBox() };
+
+ auto lastInlineItemIndex = m_lineInput.firstInlineItem.index + m_committedInlineItemCount - 1;
+ Optional<IndexAndRange::Range> partialContext;
+ if (m_trailingPartialInlineTextItem)
+ partialContext = IndexAndRange::Range { m_trailingPartialInlineTextItem->start(), m_trailingPartialInlineTextItem->length() };
+
+ auto lastCommitedItem = IndexAndRange { lastInlineItemIndex, partialContext };
+ return LineContent { lastCommitedItem, WTFMove(m_floats), m_line.close(), m_line.lineBox() };
+}
+
+LineLayout::IsEndOfLine LineLayout::placeInlineItem(const InlineItem& inlineItem)
+{
+ auto availableWidth = m_line.availableWidth() - m_uncommittedContent.width();
+ auto currentLogicalRight = m_line.lineBox().logicalRight() + m_uncommittedContent.width();
+ auto itemLogicalWidth = inlineItemWidth(formattingContext(), inlineItem, currentLogicalRight);
+
+ // FIXME: Ensure LineContext::trimmableWidth includes uncommitted content if needed.
+ auto lineIsConsideredEmpty = !m_line.hasContent() && !m_lineHasIntrusiveFloat;
+ auto breakingContext = m_lineBreaker.breakingContext(inlineItem, itemLogicalWidth, { availableWidth, currentLogicalRight, m_line.trailingTrimmableWidth(), lineIsConsideredEmpty });
+ if (breakingContext.isAtBreakingOpportunity)
+ commitPendingContent();
+
+ // Content does not fit the current line.
+ if (breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Wrap)
+ return IsEndOfLine::Yes;
+
+ // Partial content stays on the current line.
+ if (breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Split) {
+ ASSERT(inlineItem.isText());
+ auto& inlineTextItem = downcast<InlineTextItem>(inlineItem);
+ auto splitData = TextUtil::split(inlineTextItem.layoutBox(), inlineTextItem.start(), inlineTextItem.length(), itemLogicalWidth, availableWidth, currentLogicalRight);
+ // Construct a partial trailing inline item.
+ ASSERT(!m_trailingPartialInlineTextItem);
+ m_trailingPartialInlineTextItem = inlineTextItem.split(splitData.start, splitData.length);
+ m_uncommittedContent.add(*m_trailingPartialInlineTextItem, splitData.logicalWidth);
+ commitPendingContent();
+ return IsEndOfLine::Yes;
+ }
+
+ ASSERT(breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Keep);
+ if (inlineItem.isFloat()) {
+ auto& floatBox = inlineItem.layoutBox();
+ // Shrink available space for current line and move existing inline runs.
+ auto floatBoxWidth = formattingContext().geometryForBox(floatBox).marginBoxWidth();
+ floatBox.isLeftFloatingPositioned() ? m_line.moveLogicalLeft(floatBoxWidth) : m_line.moveLogicalRight(floatBoxWidth);
+ m_floats.append(makeWeakPtr(inlineItem));
+ ++m_committedInlineItemCount;
+ m_lineHasIntrusiveFloat = true;
+ return IsEndOfLine::No;
+ }
+
+ m_uncommittedContent.add(inlineItem, itemLogicalWidth);
+ if (breakingContext.isAtBreakingOpportunity)
+ commitPendingContent();
+
+ return inlineItem.isHardLineBreak() ? IsEndOfLine::Yes : IsEndOfLine::No;
+}
+
+}
+}
+
+#endif
Added: trunk/Source/WebCore/layout/inlineformatting/InlineLineLayout.h (0 => 250490)
--- trunk/Source/WebCore/layout/inlineformatting/InlineLineLayout.h (rev 0)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineLayout.h 2019-09-29 15:08:41 UTC (rev 250490)
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+#pragma once
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "InlineLine.h"
+#include "InlineLineBreaker.h"
+#include <wtf/IsoMalloc.h>
+
+namespace WebCore {
+namespace Layout {
+
+class LineLayout {
+public:
+ struct LineInput;
+ LineLayout(const InlineFormattingContext&, const LineInput&);
+
+ struct LineContent;
+ LineContent layout();
+
+ struct IndexAndRange {
+ unsigned index { 0 };
+ struct Range {
+ unsigned start { 0 };
+ unsigned length { 0 };
+ };
+ Optional<Range> partialContext;
+ };
+
+ struct LineInput {
+ LineInput(const Line::InitialConstraints&, TextAlignMode, IndexAndRange firstToProcess, const InlineItems&);
+ LineInput(const Line::InitialConstraints&, IndexAndRange firstToProcess, const InlineItems&);
+
+ Line::InitialConstraints initialConstraints;
+ TextAlignMode horizontalAlignment;
+ // FIXME Alternatively we could just have a second pass with vertical positioning (preferred width computation opts out)
+ Line::SkipAlignment skipAlignment { Line::SkipAlignment::No };
+ IndexAndRange firstInlineItem;
+ const InlineItems& inlineItems;
+ Optional<LayoutUnit> floatMinimumLogicalBottom;
+ };
+
+ struct LineContent {
+ Optional<IndexAndRange> lastCommitted;
+ Vector<WeakPtr<InlineItem>> floats;
+ const Line::RunList runList;
+ const LineBox lineBox;
+ };
+
+private:
+ const InlineFormattingContext& formattingContext() const { return m_inlineFormattingContext; }
+ enum class IsEndOfLine { No, Yes };
+ IsEndOfLine placeInlineItem(const InlineItem&);
+ void commitPendingContent();
+ LineContent close();
+
+ struct UncommittedContent {
+ struct Run {
+ const InlineItem& inlineItem;
+ LayoutUnit logicalWidth;
+ };
+ void add(const InlineItem&, LayoutUnit logicalWidth);
+ void reset();
+
+ Vector<Run> runs() { return m_uncommittedRuns; }
+ bool isEmpty() const { return m_uncommittedRuns.isEmpty(); }
+ unsigned size() const { return m_uncommittedRuns.size(); }
+ LayoutUnit width() const { return m_width; }
+
+ private:
+ Vector<Run> m_uncommittedRuns;
+ LayoutUnit m_width;
+ };
+
+ const InlineFormattingContext& m_inlineFormattingContext;
+ const LineInput& m_lineInput;
+ Line m_line;
+ LineBreaker m_lineBreaker;
+ bool m_lineHasIntrusiveFloat { false };
+ UncommittedContent m_uncommittedContent;
+ unsigned m_committedInlineItemCount { 0 };
+ Vector<WeakPtr<InlineItem>> m_floats;
+ std::unique_ptr<InlineTextItem> m_leadingPartialInlineTextItem;
+ std::unique_ptr<InlineTextItem> m_trailingPartialInlineTextItem;
+};
+
+}
+}
+#endif