WebKit Bugzilla
Attachment 370639 Details for
Bug 197198
: [LFC][IFC] Introduce DisplayRun to display tree
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-197198-20190525115247.patch (text/plain), 198.63 KB, created by
zalan
on 2019-05-25 11:52:48 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
zalan
Created:
2019-05-25 11:52:48 PDT
Size:
198.63 KB
patch
obsolete
>Subversion Revision: 245773 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index fecfbbc31bf3c182883a5033a2c6a8edeb010316..9811eac19c145b65bd17b1ab5f91c2c0f41cb4e6 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,303 @@ >+2019-05-25 Zalan Bujtas <zalan@apple.com> >+ >+ [LFC][IFC] Introduce DisplayRun to display tree >+ https://bugs.webkit.org/show_bug.cgi?id=197198 >+ >+ Reviewed by Antti Koivisto. >+ >+ Add a simple inline layout implementation. Now we've got DisplayBoxes for layout boxes and >+ DisplayRuns for inline runs. >+ >+ * Sources.txt: >+ * WebCore.xcodeproj/project.pbxproj: >+ * layout/FormattingContextGeometry.cpp: >+ (WebCore::Layout::contentHeightForFormattingContextRoot): >+ * layout/Verification.cpp: >+ (WebCore::Layout::areEssentiallyEqual): >+ (WebCore::Layout::outputMismatchingSimpleLineInformationIfNeeded): >+ (WebCore::Layout::checkForMatchingNonTextRuns): >+ (WebCore::Layout::checkForMatchingTextRuns): >+ (WebCore::Layout::outputMismatchingComplexLineInformationIfNeeded): >+ (WebCore::Layout::outputMismatchingBlockBoxInformationIfNeeded): >+ (WebCore::Layout::resolveForRelativePositionIfNeeded): Deleted. >+ * layout/blockformatting/BlockFormattingContextGeometry.cpp: >+ (WebCore::Layout::BlockFormattingContext::Geometry::inFlowNonReplacedHeightAndMargin): >+ * layout/displaytree/DisplayBox.cpp: >+ (WebCore::Display::Box::marginBox const): >+ (WebCore::Display::Box::nonCollapsedMarginBox const): >+ (WebCore::Display::Box::borderBox const): >+ (WebCore::Display::Box::paddingBox const): >+ (WebCore::Display::Box::contentBox const): >+ (WebCore::Display::Box::Rect::Rect): Deleted. >+ * layout/displaytree/DisplayBox.h: >+ (WebCore::Display::Box::rectWithMargin const): >+ (WebCore::Display::Box::horizontalMargin const): >+ (WebCore::Display::Box::Rect::intersects const): Deleted. >+ (WebCore::Display::Box::Rect::invalidateTop): Deleted. >+ (WebCore::Display::Box::Rect::invalidateLeft): Deleted. >+ (WebCore::Display::Box::Rect::invalidateWidth): Deleted. >+ (WebCore::Display::Box::Rect::invalidateHeight): Deleted. >+ (WebCore::Display::Box::Rect::hasValidPosition const): Deleted. >+ (WebCore::Display::Box::Rect::hasValidSize const): Deleted. >+ (WebCore::Display::Box::Rect::hasValidGeometry const): Deleted. >+ (WebCore::Display::Box::Rect::invalidatePosition): Deleted. >+ (WebCore::Display::Box::Rect::setHasValidPosition): Deleted. >+ (WebCore::Display::Box::Rect::setHasValidSize): Deleted. >+ (WebCore::Display::Box::Rect::top const): Deleted. >+ (WebCore::Display::Box::Rect::left const): Deleted. >+ (WebCore::Display::Box::Rect::bottom const): Deleted. >+ (WebCore::Display::Box::Rect::right const): Deleted. >+ (WebCore::Display::Box::Rect::topLeft const): Deleted. >+ (WebCore::Display::Box::Rect::bottomRight const): Deleted. >+ (WebCore::Display::Box::Rect::size const): Deleted. >+ (WebCore::Display::Box::Rect::width const): Deleted. >+ (WebCore::Display::Box::Rect::height const): Deleted. >+ (WebCore::Display::Box::Rect::setTopLeft): Deleted. >+ (WebCore::Display::Box::Rect::setTop): Deleted. >+ (WebCore::Display::Box::Rect::setLeft): Deleted. >+ (WebCore::Display::Box::Rect::setWidth): Deleted. >+ (WebCore::Display::Box::Rect::setHeight): Deleted. >+ (WebCore::Display::Box::Rect::setSize): Deleted. >+ (WebCore::Display::Box::Rect::shiftLeftTo): Deleted. >+ (WebCore::Display::Box::Rect::shiftRightTo): Deleted. >+ (WebCore::Display::Box::Rect::shiftTopTo): Deleted. >+ (WebCore::Display::Box::Rect::shiftBottomTo): Deleted. >+ (WebCore::Display::Box::Rect::moveHorizontally): Deleted. >+ (WebCore::Display::Box::Rect::moveVertically): Deleted. >+ (WebCore::Display::Box::Rect::expand): Deleted. >+ (WebCore::Display::Box::Rect::clone const): Deleted. >+ (WebCore::Display::Box::Rect::operator LayoutRect const): Deleted. >+ * layout/displaytree/DisplayRect.h: Added. >+ (WebCore::Display::Rect::expandHorizontally): >+ (WebCore::Display::Rect::expandVertically): >+ (WebCore::Display::Rect::intersects const): >+ (WebCore::Display::Rect::invalidateTop): >+ (WebCore::Display::Rect::invalidateLeft): >+ (WebCore::Display::Rect::invalidateWidth): >+ (WebCore::Display::Rect::invalidateHeight): >+ (WebCore::Display::Rect::hasValidPosition const): >+ (WebCore::Display::Rect::hasValidSize const): >+ (WebCore::Display::Rect::hasValidGeometry const): >+ (WebCore::Display::Rect::Rect): >+ (WebCore::Display::Rect::invalidatePosition): >+ (WebCore::Display::Rect::setHasValidPosition): >+ (WebCore::Display::Rect::setHasValidSize): >+ (WebCore::Display::Rect::top const): >+ (WebCore::Display::Rect::left const): >+ (WebCore::Display::Rect::bottom const): >+ (WebCore::Display::Rect::right const): >+ (WebCore::Display::Rect::topLeft const): >+ (WebCore::Display::Rect::bottomRight const): >+ (WebCore::Display::Rect::size const): >+ (WebCore::Display::Rect::width const): >+ (WebCore::Display::Rect::height const): >+ (WebCore::Display::Rect::setTopLeft): >+ (WebCore::Display::Rect::setTop): >+ (WebCore::Display::Rect::setLeft): >+ (WebCore::Display::Rect::setWidth): >+ (WebCore::Display::Rect::setHeight): >+ (WebCore::Display::Rect::setSize): >+ (WebCore::Display::Rect::shiftLeftTo): >+ (WebCore::Display::Rect::shiftRightTo): >+ (WebCore::Display::Rect::shiftTopTo): >+ (WebCore::Display::Rect::shiftBottomTo): >+ (WebCore::Display::Rect::moveHorizontally): >+ (WebCore::Display::Rect::moveVertically): >+ (WebCore::Display::Rect::expand): >+ (WebCore::Display::Rect::clone const): >+ (WebCore::Display::Rect::operator LayoutRect const): >+ * layout/displaytree/DisplayRun.h: Renamed from Source/WebCore/layout/inlineformatting/InlineRun.h. >+ (WebCore::Display::Run::TextContext::start const): >+ (WebCore::Display::Run::TextContext::end const): >+ (WebCore::Display::Run::TextContext::length const): >+ (WebCore::Display::Run::TextContext::expand): >+ (WebCore::Display::Run::logicalTopLeft const): >+ (WebCore::Display::Run::logicalLeft const): >+ (WebCore::Display::Run::logicalRight const): >+ (WebCore::Display::Run::logicalTop const): >+ (WebCore::Display::Run::logicalBottom const): >+ (WebCore::Display::Run::logicalWidth const): >+ (WebCore::Display::Run::logicalHeight const): >+ (WebCore::Display::Run::setLogicalWidth): >+ (WebCore::Display::Run::setLogicalTop): >+ (WebCore::Display::Run::setLogicalLeft): >+ (WebCore::Display::Run::setLogicalRight): >+ (WebCore::Display::Run::moveVertically): >+ (WebCore::Display::Run::moveHorizontally): >+ (WebCore::Display::Run::expandVertically): >+ (WebCore::Display::Run::expandHorizontally): >+ (WebCore::Display::Run::setTextContext): >+ (WebCore::Display::Run::textContext): >+ (WebCore::Display::Run::textContext const): >+ (WebCore::Display::Run::Run): >+ (WebCore::Display::Run::TextContext::TextContext): >+ * layout/floats/FloatAvoider.cpp: >+ (WebCore::Layout::FloatAvoider::rectInContainingBlock const): >+ * layout/floats/FloatAvoider.h: >+ (WebCore::Layout::FloatAvoider::rect const): >+ * layout/floats/FloatBox.cpp: >+ (WebCore::Layout::FloatBox::rect const): >+ * layout/floats/FloatBox.h: >+ * layout/floats/FloatingContext.cpp: >+ (WebCore::Layout::FloatPair::intersects const): >+ * layout/floats/FloatingState.h: >+ (WebCore::Layout::FloatingState::FloatItem::rectWithMargin const): >+ * layout/inlineformatting/InlineFormattingContext.cpp: >+ (WebCore::Layout::InlineFormattingContext::layout const): >+ (WebCore::Layout::InlineFormattingContext::computeIntrinsicWidthConstraints const): >+ (WebCore::Layout::InlineFormattingContext::initializeMarginBorderAndPaddingForGenericInlineBox const): >+ (WebCore::Layout::InlineFormattingContext::computeMarginBorderAndPaddingForInlineContainer const): >+ (WebCore::Layout::InlineFormattingContext::computeIntrinsicWidthForFloatBox const): >+ (WebCore::Layout::InlineFormattingContext::computeIntrinsicWidthForInlineBlock const): >+ (WebCore::Layout::InlineFormattingContext::computeHorizontalMargin const): >+ (WebCore::Layout::InlineFormattingContext::layoutFormattingContextRoot const): >+ (WebCore::Layout::InlineFormattingContext::collectInlineContent const): >+ (WebCore::Layout::InlineFormattingContext::computeMargin const): Deleted. >+ (WebCore::Layout::addDetachingRules): Deleted. >+ (WebCore::Layout::createAndAppendInlineItem): Deleted. >+ * layout/inlineformatting/InlineFormattingContext.h: >+ (WebCore::Layout::InlineFormattingContext::LineLayout::layoutState const): >+ * layout/inlineformatting/InlineFormattingContextLineLayout.cpp: >+ (WebCore::Layout::halfLeadingMetrics): >+ (WebCore::Layout::Line::availableWidth const): >+ (WebCore::Layout::Line::contentLogicalRight const): >+ (WebCore::Layout::Line::contentLogicalWidth const): >+ (WebCore::Layout::Line::logicalTop const): >+ (WebCore::Layout::Line::logicalLeft const): >+ (WebCore::Layout::Line::logicalRight const): >+ (WebCore::Layout::Line::logicalBottom const): >+ (WebCore::Layout::Line::logicalWidth const): >+ (WebCore::Layout::Line::logicalHeight const): >+ (WebCore::Layout::Line::LineItem::LineItem): >+ (WebCore::Layout::Line::Line): >+ (WebCore::Layout::Line::reset): >+ (WebCore::Layout::Line::close): >+ (WebCore::Layout::Line::removeTrailingTrimmableContent): >+ (WebCore::Layout::Line::moveLogicalLeft): >+ (WebCore::Layout::Line::moveLogicalRight): >+ (WebCore::Layout::isTrimmableContent): >+ (WebCore::Layout::Line::trailingTrimmableWidth const): >+ (WebCore::Layout::Line::hasContent const): >+ (WebCore::Layout::Line::appendNonBreakableSpace): >+ (WebCore::Layout::Line::appendInlineContainerStart): >+ (WebCore::Layout::Line::appendInlineContainerEnd): >+ (WebCore::Layout::Line::appendTextContent): >+ (WebCore::Layout::Line::appendNonTextContent): >+ (WebCore::Layout::Line::appendHardLineBreak): >+ (WebCore::Layout::UncommittedContent::isEmpty const): >+ (WebCore::Layout::UncommittedContent::width const): >+ (WebCore::Layout::UncommittedContent::add): >+ (WebCore::Layout::UncommittedContent::reset): >+ (WebCore::Layout::InlineFormattingContext::LineLayout::LineLayout): >+ (WebCore::Layout::InlineFormattingContext::LineLayout::initializeLine const): >+ (WebCore::Layout::InlineFormattingContext::LineLayout::layout const): >+ (WebCore::Layout::InlineFormattingContext::LineLayout::closeLine const): >+ (WebCore::Layout::InlineFormattingContext::LineLayout::handleFloat const): >+ (WebCore::Layout::InlineFormattingContext::LineLayout::commitInlineItemToLine const): >+ (WebCore::Layout::horizontalAdjustmentForAlignment): >+ (WebCore::Layout::InlineFormattingContext::LineLayout::alignRuns const): >+ (WebCore::Layout::Line::isClosed const): Deleted. >+ (WebCore::Layout::Line::isFirstLine const): Deleted. >+ (WebCore::Layout::Line::runs): Deleted. >+ (WebCore::Layout::Line::contentLogicalLeft const): Deleted. >+ (WebCore::Layout::Line::lastRunType const): Deleted. >+ (WebCore::Layout::Line::init): Deleted. >+ (WebCore::Layout::Line::adjustLogicalLeft): Deleted. >+ (WebCore::Layout::Line::adjustLogicalRight): Deleted. >+ (WebCore::Layout::Line::appendContent): Deleted. >+ (WebCore::Layout::InlineFormattingContext::LineLayout::initializeNewLine const): Deleted. >+ (WebCore::Layout::InlineFormattingContext::LineLayout::splitInlineRunIfNeeded const): Deleted. >+ (WebCore::Layout::InlineFormattingContext::LineLayout::createFinalRuns const): Deleted. >+ (WebCore::Layout::InlineFormattingContext::LineLayout::postProcessInlineRuns const): Deleted. >+ (WebCore::Layout::InlineFormattingContext::LineLayout::appendContentToLine const): Deleted. >+ (WebCore::Layout::InlineFormattingContext::LineLayout::computeFloatPosition const): Deleted. >+ (WebCore::Layout::InlineFormattingContext::LineLayout::placeInFlowPositionedChildren const): Deleted. >+ (WebCore::Layout::adjustedLineLogicalLeft): Deleted. >+ (WebCore::Layout::InlineFormattingContext::LineLayout::justifyRuns): Deleted. >+ (WebCore::Layout::InlineFormattingContext::LineLayout::computeExpansionOpportunities const): Deleted. >+ (WebCore::Layout::InlineFormattingContext::LineLayout::runWidth const): Deleted. >+ * layout/inlineformatting/InlineFormattingState.h: >+ (WebCore::Layout::InlineFormattingState::inlineItems): >+ (WebCore::Layout::InlineFormattingState::lineBoxes): >+ (WebCore::Layout::InlineFormattingState::addInlineItem): >+ (WebCore::Layout::InlineFormattingState::addInlineRun): >+ (WebCore::Layout::InlineFormattingState::addLineBox): >+ (WebCore::Layout::InlineFormattingState::inlineContent): Deleted. >+ (WebCore::Layout::InlineFormattingState::lastInlineItem const): Deleted. >+ (WebCore::Layout::InlineFormattingState::appendInlineRun): Deleted. >+ * layout/inlineformatting/InlineItem.h: >+ (WebCore::Layout::InlineItem::type const): >+ (WebCore::Layout::InlineItem::isText const): >+ (WebCore::Layout::InlineItem::isBox const): >+ (WebCore::Layout::InlineItem::isHardLineBreak const): >+ (WebCore::Layout::InlineItem::isFloat const): >+ (WebCore::Layout::InlineItem::isLineBreak const): >+ (WebCore::Layout::InlineItem::isContainerStart const): >+ (WebCore::Layout::InlineItem::isContainerEnd const): >+ (WebCore::Layout::InlineItem::InlineItem): >+ (WebCore::Layout::InlineItem::setWidth): >+ (WebCore::Layout::InlineItem::width const): >+ (WebCore::Layout::InlineItem::addDetachingRule): Deleted. >+ (WebCore::Layout::InlineItem::detachingRules const): Deleted. >+ (WebCore::Layout::InlineItem::nonBreakableStart const): Deleted. >+ (WebCore::Layout::InlineItem::nonBreakableEnd const): Deleted. >+ (WebCore::Layout::InlineItem::addNonBreakableStart): Deleted. >+ (WebCore::Layout::InlineItem::addNonBreakableEnd): Deleted. >+ (WebCore::Layout::InlineItem::textContent const): Deleted. >+ * layout/inlineformatting/InlineLineBox.h: Copied from Source/WebCore/layout/floats/FloatBox.h. >+ (WebCore::Layout::LineBox::logicalTopLeft const): >+ (WebCore::Layout::LineBox::logicalLeft const): >+ (WebCore::Layout::LineBox::logicalRight const): >+ (WebCore::Layout::LineBox::logicalTop const): >+ (WebCore::Layout::LineBox::logicalBottom const): >+ (WebCore::Layout::LineBox::logicalWidth const): >+ (WebCore::Layout::LineBox::logicalHeight const): >+ (WebCore::Layout::LineBox::LineBox): >+ * layout/inlineformatting/InlineLineBreaker.cpp: >+ (WebCore::Layout::LineBreaker::LineBreaker): >+ (WebCore::Layout::LineBreaker::breakingContext): >+ (WebCore::Layout::LineBreaker::wordBreakingBehavior const): >+ (WebCore::Layout::LineBreaker::runWidth const): >+ (WebCore::Layout::LineBreaker::isAtBreakingOpportunity): >+ (WebCore::Layout::LineBreaker::textWidth const): >+ (WebCore::Layout::InlineLineBreaker::InlineLineBreaker): Deleted. >+ (WebCore::Layout::InlineLineBreaker::nextRun): Deleted. >+ (WebCore::Layout::InlineLineBreaker::isAtContentEnd const): Deleted. >+ (WebCore::Layout::InlineLineBreaker::lineBreakingBehavior): Deleted. >+ (WebCore::Layout::InlineLineBreaker::runWidth const): Deleted. >+ (WebCore::Layout::InlineLineBreaker::textWidth const): Deleted. >+ (WebCore::Layout::InlineLineBreaker::splitRun): Deleted. >+ (WebCore::Layout::InlineLineBreaker::adjustSplitPositionWithHyphenation const): Deleted. >+ * layout/inlineformatting/InlineLineBreaker.h: >+ * layout/inlineformatting/InlineRunProvider.cpp: Removed. >+ * layout/inlineformatting/InlineRunProvider.h: Removed. >+ * layout/inlineformatting/InlineTextItem.cpp: Added. >+ (WebCore::Layout::isWhitespaceCharacter): >+ (WebCore::Layout::isSoftLineBreak): >+ (WebCore::Layout::moveToNextNonWhitespacePosition): >+ (WebCore::Layout::moveToNextBreakablePosition): >+ (WebCore::Layout::InlineTextItem::createAndAppendTextItems): >+ (WebCore::Layout::InlineTextItem::InlineTextItem): >+ * layout/inlineformatting/InlineTextItem.h: Copied from Source/WebCore/layout/inlineformatting/text/TextUtil.h. >+ (WebCore::Layout::InlineTextItem::start const): >+ (WebCore::Layout::InlineTextItem::end const): >+ (WebCore::Layout::InlineTextItem::length const): >+ (WebCore::Layout::InlineTextItem::isWhitespace const): >+ (WebCore::Layout::InlineTextItem::isCollapsed const): >+ * layout/inlineformatting/text/TextUtil.cpp: >+ (WebCore::Layout::TextUtil::hyphenPositionBefore): >+ (WebCore::Layout::TextUtil::width): >+ (WebCore::Layout::TextUtil::fixedPitchWidth): >+ * layout/inlineformatting/text/TextUtil.h: >+ * layout/layouttree/LayoutBox.h: >+ * layout/layouttree/LayoutReplaced.cpp: >+ (WebCore::Layout::Replaced::intrinsicRatio const): >+ * layout/layouttree/LayoutTreeBuilder.cpp: >+ (WebCore::Layout::accumulatedOffsetForInFlowPositionedContinuation): >+ (WebCore::Layout::TreeBuilder::createSubTree): >+ (WebCore::Layout::outputInlineRuns): >+ (WebCore::Layout::outputLayoutBox): >+ > 2019-05-25 Youenn Fablet <youenn@apple.com> > > media/video-remote-control-playpause.html is timing out after r245712 >diff --git a/Source/WebCore/Sources.txt b/Source/WebCore/Sources.txt >index 141022a6e60a09f31be5dbfbd029ed77fac0f4ac..ca248f3eba6144ed468157443b707be72a423d58 100644 >--- a/Source/WebCore/Sources.txt >+++ b/Source/WebCore/Sources.txt >@@ -1349,7 +1349,7 @@ layout/inlineformatting/InlineFormattingContextLineLayout.cpp > layout/inlineformatting/InlineFormattingState.cpp > layout/inlineformatting/InlineInvalidation.cpp > layout/inlineformatting/InlineLineBreaker.cpp >-layout/inlineformatting/InlineRunProvider.cpp >+layout/inlineformatting/InlineTextItem.cpp > layout/inlineformatting/text/TextUtil.cpp > layout/layouttree/LayoutBlockContainer.cpp > layout/layouttree/LayoutBox.cpp >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index e6a1f5f1d719b4af63fd9dda7e1afd745a6de907..cee0d4c0a5b8091c0a321b2cfc0d6d742943cfe5 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -2012,10 +2012,9 @@ > 6ED878C5147493F4004C3597 /* RenderTableCaption.h in Headers */ = {isa = PBXBuildFile; fileRef = 6ED878C3147493F4004C3597 /* RenderTableCaption.h */; }; > 6ED8C37A183BFF8C009E53BD /* BoxShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 6ED8C378183BFF8C009E53BD /* BoxShape.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 6EE8A77310F803F3005A4A24 /* JSWebGLContextAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = 6EE8A77110F803F3005A4A24 /* JSWebGLContextAttributes.h */; }; >- 6F219D772178D37200BB033C /* InlineRun.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F219D742178D37100BB033C /* InlineRun.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 6F1CC1DE225F8B4900720AD2 /* InlineTextItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F1CC1DD225F8B4200720AD2 /* InlineTextItem.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 6F222B761AB52D8A0094651A /* WebGLVertexArrayObjectBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6F222B751AB52D8A0094651A /* WebGLVertexArrayObjectBase.cpp */; }; > 6F3E1F622136142000A65A08 /* FloatBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F3E1F612136141700A65A08 /* FloatBox.h */; settings = {ATTRIBUTES = (Private, ); }; }; >- 6F5217C72177F5A7006583BB /* InlineRunProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F5217C42177F5A6006583BB /* InlineRunProvider.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, ); }; }; > 6F995A151A70756200A735F4 /* WebGLSync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6F995A131A70756200A735F4 /* WebGLSync.cpp */; }; >@@ -2035,7 +2034,10 @@ > 6F995A3A1A70833700A735F4 /* JSWebGLVertexArrayObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F995A301A70833700A735F4 /* JSWebGLVertexArrayObject.h */; }; > 6FA4454E898F2FC168BC38C1 /* JSBeforeUnloadEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 29E04A27BED2F81F98E9022B /* JSBeforeUnloadEvent.h */; }; > 6FB11B5C21783FD000E2A574 /* TextUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FB11B5921783FCF00E2A574 /* TextUtil.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 6FB47E632277425A00C7BCB0 /* InlineLineBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FB47E612277425A00C7BCB0 /* InlineLineBox.h */; }; > 6FB5E214221F2453003989CF /* ContentChangeObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FB5E212221F2447003989CF /* ContentChangeObserver.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 6FCE1A1A22618ABD004F0343 /* DisplayRun.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FCE1A1822618AB3004F0343 /* DisplayRun.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 6FD9CD54227E21C800E53957 /* DisplayRect.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FD9CD52227E21C800E53957 /* DisplayRect.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 6FE198172178397C00446F08 /* InlineLineBreaker.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FE198152178397C00446F08 /* InlineLineBreaker.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 6FE7CFA22177EEF2005B1573 /* InlineItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FE7CFA02177EEF1005B1573 /* InlineItem.h */; }; > 6FE7CFA42177EF10005B1573 /* LayoutLineBreakBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FE7CFA32177EF10005B1573 /* LayoutLineBreakBox.h */; settings = {ATTRIBUTES = (Private, ); }; }; >@@ -9114,15 +9116,14 @@ > 6EE8A77010F803F3005A4A24 /* JSWebGLContextAttributes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebGLContextAttributes.cpp; sourceTree = "<group>"; }; > 6EE8A77110F803F3005A4A24 /* JSWebGLContextAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebGLContextAttributes.h; sourceTree = "<group>"; }; > 6F0830DF20B46951008A945B /* BlockFormattingContextGeometry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = BlockFormattingContextGeometry.cpp; sourceTree = "<group>"; }; >- 6F219D742178D37100BB033C /* InlineRun.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineRun.h; sourceTree = "<group>"; }; >+ 6F1CC1DC225F8B4100720AD2 /* InlineTextItem.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InlineTextItem.cpp; sourceTree = "<group>"; }; >+ 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>"; }; > 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>"; }; >- 6F5217C42177F5A6006583BB /* InlineRunProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineRunProvider.h; sourceTree = "<group>"; }; >- 6F5217C62177F5A6006583BB /* InlineRunProvider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InlineRunProvider.cpp; sourceTree = "<group>"; }; > 6F73918C2106CEDD006AF262 /* LayoutUnits.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LayoutUnits.h; sourceTree = "<group>"; }; > 6F7CA3C4208C2956002F29AB /* LayoutState.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LayoutState.h; sourceTree = "<group>"; }; > 6F7CA3C5208C2956002F29AB /* LayoutState.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutState.cpp; sourceTree = "<group>"; }; >@@ -9157,8 +9158,11 @@ > 6F995A301A70833700A735F4 /* JSWebGLVertexArrayObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebGLVertexArrayObject.h; sourceTree = "<group>"; }; > 6FB11B5921783FCF00E2A574 /* TextUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextUtil.h; sourceTree = "<group>"; }; > 6FB11B5B21783FCF00E2A574 /* TextUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextUtil.cpp; sourceTree = "<group>"; }; >+ 6FB47E612277425A00C7BCB0 /* InlineLineBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineLineBox.h; sourceTree = "<group>"; }; > 6FB5E212221F2447003989CF /* ContentChangeObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ContentChangeObserver.h; sourceTree = "<group>"; }; > 6FBB860520B464B600DAD938 /* FormattingContextGeometry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FormattingContextGeometry.cpp; sourceTree = "<group>"; }; >+ 6FCE1A1822618AB3004F0343 /* DisplayRun.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DisplayRun.h; sourceTree = "<group>"; }; >+ 6FD9CD52227E21C800E53957 /* DisplayRect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DisplayRect.h; sourceTree = "<group>"; }; > 6FE198132178397B00446F08 /* InlineLineBreaker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InlineLineBreaker.cpp; sourceTree = "<group>"; }; > 6FE198152178397C00446F08 /* InlineLineBreaker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineLineBreaker.h; sourceTree = "<group>"; }; > 6FE7AA2621C37B6300296DCD /* MarginTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MarginTypes.h; sourceTree = "<group>"; }; >@@ -16375,11 +16379,11 @@ > 1123AFDD209ABBBA00736ACC /* InlineInvalidation.cpp */, > 1123AFDC209ABBBA00736ACC /* InlineInvalidation.h */, > 6FE7CFA02177EEF1005B1573 /* InlineItem.h */, >+ 6FB47E612277425A00C7BCB0 /* InlineLineBox.h */, > 6FE198132178397B00446F08 /* InlineLineBreaker.cpp */, > 6FE198152178397C00446F08 /* InlineLineBreaker.h */, >- 6F219D742178D37100BB033C /* InlineRun.h */, >- 6F5217C62177F5A6006583BB /* InlineRunProvider.cpp */, >- 6F5217C42177F5A6006583BB /* InlineRunProvider.h */, >+ 6F1CC1DC225F8B4100720AD2 /* InlineTextItem.cpp */, >+ 6F1CC1DD225F8B4200720AD2 /* InlineTextItem.h */, > ); > path = inlineformatting; > sourceTree = "<group>"; >@@ -16389,6 +16393,8 @@ > children = ( > 1199FA5A208E3C7F002358CC /* DisplayBox.cpp */, > 1199FA59208E3C7F002358CC /* DisplayBox.h */, >+ 6FD9CD52227E21C800E53957 /* DisplayRect.h */, >+ 6FCE1A1822618AB3004F0343 /* DisplayRun.h */, > ); > path = displaytree; > sourceTree = "<group>"; >@@ -28822,11 +28828,13 @@ > 0FE5FBD51C3DD51E0007A2CA /* DisplayListItems.h in Headers */, > 0FE5FBD71C3DD51E0007A2CA /* DisplayListRecorder.h in Headers */, > 0FE5FBD91C3DD51E0007A2CA /* DisplayListReplayer.h in Headers */, >+ 6FD9CD54227E21C800E53957 /* DisplayRect.h in Headers */, > 49AF2D6914435D050016A784 /* DisplayRefreshMonitor.h in Headers */, > 2D29ECC6192ECC8300984B78 /* DisplayRefreshMonitorClient.h in Headers */, > 2D29ECCA192F1F1D00984B78 /* DisplayRefreshMonitorIOS.h in Headers */, > 2DE70023192FE82A00B0975C /* DisplayRefreshMonitorMac.h in Headers */, > 2D29ECC8192ECC8300984B78 /* DisplayRefreshMonitorManager.h in Headers */, >+ 6FCE1A1A22618ABD004F0343 /* DisplayRun.h in Headers */, > FD31609112B026F700C1A359 /* Distance.h in Headers */, > 84730D771248F0B300D3A9C9 /* DistantLightSource.h in Headers */, > B2F34FE60E82F81400F627CD /* DNS.h in Headers */, >@@ -29457,12 +29465,12 @@ > 11310CF820BA4A6A0065A8D0 /* InlineInvalidation.h in Headers */, > 6FE7CFA22177EEF2005B1573 /* InlineItem.h in Headers */, > BCE789161120D6080060ECE5 /* InlineIterator.h in Headers */, >+ 6FB47E632277425A00C7BCB0 /* InlineLineBox.h in Headers */, > 6FE198172178397C00446F08 /* InlineLineBreaker.h in Headers */, >- 6F219D772178D37200BB033C /* InlineRun.h in Headers */, >- 6F5217C72177F5A7006583BB /* InlineRunProvider.h in Headers */, > AA4C3A770B2B1679002334A2 /* InlineStyleSheetOwner.h in Headers */, > BCEA485A097D93020094C9E4 /* InlineTextBox.h in Headers */, > 1C010701192594DF008A4201 /* InlineTextBoxStyle.h in Headers */, >+ 6F1CC1DE225F8B4900720AD2 /* InlineTextItem.h in Headers */, > 510A58E51BAA40B100C19282 /* InProcessIDBServer.h in Headers */, > 2EB767571DA19BDF003E23B5 /* InputEvent.h in Headers */, > E52EFDF42112875A00AD282A /* InputMode.h in Headers */, >diff --git a/Source/WebCore/layout/FormattingContextGeometry.cpp b/Source/WebCore/layout/FormattingContextGeometry.cpp >index 4136ad2bf7e397a6994b1f661f847d3c5c65dab2..b81796a48ede1d523c1b03a62a8815bd5baea198 100644 >--- a/Source/WebCore/layout/FormattingContextGeometry.cpp >+++ b/Source/WebCore/layout/FormattingContextGeometry.cpp >@@ -109,12 +109,11 @@ static LayoutUnit contentHeightForFormattingContextRoot(const LayoutState& layou > auto bottom = borderAndPaddingTop; > auto& formattingRootContainer = downcast<Container>(layoutBox); > if (formattingRootContainer.establishesInlineFormattingContext()) { >- // This is temp and will be replaced by the correct display box once inline runs move over to the display tree. >- auto& inlineRuns = downcast<InlineFormattingState>(layoutState.establishedFormattingState(layoutBox)).inlineRuns(); >- if (!inlineRuns.isEmpty()) { >- top = inlineRuns[0].logicalTop(); >- bottom = inlineRuns.last().logicalBottom(); >- } >+ auto& lineBoxes = downcast<InlineFormattingState>(layoutState.establishedFormattingState(layoutBox)).lineBoxes(); >+ // Even empty containers generate one line. >+ ASSERT(!lineBoxes.isEmpty()); >+ top = lineBoxes.first().logicalTop(); >+ bottom = lineBoxes.last().logicalBottom(); > } else if (formattingRootContainer.establishesBlockFormattingContext() || layoutBox.isDocumentBox()) { > if (formattingRootContainer.hasInFlowChild()) { > auto& firstDisplayBox = layoutState.displayBoxForLayoutBox(*formattingRootContainer.firstInFlowChild()); >diff --git a/Source/WebCore/layout/Verification.cpp b/Source/WebCore/layout/Verification.cpp >index 2e77c39e92144942ef29e40e4c7436e511200bc2..d7fe6a9f1917495ae56eebdd78b5afe48f5cdc1c 100644 >--- a/Source/WebCore/layout/Verification.cpp >+++ b/Source/WebCore/layout/Verification.cpp >@@ -35,6 +35,7 @@ > #include "LayoutTreeBuilder.h" > #include "RenderBox.h" > #include "RenderInline.h" >+#include "RenderLineBreak.h" > #include "RenderView.h" > #include <wtf/text/TextStream.h> > >@@ -46,7 +47,7 @@ static bool areEssentiallyEqual(float a, LayoutUnit b) > if (a == b.toFloat()) > return true; > >- return fabs(a - b.toFloat()) <= 8 * LayoutUnit::epsilon(); >+ return fabs(a - b.toFloat()) <= 10 * LayoutUnit::epsilon(); > } > > static bool outputMismatchingSimpleLineInformationIfNeeded(TextStream& stream, const LayoutState& layoutState, const RenderBlockFlow& blockFlow, const Container& inlineFormattingRoot) >@@ -72,33 +73,37 @@ static bool outputMismatchingSimpleLineInformationIfNeeded(TextStream& stream, c > auto& simpleRun = lineLayoutData->runAt(i); > auto& inlineRun = inlineRunList[i]; > >- auto matchingRuns = areEssentiallyEqual(simpleRun.logicalLeft, inlineRun.logicalLeft()) && areEssentiallyEqual(simpleRun.logicalRight, inlineRun.logicalRight()); >- if (matchingRuns) >- matchingRuns = (simpleRun.start == inlineRun.textContext()->start() && simpleRun.end == (inlineRun.textContext()->start() + inlineRun.textContext()->length())); >+ auto matchingRuns = areEssentiallyEqual(simpleRun.logicalLeft, inlineRun->logicalLeft()) && areEssentiallyEqual(simpleRun.logicalRight, inlineRun->logicalRight()); >+ if (matchingRuns && inlineRun->textContext()) { >+ matchingRuns = simpleRun.start == inlineRun->textContext()->start() && simpleRun.end == inlineRun->textContext()->end(); >+ // SLL handles strings in a more concatenated format <div>foo<br>bar</div> -> foo -> 0,3 bar -> 3,6 vs. 0,3 and 0,3 >+ if (!matchingRuns) >+ matchingRuns = (simpleRun.end - simpleRun.start) == (inlineRun->textContext()->end() - inlineRun->textContext()->start()); >+ } > if (matchingRuns) > continue; > >- stream << "Mismatching: simple run(" << simpleRun.start << ", " << simpleRun.end << ") (" << simpleRun.logicalLeft << ", " << simpleRun.logicalRight << ") layout run(" << inlineRun.textContext()->start() << ", " << inlineRun.textContext()->start() + inlineRun.textContext()->length() << ") (" << inlineRun.logicalLeft() << ", " << inlineRun.logicalRight() << ")"; >+ stream << "Mismatching: simple run(" << simpleRun.start << ", " << simpleRun.end << ") (" << simpleRun.logicalLeft << ", " << simpleRun.logicalRight << ") layout run(" << inlineRun->textContext()->start() << ", " << inlineRun->textContext()->end() << ") (" << inlineRun->logicalLeft() << ", " << inlineRun->logicalRight() << ")"; > stream.nextLine(); > mismatched = true; > } > return mismatched; > } > >-static bool checkForMatchingNonTextRuns(const InlineRun& inlineRun, const WebCore::InlineBox& inlineBox) >+static bool checkForMatchingNonTextRuns(const Display::Run& inlineRun, const WebCore::InlineBox& inlineBox) > { > return areEssentiallyEqual(inlineBox.logicalLeft(), inlineRun.logicalLeft()) > && areEssentiallyEqual(inlineBox.logicalRight(), inlineRun.logicalRight()) > && areEssentiallyEqual(inlineBox.logicalHeight(), inlineRun.logicalHeight()); > } > >-static bool checkForMatchingTextRuns(const InlineRun& inlineRun, float logicalLeft, float logicalRight, unsigned start, unsigned end, float logicalHeight) >+static bool checkForMatchingTextRuns(const Display::Run& inlineRun, const InlineTextBox& inlineTextBox) > { >- return areEssentiallyEqual(logicalLeft, inlineRun.logicalLeft()) >- && areEssentiallyEqual(logicalRight, inlineRun.logicalRight()) >- && start == inlineRun.textContext()->start() >- && (end == (inlineRun.textContext()->start() + inlineRun.textContext()->length())) >- && areEssentiallyEqual(logicalHeight, inlineRun.logicalHeight()); >+ return areEssentiallyEqual(inlineTextBox.logicalLeft(), inlineRun.logicalLeft()) >+ && areEssentiallyEqual(inlineTextBox.logicalRight(), inlineRun.logicalRight()) >+ && inlineTextBox.start() == inlineRun.textContext()->start() >+ && (inlineTextBox.end() + 1) == inlineRun.textContext()->end() >+ && areEssentiallyEqual(inlineTextBox.logicalHeight(), inlineRun.logicalHeight()); > } > > static void collectFlowBoxSubtree(const InlineFlowBox& flowbox, Vector<WebCore::InlineBox*>& inlineBoxes) >@@ -126,19 +131,6 @@ static void collectInlineBoxes(const RenderBlockFlow& root, Vector<WebCore::Inli > } > } > >-static LayoutUnit resolveForRelativePositionIfNeeded(const InlineTextBox& inlineTextBox) >-{ >- LayoutUnit xOffset; >- auto* parent = inlineTextBox.parent(); >- while (is<InlineFlowBox>(parent)) { >- auto& renderer = parent->renderer(); >- if (renderer.isInFlowPositioned()) >- xOffset = renderer.offsetForInFlowPosition().width(); >- parent = parent->parent(); >- } >- return xOffset; >-} >- > static bool outputMismatchingComplexLineInformationIfNeeded(TextStream& stream, const LayoutState& layoutState, const RenderBlockFlow& blockFlow, const Container& inlineFormattingRoot) > { > auto& inlineFormattingState = layoutState.establishedFormattingState(inlineFormattingRoot); >@@ -158,66 +150,30 @@ static bool outputMismatchingComplexLineInformationIfNeeded(TextStream& stream, > } > > for (unsigned inlineBoxIndex = 0; inlineBoxIndex < inlineBoxes.size() && runIndex < inlineRunList.size(); ++inlineBoxIndex) { >+ auto& inlineRun = inlineRunList[runIndex]; > auto* inlineBox = inlineBoxes[inlineBoxIndex]; > auto* inlineTextBox = is<InlineTextBox>(inlineBox) ? downcast<InlineTextBox>(inlineBox) : nullptr; >+ bool matchingRuns = inlineTextBox ? checkForMatchingTextRuns(*inlineRun, *inlineTextBox) : matchingRuns = checkForMatchingNonTextRuns(*inlineRun, *inlineBox); > >- auto& inlineRun = inlineRunList[runIndex]; >- auto matchingRuns = false; >- if (inlineTextBox) { >- auto xOffset = resolveForRelativePositionIfNeeded(*inlineTextBox); >- matchingRuns = checkForMatchingTextRuns(inlineRun, inlineTextBox->logicalLeft() + xOffset, >- inlineTextBox->logicalRight() + xOffset, >- inlineTextBox->start(), >- inlineTextBox->end() + 1, >- inlineTextBox->logicalHeight()); >- >- // <span>foobar</span>foobar generates 2 inline text boxes while we only generate one inline run. >- // also <div>foo<img style="float: left;">bar</div> too. >- auto inlineRunEnd = inlineRun.textContext()->start() + inlineRun.textContext()->length(); >- auto textRunMightBeExtended = !matchingRuns && inlineTextBox->end() < inlineRunEnd && inlineBoxIndex < inlineBoxes.size() - 1; >- >- if (textRunMightBeExtended) { >- auto logicalLeft = inlineTextBox->logicalLeft() + xOffset; >- auto logicalRight = inlineTextBox->logicalRight() + xOffset; >- auto start = inlineTextBox->start(); >- auto end = inlineTextBox->end() + 1; >- auto index = ++inlineBoxIndex; >- for (; index < inlineBoxes.size(); ++index) { >- auto* inlineBox = inlineBoxes[index]; >- auto* inlineTextBox = is<InlineTextBox>(inlineBox) ? downcast<InlineTextBox>(inlineBox) : nullptr; >- // Can't mix different inline boxes. >- if (!inlineTextBox) >- break; >- >- auto xOffset = resolveForRelativePositionIfNeeded(*inlineTextBox); >- logicalRight = inlineTextBox->logicalRight() + xOffset; >- end += (inlineTextBox->end() + 1); >- if (checkForMatchingTextRuns(inlineRun, logicalLeft, logicalRight, start, end, inlineTextBox->logicalHeight())) { >- matchingRuns = true; >- inlineBoxIndex = index; >- break; >- } >- >- // Went too far? >- if (end >= inlineRunEnd) >- break; >- } >+ if (!matchingRuns) { >+ >+ if (is<RenderLineBreak>(inlineBox->renderer())) { >+ // <br> positioning is weird at this point. It needs proper baseline. >+ matchingRuns = true; >+ ++runIndex; >+ continue; > } >- } else >- matchingRuns = checkForMatchingNonTextRuns(inlineRun, *inlineBox); >- > >- if (!matchingRuns) { >- stream << "Mismatching: run "; >+ stream << "Mismatching: run"; > > if (inlineTextBox) >- stream << "(" << inlineTextBox->start() << ", " << inlineTextBox->end() + 1 << ")"; >- stream << " (" << inlineBox->logicalLeft() << ", " << inlineBox->logicalRight() << ") (" << inlineBox->logicalWidth() << "x" << inlineBox->logicalHeight() << ")"; >+ stream << " (" << inlineTextBox->start() << ", " << inlineTextBox->end() + 1 << ")"; >+ stream << " (" << inlineBox->logicalLeft() << ", " << inlineBox->logicalTop() << ") (" << inlineBox->logicalWidth() << "x" << inlineBox->logicalHeight() << ")"; > >- stream << "inline run "; >- if (inlineRun.textContext()) >- stream << "(" << inlineRun.textContext()->start() << ", " << inlineRun.textContext()->start() + inlineRun.textContext()->length() << ") "; >- stream << "(" << inlineRun.logicalLeft() << ", " << inlineRun.logicalRight() << ") (" << inlineRun.logicalWidth() << "x" << inlineRun.logicalHeight() << ")"; >+ stream << " inline run"; >+ if (inlineRun->textContext()) >+ stream << " (" << inlineRun->textContext()->start() << ", " << inlineRun->textContext()->end() << ")"; >+ stream << " (" << inlineRun->logicalLeft() << ", " << inlineRun->logicalTop() << ") (" << inlineRun->logicalWidth() << "x" << inlineRun->logicalHeight() << ")"; > stream.nextLine(); > mismatched = true; > } >@@ -245,7 +201,7 @@ static bool outputMismatchingBlockBoxInformationIfNeeded(TextStream& stream, con > // Produce a RenderBox matching margin box. > auto borderBox = displayBox.borderBox(); > >- return Display::Box::Rect { >+ return Display::Rect { > borderBox.top() - displayBox.nonCollapsedMarginBefore(), > borderBox.left() - displayBox.computedMarginStart().valueOr(0), > displayBox.computedMarginStart().valueOr(0) + borderBox.width() + displayBox.computedMarginEnd().valueOr(0), >diff --git a/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp b/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp >index f9633b438a1b1b227da5b87146ff31ebc568625c..ae1a21edb8c52d3b61c1508331cc30d8664be1af 100644 >--- a/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp >+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp >@@ -75,10 +75,10 @@ HeightAndMargin BlockFormattingContext::Geometry::inFlowNonReplacedHeightAndMarg > > // 1. the bottom edge of the last line box, if the box establishes a inline formatting context with one or more lines > if (layoutBox.establishesInlineFormattingContext()) { >- // This is temp and will be replaced by the correct display box once inline runs move over to the display tree. >- auto& inlineRuns = downcast<InlineFormattingState>(layoutState.establishedFormattingState(layoutBox)).inlineRuns(); >- auto bottomEdge = inlineRuns.isEmpty() ? LayoutUnit() : inlineRuns.last().logicalBottom(); >- return { bottomEdge - borderAndPaddingTop, nonCollapsedMargin }; >+ auto& lineBoxes = downcast<InlineFormattingState>(layoutState.establishedFormattingState(layoutBox)).lineBoxes(); >+ // Even empty containers generate one line. >+ ASSERT(!lineBoxes.isEmpty()); >+ return { lineBoxes.last().logicalBottom() - borderAndPaddingTop, nonCollapsedMargin }; > } > > // 2. the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin... >diff --git a/Source/WebCore/layout/displaytree/DisplayBox.cpp b/Source/WebCore/layout/displaytree/DisplayBox.cpp >index 0eeeaecd374aabdb3aeef00c8f3124a6cae0af39..6ade406d5c4275ead5bf35e02d47668e06a53503 100644 >--- a/Source/WebCore/layout/displaytree/DisplayBox.cpp >+++ b/Source/WebCore/layout/displaytree/DisplayBox.cpp >@@ -36,17 +36,6 @@ namespace Display { > > WTF_MAKE_ISO_ALLOCATED_IMPL(Box); > >-Box::Rect::Rect(LayoutUnit top, LayoutUnit left, LayoutUnit width, LayoutUnit height) >- : m_rect(left, top, width, height) >-{ >-#if !ASSERT_DISABLED >- m_hasValidTop = true; >- m_hasValidLeft = true; >- m_hasValidWidth = true; >- m_hasValidHeight = true; >-#endif >-} >- > Box::Box(const RenderStyle& style) > : m_style(style) > { >@@ -88,7 +77,7 @@ Box::Style::Style(const RenderStyle& style) > { > } > >-Box::Rect Box::marginBox() const >+Rect Box::marginBox() const > { > auto borderBox = this->borderBox(); > >@@ -100,7 +89,7 @@ Box::Rect Box::marginBox() const > return marginBox; > } > >-Box::Rect Box::nonCollapsedMarginBox() const >+Rect Box::nonCollapsedMarginBox() const > { > auto borderBox = this->borderBox(); > >@@ -112,7 +101,7 @@ Box::Rect Box::nonCollapsedMarginBox() const > return marginBox; > } > >-Box::Rect Box::borderBox() const >+Rect Box::borderBox() const > { > Rect borderBox; > borderBox.setTopLeft({ }); >@@ -120,7 +109,7 @@ Box::Rect Box::borderBox() const > return borderBox; > } > >-Box::Rect Box::paddingBox() const >+Rect Box::paddingBox() const > { > auto borderBox = this->borderBox(); > >@@ -132,7 +121,7 @@ Box::Rect Box::paddingBox() const > return paddingBox; > } > >-Box::Rect Box::contentBox() const >+Rect Box::contentBox() const > { > Rect contentBox; > contentBox.setTop(contentBoxTop()); >diff --git a/Source/WebCore/layout/displaytree/DisplayBox.h b/Source/WebCore/layout/displaytree/DisplayBox.h >index 8685c378c48a886c25c1b936d06b36a2136e2e71..5cdf63bf779591a88e74823262a0a90c2197a4c0 100644 >--- a/Source/WebCore/layout/displaytree/DisplayBox.h >+++ b/Source/WebCore/layout/displaytree/DisplayBox.h >@@ -27,6 +27,7 @@ > > #if ENABLE(LAYOUT_FORMATTING_CONTEXT) > >+#include "DisplayRect.h" > #include "LayoutUnits.h" > #include "RenderStyleConstants.h" > #include <wtf/IsoMalloc.h> >@@ -60,68 +61,6 @@ public: > > Box(const RenderStyle&); > Box(const Box&); >- >- class Rect { >- public: >- Rect() = default; >- Rect(LayoutUnit top, LayoutUnit left, LayoutUnit width, LayoutUnit height); >- >- LayoutUnit top() const; >- LayoutUnit left() const; >- LayoutPoint topLeft() const; >- >- LayoutUnit bottom() const; >- LayoutUnit right() const; >- LayoutPoint bottomRight() const; >- >- LayoutUnit width() const; >- LayoutUnit height() const; >- LayoutSize size() const; >- >- void setTop(LayoutUnit); >- void setLeft(LayoutUnit); >- void setTopLeft(const LayoutPoint&); >- void setWidth(LayoutUnit); >- void setHeight(LayoutUnit); >- void setSize(const LayoutSize&); >- >- void shiftLeftTo(LayoutUnit); >- void shiftRightTo(LayoutUnit); >- void shiftTopTo(LayoutUnit); >- void shiftBottomTo(LayoutUnit); >- >- void moveHorizontally(LayoutUnit); >- void moveVertically(LayoutUnit); >- >- void expand(LayoutUnit, LayoutUnit); >- bool intersects(const Rect& rect) const { return m_rect.intersects(rect); } >- >- Rect clone() const; >- operator LayoutRect() const; >- >- private: >-#if !ASSERT_DISABLED >- void invalidateTop() { m_hasValidTop = false; } >- void invalidateLeft() { m_hasValidLeft = false; } >- void invalidateWidth() { m_hasValidWidth = false; } >- void invalidateHeight() { m_hasValidHeight = false; } >- void invalidatePosition(); >- >- bool hasValidPosition() const { return m_hasValidTop && m_hasValidLeft; } >- bool hasValidSize() const { return m_hasValidWidth && m_hasValidHeight; } >- bool hasValidGeometry() const { return hasValidPosition() && hasValidSize(); } >- >- void setHasValidPosition(); >- void setHasValidSize(); >- >- bool m_hasValidTop { false }; >- bool m_hasValidLeft { false }; >- bool m_hasValidWidth { false }; >- bool m_hasValidHeight { false }; >-#endif >- LayoutRect m_rect; >- }; >- > ~Box(); > > LayoutUnit top() const; >@@ -139,6 +78,7 @@ public: > Rect rectWithMargin() const; > > Layout::UsedVerticalMargin verticalMargin() const; >+ Layout::UsedHorizontalMargin horizontalMargin() const; > LayoutUnit marginBefore() const; > LayoutUnit marginStart() const; > LayoutUnit marginAfter() const; >@@ -179,6 +119,9 @@ public: > LayoutUnit paddingBoxHeight() const { return paddingTop().valueOr(0) + contentBoxHeight() + paddingBottom().valueOr(0); } > LayoutUnit paddingBoxWidth() const { return paddingLeft().valueOr(0) + contentBoxWidth() + paddingRight().valueOr(0); } > >+ LayoutUnit borderBoxWidth() const { return borderLeft() + paddingBoxWidth() + borderRight(); } >+ LayoutUnit marginBoxWidth() const { return marginStart() + borderBoxWidth() + marginEnd(); } >+ > Rect marginBox() const; > Rect nonCollapsedMarginBox() const; > >@@ -264,24 +207,6 @@ private: > }; > > #if !ASSERT_DISABLED >-inline void Box::Rect::invalidatePosition() >-{ >- invalidateTop(); >- invalidateLeft(); >-} >- >-inline void Box::Rect::setHasValidPosition() >-{ >- m_hasValidTop = true; >- m_hasValidLeft = true; >-} >- >-inline void Box::Rect::setHasValidSize() >-{ >- m_hasValidWidth = true; >- m_hasValidHeight = true; >-} >- > inline void Box::invalidateMargin() > { > m_hasValidHorizontalMargin = false; >@@ -289,169 +214,6 @@ inline void Box::invalidateMargin() > } > #endif > >-inline LayoutUnit Box::Rect::top() const >-{ >- ASSERT(m_hasValidTop); >- return m_rect.y(); >-} >- >-inline LayoutUnit Box::Rect::left() const >-{ >- ASSERT(m_hasValidLeft); >- return m_rect.x(); >-} >- >-inline LayoutUnit Box::Rect::bottom() const >-{ >- ASSERT(m_hasValidTop && m_hasValidHeight); >- return m_rect.maxY(); >-} >- >-inline LayoutUnit Box::Rect::right() const >-{ >- ASSERT(m_hasValidLeft && m_hasValidWidth); >- return m_rect.maxX(); >-} >- >-inline LayoutPoint Box::Rect::topLeft() const >-{ >- ASSERT(hasValidPosition()); >- return m_rect.minXMinYCorner(); >-} >- >-inline LayoutPoint Box::Rect::bottomRight() const >-{ >- ASSERT(hasValidGeometry()); >- return m_rect.maxXMaxYCorner(); >-} >- >-inline LayoutSize Box::Rect::size() const >-{ >- ASSERT(hasValidSize()); >- return m_rect.size(); >-} >- >-inline LayoutUnit Box::Rect::width() const >-{ >- ASSERT(m_hasValidWidth); >- return m_rect.width(); >-} >- >-inline LayoutUnit Box::Rect::height() const >-{ >- ASSERT(m_hasValidHeight); >- return m_rect.height(); >-} >- >-inline void Box::Rect::setTopLeft(const LayoutPoint& topLeft) >-{ >-#if !ASSERT_DISABLED >- setHasValidPosition(); >-#endif >- m_rect.setLocation(topLeft); >-} >- >-inline void Box::Rect::setTop(LayoutUnit top) >-{ >-#if !ASSERT_DISABLED >- m_hasValidTop = true; >-#endif >- m_rect.setY(top); >-} >- >-inline void Box::Rect::setLeft(LayoutUnit left) >-{ >-#if !ASSERT_DISABLED >- m_hasValidLeft = true; >-#endif >- m_rect.setX(left); >-} >- >-inline void Box::Rect::setWidth(LayoutUnit width) >-{ >-#if !ASSERT_DISABLED >- m_hasValidWidth = true; >-#endif >- m_rect.setWidth(width); >-} >- >-inline void Box::Rect::setHeight(LayoutUnit height) >-{ >-#if !ASSERT_DISABLED >- m_hasValidHeight = true; >-#endif >- m_rect.setHeight(height); >-} >- >-inline void Box::Rect::setSize(const LayoutSize& size) >-{ >-#if !ASSERT_DISABLED >- setHasValidSize(); >-#endif >- m_rect.setSize(size); >-} >- >-inline void Box::Rect::shiftLeftTo(LayoutUnit left) >-{ >- ASSERT(m_hasValidLeft); >- m_rect.shiftXEdgeTo(left); >-} >- >-inline void Box::Rect::shiftRightTo(LayoutUnit right) >-{ >- ASSERT(m_hasValidLeft && m_hasValidWidth); >- m_rect.shiftMaxXEdgeTo(right); >-} >- >-inline void Box::Rect::shiftTopTo(LayoutUnit top) >-{ >- ASSERT(m_hasValidTop); >- m_rect.shiftYEdgeTo(top); >-} >- >-inline void Box::Rect::shiftBottomTo(LayoutUnit bottom) >-{ >- ASSERT(m_hasValidTop && m_hasValidHeight); >- m_rect.shiftMaxYEdgeTo(bottom); >-} >- >-inline void Box::Rect::moveHorizontally(LayoutUnit offset) >-{ >- ASSERT(m_hasValidLeft); >- m_rect.move(offset, 0_lu); >-} >- >-inline void Box::Rect::moveVertically(LayoutUnit offset) >-{ >- ASSERT(m_hasValidTop); >- m_rect.move(0_lu, offset); >-} >- >-inline void Box::Rect::expand(LayoutUnit width, LayoutUnit height) >-{ >- ASSERT(hasValidGeometry()); >- m_rect.expand(width, height); >-} >- >-inline Box::Rect Box::Rect::clone() const >-{ >- Rect rect; >-#if !ASSERT_DISABLED >- rect.m_hasValidTop = m_hasValidTop; >- rect.m_hasValidLeft = m_hasValidLeft; >- rect.m_hasValidWidth = m_hasValidWidth; >- rect.m_hasValidHeight = m_hasValidHeight; >-#endif >- rect.m_rect = m_rect; >- return rect; >-} >- >-inline Box::Rect::operator LayoutRect() const >-{ >- ASSERT(hasValidGeometry()); >- return m_rect; >-} >- > inline LayoutUnit Box::top() const > { > ASSERT(m_hasValidTop && (m_hasEstimatedMarginBefore || m_hasValidVerticalMargin)); >@@ -566,7 +328,7 @@ inline void Box::setPadding(Optional<Layout::Edges> padding) > m_padding = padding; > } > >-inline Box::Rect Box::rectWithMargin() const >+inline Rect Box::rectWithMargin() const > { > auto marginAfter = this->marginAfter(); > if (m_verticalMargin.collapsedValues().isCollapsedThrough) >@@ -580,6 +342,12 @@ inline Layout::UsedVerticalMargin Box::verticalMargin() const > return m_verticalMargin; > } > >+inline Layout::UsedHorizontalMargin Box::horizontalMargin() const >+{ >+ ASSERT(m_hasValidHorizontalMargin); >+ return m_horizontalMargin; >+} >+ > inline LayoutUnit Box::marginBefore() const > { > ASSERT(m_hasValidVerticalMargin); >diff --git a/Source/WebCore/layout/displaytree/DisplayRect.h b/Source/WebCore/layout/displaytree/DisplayRect.h >new file mode 100644 >index 0000000000000000000000000000000000000000..72c897eac4981f21d060db45bccaff2b2a23564d >--- /dev/null >+++ b/Source/WebCore/layout/displaytree/DisplayRect.h >@@ -0,0 +1,297 @@ >+/* >+ * 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 "LayoutUnits.h" >+ >+namespace WebCore { >+ >+class RenderStyle; >+ >+namespace Display { >+ >+class Rect { >+public: >+ Rect() = default; >+ Rect(LayoutUnit top, LayoutUnit left, LayoutUnit width, LayoutUnit height); >+ >+ LayoutUnit top() const; >+ LayoutUnit left() const; >+ LayoutPoint topLeft() const; >+ >+ LayoutUnit bottom() const; >+ LayoutUnit right() const; >+ LayoutPoint bottomRight() const; >+ >+ LayoutUnit width() const; >+ LayoutUnit height() const; >+ LayoutSize size() const; >+ >+ void setTop(LayoutUnit); >+ void setLeft(LayoutUnit); >+ void setTopLeft(const LayoutPoint&); >+ void setWidth(LayoutUnit); >+ void setHeight(LayoutUnit); >+ void setSize(const LayoutSize&); >+ >+ void shiftLeftTo(LayoutUnit); >+ void shiftRightTo(LayoutUnit); >+ void shiftTopTo(LayoutUnit); >+ void shiftBottomTo(LayoutUnit); >+ >+ void moveHorizontally(LayoutUnit); >+ void moveVertically(LayoutUnit); >+ >+ void expand(LayoutUnit, LayoutUnit); >+ void expandHorizontally(LayoutUnit delta) { expand(delta, 0); } >+ void expandVertically(LayoutUnit delta) { expand(0, delta); } >+ bool intersects(const Rect& rect) const { return m_rect.intersects(rect); } >+ >+ Rect clone() const; >+ operator LayoutRect() const; >+ >+private: >+#if !ASSERT_DISABLED >+ void invalidateTop() { m_hasValidTop = false; } >+ void invalidateLeft() { m_hasValidLeft = false; } >+ void invalidateWidth() { m_hasValidWidth = false; } >+ void invalidateHeight() { m_hasValidHeight = false; } >+ void invalidatePosition(); >+ >+ bool hasValidPosition() const { return m_hasValidTop && m_hasValidLeft; } >+ bool hasValidSize() const { return m_hasValidWidth && m_hasValidHeight; } >+ bool hasValidGeometry() const { return hasValidPosition() && hasValidSize(); } >+ >+ void setHasValidPosition(); >+ void setHasValidSize(); >+ >+ bool m_hasValidTop { false }; >+ bool m_hasValidLeft { false }; >+ bool m_hasValidWidth { false }; >+ bool m_hasValidHeight { false }; >+#endif >+ LayoutRect m_rect; >+}; >+ >+inline Rect::Rect(LayoutUnit top, LayoutUnit left, LayoutUnit width, LayoutUnit height) >+ : m_rect(left, top, width, height) >+{ >+#if !ASSERT_DISABLED >+ m_hasValidTop = true; >+ m_hasValidLeft = true; >+ m_hasValidWidth = true; >+ m_hasValidHeight = true; >+#endif >+} >+ >+#if !ASSERT_DISABLED >+inline void Rect::invalidatePosition() >+{ >+ invalidateTop(); >+ invalidateLeft(); >+} >+ >+inline void Rect::setHasValidPosition() >+{ >+ m_hasValidTop = true; >+ m_hasValidLeft = true; >+} >+ >+inline void Rect::setHasValidSize() >+{ >+ m_hasValidWidth = true; >+ m_hasValidHeight = true; >+} >+#endif >+ >+inline LayoutUnit Rect::top() const >+{ >+ ASSERT(m_hasValidTop); >+ return m_rect.y(); >+} >+ >+inline LayoutUnit Rect::left() const >+{ >+ ASSERT(m_hasValidLeft); >+ return m_rect.x(); >+} >+ >+inline LayoutUnit Rect::bottom() const >+{ >+ ASSERT(m_hasValidTop && m_hasValidHeight); >+ return m_rect.maxY(); >+} >+ >+inline LayoutUnit Rect::right() const >+{ >+ ASSERT(m_hasValidLeft && m_hasValidWidth); >+ return m_rect.maxX(); >+} >+ >+inline LayoutPoint Rect::topLeft() const >+{ >+ ASSERT(hasValidPosition()); >+ return m_rect.minXMinYCorner(); >+} >+ >+inline LayoutPoint Rect::bottomRight() const >+{ >+ ASSERT(hasValidGeometry()); >+ return m_rect.maxXMaxYCorner(); >+} >+ >+inline LayoutSize Rect::size() const >+{ >+ ASSERT(hasValidSize()); >+ return m_rect.size(); >+} >+ >+inline LayoutUnit Rect::width() const >+{ >+ ASSERT(m_hasValidWidth); >+ return m_rect.width(); >+} >+ >+inline LayoutUnit Rect::height() const >+{ >+ ASSERT(m_hasValidHeight); >+ return m_rect.height(); >+} >+ >+inline void Rect::setTopLeft(const LayoutPoint& topLeft) >+{ >+#if !ASSERT_DISABLED >+ setHasValidPosition(); >+#endif >+ m_rect.setLocation(topLeft); >+} >+ >+inline void Rect::setTop(LayoutUnit top) >+{ >+#if !ASSERT_DISABLED >+ m_hasValidTop = true; >+#endif >+ m_rect.setY(top); >+} >+ >+inline void Rect::setLeft(LayoutUnit left) >+{ >+#if !ASSERT_DISABLED >+ m_hasValidLeft = true; >+#endif >+ m_rect.setX(left); >+} >+ >+inline void Rect::setWidth(LayoutUnit width) >+{ >+#if !ASSERT_DISABLED >+ m_hasValidWidth = true; >+#endif >+ m_rect.setWidth(width); >+} >+ >+inline void Rect::setHeight(LayoutUnit height) >+{ >+#if !ASSERT_DISABLED >+ m_hasValidHeight = true; >+#endif >+ m_rect.setHeight(height); >+} >+ >+inline void Rect::setSize(const LayoutSize& size) >+{ >+#if !ASSERT_DISABLED >+ setHasValidSize(); >+#endif >+ m_rect.setSize(size); >+} >+ >+inline void Rect::shiftLeftTo(LayoutUnit left) >+{ >+ ASSERT(m_hasValidLeft); >+ m_rect.shiftXEdgeTo(left); >+} >+ >+inline void Rect::shiftRightTo(LayoutUnit right) >+{ >+ ASSERT(m_hasValidLeft && m_hasValidWidth); >+ m_rect.shiftMaxXEdgeTo(right); >+} >+ >+inline void Rect::shiftTopTo(LayoutUnit top) >+{ >+ ASSERT(m_hasValidTop); >+ m_rect.shiftYEdgeTo(top); >+} >+ >+inline void Rect::shiftBottomTo(LayoutUnit bottom) >+{ >+ ASSERT(m_hasValidTop && m_hasValidHeight); >+ m_rect.shiftMaxYEdgeTo(bottom); >+} >+ >+inline void Rect::moveHorizontally(LayoutUnit offset) >+{ >+ ASSERT(m_hasValidLeft); >+ m_rect.move(LayoutSize { offset, 0 }); >+} >+ >+inline void Rect::moveVertically(LayoutUnit offset) >+{ >+ ASSERT(m_hasValidTop); >+ m_rect.move(LayoutSize { 0, offset }); >+} >+ >+inline void Rect::expand(LayoutUnit width, LayoutUnit height) >+{ >+ ASSERT(hasValidGeometry()); >+ m_rect.expand(width, height); >+} >+ >+inline Rect Rect::clone() const >+{ >+ Rect rect; >+#if !ASSERT_DISABLED >+ rect.m_hasValidTop = m_hasValidTop; >+ rect.m_hasValidLeft = m_hasValidLeft; >+ rect.m_hasValidWidth = m_hasValidWidth; >+ rect.m_hasValidHeight = m_hasValidHeight; >+#endif >+ rect.m_rect = m_rect; >+ return rect; >+} >+ >+inline Rect::operator LayoutRect() const >+{ >+ ASSERT(hasValidGeometry()); >+ return m_rect; >+} >+ >+} >+} >+#endif >diff --git a/Source/WebCore/layout/displaytree/DisplayRun.h b/Source/WebCore/layout/displaytree/DisplayRun.h >new file mode 100644 >index 0000000000000000000000000000000000000000..63929036083c40b039f9dec4933f6142a74da1b0 >--- /dev/null >+++ b/Source/WebCore/layout/displaytree/DisplayRun.h >@@ -0,0 +1,109 @@ >+/* >+ * 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 "InlineItem.h" >+#include "LayoutUnit.h" >+#include "TextFlags.h" >+ >+namespace WebCore { >+namespace Display { >+ >+struct Run { >+ struct TextContext { >+ public: >+ TextContext(unsigned position, unsigned length); >+ >+ unsigned start() const { return m_start; } >+ unsigned end() const { return start() + length(); } >+ unsigned length() const { return m_length; } >+ >+ void expand(unsigned length) { m_length += length; } >+ >+ private: >+ unsigned m_start; >+ unsigned m_length; >+ }; >+ >+ Run(Rect logicalRect); >+ Run(Rect logicalRect, TextContext); >+ Run(const Run&); >+ >+ LayoutPoint logicalTopLeft() const { return m_logicalRect.topLeft(); } >+ LayoutUnit logicalLeft() const { return m_logicalRect.left(); } >+ LayoutUnit logicalRight() const { return m_logicalRect.right(); } >+ LayoutUnit logicalTop() const { return m_logicalRect.top(); } >+ LayoutUnit logicalBottom() const { return m_logicalRect.bottom(); } >+ >+ LayoutUnit logicalWidth() const { return m_logicalRect.width(); } >+ LayoutUnit logicalHeight() const { return m_logicalRect.height(); } >+ >+ void setLogicalWidth(LayoutUnit width) { m_logicalRect.setWidth(width); } >+ void setLogicalTop(LayoutUnit logicalTop) { m_logicalRect.setTop(logicalTop); } >+ void setLogicalLeft(LayoutUnit logicalLeft) { m_logicalRect.setLeft(logicalLeft); } >+ void setLogicalRight(LayoutUnit logicalRight) { m_logicalRect.shiftRightTo(logicalRight); } >+ void moveVertically(LayoutUnit delta) { m_logicalRect.moveVertically(delta); } >+ void moveHorizontally(LayoutUnit delta) { m_logicalRect.moveHorizontally(delta); } >+ void expandVertically(LayoutUnit delta) { m_logicalRect.expand(0, delta); } >+ void expandHorizontally(LayoutUnit delta) { m_logicalRect.expand(delta, 0); } >+ >+ void setTextContext(TextContext textContext) { m_textContext.emplace(textContext); } >+ Optional<TextContext>& textContext() { return m_textContext; } >+ Optional<TextContext> textContext() const { return m_textContext; } >+ >+private: >+ Rect m_logicalRect; >+ Optional<TextContext> m_textContext; >+}; >+ >+inline Run::Run(Rect logicalRect) >+ : m_logicalRect(logicalRect) >+{ >+} >+ >+inline Run::Run(Rect logicalRect, TextContext textContext) >+ : m_logicalRect(logicalRect) >+ , m_textContext(textContext) >+{ >+} >+ >+inline Run::TextContext::TextContext(unsigned start, unsigned length) >+ : m_start(start) >+ , m_length(length) >+{ >+} >+ >+inline Run::Run(const Run& other) >+{ >+ m_logicalRect = other.m_logicalRect; >+ m_textContext = other.m_textContext; >+} >+ >+} >+} >+#endif >diff --git a/Source/WebCore/layout/floats/FloatAvoider.cpp b/Source/WebCore/layout/floats/FloatAvoider.cpp >index 151d88e267b6b05060db64335329cd0a10381a07..870cff5fcf3d22da356f57abe2307ea52d48dbff 100644 >--- a/Source/WebCore/layout/floats/FloatAvoider.cpp >+++ b/Source/WebCore/layout/floats/FloatAvoider.cpp >@@ -113,7 +113,7 @@ bool FloatAvoider::overflowsContainingBlock() const > return containingBlockContentBoxRight < right; > } > >-Display::Box::Rect FloatAvoider::rectInContainingBlock() const >+Display::Rect FloatAvoider::rectInContainingBlock() const > { > // From formatting root coordinate system back to containing block's. > if (layoutBox().containingBlock() == &floatingState().root()) >diff --git a/Source/WebCore/layout/floats/FloatAvoider.h b/Source/WebCore/layout/floats/FloatAvoider.h >index 2c323dd80f666f873d56e3f45caa31da89b0f4ed..6ed9d43d3bffab93a0d88d8671f4e807b02351bc 100644 >--- a/Source/WebCore/layout/floats/FloatAvoider.h >+++ b/Source/WebCore/layout/floats/FloatAvoider.h >@@ -46,8 +46,8 @@ public: > FloatAvoider(const Box&, const FloatingState&, const LayoutState&); > virtual ~FloatAvoider() = default; > >- virtual Display::Box::Rect rect() const { return m_absoluteDisplayBox.rect(); } >- Display::Box::Rect rectInContainingBlock() const; >+ virtual Display::Rect rect() const { return m_absoluteDisplayBox.rect(); } >+ Display::Rect rectInContainingBlock() const; > > struct HorizontalConstraints { > Optional<PositionInContextRoot> left; >diff --git a/Source/WebCore/layout/floats/FloatBox.cpp b/Source/WebCore/layout/floats/FloatBox.cpp >index beb757e32714cb4e9e7fc5280c67ef9409eb5acd..b2e86c152167c3ea23da7498c677ff4493ffd8ef 100644 >--- a/Source/WebCore/layout/floats/FloatBox.cpp >+++ b/Source/WebCore/layout/floats/FloatBox.cpp >@@ -41,7 +41,7 @@ FloatBox::FloatBox(const Box& layoutBox, const FloatingState& floatingState, con > displayBox().setTopLeft({ initialHorizontalPosition(), initialVerticalPosition() }); > } > >-Display::Box::Rect FloatBox::rect() const >+Display::Rect FloatBox::rect() const > { > auto rect = displayBox().rect(); > return { rect.top() - marginBefore(), rect.left() - marginStart(), marginStart() + rect.width() + marginEnd(), marginBefore() + rect.height() + marginAfter() }; >diff --git a/Source/WebCore/layout/floats/FloatBox.h b/Source/WebCore/layout/floats/FloatBox.h >index 2edcae88d72c3fc118d448a189ece001f3ee0062..97d215075bed184e38aafd4d17304527b5a00e00 100644 >--- a/Source/WebCore/layout/floats/FloatBox.h >+++ b/Source/WebCore/layout/floats/FloatBox.h >@@ -43,7 +43,7 @@ class FloatBox : public FloatAvoider { > public: > FloatBox(const Box&, const FloatingState&, const LayoutState&); > >- Display::Box::Rect rect() const final; >+ Display::Rect rect() const final; > > private: > bool isLeftAligned() const final { return layoutBox().isLeftFloatingPositioned(); } >diff --git a/Source/WebCore/layout/floats/FloatingContext.cpp b/Source/WebCore/layout/floats/FloatingContext.cpp >index 095af9f08dc8188f677de60f215979c0e2504b34..9495d33084162f612cba85cf938d57739d6ca727 100644 >--- a/Source/WebCore/layout/floats/FloatingContext.cpp >+++ b/Source/WebCore/layout/floats/FloatingContext.cpp >@@ -74,7 +74,7 @@ public: > bool isEmpty() const { return m_floatPair.isEmpty(); } > const FloatingState::FloatItem* left() const; > const FloatingState::FloatItem* right() const; >- bool intersects(const Display::Box::Rect&) const; >+ bool intersects(const Display::Rect&) const; > PositionInContextRoot verticalConstraint() const { return m_verticalPosition; } > FloatAvoider::HorizontalConstraints horizontalConstraints() const; > PositionInContextRoot bottom() const; >@@ -370,7 +370,7 @@ const FloatingState::FloatItem* FloatPair::right() const > return &m_floats[*m_floatPair.right]; > } > >-bool FloatPair::intersects(const Display::Box::Rect& floatAvoiderRect) const >+bool FloatPair::intersects(const Display::Rect& floatAvoiderRect) const > { > auto intersects = [&](auto* floating) { > return floating && floating->rectWithMargin().intersects(floatAvoiderRect); >diff --git a/Source/WebCore/layout/floats/FloatingState.h b/Source/WebCore/layout/floats/FloatingState.h >index 0efae84d73b5ac2933fe515896bdaa42f25a88da..e1cb8d20f8579e759706e1e912ac3b75e4b29d66 100644 >--- a/Source/WebCore/layout/floats/FloatingState.h >+++ b/Source/WebCore/layout/floats/FloatingState.h >@@ -74,7 +74,7 @@ public: > bool isLeftPositioned() const { return m_layoutBox->isLeftFloatingPositioned(); } > bool isDescendantOfFormattingRoot(const Box&) const; > >- Display::Box::Rect rectWithMargin() const { return m_absoluteDisplayBox.rectWithMargin(); } >+ Display::Rect rectWithMargin() const { return m_absoluteDisplayBox.rectWithMargin(); } > PositionInContextRoot bottom() const { return { m_absoluteDisplayBox.bottom() }; } > > private: >diff --git a/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp b/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp >index e3c1536dcd32a1efed8128d332b118e28bdd9e72..483b37dfce695bee3cbe320dc7685e9470d0fb4e 100644 >--- a/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp >+++ b/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp >@@ -30,7 +30,7 @@ > > #include "InlineFormattingState.h" > #include "InlineLineBreaker.h" >-#include "InlineRunProvider.h" >+#include "InlineTextItem.h" > #include "LayoutBox.h" > #include "LayoutContainer.h" > #include "LayoutInlineBox.h" >@@ -77,18 +77,23 @@ void InlineFormattingContext::layout() const > while (layoutBox) { > if (layoutBox->establishesFormattingContext()) > layoutFormattingContextRoot(*layoutBox, usedValues); >- else if (is<Container>(*layoutBox)) { >- auto& inlineContainer = downcast<InlineContainer>(*layoutBox); >- computeMargin(inlineContainer, usedValues); >- computeBorderAndPadding(inlineContainer, usedValues); >- } else if (layoutBox->isReplaced()) >+ else if (is<Container>(*layoutBox)) >+ computeMarginBorderAndPaddingForInlineContainer(downcast<InlineContainer>(*layoutBox), usedValues); >+ else if (layoutBox->isReplaced()) > computeWidthAndHeightForReplacedInlineBox(*layoutBox, usedValues); >+ else if (is<InlineBox>(*layoutBox)) >+ initializeMarginBorderAndPaddingForGenericInlineBox(downcast<InlineBox>(*layoutBox)); >+ else >+ ASSERT_NOT_REACHED(); > layoutBox = nextInPreOrder(*layoutBox, root); > } > >- InlineRunProvider inlineRunProvider; >- collectInlineContent(inlineRunProvider); >- LineLayout(*this).layout(inlineRunProvider); >+ // FIXME: This is such a waste when intrinsic width computation already collected the inline items. >+ formattingState().inlineItems().clear(); >+ formattingState().inlineRuns().clear(); >+ >+ collectInlineContent(); >+ LineLayout(*this).layout(); > LOG_WITH_STREAM(FormattingContextLayout, stream << "[End] -> inline formatting context -> formatting root(" << &root << ")"); > } > >@@ -120,30 +125,30 @@ void InlineFormattingContext::computeIntrinsicWidthConstraints() const > computeWidthAndMargin(*layoutBox, usedValues); > else { > // Simple inline container with no intrinsic width <span>. >- computeMargin(*layoutBox, usedValues); >+ computeHorizontalMargin(*layoutBox, usedValues); > } > } > layoutBox = nextInPreOrder(*layoutBox, root); > } > >- InlineRunProvider inlineRunProvider; >- collectInlineContent(inlineRunProvider); >+ collectInlineContent(); > > auto maximumLineWidth = [&](auto availableWidth) { >- LayoutUnit maxContentLogicalRight; >- auto lineBreaker = InlineLineBreaker { layoutState, formattingState().inlineContent(), inlineRunProvider.runs() }; >- LayoutUnit lineLogicalRight; >- > // Switch to the min/max formatting root width values before formatting the lines. > for (auto* formattingRoot : formattingContextRootList) { > auto intrinsicWidths = layoutState.formattingStateForBox(*formattingRoot).intrinsicWidthConstraints(*formattingRoot); > layoutState.displayBoxForLayoutBox(*formattingRoot).setContentBoxWidth(availableWidth ? intrinsicWidths->maximum : intrinsicWidths->minimum); > } >+ LayoutUnit maxContentLogicalRight; >+ LayoutUnit lineLogicalRight; > >- while (auto run = lineBreaker.nextRun(lineLogicalRight, availableWidth, !lineLogicalRight)) { >- if (run->position == InlineLineBreaker::Run::Position::LineBegin) >+ LineBreaker lineBreaker(layoutState); >+ auto& inlineContent = formattingState().inlineItems(); >+ for (auto& inlineItem : inlineContent) { >+ auto breakingContext = lineBreaker.breakingContext(*inlineItem, { availableWidth, lineLogicalRight, !lineLogicalRight }); >+ if (breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Wrap) > lineLogicalRight = 0; >- lineLogicalRight += run->width; >+ lineLogicalRight += inlineItem->width(); > > maxContentLogicalRight = std::max(maxContentLogicalRight, lineLogicalRight); > } >@@ -154,22 +159,34 @@ void InlineFormattingContext::computeIntrinsicWidthConstraints() const > layoutState.formattingStateForBox(root).setIntrinsicWidthConstraints(root, intrinsicWidthConstraints); > } > >-void InlineFormattingContext::computeIntrinsicWidthForFloatBox(const Box& layoutBox) const >+void InlineFormattingContext::initializeMarginBorderAndPaddingForGenericInlineBox(const InlineBox& layoutBox) const > { >- ASSERT(layoutBox.isFloatingPositioned()); >+ ASSERT(layoutBox.isAnonymous() || is<LineBreakBox>(layoutBox)); > auto& layoutState = this->layoutState(); >+ auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox); >+ >+ displayBox.setVerticalMargin({ { }, { } }); >+ displayBox.setHorizontalMargin({ }); >+ displayBox.setBorder({ { }, { } }); >+ displayBox.setPadding({ }); >+} > >- auto usedHorizontalValues = UsedHorizontalValues { }; >- computeBorderAndPadding(layoutBox, usedHorizontalValues); >- computeMargin(layoutBox, usedHorizontalValues); >- layoutState.createFormattingContext(layoutBox)->computeIntrinsicWidthConstraints(); >+void InlineFormattingContext::computeMarginBorderAndPaddingForInlineContainer(const InlineContainer& container, UsedHorizontalValues usedValues) const >+{ >+ computeHorizontalMargin(container, usedValues); >+ computeBorderAndPadding(container, usedValues); >+ // Inline containers (<span>) have 0 vertical margins. >+ layoutState().displayBoxForLayoutBox(container).setVerticalMargin({ { }, { } }); >+} > >- auto usedVerticalValues = UsedVerticalValues { }; >- auto heightAndMargin = Geometry::floatingHeightAndMargin(layoutState, layoutBox, usedVerticalValues, usedHorizontalValues); >+void InlineFormattingContext::computeIntrinsicWidthForFloatBox(const Box& layoutBox) const >+{ >+ ASSERT(layoutBox.isFloatingPositioned()); > >- auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox); >- displayBox.setContentBoxHeight(heightAndMargin.height); >- displayBox.setVerticalMargin({ heightAndMargin.nonCollapsedMargin, { } }); >+ auto usedValues = UsedHorizontalValues { }; >+ computeBorderAndPadding(layoutBox, usedValues); >+ computeHorizontalMargin(layoutBox, usedValues); >+ layoutState().createFormattingContext(layoutBox)->computeIntrinsicWidthConstraints(); > } > > void InlineFormattingContext::computeIntrinsicWidthForInlineBlock(const Box& layoutBox) const >@@ -178,11 +195,11 @@ void InlineFormattingContext::computeIntrinsicWidthForInlineBlock(const Box& lay > > auto usedValues = UsedHorizontalValues { }; > computeBorderAndPadding(layoutBox, usedValues); >- computeMargin(layoutBox, usedValues); >+ computeHorizontalMargin(layoutBox, usedValues); > layoutState().createFormattingContext(layoutBox)->computeIntrinsicWidthConstraints(); > } > >-void InlineFormattingContext::computeMargin(const Box& layoutBox, UsedHorizontalValues usedValues) const >+void InlineFormattingContext::computeHorizontalMargin(const Box& layoutBox, UsedHorizontalValues usedValues) const > { > auto computedHorizontalMargin = Geometry::computedHorizontalMargin(layoutBox, usedValues); > auto& displayBox = layoutState().displayBoxForLayoutBox(layoutBox); >@@ -235,6 +252,8 @@ void InlineFormattingContext::layoutFormattingContextRoot(const Box& root, UsedH > > computeBorderAndPadding(root, usedValues); > computeWidthAndMargin(root, usedValues); >+ // This is similar to static positioning in block formatting context. We just need to initialize the top left position. >+ layoutState().displayBoxForLayoutBox(root).setTopLeft({ 0, 0 }); > // Swich over to the new formatting context (the one that the root creates). > auto formattingContext = layoutState().createFormattingContext(root); > formattingContext->layout(); >@@ -256,88 +275,29 @@ void InlineFormattingContext::computeWidthAndHeightForReplacedInlineBox(const Bo > computeHeightAndMargin(layoutBox); > } > >-static void addDetachingRules(InlineItem& inlineItem, Optional<LayoutUnit> nonBreakableStartWidth, Optional<LayoutUnit> nonBreakableEndWidth) >-{ >- OptionSet<InlineItem::DetachingRule> detachingRules; >- if (nonBreakableStartWidth) { >- detachingRules.add(InlineItem::DetachingRule::BreakAtStart); >- inlineItem.addNonBreakableStart(*nonBreakableStartWidth); >- } >- if (nonBreakableEndWidth) { >- detachingRules.add(InlineItem::DetachingRule::BreakAtEnd); >- inlineItem.addNonBreakableEnd(*nonBreakableEndWidth); >- } >- inlineItem.addDetachingRule(detachingRules); >-} >- >-static InlineItem& createAndAppendInlineItem(InlineRunProvider& inlineRunProvider, InlineContent& inlineContent, const Box& layoutBox) >-{ >- ASSERT(layoutBox.isInlineLevelBox() || layoutBox.isFloatingPositioned()); >- auto inlineItem = std::make_unique<InlineItem>(layoutBox); >- auto* inlineItemPtr = inlineItem.get(); >- inlineContent.add(WTFMove(inlineItem)); >- inlineRunProvider.append(*inlineItemPtr); >- return *inlineItemPtr; >-} >- >-void InlineFormattingContext::collectInlineContent(InlineRunProvider& inlineRunProvider) const >+void InlineFormattingContext::collectInlineContent() const > { > if (!is<Container>(root())) > return; > auto& root = downcast<Container>(this->root()); > if (!root.hasInFlowOrFloatingChild()) > return; >- // The logic here is very similar to BFC layout. >- // 1. Travers down the layout tree and collect "start" unbreakable widths (margin-left, border-left, padding-left) >- // 2. Create InlineItem per leaf inline box (text nodes, inline-blocks, floats) and set "start" unbreakable width on them. >- // 3. Climb back and collect "end" unbreakable width and set it on the last InlineItem. >- auto& layoutState = this->layoutState(); >- auto& inlineContent = formattingState().inlineContent(); >- >- enum class NonBreakableWidthType { Start, End }; >- auto nonBreakableWidth = [&](auto& container, auto type) { >- auto& displayBox = layoutState.displayBoxForLayoutBox(container); >- if (type == NonBreakableWidthType::Start) >- return displayBox.marginStart() + displayBox.borderLeft() + displayBox.paddingLeft().valueOr(0); >- return displayBox.marginEnd() + displayBox.borderRight() + displayBox.paddingRight().valueOr(0); >- }; >- >+ // Traverse the tree and create inline items out of containers and leaf nodes. This essentially turns the tree inline structure into a flat one. >+ // <span>text<span></span><img></span> -> [ContainerStart][InlineBox][ContainerStart][ContainerEnd][InlineBox][ContainerEnd] >+ auto& formattingState = this->formattingState(); > LayoutQueue layoutQueue; > layoutQueue.append(root.firstInFlowOrFloatingChild()); >- >- Optional<LayoutUnit> nonBreakableStartWidth; >- Optional<LayoutUnit> nonBreakableEndWidth; >- InlineItem* lastInlineItem = nullptr; > while (!layoutQueue.isEmpty()) { >+ auto treatAsInlineContainer = [](auto& layoutBox) { >+ return is<Container>(layoutBox) && !layoutBox.establishesFormattingContext(); >+ }; > while (true) { > auto& layoutBox = *layoutQueue.last(); >- if (!is<Container>(layoutBox)) >+ if (!treatAsInlineContainer(layoutBox)) > break; >+ // This is the start of an inline container (e.g. <span>). >+ formattingState.addInlineItem(std::make_unique<InlineItem>(layoutBox, InlineItem::Type::ContainerStart)); > auto& container = downcast<Container>(layoutBox); >- >- if (container.establishesFormattingContext()) { >- // Formatting contexts are treated as leaf nodes. >- auto& inlineItem = createAndAppendInlineItem(inlineRunProvider, inlineContent, container); >- auto& displayBox = layoutState.displayBoxForLayoutBox(container); >- auto currentNonBreakableStartWidth = nonBreakableStartWidth.valueOr(0) + displayBox.marginStart() + nonBreakableEndWidth.valueOr(0); >- addDetachingRules(inlineItem, currentNonBreakableStartWidth, displayBox.marginEnd()); >- nonBreakableStartWidth = { }; >- nonBreakableEndWidth = { }; >- >- // Formatting context roots take care of their subtrees. Continue with next sibling if exists. >- layoutQueue.removeLast(); >- if (!container.nextInFlowOrFloatingSibling()) >- break; >- layoutQueue.append(container.nextInFlowOrFloatingSibling()); >- continue; >- } >- >- // Check if this non-formatting context container has any non-breakable start properties (margin-left, border-left, padding-left) >- // <span style="padding-left: 5px"><span style="padding-left: 5px">foobar</span></span> -> 5px + 5px >- auto currentNonBreakableStartWidth = nonBreakableWidth(layoutBox, NonBreakableWidthType::Start); >- if (currentNonBreakableStartWidth || layoutBox.isPositioned()) >- nonBreakableStartWidth = nonBreakableStartWidth.valueOr(0) + currentNonBreakableStartWidth; >- > if (!container.hasInFlowOrFloatingChild()) > break; > layoutQueue.append(container.firstInFlowOrFloatingChild()); >@@ -345,29 +305,19 @@ void InlineFormattingContext::collectInlineContent(InlineRunProvider& inlineRunP > > while (!layoutQueue.isEmpty()) { > auto& layoutBox = *layoutQueue.takeLast(); >- if (is<Container>(layoutBox)) { >- // This is the end of an inline container. Compute the non-breakable end width and add it to the last inline box. >- // <span style="padding-right: 5px">foobar</span> -> 5px; last inline item -> "foobar" >- auto currentNonBreakableEndWidth = nonBreakableWidth(layoutBox, NonBreakableWidthType::End); >- if (currentNonBreakableEndWidth || layoutBox.isPositioned()) >- nonBreakableEndWidth = nonBreakableEndWidth.valueOr(0) + currentNonBreakableEndWidth; >- // Add it to the last inline box >- if (lastInlineItem) { >- addDetachingRules(*lastInlineItem, { }, nonBreakableEndWidth); >- nonBreakableEndWidth = { }; >- } >- } else { >- // Leaf inline box >- auto& inlineItem = createAndAppendInlineItem(inlineRunProvider, inlineContent, layoutBox); >- // Add start and the (through empty containers) accumulated end width. >- // <span style="padding-left: 1px">foobar</span> -> nonBreakableStartWidth: 1px; >- // <span style="padding: 5px"></span>foobar -> nonBreakableStartWidth: 5px; nonBreakableEndWidth: 5px >- if (nonBreakableStartWidth || nonBreakableEndWidth) { >- addDetachingRules(inlineItem, nonBreakableStartWidth.valueOr(0) + nonBreakableEndWidth.valueOr(0), { }); >- nonBreakableStartWidth = { }; >- nonBreakableEndWidth = { }; >- } >- lastInlineItem = &inlineItem; >+ // This is the end of an inline container (e.g. </span>). >+ if (treatAsInlineContainer(layoutBox)) >+ formattingState.addInlineItem(std::make_unique<InlineItem>(layoutBox, InlineItem::Type::ContainerEnd)); >+ else if (is<LineBreakBox>(layoutBox)) >+ formattingState.addInlineItem(std::make_unique<InlineItem>(layoutBox, InlineItem::Type::HardLineBreak)); >+ else if (layoutBox.isFloatingPositioned()) >+ formattingState.addInlineItem(std::make_unique<InlineItem>(layoutBox, InlineItem::Type::Float)); >+ else { >+ ASSERT(is<InlineBox>(layoutBox) || layoutBox.isInlineBlockBox()); >+ if (is<InlineBox>(layoutBox) && downcast<InlineBox>(layoutBox).hasTextContent()) >+ InlineTextItem::createAndAppendTextItems(formattingState.inlineItems(), downcast<InlineBox>(layoutBox)); >+ else >+ formattingState.addInlineItem(std::make_unique<InlineItem>(layoutBox, InlineItem::Type::Box)); > } > > if (auto* nextSibling = layoutBox.nextInFlowOrFloatingSibling()) { >diff --git a/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h b/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h >index a4fb31584adf8b81d8d5c61c3372612b0da93281..9b0d6226b53acc4e1bfae255fddf95810655e0da 100644 >--- a/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h >+++ b/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h >@@ -30,7 +30,6 @@ > #include "DisplayBox.h" > #include "FormattingContext.h" > #include "InlineFormattingState.h" >-#include "InlineRun.h" > #include <wtf/IsoMalloc.h> > > namespace WebCore { >@@ -38,7 +37,6 @@ namespace Layout { > > class FloatingState; > class InlineContainer; >-class InlineRunProvider; > class Line; > > // This class implements the layout logic for inline formatting contexts. >@@ -55,21 +53,15 @@ private: > class LineLayout { > public: > LineLayout(const InlineFormattingContext&); >- void layout(const InlineRunProvider&) const; >+ void layout() const; > > private: >- enum class IsLastLine { No, Yes }; >- void initializeNewLine(Line&) const; >- void closeLine(Line&, IsLastLine) const; >- void appendContentToLine(Line&, const InlineRunProvider::Run&, const LayoutSize&) const; >- void postProcessInlineRuns(Line&, IsLastLine) const; >- void createFinalRuns(Line&) const; >- void splitInlineRunIfNeeded(const InlineRun&, InlineRuns& splitRuns) const; >- void computeFloatPosition(const FloatingContext&, Line&, const Box&) const; >- void placeInFlowPositionedChildren(unsigned firstRunIndex) const; >- void alignRuns(TextAlignMode, Line&, IsLastLine) const; >- void computeExpansionOpportunities(Line&, const InlineRunProvider::Run&, InlineRunProvider::Run::Type lastRunType) const; >- LayoutUnit runWidth(const InlineContent&, const InlineItem&, ItemPosition from, unsigned length, LayoutUnit contentLogicalLeft) const; >+ LayoutState& layoutState() const { return m_formattingContext.layoutState(); } >+ void initializeLine(Line&, LayoutUnit lineLogicalTop) const; >+ void closeLine(Line&) const; >+ void commitInlineItemToLine(Line&, const InlineItem&) const; >+ void handleFloat(Line&, const FloatingContext&, const InlineItem& floatBox) const; >+ void alignRuns(TextAlignMode, unsigned firstRunIndex, LayoutUnit availableWidth) const; > > private: > static void justifyRuns(Line&); >@@ -89,13 +81,15 @@ private: > > void layoutFormattingContextRoot(const Box&, UsedHorizontalValues) const; > void computeIntrinsicWidthForFloatBox(const Box&) const; >+ void computeMarginBorderAndPaddingForInlineContainer(const InlineContainer&, UsedHorizontalValues) const; >+ void initializeMarginBorderAndPaddingForGenericInlineBox(const InlineBox&) const; > void computeIntrinsicWidthForInlineBlock(const Box&) const; > void computeWidthAndHeightForReplacedInlineBox(const Box&, UsedHorizontalValues) const; >- void computeMargin(const Box&, UsedHorizontalValues) const; >+ void computeHorizontalMargin(const Box&, UsedHorizontalValues) const; > void computeHeightAndMargin(const Box&) const; > void computeWidthAndMargin(const Box&, UsedHorizontalValues) const; > >- void collectInlineContent(InlineRunProvider&) const; >+ void collectInlineContent() const; > > InlineFormattingState& formattingState() const { return downcast<InlineFormattingState>(FormattingContext::formattingState()); } > }; >diff --git a/Source/WebCore/layout/inlineformatting/InlineFormattingContextLineLayout.cpp b/Source/WebCore/layout/inlineformatting/InlineFormattingContextLineLayout.cpp >index 3675fadf918f170998893ded348abe755d040aff..ea7bd66cd2405d154a67f56e214fd64ba1411c0a 100644 >--- a/Source/WebCore/layout/inlineformatting/InlineFormattingContextLineLayout.cpp >+++ b/Source/WebCore/layout/inlineformatting/InlineFormattingContextLineLayout.cpp >@@ -32,7 +32,6 @@ > #include "FloatingState.h" > #include "InlineFormattingState.h" > #include "InlineLineBreaker.h" >-#include "InlineRunProvider.h" > #include "LayoutBox.h" > #include "LayoutContainer.h" > #include "LayoutState.h" >@@ -41,230 +40,333 @@ > namespace WebCore { > namespace Layout { > >+struct UsedHeightAndDepth { >+ LayoutUnit height; >+ LayoutUnit depth; >+}; >+ >+static UsedHeightAndDepth halfLeadingMetrics(const FontMetrics& fontMetrics, LayoutUnit lineLogicalHeight) >+{ >+ auto ascent = fontMetrics.ascent(); >+ auto descent = fontMetrics.descent(); >+ // 10.8.1 Leading and half-leading >+ auto leading = lineLogicalHeight - (ascent + descent); >+ // Inline tree is all integer based. >+ auto adjustedAscent = std::max((ascent + leading / 2).floor(), 0); >+ auto adjustedDescent = std::max((descent + leading / 2).ceil(), 0); >+ return { adjustedAscent, adjustedDescent }; >+} >+ > class Line { > public: >- void init(const LayoutPoint& topLeft, LayoutUnit availableWidth, LayoutUnit minimalHeight); >- void close(); >+ Line(const LayoutState&); >+ >+ void reset(const LayoutPoint& topLeft, LayoutUnit availableWidth, LayoutUnit minimumLineHeight, LayoutUnit baselineOffset); >+ >+ struct LineItem { >+ LineItem(Display::Run, const InlineItem&, bool isCollapsed, bool canBeExtended); >+ >+ // Relative to the baseline. >+ Display::Run inlineRun; >+ const InlineItem& inlineItem; >+ bool isCollapsed { false }; >+ bool canBeExtended { false }; >+ }; >+ >+ using LineItems = Vector<std::unique_ptr<LineItem>>; >+ const LineItems& close(); > >- void appendContent(const InlineRunProvider::Run&, const LayoutSize&); >+ void appendTextContent(const InlineTextItem&, LayoutSize); >+ void appendNonReplacedInlineBox(const InlineItem&, LayoutSize); >+ void appendReplacedInlineBox(const InlineItem&, LayoutSize); >+ void appendInlineContainerStart(const InlineItem&); >+ void appendInlineContainerEnd(const InlineItem&); >+ void appendHardLineBreak(const InlineItem&); > >- void adjustLogicalLeft(LayoutUnit delta); >- void adjustLogicalRight(LayoutUnit delta); >+ bool hasContent() const; > >- bool hasContent() const { return !m_inlineRuns.isEmpty(); } >- bool isClosed() const { return m_closed; } >- bool isFirstLine() const { return m_isFirstLine; } >- Vector<InlineRun>& runs() { return m_inlineRuns; } >+ LayoutUnit trailingTrimmableWidth() const; > >- LayoutUnit contentLogicalRight() const; >- LayoutUnit contentLogicalLeft() const { return m_logicalRect.left(); } >- LayoutUnit availableWidth() const { return m_availableWidth; } >- Optional<InlineRunProvider::Run::Type> lastRunType() const { return m_lastRunType; } >+ void moveLogicalLeft(LayoutUnit); >+ void moveLogicalRight(LayoutUnit); > >- LayoutUnit logicalTop() const { return m_logicalRect.top(); } >- LayoutUnit logicalBottom() const { return m_logicalRect.bottom(); } >- LayoutUnit logicalHeight() const { return logicalBottom() - logicalTop(); } >+ LayoutUnit availableWidth() const { return logicalWidth() - contentLogicalWidth(); } >+ >+ LayoutUnit contentLogicalRight() const { return logicalLeft() + contentLogicalWidth(); } >+ LayoutUnit contentLogicalWidth() const { return m_contentLogicalWidth; } >+ >+ LayoutUnit logicalTop() const { return m_logicalTopLeft.y(); } >+ LayoutUnit logicalLeft() const { return m_logicalTopLeft.x(); } >+ LayoutUnit logicalRight() const { return logicalLeft() + logicalWidth(); } >+ LayoutUnit logicalBottom() const { return logicalTop() + logicalHeight(); } >+ LayoutUnit logicalWidth() const { return m_lineLogicalWidth; } >+ LayoutUnit logicalHeight() const { return m_logicalHeight.height + m_logicalHeight.depth; } > > private: >- struct TrailingTrimmableContent { >- LayoutUnit width; >- unsigned length; >- }; >- Optional<TrailingTrimmableContent> m_trailingTrimmableContent; >- Optional<InlineRunProvider::Run::Type> m_lastRunType; >- bool m_lastRunCanExpand { false }; >+ void appendNonBreakableSpace(const InlineItem&, const Display::Rect& logicalRect); >+ void removeTrailingTrimmableContent(); >+ >+ const LayoutState& m_layoutState; >+ LineItems m_lineItems; >+ ListHashSet<LineItem*> m_trimmableContent; > >- Display::Box::Rect m_logicalRect; >- LayoutUnit m_availableWidth; >+ LayoutPoint m_logicalTopLeft; >+ LayoutUnit m_contentLogicalWidth; > >- Vector<InlineRun> m_inlineRuns; >- bool m_isFirstLine { true }; >- bool m_closed { true }; >+ UsedHeightAndDepth m_logicalHeight; >+ LayoutUnit m_lineLogicalWidth; > }; > >-void Line::init(const LayoutPoint& topLeft, LayoutUnit availableWidth, LayoutUnit minimalHeight) >+Line::LineItem::LineItem(Display::Run inlineRun, const InlineItem& inlineItem, bool isCollapsed, bool canBeExtended) >+ : inlineRun(inlineRun) >+ , inlineItem(inlineItem) >+ , isCollapsed(isCollapsed) >+ , canBeExtended(canBeExtended) > { >- m_logicalRect.setTopLeft(topLeft); >- m_logicalRect.setWidth(availableWidth); >- m_logicalRect.setHeight(minimalHeight); >- m_availableWidth = availableWidth; >- >- m_inlineRuns.clear(); >- m_lastRunType = { }; >- m_lastRunCanExpand = false; >- m_trailingTrimmableContent = { }; >- m_closed = false; > } > >-void Line::adjustLogicalLeft(LayoutUnit delta) >+Line::Line(const LayoutState& layoutState) >+ : m_layoutState(layoutState) > { >- ASSERT(delta > 0); >- >- m_availableWidth -= delta; >- m_logicalRect.shiftLeftTo(m_logicalRect.left() + delta); >+} > >- for (auto& inlineRun : m_inlineRuns) >- inlineRun.moveHorizontally(delta); >+void Line::reset(const LayoutPoint& topLeft, LayoutUnit availableWidth, LayoutUnit minimumHeight, LayoutUnit baselineOffset) >+{ >+ m_logicalTopLeft = topLeft; >+ m_lineLogicalWidth = availableWidth; >+ m_logicalHeight = { baselineOffset, minimumHeight - baselineOffset }; >+ >+ m_contentLogicalWidth = { }; >+ >+ m_lineItems.clear(); >+ m_trimmableContent.clear(); > } > >-void Line::adjustLogicalRight(LayoutUnit delta) >+const Line::LineItems& Line::close() > { >- ASSERT(delta > 0); >+ removeTrailingTrimmableContent(); >+ // Convert inline run geometry from relative to the baseline to relative to logical top. >+ for (auto& lineItem : m_lineItems) { >+ auto adjustedLogicalTop = lineItem->inlineRun.logicalTop() + m_logicalHeight.height + m_logicalTopLeft.y(); >+ lineItem->inlineRun.setLogicalTop(adjustedLogicalTop); >+ } >+ return m_lineItems; >+} > >- m_availableWidth -= delta; >- m_logicalRect.shiftRightTo(m_logicalRect.right() - delta); >+void Line::removeTrailingTrimmableContent() >+{ >+ // Collapse trimmable trailing content >+ LayoutUnit trimmableWidth; >+ for (auto* trimmableRun : m_trimmableContent) { >+ trimmableRun->isCollapsed = true; >+ trimmableWidth += trimmableRun->inlineRun.logicalWidth(); >+ } >+ m_contentLogicalWidth -= trimmableWidth; > } > >-static bool isTrimmableContent(const InlineRunProvider::Run& inlineRun) >+void Line::moveLogicalLeft(LayoutUnit delta) > { >- return inlineRun.isWhitespace() && inlineRun.style().collapseWhiteSpace(); >+ if (!delta) >+ return; >+ ASSERT(delta > 0); >+ // Shrink the line and move the items. >+ m_logicalTopLeft.move(delta, 0); >+ m_lineLogicalWidth -= delta; >+ for (auto& lineItem : m_lineItems) >+ lineItem->inlineRun.moveHorizontally(delta); > } > >-LayoutUnit Line::contentLogicalRight() const >+void Line::moveLogicalRight(LayoutUnit delta) > { >- if (m_inlineRuns.isEmpty()) >- return m_logicalRect.left(); >+ ASSERT(delta > 0); >+ m_lineLogicalWidth -= delta; >+} > >- return m_inlineRuns.last().logicalRight(); >+static bool isTrimmableContent(const InlineItem& inlineItem) >+{ >+ if (!is<InlineTextItem>(inlineItem)) >+ return false; >+ auto& inlineTextItem = downcast<InlineTextItem>(inlineItem); >+ return inlineTextItem.isWhitespace() && inlineTextItem.style().collapseWhiteSpace(); > } > >-void Line::appendContent(const InlineRunProvider::Run& run, const LayoutSize& runSize) >+LayoutUnit Line::trailingTrimmableWidth() const > { >- ASSERT(!isClosed()); >- >- // Append this text run to the end of the last text run, if the last run is continuous. >- Optional<InlineRun::TextContext> textRun; >- if (run.isText()) { >- auto textContext = run.textContext(); >- auto runLength = textContext->isCollapsed() ? 1 : textContext->length(); >- textRun = InlineRun::TextContext { textContext->start(), runLength }; >- } >+ LayoutUnit trimmableWidth; >+ for (auto* trimmableRun : m_trimmableContent) >+ trimmableWidth += trimmableRun->inlineRun.logicalWidth(); >+ return trimmableWidth; >+} > >- auto requiresNewInlineRun = !hasContent() || !run.isText() || !m_lastRunCanExpand; >- if (requiresNewInlineRun) { >- // FIXME: This needs proper baseline handling >- auto inlineRun = InlineRun { { logicalTop(), contentLogicalRight(), runSize.width(), runSize.height() }, run.inlineItem() }; >- if (textRun) >- inlineRun.setTextContext({ textRun->start(), textRun->length() }); >- m_inlineRuns.append(inlineRun); >- m_logicalRect.setHeight(std::max(runSize.height(), m_logicalRect.height())); >- } else { >- // Non-text runs always require new inline run. >- ASSERT(textRun); >- auto& inlineRun = m_inlineRuns.last(); >- ASSERT(runSize.height() == inlineRun.logicalHeight()); >- inlineRun.setLogicalWidth(inlineRun.logicalWidth() + runSize.width()); >- inlineRun.textContext()->setLength(inlineRun.textContext()->length() + textRun->length()); >+bool Line::hasContent() const >+{ >+ // Return false for empty containers like <span></span>. >+ if (m_lineItems.isEmpty()) >+ return false; >+ for (auto& lineItem : m_lineItems) { >+ if (lineItem->inlineItem.isContainerStart() || lineItem->inlineItem.isContainerEnd()) >+ continue; >+ if (!lineItem->isCollapsed) >+ return true; > } >+ return false; >+} > >- m_availableWidth -= runSize.width(); >- m_lastRunType = run.type(); >- m_lastRunCanExpand = run.isText() && !run.textContext()->isCollapsed(); >- m_trailingTrimmableContent = { }; >- if (isTrimmableContent(run)) >- m_trailingTrimmableContent = TrailingTrimmableContent { runSize.width(), textRun->length() }; >+void Line::appendNonBreakableSpace(const InlineItem& inlineItem, const Display::Rect& logicalRect) >+{ >+ m_lineItems.append(std::make_unique<LineItem>(Display::Run { logicalRect }, inlineItem, false, false)); >+ m_contentLogicalWidth += inlineItem.width(); > } > >-void Line::close() >+void Line::appendInlineContainerStart(const InlineItem& inlineItem) > { >- auto trimTrailingContent = [&] { >- if (!m_trailingTrimmableContent) >- return; >- auto& lastInlineRun = m_inlineRuns.last(); >- lastInlineRun.setLogicalWidth(lastInlineRun.logicalWidth() - m_trailingTrimmableContent->width); >- lastInlineRun.textContext()->setLength(lastInlineRun.textContext()->length() - m_trailingTrimmableContent->length); >- >- if (!lastInlineRun.textContext()->length()) >- m_inlineRuns.removeLast(); >- m_availableWidth += m_trailingTrimmableContent->width; >- m_trailingTrimmableContent = { }; >+ auto& layoutBox = inlineItem.layoutBox(); >+ auto& style = layoutBox.style(); >+ auto& fontMetrics = style.fontMetrics(); >+ >+ auto alignAndAdjustLineHeight = [&] { >+ LayoutUnit inlineBoxHeight = style.computedLineHeight(); >+ >+ auto halfLeading = halfLeadingMetrics(fontMetrics, inlineBoxHeight); >+ if (halfLeading.depth > 0) >+ m_logicalHeight.depth = std::max(m_logicalHeight.depth, halfLeading.depth); >+ if (halfLeading.height > 0) >+ m_logicalHeight.height = std::max(m_logicalHeight.height, halfLeading.height); > }; > >- if (!hasContent()) >- return; >- >- trimTrailingContent(); >- m_isFirstLine = false; >- m_closed = true; >+ alignAndAdjustLineHeight(); >+ auto& displayBox = m_layoutState.displayBoxForLayoutBox(layoutBox); >+ auto containerHeight = fontMetrics.height() + displayBox.verticalBorder() + displayBox.verticalPadding().valueOr(0); >+ auto logicalTop = -fontMetrics.ascent() - displayBox.borderTop() - displayBox.paddingTop().valueOr(0); >+ auto logicalRect = Display::Rect { logicalTop, contentLogicalRight(), inlineItem.width(), containerHeight }; >+ appendNonBreakableSpace(inlineItem, logicalRect); > } > >-InlineFormattingContext::LineLayout::LineLayout(const InlineFormattingContext& inlineFormattingContext) >- : m_formattingContext(inlineFormattingContext) >- , m_formattingState(m_formattingContext.formattingState()) >- , m_floatingState(m_formattingState.floatingState()) >- , m_formattingRoot(downcast<Container>(m_formattingContext.root())) >+void Line::appendInlineContainerEnd(const InlineItem& inlineItem) > { >+ // This is really just a placeholder to mark the end of the inline level container. >+ auto logicalRect = Display::Rect { 0, contentLogicalRight(), inlineItem.width(), 0 }; >+ appendNonBreakableSpace(inlineItem, logicalRect); > } > >-static bool isTrimmableContent(const InlineLineBreaker::Run& run) >+void Line::appendTextContent(const InlineTextItem& inlineItem, LayoutSize runSize) > { >- return run.content.isWhitespace() && run.content.style().collapseWhiteSpace(); >+ auto isTrimmable = isTrimmableContent(inlineItem); >+ if (!isTrimmable) >+ m_trimmableContent.clear(); >+ >+ auto shouldCollapseCompletely = [&] { >+ if (!isTrimmable) >+ return false; >+ // Leading whitespace. >+ if (m_lineItems.isEmpty()) >+ return true; >+ // Check if the last item is trimmable as well. >+ for (int index = m_lineItems.size() - 1; index >= 0; --index) { >+ auto& inlineItem = m_lineItems[index]->inlineItem; >+ if (inlineItem.isBox()) >+ return false; >+ if (inlineItem.isText()) >+ return inlineItem.isText() && isTrimmableContent(downcast<InlineTextItem>(inlineItem)); >+ ASSERT(inlineItem.isContainerStart() || inlineItem.isContainerEnd()); >+ } >+ return true; >+ }; >+ >+ // Collapsed line items don't contribute to the line width. >+ auto isCompletelyCollapsed = shouldCollapseCompletely(); >+ auto canBeExtended = !isCompletelyCollapsed && !inlineItem.isCollapsed(); >+ auto logicalRect = Display::Rect { -inlineItem.style().fontMetrics().ascent(), contentLogicalRight(), runSize.width(), runSize.height() }; >+ auto textContext = Display::Run::TextContext { inlineItem.start(), inlineItem.isCollapsed() ? 1 : inlineItem.length() }; >+ auto displayRun = Display::Run(logicalRect, textContext); >+ >+ auto lineItem = std::make_unique<LineItem>(displayRun, inlineItem, isCompletelyCollapsed, canBeExtended); >+ if (isTrimmable) >+ m_trimmableContent.add(lineItem.get()); >+ >+ m_lineItems.append(WTFMove(lineItem)); >+ m_contentLogicalWidth += isCompletelyCollapsed ? LayoutUnit() : runSize.width(); > } > >-void InlineFormattingContext::LineLayout::layout(const InlineRunProvider& inlineRunProvider) const >+void Line::appendNonReplacedInlineBox(const InlineItem& inlineItem, LayoutSize runSize) > { >- auto& layoutState = m_formattingContext.layoutState(); >- auto floatingContext = FloatingContext { m_floatingState }; >- >- Line line; >- initializeNewLine(line); >+ auto alignAndAdjustLineHeight = [&] { >+ auto inlineBoxHeight = runSize.height(); >+ // FIXME: We need to look inside the inline-block's formatting context and check the lineboxes (if any) to be able to baseline align. >+ if (inlineItem.layoutBox().establishesInlineFormattingContext()) { >+ if (inlineBoxHeight == logicalHeight()) >+ return; >+ // FIXME: This fails when the line height difference comes from font-size diff. >+ m_logicalHeight.depth = std::max<LayoutUnit>(0, m_logicalHeight.depth); >+ m_logicalHeight.height = std::max(inlineBoxHeight, m_logicalHeight.height); >+ return; >+ } >+ // 0 descent -> baseline aligment for now. >+ m_logicalHeight.depth = std::max<LayoutUnit>(0, m_logicalHeight.depth); >+ m_logicalHeight.height = std::max(inlineBoxHeight, m_logicalHeight.height); >+ }; > >- InlineLineBreaker lineBreaker(layoutState, m_formattingState.inlineContent(), inlineRunProvider.runs()); >- while (auto run = lineBreaker.nextRun(line.contentLogicalRight(), line.availableWidth(), !line.hasContent())) { >- auto isFirstRun = run->position == InlineLineBreaker::Run::Position::LineBegin; >- auto isLastRun = run->position == InlineLineBreaker::Run::Position::LineEnd; >- auto generatesInlineRun = true; >+ alignAndAdjustLineHeight(); >+ auto& displayBox = m_layoutState.displayBoxForLayoutBox(inlineItem.layoutBox()); >+ auto logicalTop = -runSize.height(); >+ auto horizontalMargin = displayBox.horizontalMargin(); >+ auto logicalRect = Display::Rect { logicalTop, contentLogicalRight() + horizontalMargin.start, runSize.width(), runSize.height() }; > >- // Position float and adjust the runs on line. >- if (run->content.isFloat()) { >- auto& floatBox = run->content.inlineItem().layoutBox(); >- computeFloatPosition(floatingContext, line, floatBox); >- m_floatingState.append(floatBox); >+ m_lineItems.append(std::make_unique<LineItem>(Display::Run { logicalRect }, inlineItem, false, false)); >+ m_contentLogicalWidth += (runSize.width() + horizontalMargin.start + horizontalMargin.end); >+ m_trimmableContent.clear(); >+} > >- auto floatBoxWidth = layoutState.displayBoxForLayoutBox(floatBox).marginBox().width(); >- // Shrink availble space for current line and move existing inline runs. >- floatBox.isLeftFloatingPositioned() ? line.adjustLogicalLeft(floatBoxWidth) : line.adjustLogicalRight(floatBoxWidth); >+void Line::appendReplacedInlineBox(const InlineItem& inlineItem, LayoutSize runSize) >+{ >+ // FIXME Surely replaced boxes behave differently. >+ appendNonReplacedInlineBox(inlineItem, runSize); >+} > >- generatesInlineRun = false; >- } >+void Line::appendHardLineBreak(const InlineItem& inlineItem) >+{ >+ auto ascent = inlineItem.layoutBox().style().fontMetrics().ascent(); >+ auto logicalRect = Display::Rect { -ascent, contentLogicalRight(), { }, logicalHeight() }; >+ m_lineItems.append(std::make_unique<LineItem>(Display::Run { logicalRect }, inlineItem, false, false)); >+} > >- // 1. Initialize new line if needed. >- // 2. Append inline run unless it is skipped. >- // 3. Close current line if needed. >- if (isFirstRun) { >- // When the first run does not generate an actual inline run, the next run comes in first-run as well. >- // No need to spend time on closing/initializing. >- // Skip leading whitespace. >- if (!generatesInlineRun || isTrimmableContent(*run)) >- continue; >+struct UncommittedContent { >+ void add(InlineItem&); >+ void reset(); > >- if (line.hasContent()) { >- // Previous run ended up being at the line end. Adjust the line accordingly. >- if (!line.isClosed()) >- closeLine(line, IsLastLine::No); >- initializeNewLine(line); >- } >- } >+ Vector<InlineItem*> inlineItems() { return m_inlineItems; } >+ bool isEmpty() const { return m_inlineItems.isEmpty(); } >+ LayoutUnit width() const { return m_width; } > >- if (generatesInlineRun) { >- auto width = run->width; >- auto height = run->content.isText() ? LayoutUnit(m_formattingRoot.style().computedLineHeight()) : layoutState.displayBoxForLayoutBox(run->content.inlineItem().layoutBox()).height(); >- appendContentToLine(line, run->content, { width, height }); >- } >+private: >+ Vector<InlineItem*> m_inlineItems; >+ LayoutUnit m_width; >+}; > >- if (isLastRun) >- closeLine(line, IsLastLine::No); >- } >+void UncommittedContent::add(InlineItem& inlineItem) >+{ >+ m_inlineItems.append(&inlineItem); >+ m_width += inlineItem.width(); >+} > >- closeLine(line, IsLastLine::Yes); >+void UncommittedContent::reset() >+{ >+ m_inlineItems.clear(); >+ m_width = 0; > } > >-void InlineFormattingContext::LineLayout::initializeNewLine(Line& line) const >+InlineFormattingContext::LineLayout::LineLayout(const InlineFormattingContext& inlineFormattingContext) >+ : m_formattingContext(inlineFormattingContext) >+ , m_formattingState(m_formattingContext.formattingState()) >+ , m_floatingState(m_formattingState.floatingState()) >+ , m_formattingRoot(downcast<Container>(m_formattingContext.root())) > { >- auto& formattingRootDisplayBox = m_formattingContext.layoutState().displayBoxForLayoutBox(m_formattingRoot); >+} > >+void InlineFormattingContext::LineLayout::initializeLine(Line& line, LayoutUnit lineLogicalTop) const >+{ >+ auto& formattingRootDisplayBox = layoutState().displayBoxForLayoutBox(m_formattingRoot); > auto lineLogicalLeft = formattingRootDisplayBox.contentBoxLeft(); >- auto lineLogicalTop = line.isFirstLine() ? formattingRootDisplayBox.contentBoxTop() : line.logicalBottom(); > auto availableWidth = formattingRootDisplayBox.contentBoxWidth(); > > // Check for intruding floats and adjust logical left/available width for this line accordingly. >@@ -291,314 +393,239 @@ void InlineFormattingContext::LineLayout::initializeNewLine(Line& line) const > } > } > >- line.init({ lineLogicalLeft, lineLogicalTop }, availableWidth, m_formattingRoot.style().computedLineHeight()); >+ auto& formattingRootStyle = m_formattingRoot.style(); >+ auto mimimumLineHeight = formattingRootStyle.computedLineHeight(); >+ auto baselineOffset = halfLeadingMetrics(formattingRootStyle.fontMetrics(), mimimumLineHeight).height; >+ line.reset({ lineLogicalLeft, lineLogicalTop }, availableWidth, mimimumLineHeight, baselineOffset); > } > >-void InlineFormattingContext::LineLayout::splitInlineRunIfNeeded(const InlineRun& inlineRun, InlineRuns& splitRuns) const >+void InlineFormattingContext::LineLayout::layout() const > { >- ASSERT(inlineRun.textContext()); >- ASSERT(inlineRun.overlapsMultipleInlineItems()); >- // In certain cases, a run can overlap multiple inline elements like this: >- // <span>normal text content</span><span style="position: relative; left: 10px;">but this one needs a dedicated run</span><span>end of text</span> >- // The content above generates one long run <normal text contentbut this one needs dedicated runend of text> >- // However, since the middle run is positioned, it needs to be moved independently from the rest of the content, hence it needs a dedicated inline run. >- >- // 1. Start with the first inline item (element) and travers the list until >- // 2. either find an inline item that needs a dedicated run or we reach the end of the run >- // 3. Create dedicate inline runs. >- auto& inlineContent = m_formattingState.inlineContent(); >- auto contentStart = inlineRun.logicalLeft(); >- auto startPosition = inlineRun.textContext()->start(); >- auto remaningLength = inlineRun.textContext()->length(); >- >- struct Uncommitted { >- const InlineItem* firstInlineItem { nullptr }; >- const InlineItem* lastInlineItem { nullptr }; >- unsigned length { 0 }; >- }; >- Optional<Uncommitted> uncommitted; >- >- auto commit = [&] { >- if (!uncommitted) >- return; >- >- contentStart += uncommitted->firstInlineItem->nonBreakableStart(); >- >- auto runWidth = this->runWidth(inlineContent, *uncommitted->firstInlineItem, startPosition, uncommitted->length, contentStart); >- auto run = InlineRun { { inlineRun.logicalTop(), contentStart, runWidth, inlineRun.logicalHeight() }, *uncommitted->firstInlineItem }; >- run.setTextContext({ startPosition, uncommitted->length }); >- splitRuns.append(run); >- >- contentStart += runWidth + uncommitted->lastInlineItem->nonBreakableEnd(); >- >- startPosition = 0; >- uncommitted = { }; >+ auto floatingContext = FloatingContext { m_floatingState }; >+ Line line(layoutState()); >+ initializeLine(line, layoutState().displayBoxForLayoutBox(m_formattingRoot).contentBoxTop()); >+ >+ UncommittedContent uncommittedContent; >+ auto commitPendingContent = [&] { >+ for (auto* uncommitted : uncommittedContent.inlineItems()) >+ commitInlineItemToLine(line, *uncommitted); >+ uncommittedContent.reset(); > }; > >- for (auto iterator = inlineContent.find(const_cast<InlineItem*>(&inlineRun.inlineItem())); iterator != inlineContent.end() && remaningLength > 0; ++iterator) { >- auto& inlineItem = **iterator; >+ LineBreaker lineBreaker(layoutState()); >+ auto& inlineContent = m_formattingState.inlineItems(); >+ for (auto& inlineItem : inlineContent) { >+ // Iterate through the inline content and try to put the inline boxes on the current line. >+ if (inlineItem->isHardLineBreak()) { >+ // Close the current line then create and immediately close another one. >+ commitPendingContent(); >+ commitInlineItemToLine(line, *inlineItem); >+ closeLine(line); >+ } else { >+ auto availableWidth = line.availableWidth() - uncommittedContent.width(); >+ auto currentLogicalRight = line.contentLogicalRight() + uncommittedContent.width(); >+ // FIXME: Ensure LineContext::trimmableWidth includes uncommitted content if needed. >+ auto breakingContext = lineBreaker.breakingContext(*inlineItem, { availableWidth, currentLogicalRight, line.trailingTrimmableWidth(), !line.hasContent() }); >+ if (breakingContext.isAtBreakingOpportunity) >+ commitPendingContent(); >+ >+ if (breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Break) { >+ ASSERT_NOT_IMPLEMENTED_YET(); >+ continue; >+ } > >- // Skip all non-inflow boxes (floats, out-of-flow positioned elements). They don't participate in the inline run context. >- if (!inlineItem.layoutBox().isInFlow()) >- continue; >+ if (breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Wrap) >+ closeLine(line); > >- auto currentLength = [&] { >- return std::min(remaningLength, inlineItem.textContent().length() - startPosition); >- }; >- >- // 1. Break before/after -> requires dedicated run -> commit what we've got so far and also commit the current inline element as a separate inline run. >- // 2. Break at the beginning of the inline element -> commit what we've got so far. Current element becomes the first uncommitted. >- // 3. Break at the end of the inline element -> commit what we've got so far including the current element. >- // 4. Inline element does not require run breaking -> add current inline element to uncommitted. Jump to the next element. >- auto detachingRules = inlineItem.detachingRules(); >- >- // #1 >- if (detachingRules.containsAll({ InlineItem::DetachingRule::BreakAtStart, InlineItem::DetachingRule::BreakAtEnd })) { >- commit(); >- auto contentLength = currentLength(); >- uncommitted = Uncommitted { &inlineItem, &inlineItem, contentLength }; >- remaningLength -= contentLength; >- commit(); >- continue; >+ if (inlineItem->isFloat()) >+ handleFloat(line, floatingContext, *inlineItem); >+ else { >+ if (breakingContext.isAtBreakingOpportunity) >+ commitInlineItemToLine(line, *inlineItem); >+ else >+ uncommittedContent.add(*inlineItem); >+ } > } >- >- // #2 >- if (detachingRules.contains(InlineItem::DetachingRule::BreakAtStart)) >- commit(); >- >- // Add current inline item to uncommitted. >- // #3 and #4 >- auto contentLength = currentLength(); >- if (!uncommitted) >- uncommitted = Uncommitted { &inlineItem, &inlineItem, 0 }; >- uncommitted->length += contentLength; >- uncommitted->lastInlineItem = &inlineItem; >- remaningLength -= contentLength; >- >- // #3 >- if (detachingRules.contains(InlineItem::DetachingRule::BreakAtEnd)) >- commit(); > } >- // Either all inline elements needed dedicated runs or neither of them. >- if (!remaningLength || remaningLength == inlineRun.textContext()->length()) >- return; >- >- commit(); >-} >- >-void InlineFormattingContext::LineLayout::createFinalRuns(Line& line) const >-{ >- for (auto& inlineRun : line.runs()) { >- if (inlineRun.overlapsMultipleInlineItems()) { >- InlineRuns splitRuns; >- splitInlineRunIfNeeded(inlineRun, splitRuns); >- for (auto& splitRun : splitRuns) >- m_formattingState.appendInlineRun(splitRun); >- >- if (!splitRuns.isEmpty()) >- continue; >- } >- >- auto finalRun = [&] { >- auto& inlineItem = inlineRun.inlineItem(); >- if (inlineItem.detachingRules().isEmpty()) >- return inlineRun; >- >- InlineRun adjustedRun = inlineRun; >- auto width = inlineRun.logicalWidth() - inlineItem.nonBreakableStart() - inlineItem.nonBreakableEnd(); >- adjustedRun.setLogicalLeft(inlineRun.logicalLeft() + inlineItem.nonBreakableStart()); >- adjustedRun.setLogicalWidth(width); >- return adjustedRun; >- }; >- >- m_formattingState.appendInlineRun(finalRun()); >+ // Process remaining uncommitted content. >+ if (!uncommittedContent.isEmpty()) { >+ if (line.availableWidth() < uncommittedContent.width()) >+ closeLine(line); >+ commitPendingContent(); > } >+ closeLine(line); > } > >-void InlineFormattingContext::LineLayout::postProcessInlineRuns(Line& line, IsLastLine isLastLine) const >+void InlineFormattingContext::LineLayout::closeLine(Line& line) const > { >- alignRuns(m_formattingRoot.style().textAlign(), line, isLastLine); >- auto firstRunIndex = m_formattingState.inlineRuns().size(); >- createFinalRuns(line); >+ auto& lineItems = line.close(); >+ if (lineItems.isEmpty()) { >+ // Spec tells us to create a zero height, empty line box. >+ auto lineBox = Display::Rect { line.logicalTop(), line.logicalLeft(), 0 , 0 }; >+ m_formattingState.addLineBox({ lineBox }); >+ return; >+ } > >- placeInFlowPositionedChildren(firstRunIndex); >-} >+ auto& inlineDisplayRuns = m_formattingState.inlineRuns(); >+ Optional<unsigned> previousLineLastRunIndex = inlineDisplayRuns.isEmpty() ? Optional<unsigned>() : inlineDisplayRuns.size() - 1; >+ // 9.4.2 Inline formatting contexts >+ // A line box is always tall enough for all of the boxes it contains. >+ auto lineBox = Display::Rect { line.logicalTop(), line.logicalLeft(), 0 , line.logicalHeight() }; >+ // Create final display runs. >+ for (unsigned index = 0; index < lineItems.size(); ++index) { >+ auto& lineItem = lineItems.at(index); >+ >+ auto& inlineItem = lineItem->inlineItem; >+ auto& inlineRun = lineItem->inlineRun; >+ auto& layoutBox = inlineItem.layoutBox(); >+ auto& displayBox = layoutState().displayBoxForLayoutBox(layoutBox); >+ >+ if (inlineItem.isHardLineBreak()) { >+ displayBox.setTopLeft(inlineRun.logicalTopLeft()); >+ displayBox.setContentBoxWidth(inlineRun.logicalWidth()); >+ displayBox.setContentBoxHeight(inlineRun.logicalHeight()); >+ m_formattingState.addInlineRun(std::make_unique<Display::Run>(inlineRun)); >+ continue; >+ } > >-void InlineFormattingContext::LineLayout::closeLine(Line& line, IsLastLine isLastLine) const >-{ >- line.close(); >- if (!line.hasContent()) >- return; >+ // Inline level box (replaced or inline-block) >+ if (inlineItem.isBox()) { >+ auto topLeft = inlineRun.logicalTopLeft(); >+ if (layoutBox.isInFlowPositioned()) >+ topLeft += Geometry::inFlowPositionedPositionOffset(layoutState(), layoutBox); >+ displayBox.setTopLeft(topLeft); >+ lineBox.expandHorizontally(inlineRun.logicalWidth()); >+ m_formattingState.addInlineRun(std::make_unique<Display::Run>(inlineRun)); >+ continue; >+ } > >- postProcessInlineRuns(line, isLastLine); >-} >+ // Inline level container start (<span>) >+ if (inlineItem.isContainerStart()) { >+ displayBox.setTopLeft(inlineRun.logicalTopLeft()); >+ lineBox.expandHorizontally(inlineRun.logicalWidth()); >+ continue; >+ } > >-void InlineFormattingContext::LineLayout::appendContentToLine(Line& line, const InlineRunProvider::Run& run, const LayoutSize& runSize) const >-{ >- auto lastRunType = line.lastRunType(); >- line.appendContent(run, runSize); >+ // Inline level container end (</span>) >+ if (inlineItem.isContainerEnd()) { >+ if (layoutBox.isInFlowPositioned()) { >+ auto inflowOffset = Geometry::inFlowPositionedPositionOffset(layoutState(), layoutBox); >+ displayBox.moveHorizontally(inflowOffset.width()); >+ displayBox.moveVertically(inflowOffset.height()); >+ } >+ auto marginBoxWidth = inlineRun.logicalLeft() - displayBox.left(); >+ auto contentBoxWidth = marginBoxWidth - (displayBox.marginStart() + displayBox.borderLeft() + displayBox.paddingLeft().valueOr(0)); >+ // FIXME fix it for multiline. >+ displayBox.setContentBoxWidth(contentBoxWidth); >+ displayBox.setContentBoxHeight(inlineRun.logicalHeight()); >+ lineBox.expandHorizontally(inlineRun.logicalWidth()); >+ continue; >+ } > >- if (m_formattingRoot.style().textAlign() == TextAlignMode::Justify) >- computeExpansionOpportunities(line, run, lastRunType.valueOr(InlineRunProvider::Run::Type::NonWhitespace)); >+ // Text content. Try to join multiple text runs when possible. >+ ASSERT(inlineRun.textContext()); >+ const Line::LineItem* previousLineItem = !index ? nullptr : lineItems[index - 1].get(); >+ if (!lineItem->isCollapsed) { >+ auto& inlineTextItem = downcast<InlineTextItem>(inlineItem); >+ auto previousRunCanBeExtended = previousLineItem ? previousLineItem->canBeExtended : false; >+ auto requiresNewRun = !index || !previousRunCanBeExtended || &layoutBox != &previousLineItem->inlineItem.layoutBox(); >+ if (requiresNewRun) >+ m_formattingState.addInlineRun(std::make_unique<Display::Run>(inlineRun)); >+ else { >+ auto& lastDisplayRun = m_formattingState.inlineRuns().last(); >+ lastDisplayRun->expandHorizontally(inlineTextItem.width()); >+ lastDisplayRun->textContext()->expand(inlineRun.textContext()->length()); >+ } >+ lineBox.expandHorizontally(inlineRun.logicalWidth()); >+ } >+ // FIXME take content breaking into account when part of the layout box is on the previous line. >+ auto firstInlineRunForLayoutBox = !previousLineItem || &previousLineItem->inlineItem.layoutBox() != &layoutBox; >+ if (firstInlineRunForLayoutBox) { >+ // Setup display box for the associated layout box. >+ displayBox.setTopLeft(inlineRun.logicalTopLeft()); >+ displayBox.setContentBoxWidth(inlineRun.logicalWidth()); >+ displayBox.setContentBoxHeight(inlineRun.logicalHeight()); >+ } else { >+ // FIXME fix it for multirun/multiline. >+ displayBox.setContentBoxWidth(displayBox.contentBoxWidth() + inlineRun.logicalWidth()); >+ } >+ } >+ // FIXME linebox needs to be ajusted after content alignment. >+ m_formattingState.addLineBox({ lineBox }); >+ if (line.hasContent()) >+ alignRuns(m_formattingRoot.style().textAlign(), previousLineLastRunIndex.valueOr(-1) + 1, line.availableWidth()); >+ initializeLine(line, line.logicalBottom()); > } > >-void InlineFormattingContext::LineLayout::computeFloatPosition(const FloatingContext& floatingContext, Line& line, const Box& floatBox) const >+void InlineFormattingContext::LineLayout::handleFloat(Line& line, const FloatingContext& floatingContext, const InlineItem& floatItem) const > { >- auto& layoutState = m_formattingContext.layoutState(); >- ASSERT(layoutState.hasDisplayBox(floatBox)); >- auto& displayBox = layoutState.displayBoxForLayoutBox(floatBox); >- >+ auto& floatBox = floatItem.layoutBox(); >+ ASSERT(layoutState().hasDisplayBox(floatBox)); >+ auto& displayBox = layoutState().displayBoxForLayoutBox(floatBox); > // Set static position first. > displayBox.setTopLeft({ line.contentLogicalRight(), line.logicalTop() }); > // Float it. > displayBox.setTopLeft(floatingContext.positionForFloat(floatBox)); >+ m_floatingState.append(floatBox); >+ // Shrink availble space for current line and move existing inline runs. >+ auto floatBoxWidth = floatItem.width(); >+ floatBox.isLeftFloatingPositioned() ? line.moveLogicalLeft(floatBoxWidth) : line.moveLogicalRight(floatBoxWidth); > } > >-void InlineFormattingContext::LineLayout::placeInFlowPositionedChildren(unsigned fistRunIndex) const >+void InlineFormattingContext::LineLayout::commitInlineItemToLine(Line& line, const InlineItem& inlineItem) const > { >- auto& layoutState = m_formattingContext.layoutState(); >- auto& inlineRuns = m_formattingState.inlineRuns(); >- for (auto runIndex = fistRunIndex; runIndex < inlineRuns.size(); ++runIndex) { >- auto& inlineRun = inlineRuns[runIndex]; >- >- auto positionOffset = [&](auto& layoutBox) { >- // FIXME: Need to figure out whether in-flow offset should stick. This might very well be temporary. >- Optional<LayoutSize> offset; >- for (auto* box = &layoutBox; box != &m_formattingRoot; box = box->parent()) { >- if (!box->isInFlowPositioned()) >- continue; >- offset = offset.valueOr(LayoutSize()) + Geometry::inFlowPositionedPositionOffset(layoutState, *box); >- } >- return offset; >- }; >+ if (inlineItem.isContainerStart()) >+ return line.appendInlineContainerStart(inlineItem); > >- if (auto offset = positionOffset(inlineRun.inlineItem().layoutBox())) { >- inlineRun.moveVertically(offset->height()); >- inlineRun.moveHorizontally(offset->width()); >- } >- } >+ if (inlineItem.isContainerEnd()) >+ return line.appendInlineContainerEnd(inlineItem); >+ >+ if (inlineItem.isHardLineBreak()) >+ return line.appendHardLineBreak(inlineItem); >+ >+ auto width = inlineItem.width(); >+ if (is<InlineTextItem>(inlineItem)) >+ return line.appendTextContent(downcast<InlineTextItem>(inlineItem), { width, inlineItem.style().fontMetrics().height() }); >+ >+ auto& layoutBox = inlineItem.layoutBox(); >+ auto& displayBox = layoutState().displayBoxForLayoutBox(layoutBox); >+ if (layoutBox.isReplaced()) >+ return line.appendReplacedInlineBox(inlineItem, { width, displayBox.height() }); >+ >+ line.appendNonReplacedInlineBox(inlineItem, { width, displayBox.height() }); > } > >-static LayoutUnit adjustedLineLogicalLeft(TextAlignMode align, LayoutUnit lineLogicalLeft, LayoutUnit remainingWidth) >+static Optional<LayoutUnit> horizontalAdjustmentForAlignment(TextAlignMode align, LayoutUnit remainingWidth) > { > switch (align) { > case TextAlignMode::Left: > case TextAlignMode::WebKitLeft: > case TextAlignMode::Start: >- return lineLogicalLeft; >+ return { }; > case TextAlignMode::Right: > case TextAlignMode::WebKitRight: > case TextAlignMode::End: >- return lineLogicalLeft + std::max(remainingWidth, 0_lu); >+ return std::max(remainingWidth, 0_lu); > case TextAlignMode::Center: > case TextAlignMode::WebKitCenter: >- return lineLogicalLeft + std::max(remainingWidth / 2, 0_lu); >+ return std::max(remainingWidth / 2, 0_lu); > case TextAlignMode::Justify: > ASSERT_NOT_REACHED(); > break; > } > ASSERT_NOT_REACHED(); >- return lineLogicalLeft; >-} >- >-void InlineFormattingContext::LineLayout::justifyRuns(Line& line) >-{ >- auto& inlineRuns = line.runs(); >- auto& lastInlineRun = inlineRuns.last(); >- >- // Adjust (forbid) trailing expansion for the last text run on line. >- auto expansionBehavior = lastInlineRun.expansionOpportunity().behavior; >- // Remove allow and add forbid. >- expansionBehavior ^= AllowTrailingExpansion; >- expansionBehavior |= ForbidTrailingExpansion; >- lastInlineRun.expansionOpportunity().behavior = expansionBehavior; >- >- // Collect expansion opportunities and justify the runs. >- auto widthToDistribute = line.availableWidth(); >- if (widthToDistribute <= 0) >- return; >- >- auto expansionOpportunities = 0; >- for (auto& inlineRun : inlineRuns) >- expansionOpportunities += inlineRun.expansionOpportunity().count; >- >- if (!expansionOpportunities) >- return; >- >- float expansion = widthToDistribute.toFloat() / expansionOpportunities; >- LayoutUnit accumulatedExpansion; >- for (auto& inlineRun : inlineRuns) { >- LayoutUnit expansionForRun { inlineRun.expansionOpportunity().count * expansion }; >- >- inlineRun.expansionOpportunity().expansion = expansionForRun; >- inlineRun.setLogicalLeft(inlineRun.logicalLeft() + accumulatedExpansion); >- inlineRun.setLogicalWidth(inlineRun.logicalWidth() + expansionForRun); >- accumulatedExpansion += expansionForRun; >- } >+ return { }; > } > >-void InlineFormattingContext::LineLayout::computeExpansionOpportunities(Line& line, const InlineRunProvider::Run& run, InlineRunProvider::Run::Type lastRunType) const >+void InlineFormattingContext::LineLayout::alignRuns(TextAlignMode textAlign, unsigned firstRunIndex, LayoutUnit availableWidth) const > { >- auto isExpansionOpportunity = [](auto currentRunIsWhitespace, auto lastRunIsWhitespace) { >- return currentRunIsWhitespace || (!currentRunIsWhitespace && !lastRunIsWhitespace); >- }; >- >- auto expansionBehavior = [](auto isAtExpansionOpportunity) { >- ExpansionBehavior expansionBehavior = AllowTrailingExpansion; >- expansionBehavior |= isAtExpansionOpportunity ? ForbidLeadingExpansion : AllowLeadingExpansion; >- return expansionBehavior; >- }; >- >- auto isAtExpansionOpportunity = isExpansionOpportunity(run.isWhitespace(), lastRunType == InlineRunProvider::Run::Type::Whitespace); >- >- auto& currentInlineRun = line.runs().last(); >- auto& expansionOpportunity = currentInlineRun.expansionOpportunity(); >- if (isAtExpansionOpportunity) >- ++expansionOpportunity.count; >- >- expansionOpportunity.behavior = expansionBehavior(isAtExpansionOpportunity); >-} >- >-void InlineFormattingContext::LineLayout::alignRuns(TextAlignMode textAlign, Line& line, IsLastLine isLastLine) const >-{ >- auto adjutedTextAlignment = textAlign != TextAlignMode::Justify ? textAlign : isLastLine == IsLastLine::No ? TextAlignMode::Justify : TextAlignMode::Left; >- if (adjutedTextAlignment == TextAlignMode::Justify) { >- justifyRuns(line); >+ auto adjustment = horizontalAdjustmentForAlignment(textAlign, availableWidth); >+ if (!adjustment) > return; >- } > >- auto lineLogicalLeft = line.contentLogicalLeft(); >- auto adjustedLogicalLeft = adjustedLineLogicalLeft(adjutedTextAlignment, lineLogicalLeft, line.availableWidth()); >- if (adjustedLogicalLeft == lineLogicalLeft) >- return; >- >- auto delta = adjustedLogicalLeft - lineLogicalLeft; >- for (auto& inlineRun : line.runs()) >- inlineRun.setLogicalLeft(inlineRun.logicalLeft() + delta); >-} >- >-LayoutUnit InlineFormattingContext::LineLayout::runWidth(const InlineContent& inlineContent, const InlineItem& inlineItem, ItemPosition from, unsigned length, LayoutUnit contentLogicalLeft) const >-{ >- LayoutUnit width; >- auto startPosition = from; >- auto iterator = inlineContent.find(const_cast<InlineItem*>(&inlineItem)); >-#if !ASSERT_DISABLED >- auto inlineItemEnd = inlineContent.end(); >-#endif >- while (length) { >- ASSERT(iterator != inlineItemEnd); >- auto& currentInlineItem = **iterator; >- auto endPosition = std::min<ItemPosition>(startPosition + length, currentInlineItem.textContent().length()); >- auto textWidth = TextUtil::width(currentInlineItem, startPosition, endPosition, contentLogicalLeft); >- >- contentLogicalLeft += textWidth; >- width += textWidth; >- length -= (endPosition - startPosition); >- >- startPosition = 0; >- ++iterator; >- } >- return width; >+ auto& inlineDisplayRuns = m_formattingState.inlineRuns(); >+ for (unsigned index = firstRunIndex; index < inlineDisplayRuns.size(); ++index) >+ inlineDisplayRuns[index]->moveHorizontally(*adjustment); > } > > } >diff --git a/Source/WebCore/layout/inlineformatting/InlineFormattingState.h b/Source/WebCore/layout/inlineformatting/InlineFormattingState.h >index 662a83c3ebc51ba7b0e3c4eaccf51844e9ed659c..d74dce5382c27dce961aa66439793207191b5fac 100644 >--- a/Source/WebCore/layout/inlineformatting/InlineFormattingState.h >+++ b/Source/WebCore/layout/inlineformatting/InlineFormattingState.h >@@ -27,15 +27,20 @@ > > #if ENABLE(LAYOUT_FORMATTING_CONTEXT) > >+#include "DisplayRun.h" > #include "FormattingState.h" > #include "InlineItem.h" >-#include "InlineRun.h" >+#include "InlineLineBox.h" > #include <wtf/IsoMalloc.h> > #include <wtf/OptionSet.h> > > namespace WebCore { > namespace Layout { > >+// Temp >+using InlineItems = ListHashSet<std::unique_ptr<InlineItem>>; >+using InlineRuns = Vector<std::unique_ptr<Display::Run>>; >+using LineBoxes = Vector<LineBox>; > // InlineFormattingState holds the state for a particular inline formatting context tree. > class InlineFormattingState : public FormattingState { > WTF_MAKE_ISO_ALLOCATED(InlineFormattingState); >@@ -43,16 +48,20 @@ public: > InlineFormattingState(Ref<FloatingState>&&, LayoutState&); > virtual ~InlineFormattingState(); > >- InlineContent& inlineContent() { return m_inlineContent; } >- InlineItem* lastInlineItem() const { return m_inlineContent.isEmpty() ? nullptr : m_inlineContent.last().get(); } >+ void addInlineTextItem(); > >- // Temp >+ InlineItems& inlineItems() { return m_inlineItems; } > InlineRuns& inlineRuns() { return m_inlineRuns; } >- void appendInlineRun(InlineRun inlineRun) { m_inlineRuns.append(inlineRun); } >+ LineBoxes& lineBoxes() { return m_lineBoxes; } >+ >+ void addInlineItem(std::unique_ptr<InlineItem>&& inlineItem) { m_inlineItems.add(WTFMove(inlineItem)); } >+ void addInlineRun(std::unique_ptr<Display::Run>&& inlineRun) { m_inlineRuns.append(WTFMove(inlineRun)); } >+ void addLineBox(LineBox lineBox) { m_lineBoxes.append(lineBox); } > > private: >- InlineContent m_inlineContent; >+ InlineItems m_inlineItems; > InlineRuns m_inlineRuns; >+ LineBoxes m_lineBoxes; > }; > > } >diff --git a/Source/WebCore/layout/inlineformatting/InlineItem.h b/Source/WebCore/layout/inlineformatting/InlineItem.h >index 5a10fc1d1ffca6344e0400e59d6a5007a15bb84e..87ed9c36f6c923ae8e4f8997496ebcac5acfe9c4 100644 >--- a/Source/WebCore/layout/inlineformatting/InlineItem.h >+++ b/Source/WebCore/layout/inlineformatting/InlineItem.h >@@ -36,83 +36,57 @@ namespace Layout { > > class InlineItem { > public: >- InlineItem(const Box& layoutBox); >+ enum class Type { Text, HardLineBreak, Box, Float, ContainerStart, ContainerEnd }; >+ InlineItem(const Box& layoutBox, Type); > >- enum class Type { Text, HardLineBreak, InlineBox, Float }; >- Type type() const; >+ Type type() const { return m_type; } > const Box& layoutBox() const { return m_layoutBox; } > const RenderStyle& style() const { return m_layoutBox.style(); } >- String textContent() const; >- // DetachingRule indicates whether the inline element needs to be wrapped in a dediceted run or break from previous/next runs. >- // <span>start</span><span style="position: relative;"> middle </span><span>end</span> >- // input to line breaking -> <start middle end> >- // output of line breaking (considering infinite constraint) -> <start middle end> >- // due to the in-flow positioning, the final runs are: <start>< middle ><end> >- // "start" -> n/a >- // " middle " -> BreakAtStart and BreakAtEnd >- // "end" -> n/a >- // >- // <span>parent </span><span style="padding: 10px;">start<span> middle </span>end</span><span> parent</span> >- // input to line breaking -> <parent start middle end parent> >- // output of line breaking (considering infinite constraint) -> <parent start middle end parent> >- // due to padding, final runs -> <parent><start middle end><parent> >- // "parent" -> n/a >- // "start" -> BreakAtStart >- // " middle " -> n/a >- // "end" -> BreakAtEnd >- // "parent" -> n/a >- enum class DetachingRule { >- BreakAtStart = 1 << 0, >- BreakAtEnd = 1 << 1 >- }; >- void addDetachingRule(OptionSet<DetachingRule> detachingRule) { m_detachingRules.add(detachingRule); } >- OptionSet<DetachingRule> detachingRules() const { return m_detachingRules; } >+ void setWidth(LayoutUnit); >+ LayoutUnit width() const; > >- // Non-breakable start/end marks margin/padding/border space (even when it does not directly come from the associated layout box) >- // <span style="padding: 5px"><span>nested content with padding parent</span</span> >- // <nested content with padding parent> inline run has 5px non-breakable start/end. >- LayoutUnit nonBreakableStart() const { return m_nonBreakableStart; } >- LayoutUnit nonBreakableEnd() const { return m_nonBreakableEnd; } >- void addNonBreakableStart(LayoutUnit value) { m_nonBreakableStart += value; } >- void addNonBreakableEnd(LayoutUnit value) { m_nonBreakableEnd += value; } >+ bool isText() const { return type() == Type::Text; } >+ bool isBox() const { return type() == Type::Box; } >+ bool isHardLineBreak() const { return type() == Type::HardLineBreak; } >+ bool isFloat() const { return type() == Type::Float; } >+ bool isLineBreak() const { return type() == Type::HardLineBreak; } >+ bool isContainerStart() const { return type() == Type::ContainerStart; } >+ bool isContainerEnd() const { return type() == Type::ContainerEnd; } > > private: > const Box& m_layoutBox; >- OptionSet<DetachingRule> m_detachingRules; >- LayoutUnit m_nonBreakableStart; >- LayoutUnit m_nonBreakableEnd; >+ const Type m_type; >+ LayoutUnit m_width; >+#if !ASSERT_DISABLED >+ bool m_hasValidWidth { false }; >+#endif > }; > >-using InlineContent = ListHashSet<std::unique_ptr<InlineItem>>; >- >-inline InlineItem::InlineItem(const Box& layoutBox) >+inline InlineItem::InlineItem(const Box& layoutBox, Type type) > : m_layoutBox(layoutBox) >+ , m_type(type) > { > } > >-inline InlineItem::Type InlineItem::type() const >+inline void InlineItem::setWidth(LayoutUnit width) > { >- if (is<InlineBox>(m_layoutBox) && downcast<InlineBox>(m_layoutBox).hasTextContent()) >- return Type::Text; >- >- if (is<LineBreakBox>(m_layoutBox)) >- return Type::HardLineBreak; >- >- if (m_layoutBox.isFloatingPositioned()) >- return Type::Float; >- >- ASSERT(m_layoutBox.isInlineLevelBox()); >- return Type::InlineBox; >+#if !ASSERT_DISABLED >+ m_hasValidWidth = true; >+#endif >+ m_width = width; > } > >-inline String InlineItem::textContent() const >+inline LayoutUnit InlineItem::width() const > { >- if (type() != Type::Text) >- return { }; >- >- return downcast<InlineBox>(m_layoutBox).textContent(); >+ ASSERT(m_hasValidWidth); >+ return m_width; > } > >+#define SPECIALIZE_TYPE_TRAITS_INLINE_ITEM(ToValueTypeName, predicate) \ >+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::Layout::ToValueTypeName) \ >+ static bool isType(const WebCore::Layout::InlineItem& inlineItem) { return inlineItem.predicate; } \ >+SPECIALIZE_TYPE_TRAITS_END() >+ > } > } > #endif >diff --git a/Source/WebCore/layout/inlineformatting/InlineLineBox.h b/Source/WebCore/layout/inlineformatting/InlineLineBox.h >new file mode 100644 >index 0000000000000000000000000000000000000000..ce2f246cdd2609729a82151dbf98f69cf9a2237a >--- /dev/null >+++ b/Source/WebCore/layout/inlineformatting/InlineLineBox.h >@@ -0,0 +1,61 @@ >+/* >+ * 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 "DisplayBox.h" >+ >+namespace WebCore { >+namespace Layout { >+ >+class LineBox { >+public: >+ LineBox(Display::Rect); >+ >+ LayoutPoint logicalTopLeft() const { return m_rect.topLeft(); } >+ >+ LayoutUnit logicalLeft() const { return m_rect.left(); } >+ LayoutUnit logicalRight() const { return m_rect.right(); } >+ LayoutUnit logicalTop() const { return m_rect.top(); } >+ LayoutUnit logicalBottom() const { return m_rect.bottom(); } >+ >+ LayoutUnit logicalWidth() const { return m_rect.width(); } >+ LayoutUnit logicalHeight() const { return m_rect.height(); } >+ >+private: >+ Display::Rect m_rect; >+}; >+ >+inline LineBox::LineBox(Display::Rect rect) >+ : m_rect(rect) >+{ >+} >+ >+} >+} >+ >+#endif >diff --git a/Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp b/Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp >index 576a0bb795437e013742a7286943af2481004fec..61646b8a154bae969d895f0768a8b67197a458d0 100644 >--- a/Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp >+++ b/Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp >@@ -28,173 +28,102 @@ > > #if ENABLE(LAYOUT_FORMATTING_CONTEXT) > >-#include "FontCascade.h" > #include "Hyphenation.h" >-#include "InlineRunProvider.h" >-#include "TextUtil.h" >-#include <wtf/IsoMallocInlines.h> >+#include "LayoutState.h" > > namespace WebCore { > namespace Layout { > >-WTF_MAKE_ISO_ALLOCATED_IMPL(InlineLineBreaker); >- >-InlineLineBreaker::InlineLineBreaker(const LayoutState& layoutState, const InlineContent& inlineContent, const Vector<InlineRunProvider::Run>& inlineRuns) >+LineBreaker::LineBreaker(const LayoutState& layoutState) > : m_layoutState(layoutState) >- , m_inlineContent(inlineContent) >- , m_inlineRuns(inlineRuns) > { > } > >-Optional<InlineLineBreaker::Run> InlineLineBreaker::nextRun(LayoutUnit contentLogicalLeft, LayoutUnit availableWidth, bool lineIsEmpty) >+LineBreaker::BreakingContext LineBreaker::breakingContext(InlineItem& inlineItem, LineContext lineContext) > { >- if (isAtContentEnd()) >- return WTF::nullopt; >- >- InlineRunProvider::Run currentInlineRun = m_inlineRuns[m_currentRunIndex]; >- // Adjust the current run if it is split midword. >- if (m_splitPosition) { >- ASSERT(currentInlineRun.isText()); >- m_splitPosition = WTF::nullopt; >- } >- >- if (currentInlineRun.isLineBreak()) { >- ++m_currentRunIndex; >- return Run { Run::Position::LineEnd, 0, currentInlineRun }; >- } >- >- auto contentWidth = runWidth(currentInlineRun, contentLogicalLeft); >- // 1. Plenty of space left. >- if (contentWidth <= availableWidth) { >- ++m_currentRunIndex; >- return Run { lineIsEmpty ? Run::Position::LineBegin : Run::Position::Undetermined, contentWidth, currentInlineRun }; >- } >- >- // 2. No space left whatsoever. >- if (availableWidth <= 0) { >- ++m_currentRunIndex; >- return Run { Run::Position::LineBegin, contentWidth, currentInlineRun }; >- } >- >- // 3. Some space left. Let's find out what we need to do with this run. >- auto breakingBehavior = lineBreakingBehavior(currentInlineRun, lineIsEmpty); >- if (breakingBehavior == LineBreakingBehavior::Keep) { >- ++m_currentRunIndex; >- return Run { lineIsEmpty ? Run::Position::LineBegin : Run::Position::Undetermined, contentWidth, currentInlineRun }; >- } >- >- if (breakingBehavior == LineBreakingBehavior::WrapToNextLine) { >- ++m_currentRunIndex; >- return Run { Run::Position::LineBegin, contentWidth, currentInlineRun }; >- } >- >- ASSERT(breakingBehavior == LineBreakingBehavior::Break); >- // Split content. >- return splitRun(currentInlineRun, contentLogicalLeft, availableWidth, lineIsEmpty); >+ inlineItem.setWidth(runWidth(inlineItem, lineContext.logicalLeft)); >+ // First content always stays on line. >+ if (lineContext.isEmpty || inlineItem.width() <= lineContext.availableWidth) >+ return { BreakingBehavior::Keep, isAtBreakingOpportunity(inlineItem) }; >+ >+ if (is<InlineTextItem>(inlineItem)) >+ return { wordBreakingBehavior(downcast<InlineTextItem>(inlineItem), lineContext.isEmpty), isAtBreakingOpportunity(inlineItem) }; >+ >+ // Wrap non-text boxes to the next line unless we can trim trailing whitespace. >+ auto availableWidth = lineContext.availableWidth + lineContext.trimmableWidth; >+ if (inlineItem.width() <= availableWidth) >+ return { BreakingBehavior::Keep, isAtBreakingOpportunity(inlineItem) }; >+ return { BreakingBehavior::Wrap, isAtBreakingOpportunity(inlineItem) }; > } > >-bool InlineLineBreaker::isAtContentEnd() const >+LineBreaker::BreakingBehavior LineBreaker::wordBreakingBehavior(const InlineTextItem& inlineItem, bool lineIsEmpty) const > { >- return m_currentRunIndex == m_inlineRuns.size(); >-} >- >-InlineLineBreaker::LineBreakingBehavior InlineLineBreaker::lineBreakingBehavior(const InlineRunProvider::Run& inlineRun, bool lineIsEmpty) >-{ >- // Line breaking behaviour: >+ // Word breaking behaviour: > // 1. Whitesapce collapse on -> push whitespace to next line. > // 2. Whitespace collapse off -> whitespace is split where possible. > // 3. Non-whitespace -> first run on the line -> either split or kept on the line. (depends on overflow-wrap) > // 4. Non-whitespace -> already content on the line -> either gets split (word-break: break-all) or gets pushed to the next line. > // (Hyphenate when possible) > // 5. Non-text type -> next line >- auto& style = inlineRun.style(); >+ auto& style = inlineItem.style(); > >- if (inlineRun.isWhitespace()) >- return style.collapseWhiteSpace() ? LineBreakingBehavior::WrapToNextLine : LineBreakingBehavior::Break; >+ if (inlineItem.isWhitespace()) >+ return style.collapseWhiteSpace() ? BreakingBehavior::Wrap : BreakingBehavior::Break; > >- if (inlineRun.isNonWhitespace()) { >- auto shouldHypenate = !m_hyphenationIsDisabled && style.hyphens() == Hyphens::Auto && canHyphenate(style.locale()); >- if (shouldHypenate) >- return LineBreakingBehavior::Break; >+ auto shouldHypenate = !m_hyphenationIsDisabled && style.hyphens() == Hyphens::Auto && canHyphenate(style.locale()); >+ if (shouldHypenate) >+ return BreakingBehavior::Break; > >- if (style.autoWrap()) { >- // Break any word >- if (style.wordBreak() == WordBreak::BreakAll) >- return LineBreakingBehavior::Break; >+ if (style.autoWrap()) { >+ // Break any word >+ if (style.wordBreak() == WordBreak::BreakAll) >+ return BreakingBehavior::Break; > >- // Break first run on line. >- if (lineIsEmpty && style.breakWords() && style.preserveNewline()) >- return LineBreakingBehavior::Break; >- } >- >- // Non-breakable non-whitespace run. >- return lineIsEmpty ? LineBreakingBehavior::Keep : LineBreakingBehavior::WrapToNextLine; >+ // Break first run on line. >+ if (lineIsEmpty && style.breakWords() && style.preserveNewline()) >+ return BreakingBehavior::Break; > } > >- ASSERT(inlineRun.isBox() || inlineRun.isFloat()); >- // Non-text inline runs. >- return LineBreakingBehavior::WrapToNextLine; >+ // Non-breakable non-whitespace run. >+ return lineIsEmpty ? BreakingBehavior::Keep : BreakingBehavior::Wrap; > } > >-LayoutUnit InlineLineBreaker::runWidth(const InlineRunProvider::Run& inlineRun, LayoutUnit contentLogicalLeft) const >+LayoutUnit LineBreaker::runWidth(const InlineItem& inlineItem, LayoutUnit contentLogicalLeft) const > { >- ASSERT(!inlineRun.isLineBreak()); >+ if (inlineItem.isLineBreak()) >+ return 0; > >- if (inlineRun.isText()) >- return textWidth(inlineRun, contentLogicalLeft); >+ if (is<InlineTextItem>(inlineItem)) >+ return textWidth(downcast<InlineTextItem>(inlineItem), contentLogicalLeft); > >- ASSERT(inlineRun.isBox() || inlineRun.isFloat()); >- auto& inlineItem = inlineRun.inlineItem(); > auto& layoutBox = inlineItem.layoutBox(); > ASSERT(m_layoutState.hasDisplayBox(layoutBox)); > auto& displayBox = m_layoutState.displayBoxForLayoutBox(layoutBox); >- return inlineItem.nonBreakableStart() + displayBox.width() + inlineItem.nonBreakableEnd(); >-} > >-LayoutUnit InlineLineBreaker::textWidth(const InlineRunProvider::Run& inlineRun, LayoutUnit contentLogicalLeft) const >-{ >- // FIXME: Find a way to merge this and InlineFormattingContext::Geometry::runWidth. >- auto& inlineItem = inlineRun.inlineItem(); >- auto textContext = inlineRun.textContext(); >- auto startPosition = textContext->start(); >- auto length = textContext->isCollapsed() ? 1 : textContext->length(); >- >- // FIXME: It does not do proper kerning/ligature handling. >- LayoutUnit width; >- auto iterator = m_inlineContent.find(const_cast<InlineItem*>(&inlineItem)); >-#if !ASSERT_DISABLED >- auto inlineItemEnd = m_inlineContent.end(); >-#endif >- while (length) { >- ASSERT(iterator != inlineItemEnd); >- auto& currentInlineItem = **iterator; >- auto inlineItemLength = currentInlineItem.textContent().length(); >- auto endPosition = std::min<ItemPosition>(startPosition + length, inlineItemLength); >- auto textWidth = TextUtil::width(currentInlineItem, startPosition, endPosition, contentLogicalLeft); >- >- auto nonBreakableStart = !startPosition ? currentInlineItem.nonBreakableStart() : 0_lu; >- auto nonBreakableEnd = endPosition == inlineItemLength ? currentInlineItem.nonBreakableEnd() : 0_lu; >- auto contentWidth = nonBreakableStart + textWidth + nonBreakableEnd; >- contentLogicalLeft += contentWidth; >- width += contentWidth; >- length -= (endPosition - startPosition); >- >- startPosition = 0; >- ++iterator; >- } >- return width; >+ if (inlineItem.isContainerStart()) >+ return displayBox.marginStart() + displayBox.borderLeft() + displayBox.paddingLeft().valueOr(0); >+ >+ if (inlineItem.isContainerEnd()) >+ return displayBox.marginEnd() + displayBox.borderRight() + displayBox.paddingRight().valueOr(0); >+ >+ if (inlineItem.isFloat()) >+ return displayBox.marginBoxWidth(); >+ >+ return displayBox.width(); > } > >-InlineLineBreaker::Run InlineLineBreaker::splitRun(const InlineRunProvider::Run& inlineRun, LayoutUnit, LayoutUnit, bool) >+bool LineBreaker::isAtBreakingOpportunity(const InlineItem& inlineItem) > { >- return { Run::Position::Undetermined, { }, inlineRun }; >+ if (is<InlineTextItem>(inlineItem)) >+ return downcast<InlineTextItem>(inlineItem).isWhitespace(); >+ return !inlineItem.isFloat() && !inlineItem.isContainerStart() && !inlineItem.isContainerEnd(); > } > >-Optional<ItemPosition> InlineLineBreaker::adjustSplitPositionWithHyphenation(const InlineRunProvider::Run&, ItemPosition, LayoutUnit, LayoutUnit, bool) const >+LayoutUnit LineBreaker::textWidth(const InlineTextItem& inlineTextItem, LayoutUnit contentLogicalLeft) const > { >- return { }; >+ auto end = inlineTextItem.isCollapsed() ? inlineTextItem.start() + 1 : inlineTextItem.end(); >+ return TextUtil::width(downcast<InlineBox>(inlineTextItem.layoutBox()), inlineTextItem.start(), end, contentLogicalLeft); > } >- > } > } > #endif >diff --git a/Source/WebCore/layout/inlineformatting/InlineLineBreaker.h b/Source/WebCore/layout/inlineformatting/InlineLineBreaker.h >index 387b0fcf35f6568150af5b036ca0aec8bc1b7989..065330263dd7a4c96b2d943f78c4132bc84c6439 100644 >--- a/Source/WebCore/layout/inlineformatting/InlineLineBreaker.h >+++ b/Source/WebCore/layout/inlineformatting/InlineLineBreaker.h >@@ -27,41 +27,37 @@ > > #if ENABLE(LAYOUT_FORMATTING_CONTEXT) > >-#include "InlineRunProvider.h" >-#include <wtf/IsoMalloc.h> >- > namespace WebCore { > namespace Layout { > >-class InlineLineBreaker { >- WTF_MAKE_ISO_ALLOCATED(InlineLineBreaker); >+class InlineTextItem; >+ >+class LineBreaker { > public: >- InlineLineBreaker(const LayoutState&, const InlineContent&, const Vector<InlineRunProvider::Run>&); >+ LineBreaker(const LayoutState&); > >- struct Run { >- enum class Position { Undetermined, LineBegin, LineEnd }; >- Position position; >- LayoutUnit width; >- InlineRunProvider::Run content; >+ enum class BreakingBehavior { Keep, Break, Wrap }; >+ struct BreakingContext { >+ BreakingBehavior breakingBehavior; >+ bool isAtBreakingOpportunity { false }; >+ }; >+ struct LineContext { >+ LayoutUnit availableWidth; >+ LayoutUnit logicalLeft; >+ LayoutUnit trimmableWidth; >+ bool isEmpty { false }; > }; >- Optional<Run> nextRun(LayoutUnit contentLogicalLeft, LayoutUnit availableWidth, bool lineIsEmpty); >+ BreakingContext breakingContext(InlineItem&, const LineContext); > > private: >- enum class LineBreakingBehavior { Keep, Break, WrapToNextLine }; >- LineBreakingBehavior lineBreakingBehavior(const InlineRunProvider::Run&, bool lineIsEmpty); >- bool isAtContentEnd() const; >- Run splitRun(const InlineRunProvider::Run&, LayoutUnit contentLogicalLeft, LayoutUnit availableWidth, bool lineIsEmpty); >- LayoutUnit runWidth(const InlineRunProvider::Run&, LayoutUnit contentLogicalLeft) const; >- LayoutUnit textWidth(const InlineRunProvider::Run&, LayoutUnit contentLogicalLeft) const; >- Optional<ItemPosition> adjustSplitPositionWithHyphenation(const InlineRunProvider::Run&, ItemPosition splitPosition, LayoutUnit contentLogicalLeft, LayoutUnit availableWidth, bool isLineEmpty) const; > >- const LayoutState& m_layoutState; >- const InlineContent& m_inlineContent; >- const Vector<InlineRunProvider::Run>& m_inlineRuns; >+ BreakingBehavior wordBreakingBehavior(const InlineTextItem&, bool lineIsEmpty) const; >+ bool isAtBreakingOpportunity(const InlineItem&); >+ LayoutUnit runWidth(const InlineItem&, LayoutUnit contentLogicalLeft) const; >+ LayoutUnit textWidth(const InlineTextItem&, LayoutUnit contentLogicalLeft) const; > >- unsigned m_currentRunIndex { 0 }; >- Optional<ItemPosition> m_splitPosition; >- bool m_hyphenationIsDisabled { false }; >+ const LayoutState& m_layoutState; >+ bool m_hyphenationIsDisabled { true }; > }; > > } >diff --git a/Source/WebCore/layout/inlineformatting/InlineRun.h b/Source/WebCore/layout/inlineformatting/InlineRun.h >deleted file mode 100644 >index d6554416aa5115029f5d53f6a0471bedd1ee115e..0000000000000000000000000000000000000000 >--- a/Source/WebCore/layout/inlineformatting/InlineRun.h >+++ /dev/null >@@ -1,115 +0,0 @@ >-/* >- * 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. 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 "InlineRunProvider.h" >-#include "LayoutUnit.h" >- >-namespace WebCore { >-namespace Layout { >- >-struct InlineRun { >- InlineRun(Display::Box::Rect logicalRect, const InlineItem&); >- >- LayoutUnit logicalLeft() const { return m_logicalRect.left(); } >- LayoutUnit logicalRight() const { return m_logicalRect.right(); } >- LayoutUnit logicalTop() const { return m_logicalRect.top(); } >- LayoutUnit logicalBottom() const { return m_logicalRect.bottom(); } >- >- LayoutUnit logicalWidth() const { return m_logicalRect.width(); } >- LayoutUnit logicalHeight() const { return m_logicalRect.height(); } >- bool overlapsMultipleInlineItems() const; >- >- void setLogicalWidth(LayoutUnit width) { m_logicalRect.setWidth(width); } >- void setLogicalLeft(LayoutUnit logicalLeft) { m_logicalRect.setLeft(logicalLeft); } >- void setLogicalRight(LayoutUnit logicalRight) { m_logicalRect.shiftRightTo(logicalRight); } >- void moveVertically(LayoutUnit delta) { m_logicalRect.moveVertically(delta); } >- void moveHorizontally(LayoutUnit delta) { m_logicalRect.moveHorizontally(delta); } >- >- struct ExpansionOpportunity { >- unsigned count { 0 }; >- ExpansionBehavior behavior { ForbidLeadingExpansion | ForbidTrailingExpansion }; >- LayoutUnit expansion; >- }; >- ExpansionOpportunity& expansionOpportunity() { return m_expansionOpportunity; } >- >- struct TextContext { >- public: >- TextContext(ItemPosition, unsigned length); >- >- void setStart(ItemPosition start) { m_start = start; } >- void setLength(unsigned length) { m_length = length; } >- >- ItemPosition start() const { return m_start; } >- unsigned length() const { return m_length; } >- >- private: >- ItemPosition m_start; >- unsigned m_length; >- }; >- void setTextContext(TextContext textContext) { m_textContext.emplace(textContext); } >- Optional<TextContext>& textContext() { return m_textContext; } >- Optional<TextContext> textContext() const { return m_textContext; } >- >- const InlineItem& inlineItem() const { return m_inlineItem; } >- >-private: >- Display::Box::Rect m_logicalRect; >- ExpansionOpportunity m_expansionOpportunity; >- >- const InlineItem& m_inlineItem; >- Optional<TextContext> m_textContext; >-}; >- >-using InlineRuns = Vector<InlineRun>; >- >-inline InlineRun::InlineRun(Display::Box::Rect logicalRect, const InlineItem& inlineItem) >- : m_logicalRect(logicalRect) >- , m_inlineItem(inlineItem) >-{ >-} >- >-inline InlineRun::TextContext::TextContext(ItemPosition start, unsigned length) >- : m_start(start) >- , m_length(length) >-{ >-} >- >-inline bool InlineRun::overlapsMultipleInlineItems() const >-{ >- // Only text content can overlap multiple inline elements. >- if (!m_textContext) >- return false; >- >- auto endPosition = m_textContext->start() + m_textContext->length(); >- return endPosition > m_inlineItem.textContent().length(); >-} >- >-} >-} >-#endif >diff --git a/Source/WebCore/layout/inlineformatting/InlineRunProvider.cpp b/Source/WebCore/layout/inlineformatting/InlineRunProvider.cpp >deleted file mode 100644 >index 9eb20f0afd712b536201d06f7cb4375e8b1e4cd9..0000000000000000000000000000000000000000 >--- a/Source/WebCore/layout/inlineformatting/InlineRunProvider.cpp >+++ /dev/null >@@ -1,198 +0,0 @@ >-/* >- * 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. 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 "InlineRunProvider.h" >- >-#if ENABLE(LAYOUT_FORMATTING_CONTEXT) >- >-#include "BreakLines.h" >-#include "LayoutInlineBox.h" >-#include <wtf/IsoMallocInlines.h> >- >-namespace WebCore { >-namespace Layout { >- >-WTF_MAKE_ISO_ALLOCATED_IMPL(InlineRunProvider); >- >-InlineRunProvider::InlineRunProvider() >-{ >-} >- >-void InlineRunProvider::append(const InlineItem& inlineItem) >-{ >- switch (inlineItem.type()) { >- case InlineItem::Type::Text: >- // Special case text content. They can overlap multiple items. <span>foo</span><span>bar</span> >- processInlineTextItem(inlineItem); >- break; >- case InlineItem::Type::HardLineBreak: >- m_inlineRuns.append(InlineRunProvider::Run::createHardLineBreakRun(inlineItem)); >- break; >- case InlineItem::Type::InlineBox: >- m_inlineRuns.append(InlineRunProvider::Run::createBoxRun(inlineItem)); >- break; >- case InlineItem::Type::Float: >- m_inlineRuns.append(InlineRunProvider::Run::createFloatRun(inlineItem)); >- break; >- default: >- ASSERT_NOT_IMPLEMENTED_YET(); >- } >-} >- >-void InlineRunProvider::insertBefore(const Box&, const Box&) >-{ >-} >- >-void InlineRunProvider::remove(const Box&) >-{ >-} >- >-static inline bool isWhitespace(char character, bool preserveNewline) >-{ >- return character == ' ' || character == '\t' || (character == '\n' && !preserveNewline); >-} >- >-static inline bool isSoftLineBreak(char character, bool preserveNewline) >-{ >- return preserveNewline && character == '\n'; >-} >- >-bool InlineRunProvider::isContinousContent(InlineRunProvider::Run::Type newRunType, const InlineItem& newInlineItem) >-{ >- if (m_inlineRuns.isEmpty()) >- return false; >- >- auto& lastRun = m_inlineRuns.last(); >- // Same element, check type only. >- if (&newInlineItem == &lastRun.inlineItem()) >- return newRunType == lastRun.type(); >- >- // This new run is from a different inline box. >- // FIXME: check style. >- if (newRunType == InlineRunProvider::Run::Type::NonWhitespace && lastRun.isNonWhitespace()) >- return true; >- >- if (newRunType == InlineRunProvider::Run::Type::Whitespace && lastRun.isWhitespace()) >- return newInlineItem.style().collapseWhiteSpace() == lastRun.style().collapseWhiteSpace(); >- >- return false; >-} >- >-void InlineRunProvider::processInlineTextItem(const InlineItem& inlineItem) >-{ >- // We need to reset the run iterator when the text content is not continuous. >- // <span>foo</span><img src=""><span>bar</span> (FIXME: floats?) >- if (!m_inlineRuns.isEmpty() && !m_inlineRuns.last().isText()) { >- m_lineBreakIterator.resetPriorContext(); >- m_lineBreakIterator.resetStringAndReleaseIterator("", "", LineBreakIteratorMode::Default); >- } >- >- auto& style = inlineItem.style(); >- auto text = inlineItem.textContent(); >- ItemPosition currentItemPosition = 0; >- while (currentItemPosition < text.length()) { >- >- // Soft linebreak? >- if (isSoftLineBreak(text[currentItemPosition], style.preserveNewline())) { >- m_inlineRuns.append(InlineRunProvider::Run::createSoftLineBreakRun(inlineItem)); >- ++currentItemPosition; >- continue; >- } >- >- auto isWhitespaceRun = isWhitespace(text[currentItemPosition], style.preserveNewline()); >- auto length = isWhitespaceRun ? moveToNextNonWhitespacePosition(inlineItem, currentItemPosition) : moveToNextBreakablePosition(inlineItem, currentItemPosition); >- >- if (isContinousContent(isWhitespaceRun ? InlineRunProvider::Run::Type::Whitespace : InlineRunProvider::Run::Type::NonWhitespace, inlineItem)) >- m_inlineRuns.last().textContext()->expand(length); >- else { >- m_inlineRuns.append(isWhitespaceRun ? InlineRunProvider::Run::createWhitespaceRun(inlineItem, currentItemPosition, length, style.collapseWhiteSpace()) >- : InlineRunProvider::Run::createNonWhitespaceRun(inlineItem, currentItemPosition, length)); >- } >- >- currentItemPosition += length; >- } >-} >- >-unsigned InlineRunProvider::moveToNextNonWhitespacePosition(const InlineItem& inlineItem, ItemPosition currentItemPosition) >-{ >- auto text = inlineItem.textContent(); >- auto preserveNewline = inlineItem.style().preserveNewline(); >- auto nextNonWhiteSpacePosition = currentItemPosition; >- >- while (nextNonWhiteSpacePosition < text.length() && isWhitespace(text[nextNonWhiteSpacePosition], preserveNewline)) >- ++nextNonWhiteSpacePosition; >- return nextNonWhiteSpacePosition - currentItemPosition; >-} >- >-unsigned InlineRunProvider::moveToNextBreakablePosition(const InlineItem& inlineItem, ItemPosition currentItemPosition) >-{ >- auto findNextBreakablePosition = [&](auto inlineText, auto& style, ItemPosition startPosition) { >- // Swap iterator's content if we advanced to a new string. >- auto iteratorText = m_lineBreakIterator.stringView(); >- >- if (iteratorText != inlineText) { >- auto textLength = iteratorText.length(); >- auto lastCharacter = textLength > 0 ? iteratorText[textLength - 1] : 0; >- auto secondToLastCharacter = textLength > 1 ? iteratorText[textLength - 2] : 0; >- m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter); >- m_lineBreakIterator.resetStringAndReleaseIterator(inlineText, style.locale(), LineBreakIteratorMode::Default); >- } >- >- auto keepAllWordsForCJK = style.wordBreak() == WordBreak::KeepAll; >- auto breakNBSP = style.autoWrap() && style.nbspMode() == NBSPMode::Space; >- >- if (keepAllWordsForCJK) { >- if (breakNBSP) >- return nextBreakablePositionKeepingAllWords(m_lineBreakIterator, startPosition); >- return nextBreakablePositionKeepingAllWordsIgnoringNBSP(m_lineBreakIterator, startPosition); >- } >- >- if (m_lineBreakIterator.mode() == LineBreakIteratorMode::Default) { >- if (breakNBSP) >- return WebCore::nextBreakablePosition(m_lineBreakIterator, startPosition); >- return nextBreakablePositionIgnoringNBSP(m_lineBreakIterator, startPosition); >- } >- >- if (breakNBSP) >- return nextBreakablePositionWithoutShortcut(m_lineBreakIterator, startPosition); >- return nextBreakablePositionIgnoringNBSPWithoutShortcut(m_lineBreakIterator, startPosition); >- }; >- >- auto& style = inlineItem.style(); >- auto textLength = inlineItem.textContent().length(); >- ASSERT(textLength); >- while (currentItemPosition < textLength - 1) { >- auto nextBreakablePosition = findNextBreakablePosition(inlineItem.textContent(), style, currentItemPosition); >- if (nextBreakablePosition != currentItemPosition) >- return nextBreakablePosition - currentItemPosition; >- ++currentItemPosition; >- } >- return textLength; >-} >- >-} >-} >-#endif >diff --git a/Source/WebCore/layout/inlineformatting/InlineRunProvider.h b/Source/WebCore/layout/inlineformatting/InlineRunProvider.h >deleted file mode 100644 >index d77c148eeee0cada245661efeb8fc567deed8608..0000000000000000000000000000000000000000 >--- a/Source/WebCore/layout/inlineformatting/InlineRunProvider.h >+++ /dev/null >@@ -1,169 +0,0 @@ >-/* >- * 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. 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 "InlineItem.h" >-#include <wtf/IsoMalloc.h> >-#include <wtf/text/TextBreakIterator.h> >- >-namespace WebCore { >-namespace Layout { >- >-using ItemPosition = unsigned; >- >-class InlineRunProvider { >- WTF_MAKE_ISO_ALLOCATED(InlineRunProvider); >-public: >- InlineRunProvider(); >- >- void append(const InlineItem&); >- void insertBefore(const Box&, const Box& before); >- void remove(const Box&); >- >- struct Run { >- >- static Run createBoxRun(const InlineItem&); >- static Run createFloatRun(const InlineItem&); >- static Run createHardLineBreakRun(const InlineItem&); >- static Run createSoftLineBreakRun(const InlineItem&); >- static Run createWhitespaceRun(const InlineItem&, ItemPosition start, unsigned length, bool isCollapsible); >- static Run createNonWhitespaceRun(const InlineItem&, ItemPosition start, unsigned length); >- >- enum class Type { >- Box, >- Float, >- SoftLineBreak, >- HardLineBreak, >- Whitespace, >- NonWhitespace >- }; >- Type type() const { return m_type; } >- bool isText() const { return m_type == Run::Type::Whitespace || m_type == Run::Type::NonWhitespace || m_type == Run::Type::SoftLineBreak || m_type == Run::Type::HardLineBreak; } >- bool isWhitespace() const { return m_type == Type::Whitespace; } >- bool isNonWhitespace() const { return m_type == Type::NonWhitespace; } >- bool isLineBreak() const { return m_type == Run::Type::SoftLineBreak || m_type == Run::Type::HardLineBreak; } >- bool isBox() const { return m_type == Type::Box; } >- bool isFloat() const { return m_type == Type::Float; } >- >- struct TextContext { >- >- enum class IsCollapsed { No, Yes }; >- TextContext(ItemPosition, unsigned length, IsCollapsed); >- >- ItemPosition start() const { return m_start; } >- // Note that 'end' position does not equal to start + length when run overlaps multiple InlineItems. >- unsigned length() const { return m_length; } >- bool isCollapsed() const { return m_isCollapsed == IsCollapsed::Yes; } >- >- private: >- friend class InlineRunProvider; >- >- void expand(unsigned length) { m_length += length; } >- >- ItemPosition m_start { 0 }; >- unsigned m_length { 0 }; >- IsCollapsed m_isCollapsed { IsCollapsed::No }; >- }; >- Optional<TextContext> textContext() const { return m_textContext; } >- // Note that style() and inlineItem() always returns the first InlineItem for a run. >- const RenderStyle& style() const { return m_inlineItem.style(); } >- const InlineItem& inlineItem() const { return m_inlineItem; } >- >- private: >- friend class InlineRunProvider; >- >- Run(const InlineItem&, Type, Optional<TextContext>); >- Optional<TextContext>& textContext() { return m_textContext; } >- >- const Type m_type; >- const InlineItem& m_inlineItem; >- Optional<TextContext> m_textContext; >- }; >- const Vector<InlineRunProvider::Run>& runs() const { return m_inlineRuns; } >- >-private: >- void commitTextRun(); >- void processInlineTextItem(const InlineItem&); >- unsigned moveToNextNonWhitespacePosition(const InlineItem&, ItemPosition currentPosition); >- unsigned moveToNextBreakablePosition(const InlineItem&, ItemPosition currentPosition); >- bool isContinousContent(Run::Type newRunType, const InlineItem& newInlineItem); >- >- LazyLineBreakIterator m_lineBreakIterator; >- >- Vector<InlineRunProvider::Run> m_inlineRuns; >-}; >- >-inline InlineRunProvider::Run InlineRunProvider::Run::createBoxRun(const InlineItem& inlineItem) >-{ >- return { inlineItem, Type::Box, WTF::nullopt }; >-} >- >-inline InlineRunProvider::Run InlineRunProvider::Run::createFloatRun(const InlineItem& inlineItem) >-{ >- return { inlineItem, Type::Float, WTF::nullopt }; >-} >- >-inline InlineRunProvider::Run InlineRunProvider::Run::createSoftLineBreakRun(const InlineItem& inlineItem) >-{ >- return { inlineItem, Type::SoftLineBreak, WTF::nullopt }; >-} >- >-inline InlineRunProvider::Run InlineRunProvider::Run::createHardLineBreakRun(const InlineItem& inlineItem) >-{ >- return { inlineItem, Type::HardLineBreak, WTF::nullopt }; >-} >- >-inline InlineRunProvider::Run InlineRunProvider::Run::createWhitespaceRun(const InlineItem& inlineItem, ItemPosition start, unsigned length, bool isCollapsible) >-{ >- ASSERT(length); >- auto isCollapsed = isCollapsible && length > 1 ? TextContext::IsCollapsed::Yes : TextContext::IsCollapsed::No; >- return { inlineItem, Type::Whitespace, TextContext(start, length, isCollapsed) }; >-} >- >-inline InlineRunProvider::Run InlineRunProvider::Run::createNonWhitespaceRun(const InlineItem& inlineItem, ItemPosition start, unsigned length) >-{ >- return { inlineItem, Type::NonWhitespace, TextContext(start, length, TextContext::IsCollapsed::No) }; >-} >- >-inline InlineRunProvider::Run::Run(const InlineItem& inlineItem, Type type, Optional<TextContext> textContext) >- : m_type(type) >- , m_inlineItem(inlineItem) >- , m_textContext(textContext) >-{ >-} >- >-inline InlineRunProvider::Run::TextContext::TextContext(ItemPosition start, unsigned length, IsCollapsed isCollapsed) >- : m_start(start) >- , m_length(length) >- , m_isCollapsed(isCollapsed) >-{ >-} >- >-} >-} >-#endif >diff --git a/Source/WebCore/layout/inlineformatting/InlineTextItem.cpp b/Source/WebCore/layout/inlineformatting/InlineTextItem.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..cf542464fdbbf46f418b011ca0483a5e7b92d18c >--- /dev/null >+++ b/Source/WebCore/layout/inlineformatting/InlineTextItem.cpp >@@ -0,0 +1,130 @@ >+/* >+ * 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. 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 "InlineTextItem.h" >+ >+#if ENABLE(LAYOUT_FORMATTING_CONTEXT) >+ >+#include "BreakLines.h" >+#include "LayoutInlineBox.h" >+ >+namespace WebCore { >+namespace Layout { >+ >+static inline bool isWhitespaceCharacter(char character, bool preserveNewline) >+{ >+ return character == ' ' || character == '\t' || (character == '\n' && !preserveNewline); >+} >+ >+static inline bool isSoftLineBreak(char character, bool preserveNewline) >+{ >+ return preserveNewline && character == '\n'; >+} >+ >+static unsigned moveToNextNonWhitespacePosition(String textContent, unsigned startPosition, bool preserveNewline) >+{ >+ auto nextNonWhiteSpacePosition = startPosition; >+ while (nextNonWhiteSpacePosition < textContent.length() && isWhitespaceCharacter(textContent[nextNonWhiteSpacePosition], preserveNewline)) >+ ++nextNonWhiteSpacePosition; >+ return nextNonWhiteSpacePosition - startPosition; >+} >+ >+static unsigned moveToNextBreakablePosition(unsigned startPosition, LazyLineBreakIterator lineBreakIterator, const RenderStyle& style) >+{ >+ auto findNextBreakablePosition = [&](auto startPosition) { >+ auto keepAllWordsForCJK = style.wordBreak() == WordBreak::KeepAll; >+ auto breakNBSP = style.autoWrap() && style.nbspMode() == NBSPMode::Space; >+ >+ if (keepAllWordsForCJK) { >+ if (breakNBSP) >+ return nextBreakablePositionKeepingAllWords(lineBreakIterator, startPosition); >+ return nextBreakablePositionKeepingAllWordsIgnoringNBSP(lineBreakIterator, startPosition); >+ } >+ >+ if (lineBreakIterator.mode() == LineBreakIteratorMode::Default) { >+ if (breakNBSP) >+ return WebCore::nextBreakablePosition(lineBreakIterator, startPosition); >+ return nextBreakablePositionIgnoringNBSP(lineBreakIterator, startPosition); >+ } >+ >+ if (breakNBSP) >+ return nextBreakablePositionWithoutShortcut(lineBreakIterator, startPosition); >+ return nextBreakablePositionIgnoringNBSPWithoutShortcut(lineBreakIterator, startPosition); >+ }; >+ >+ auto textLength = lineBreakIterator.stringView().length(); >+ auto currentPosition = startPosition; >+ while (currentPosition < textLength - 1) { >+ auto nextBreakablePosition = findNextBreakablePosition(currentPosition); >+ if (nextBreakablePosition != currentPosition) >+ return nextBreakablePosition - currentPosition; >+ ++currentPosition; >+ } >+ return textLength - startPosition; >+} >+ >+void InlineTextItem::createAndAppendTextItems(InlineItems& inlineContent, const InlineBox& inlineBox) >+{ >+ auto& style = inlineBox.style(); >+ auto preserveNewline = style.preserveNewline(); >+ auto collapseWhiteSpace = style.collapseWhiteSpace(); >+ auto text = inlineBox.textContent(); >+ LazyLineBreakIterator lineBreakIterator(text); >+ >+ unsigned currentPosition = 0; >+ while (currentPosition < text.length()) { >+ // Soft linebreak? >+ if (isSoftLineBreak(text[currentPosition], preserveNewline)) { >+ inlineContent.add(std::make_unique<InlineTextItem>(inlineBox, currentPosition, 1, true, false)); >+ ++currentPosition; >+ continue; >+ } >+ if (isWhitespaceCharacter(text[currentPosition], preserveNewline)) { >+ auto length = moveToNextNonWhitespacePosition(text, currentPosition, preserveNewline); >+ auto isCollapsed = collapseWhiteSpace && length > 1; >+ inlineContent.add(std::make_unique<InlineTextItem>(inlineBox, currentPosition, length, true, isCollapsed)); >+ currentPosition += length; >+ continue; >+ } >+ >+ auto length = moveToNextBreakablePosition(currentPosition, lineBreakIterator, style); >+ inlineContent.add(std::make_unique<InlineTextItem>(inlineBox, currentPosition, length, false, false)); >+ currentPosition += length; >+ } >+} >+ >+InlineTextItem::InlineTextItem(const InlineBox& inlineBox, unsigned start, unsigned length, bool isWhitespace, bool isCollapsed) >+ : InlineItem(inlineBox, Type::Text) >+ , m_start(start) >+ , m_length(length) >+ , m_isWhitespace(isWhitespace) >+ , m_isCollapsed(isCollapsed) >+{ >+} >+ >+} >+} >+#endif >diff --git a/Source/WebCore/layout/inlineformatting/InlineTextItem.h b/Source/WebCore/layout/inlineformatting/InlineTextItem.h >new file mode 100644 >index 0000000000000000000000000000000000000000..2874f28a31dcd00abede8897574513cbe29e16de >--- /dev/null >+++ b/Source/WebCore/layout/inlineformatting/InlineTextItem.h >@@ -0,0 +1,60 @@ >+/* >+ * 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. 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 "InlineItem.h" >+ >+namespace WebCore { >+namespace Layout { >+ >+class InlineTextItem : public InlineItem { >+public: >+ static void createAndAppendTextItems(InlineItems&, const InlineBox&); >+ >+ InlineTextItem(const InlineBox&, unsigned start, unsigned length, bool isWhitespace, bool isCollapsed); >+ >+ unsigned start() const { return m_start; } >+ unsigned end() const { return start() + length(); } >+ unsigned length() const { return m_length; } >+ >+ bool isWhitespace() const { return m_isWhitespace; } >+ bool isCollapsed() const { return m_isCollapsed; } >+ >+private: >+ unsigned m_start { 0 }; >+ unsigned m_length { 0 }; >+ bool m_isWhitespace { false }; >+ bool m_isCollapsed { false }; >+}; >+ >+} >+} >+ >+SPECIALIZE_TYPE_TRAITS_INLINE_ITEM(InlineTextItem, isText()) >+ >+#endif >diff --git a/Source/WebCore/layout/inlineformatting/text/TextUtil.cpp b/Source/WebCore/layout/inlineformatting/text/TextUtil.cpp >index 375ed723cd2b2984df73e0e73211ba028418fe08..c139eaba757696d3c876f444dcc97fec7c3a63eb 100644 >--- a/Source/WebCore/layout/inlineformatting/text/TextUtil.cpp >+++ b/Source/WebCore/layout/inlineformatting/text/TextUtil.cpp >@@ -34,19 +34,19 @@ > namespace WebCore { > namespace Layout { > >-Optional<ItemPosition> TextUtil::hyphenPositionBefore(const InlineItem&, ItemPosition, unsigned) >+Optional<unsigned> TextUtil::hyphenPositionBefore(const InlineItem&, unsigned, unsigned) > { > return WTF::nullopt; > } > >-LayoutUnit TextUtil::width(const InlineItem& inlineTextItem, ItemPosition from, ItemPosition to, LayoutUnit contentLogicalLeft) >+LayoutUnit TextUtil::width(const InlineBox& inlineBox, unsigned from, unsigned to, LayoutUnit contentLogicalLeft) > { >- auto& style = inlineTextItem.style(); >+ auto& style = inlineBox.style(); > auto& font = style.fontCascade(); > if (!font.size() || from == to) > return 0; > >- auto text = inlineTextItem.textContent(); >+ auto text = inlineBox.textContent(); > ASSERT(to <= text.length()); > > if (font.isFixedPitch()) >@@ -70,7 +70,7 @@ LayoutUnit TextUtil::width(const InlineItem& inlineTextItem, ItemPosition from, > return std::max<LayoutUnit>(0, width); > } > >-LayoutUnit TextUtil::fixedPitchWidth(String text, const RenderStyle& style, ItemPosition from, ItemPosition to, LayoutUnit contentLogicalLeft) >+LayoutUnit TextUtil::fixedPitchWidth(String text, const RenderStyle& style, unsigned from, unsigned to, LayoutUnit contentLogicalLeft) > { > auto& font = style.fontCascade(); > auto monospaceCharacterWidth = font.spaceWidth(); >diff --git a/Source/WebCore/layout/inlineformatting/text/TextUtil.h b/Source/WebCore/layout/inlineformatting/text/TextUtil.h >index 836a9ec40d3a72eb92674a53b372e50d2f3dacb7..d0fea6ad1ddd729d74f9bdfb1bc9d21c987d2e0c 100644 >--- a/Source/WebCore/layout/inlineformatting/text/TextUtil.h >+++ b/Source/WebCore/layout/inlineformatting/text/TextUtil.h >@@ -28,18 +28,17 @@ > #if ENABLE(LAYOUT_FORMATTING_CONTEXT) > > #include "InlineItem.h" >-#include "InlineRunProvider.h" > > namespace WebCore { > namespace Layout { > > class TextUtil { > public: >- static LayoutUnit width(const InlineItem&, ItemPosition from, ItemPosition to, LayoutUnit contentLogicalLeft); >- static Optional<ItemPosition> hyphenPositionBefore(const InlineItem&, ItemPosition from, unsigned length); >+ static LayoutUnit width(const InlineBox&, unsigned from, unsigned to, LayoutUnit contentLogicalLeft); >+ static Optional<unsigned> hyphenPositionBefore(const InlineItem&, unsigned from, unsigned length); > > private: >- static LayoutUnit fixedPitchWidth(String, const RenderStyle&, ItemPosition from, ItemPosition to, LayoutUnit contentLogicalLeft); >+ static LayoutUnit fixedPitchWidth(String, const RenderStyle&, unsigned from, unsigned to, LayoutUnit contentLogicalLeft); > }; > > } >diff --git a/Source/WebCore/layout/layouttree/LayoutBox.h b/Source/WebCore/layout/layouttree/LayoutBox.h >index 62fb0d148081c1b4c3f28d07e098b7a65bba8121..ad2d3f87b8bbafdc443bb8376887a5d0fc6dfbd7 100644 >--- a/Source/WebCore/layout/layouttree/LayoutBox.h >+++ b/Source/WebCore/layout/layouttree/LayoutBox.h >@@ -155,7 +155,7 @@ private: > > std::unique_ptr<Replaced> m_replaced; > >- unsigned m_baseTypeFlags : 5; >+ unsigned m_baseTypeFlags : 6; > }; > > } >diff --git a/Source/WebCore/layout/layouttree/LayoutReplaced.cpp b/Source/WebCore/layout/layouttree/LayoutReplaced.cpp >index e9074231666575142799d6987bf6ba23ecb690c7..4f3dddbf164cb8d9db9ae0f66debaef2b136c038 100644 >--- a/Source/WebCore/layout/layouttree/LayoutReplaced.cpp >+++ b/Source/WebCore/layout/layouttree/LayoutReplaced.cpp >@@ -80,7 +80,7 @@ LayoutUnit Replaced::intrinsicRatio() const > ASSERT(hasIntrinsicRatio() || (hasIntrinsicWidth() && hasIntrinsicHeight())); > if (m_intrinsicRatio) > return *m_intrinsicRatio; >- if (m_intrinsicSize) >+ if (m_intrinsicSize && m_intrinsicSize->height()) > return m_intrinsicSize->width() / m_intrinsicSize->height(); > return 1; > } >diff --git a/Source/WebCore/layout/layouttree/LayoutTreeBuilder.cpp b/Source/WebCore/layout/layouttree/LayoutTreeBuilder.cpp >index e6102dcaed4af834fa00ea4e4b72e6cffab8697f..d6f2a3eaba13d1505267973d56cf73a695f6213c 100644 >--- a/Source/WebCore/layout/layouttree/LayoutTreeBuilder.cpp >+++ b/Source/WebCore/layout/layouttree/LayoutTreeBuilder.cpp >@@ -29,6 +29,7 @@ > #if ENABLE(LAYOUT_FORMATTING_CONTEXT) > > #include "DisplayBox.h" >+#include "DisplayRun.h" > #include "InlineFormattingState.h" > #include "LayoutBlockContainer.h" > #include "LayoutBox.h" >@@ -42,6 +43,7 @@ > #include "RenderElement.h" > #include "RenderImage.h" > #include "RenderInline.h" >+#include "RenderLineBreak.h" > #include "RenderStyle.h" > #include "RenderView.h" > #include <wtf/text/TextStream.h> >@@ -60,6 +62,15 @@ std::unique_ptr<Container> TreeBuilder::createLayoutTree(const RenderView& rende > return initialContainingBlock; > } > >+static Optional<LayoutSize> accumulatedOffsetForInFlowPositionedContinuation(const RenderBox& block) >+{ >+ // FIXE: This is a workaround of the continuation logic when the relatively positioned parent inline box >+ // becomes a sibling box of this block and only reachable through the continuation link which we don't have here. >+ if (!block.isAnonymous() || !block.isInFlowPositioned() || !block.isContinuation()) >+ return { }; >+ return block.relativePositionOffset(); >+} >+ > void TreeBuilder::createSubTree(const RenderElement& rootRenderer, Container& rootContainer) > { > auto elementAttributes = [] (const RenderElement& renderer) -> Optional<Box::ElementAttributes> { >@@ -97,6 +108,9 @@ void TreeBuilder::createSubTree(const RenderElement& rootRenderer, Container& ro > if (is<RenderText>(child)) { > box = std::make_unique<InlineBox>(Optional<Box::ElementAttributes>(), RenderStyle::createAnonymousStyleWithDisplay(rootRenderer.style(), DisplayType::Inline)); > downcast<InlineBox>(*box).setTextContent(downcast<RenderText>(child).originalText()); >+ } else if (is<RenderLineBreak>(child)) { >+ auto& renderer = downcast<RenderLineBreak>(child); >+ box = std::make_unique<LineBreakBox>(elementAttributes(renderer), RenderStyle::clone(renderer.style())); > } else if (is<RenderReplaced>(child)) { > auto& renderer = downcast<RenderReplaced>(child); > auto display = renderer.style().display(); >@@ -115,9 +129,15 @@ void TreeBuilder::createSubTree(const RenderElement& rootRenderer, Container& ro > } else if (is<RenderElement>(child)) { > auto& renderer = downcast<RenderElement>(child); > auto display = renderer.style().display(); >- if (display == DisplayType::Block) >- box = std::make_unique<BlockContainer>(elementAttributes(renderer), RenderStyle::clone(renderer.style())); >- else if (display == DisplayType::Inline) >+ if (display == DisplayType::Block) { >+ if (auto offset = accumulatedOffsetForInFlowPositionedContinuation(downcast<RenderBox>(renderer))) { >+ auto style = RenderStyle::clonePtr(renderer.style()); >+ style->setTop({ offset->height(), Fixed }); >+ style->setLeft({ offset->width(), Fixed }); >+ box = std::make_unique<BlockContainer>(elementAttributes(renderer), WTFMove(*style)); >+ } else >+ box = std::make_unique<BlockContainer>(elementAttributes(renderer), RenderStyle::clone(renderer.style())); >+ } else if (display == DisplayType::Inline) > box = std::make_unique<InlineContainer>(elementAttributes(renderer), RenderStyle::clone(renderer.style())); > else if (display == DisplayType::InlineBlock) > box = std::make_unique<InlineContainer>(elementAttributes(renderer), RenderStyle::clone(renderer.style())); >@@ -157,20 +177,30 @@ void TreeBuilder::createSubTree(const RenderElement& rootRenderer, Container& ro > #if ENABLE(TREE_DEBUGGING) > static void outputInlineRuns(TextStream& stream, const LayoutState& layoutState, const Container& inlineFormattingRoot, unsigned depth) > { >- auto& inlineFormattingState = layoutState.establishedFormattingState(inlineFormattingRoot); >- ASSERT(is<InlineFormattingState>(inlineFormattingState)); >- auto& inlineRuns = downcast<InlineFormattingState>(inlineFormattingState).inlineRuns(); >+ auto& inlineFormattingState = downcast<InlineFormattingState>(layoutState.establishedFormattingState(inlineFormattingRoot)); >+ auto& inlineRuns = inlineFormattingState.inlineRuns(); >+ auto& lineBoxes = inlineFormattingState.lineBoxes(); >+ >+ unsigned printedCharacters = 0; >+ while (++printedCharacters <= depth * 3) >+ stream << " "; >+ >+ stream << "lines are -> "; >+ for (auto& lineBox : lineBoxes) >+ stream << "[" << lineBox.logicalLeft() << "," << lineBox.logicalTop() << " " << lineBox.logicalWidth() << "x" << lineBox.logicalHeight() << "] "; >+ stream.nextLine(); > > for (auto& inlineRun : inlineRuns) { > unsigned printedCharacters = 0; >- while (++printedCharacters <= depth * 2) >+ while (++printedCharacters <= depth * 3) > stream << " "; >- stream << "run"; >- if (inlineRun.textContext()) >- stream << "(" << inlineRun.textContext()->start() << ", " << inlineRun.textContext()->start() + inlineRun.textContext()->length() << ") "; >- else >- stream << "(x, x) "; >- stream << "at [" << inlineRun.logicalLeft() << ", " << inlineRun.logicalTop() << "] size [" << inlineRun.logicalWidth() << " " << inlineRun.logicalHeight() << "]"; >+ if (inlineRun->textContext()) >+ stream << "inline text box"; >+ else >+ stream << "inline box"; >+ stream << " at (" << inlineRun->logicalLeft() << "," << inlineRun->logicalTop() << ") size " << inlineRun->logicalWidth() << "x" << inlineRun->logicalHeight(); >+ if (inlineRun->textContext()) >+ stream << " run(" << inlineRun->textContext()->start() << ", " << inlineRun->textContext()->end() << ")"; > stream.nextLine(); > } > } >@@ -181,33 +211,46 @@ static void outputLayoutBox(TextStream& stream, const Box& layoutBox, const Disp > while (++printedCharacters <= depth * 2) > stream << " "; > >- if (is<InlineContainer>(layoutBox)) >- stream << "inline container"; >- else if (is<InlineBox>(layoutBox)) { >+ if (layoutBox.isFloatingPositioned()) >+ stream << "[float] "; >+ >+ if (is<InlineContainer>(layoutBox)) { >+ // FIXME: fix names >+ if (layoutBox.isInlineBlockBox()) >+ stream << "DIV inline-block container"; >+ else >+ stream << "SPAN inline container"; >+ } else if (is<InlineBox>(layoutBox)) { > if (layoutBox.replaced()) >- stream << "inline replaced box"; >- else if (downcast<InlineBox>(layoutBox).hasTextContent()) { >- auto textContent = downcast<InlineBox>(layoutBox).textContent(); >- stream << "inline text [\"" << textContent.utf8().data() << "\"]"; >- } else >+ stream << "IMG replaced inline box"; >+ else if (layoutBox.isAnonymous()) >+ stream << "anonymous inline box"; >+ else if (is<LineBreakBox>(layoutBox)) >+ stream << "BR line break"; >+ else > stream << "inline box"; > } else if (is<BlockContainer>(layoutBox)) { > if (!layoutBox.parent()) >- stream << "initial "; >- stream << "block container"; >+ stream << "Initial"; >+ else if (layoutBox.isDocumentBox()) >+ stream << "HTML"; >+ else if (layoutBox.isBodyBox()) >+ stream << "BODY"; >+ else { >+ // FIXME >+ stream << "DIV"; >+ } >+ stream << " block container"; > } else if (layoutBox.isBlockLevelBox()) > stream << "block box"; > else > stream << "box"; > // FIXME: Inline text runs don't create display boxes yet. >- if (displayBox) { >- // FIXME: display box is not completely set yet. >- if ((is<InlineBox>(layoutBox) || is<InlineContainer>(layoutBox)) && !layoutBox.isFloatingPositioned()) >- stream << " at [" << "." << " " << "." << "] size [" << displayBox->width() << " " << displayBox->height() << "]"; >- else >- stream << " at [" << displayBox->left() << " " << displayBox->top() << "] size [" << displayBox->width() << " " << displayBox->height() << "]"; >- } >- stream << " [" << &layoutBox << "]"; >+ if (displayBox) >+ stream << " at (" << displayBox->left() << "," << displayBox->top() << ") size " << displayBox->width() << "x" << displayBox->height(); >+ stream << " layout box->(" << &layoutBox << ")"; >+ if (is<InlineBox>(layoutBox) && downcast<InlineBox>(layoutBox).hasTextContent()) >+ stream << " text content [\"" << downcast<InlineBox>(layoutBox).textContent().utf8().data() << "\"]"; > > stream.nextLine(); > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 197198
:
368031
|
368107
|
368198
|
368210
|
368282
|
370379
|
370394
|
370549
| 370639