WebKit Bugzilla
Attachment 368282 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-20190425160530.patch (text/plain), 148.26 KB, created by
zalan
on 2019-04-25 16:05:34 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
zalan
Created:
2019-04-25 16:05:34 PDT
Size:
148.26 KB
patch
obsolete
>Subversion Revision: 244098 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index af2d5e3add3f8c3681d945d5bfcb43d5fe260d79..e9a98f11582d1acbd31f85033793fe401b707bd9 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,170 @@ >+2019-04-23 Zalan Bujtas <zalan@apple.com> >+ >+ [LFC][IFC] Introduce DisplayRun to the display tree >+ https://bugs.webkit.org/show_bug.cgi?id=197198 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ WIP. >+ >+ * 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::LayoutState::verifyAndOutputMismatchingLayoutTree const): >+ (WebCore::Layout::resolveForRelativePositionIfNeeded): Deleted. >+ * layout/blockformatting/BlockFormattingContextGeometry.cpp: >+ (WebCore::Layout::BlockFormattingContext::Geometry::inFlowNonReplacedHeightAndMargin): >+ * layout/displaytree/DisplayBox.h: >+ (WebCore::Display::Box::horizontalMargin const): >+ * layout/displaytree/DisplayRun.h: Renamed from Source/WebCore/layout/inlineformatting/InlineRun.h. >+ (WebCore::Display::Run::TextContext::setStart): >+ (WebCore::Display::Run::TextContext::setLength): >+ (WebCore::Display::Run::TextContext::start const): >+ (WebCore::Display::Run::TextContext::end const): >+ (WebCore::Display::Run::TextContext::length const): >+ (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::setLogicalLeft): >+ (WebCore::Display::Run::setLogicalRight): >+ (WebCore::Display::Run::moveVertically): >+ (WebCore::Display::Run::moveHorizontally): >+ (WebCore::Display::Run::expandVertically): >+ (WebCore::Display::Run::expandHorizontally): >+ (WebCore::Display::Run::expansionOpportunity): >+ (WebCore::Display::Run::setTextContext): >+ (WebCore::Display::Run::textContext): >+ (WebCore::Display::Run::textContext const): >+ (WebCore::Display::Run::Run): >+ (WebCore::Display::Run::TextContext::TextContext): >+ * layout/inlineformatting/InlineFormattingContext.cpp: >+ (WebCore::Layout::InlineFormattingContext::layout const): >+ (WebCore::Layout::InlineFormattingContext::computeIntrinsicWidthConstraints const): >+ (WebCore::Layout::InlineFormattingContext::computeIntrinsicWidthForFloatBox const): >+ (WebCore::Layout::InlineFormattingContext::computeIntrinsicWidthForInlineBlock const): >+ (WebCore::Layout::InlineFormattingContext::initializeVerticalMarginForInlineContainer const): >+ (WebCore::Layout::InlineFormattingContext::computeHorizontalMargin const): >+ (WebCore::Layout::InlineFormattingContext::collectInlineContent const): >+ (WebCore::Layout::InlineFormattingContext::computeMargin const): Deleted. >+ (WebCore::Layout::addDetachingRules): Deleted. >+ (WebCore::Layout::createAndAppendInlineItem): Deleted. >+ * layout/inlineformatting/InlineFormattingContext.h: >+ * layout/inlineformatting/InlineFormattingContextLineLayout.cpp: >+ (WebCore::Layout::Line::runs): >+ (WebCore::Layout::Line::isEmpty const): >+ (WebCore::Layout::Line::isFirstLine const): >+ (WebCore::Layout::Line::availableWidth const): >+ (WebCore::Layout::Line::logicalLeft const): >+ (WebCore::Layout::Line::logicalRight const): >+ (WebCore::Layout::Line::init): >+ (WebCore::Layout::Line::close): >+ (WebCore::Layout::isTrimmableContent): >+ (WebCore::Layout::Line::hasTrailingWhitespace const): >+ (WebCore::Layout::Line::trailingWhitespaceWidth const): >+ (WebCore::Layout::Line::hasContent const): >+ (WebCore::Layout::Line::appendNonBreakableSpace): >+ (WebCore::Layout::Line::appendTextContent): >+ (WebCore::Layout::Line::appendNonTextContent): >+ (WebCore::Layout::Line::adjustLogicalLeft): >+ (WebCore::Layout::Line::adjustLogicalRight): >+ (WebCore::Layout::InlineFormattingContext::LineLayout::layout const): >+ (WebCore::Layout::InlineFormattingContext::LineLayout::closeLine const): >+ (WebCore::Layout::InlineFormattingContext::LineLayout::commitInlineItemToLine const): >+ (WebCore::Layout::InlineFormattingContext::LineLayout::computeFloatPosition const): >+ (WebCore::Layout::InlineFormattingContext::LineLayout::justifyRuns): >+ (WebCore::Layout::InlineFormattingContext::LineLayout::computeExpansionOpportunities const): >+ (WebCore::Layout::InlineFormattingContext::LineLayout::alignRuns const): >+ (WebCore::Layout::Line::contentLogicalLeft const): Deleted. >+ (WebCore::Layout::Line::lastRunType const): Deleted. >+ (WebCore::Layout::Line::contentLogicalRight const): Deleted. >+ (WebCore::Layout::Line::appendContent): 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::placeInFlowPositionedChildren const): Deleted. >+ (WebCore::Layout::InlineFormattingContext::LineLayout::runWidth const): Deleted. >+ * layout/inlineformatting/InlineFormattingState.h: >+ (WebCore::Layout::InlineFormattingState::inlineItems): >+ (WebCore::Layout::InlineFormattingState::addInlineItem): >+ (WebCore::Layout::InlineFormattingState::addInlineRun): >+ (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/InlineLineBreaker.cpp: >+ (WebCore::Layout::LineBreaker::LineBreaker): >+ (WebCore::Layout::LineBreaker::breakingContext): >+ (WebCore::Layout::LineBreaker::wordBreakingBehavior const): >+ (WebCore::Layout::LineBreaker::runWidth const): >+ (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/LayoutReplaced.cpp: >+ (WebCore::Layout::Replaced::intrinsicRatio const): >+ * layout/layouttree/LayoutTreeBuilder.cpp: >+ (WebCore::Layout::outputInlineRuns): >+ (WebCore::Layout::outputLayoutBox): >+ * page/FrameViewLayoutContext.cpp: >+ (WebCore::layoutUsingFormattingContext): >+ > 2019-04-09 Zalan Bujtas <zalan@apple.com> > > [AutoSizing] Avoid making text paragraphs scroll horizontally when there is a wide table >diff --git a/Source/WebCore/Sources.txt b/Source/WebCore/Sources.txt >index 219c8b70dc9f589aef686e3b2da146ab390f7805..d051dbcb9ddfc9cbb95c047618e162f1dfdae357 100644 >--- a/Source/WebCore/Sources.txt >+++ b/Source/WebCore/Sources.txt >@@ -1343,7 +1343,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 8a0927cc654dc6056e9adcc2160b92b62af6d97c..da74b98b952ef5c67a522aa2947ea49492e11384 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -2004,10 +2004,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 */; }; >@@ -2028,6 +2027,7 @@ > 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, ); }; }; > 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, ); }; }; > 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, ); }; }; >@@ -9085,15 +9085,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>"; }; >@@ -9130,6 +9129,7 @@ > 6FB11B5B21783FCF00E2A574 /* TextUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextUtil.cpp; 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>"; }; > 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>"; }; >@@ -16338,9 +16338,8 @@ > 6FE7CFA02177EEF1005B1573 /* InlineItem.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>"; >@@ -16350,6 +16349,7 @@ > children = ( > 1199FA5A208E3C7F002358CC /* DisplayBox.cpp */, > 1199FA59208E3C7F002358CC /* DisplayBox.h */, >+ 6FCE1A1822618AB3004F0343 /* DisplayRun.h */, > ); > path = displaytree; > sourceTree = "<group>"; >@@ -28762,6 +28762,7 @@ > 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 */, >@@ -29390,11 +29391,10 @@ > 6FE7CFA22177EEF2005B1573 /* InlineItem.h in Headers */, > BCE789161120D6080060ECE5 /* InlineIterator.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 967cfd4998b6a1a0897d062ff0dbab5ed5a173e7..18963c3566d2c1d53dde7080566c7ace8b3a89c6 100644 >--- a/Source/WebCore/layout/FormattingContextGeometry.cpp >+++ b/Source/WebCore/layout/FormattingContextGeometry.cpp >@@ -112,8 +112,8 @@ static LayoutUnit contentHeightForFormattingContextRoot(const LayoutState& layou > // 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(); >+ top = inlineRuns[0]->logicalTop(); >+ bottom = inlineRuns.last()->logicalBottom(); > } > } else if (formattingRootContainer.establishesBlockFormattingContext() || layoutBox.isDocumentBox()) { > if (formattingRootContainer.hasInFlowChild()) { >diff --git a/Source/WebCore/layout/Verification.cpp b/Source/WebCore/layout/Verification.cpp >index 2e77c39e92144942ef29e40e4c7436e511200bc2..f06e3debf374cc0311bd3d6468730fb0c2251f4e 100644 >--- a/Source/WebCore/layout/Verification.cpp >+++ b/Source/WebCore/layout/Verification.cpp >@@ -46,7 +46,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 +72,33 @@ 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()); >+ 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())); >+ matchingRuns = simpleRun.start == inlineRun->textContext()->start() && simpleRun.end == inlineRun->textContext()->end(); > 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 +126,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,54 +145,10 @@ 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; >- >- 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; >- } >- } >- } else >- matchingRuns = checkForMatchingNonTextRuns(inlineRun, *inlineBox); >- >+ bool matchingRuns = inlineTextBox ? checkForMatchingTextRuns(*inlineRun, *inlineTextBox) : matchingRuns = checkForMatchingNonTextRuns(*inlineRun, *inlineBox); > > if (!matchingRuns) { > stream << "Mismatching: run "; >@@ -214,10 +157,10 @@ static bool outputMismatchingComplexLineInformationIfNeeded(TextStream& stream, > stream << "(" << inlineTextBox->start() << ", " << inlineTextBox->end() + 1 << ")"; > stream << " (" << inlineBox->logicalLeft() << ", " << inlineBox->logicalRight() << ") (" << 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->logicalRight() << ") (" << inlineRun->logicalWidth() << "x" << inlineRun->logicalHeight() << ")"; > stream.nextLine(); > mismatched = true; > } >diff --git a/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp b/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp >index f9633b438a1b1b227da5b87146ff31ebc568625c..1cc63975273567eea4b0de9c1840e5745d96324e 100644 >--- a/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp >+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp >@@ -77,7 +77,7 @@ HeightAndMargin BlockFormattingContext::Geometry::inFlowNonReplacedHeightAndMarg > 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(); >+ auto bottomEdge = inlineRuns.isEmpty() ? LayoutUnit() : inlineRuns.last()->logicalBottom(); > return { bottomEdge - borderAndPaddingTop, nonCollapsedMargin }; > } > >diff --git a/Source/WebCore/layout/displaytree/DisplayBox.h b/Source/WebCore/layout/displaytree/DisplayBox.h >index d4cd7ba141690e8bcfd37799e22b62db88fd63ef..1133e499b195d0349c0ef35286db2ac3c83e33d1 100644 >--- a/Source/WebCore/layout/displaytree/DisplayBox.h >+++ b/Source/WebCore/layout/displaytree/DisplayBox.h >@@ -139,6 +139,7 @@ public: > Rect rectWithMargin() const; > > Layout::UsedVerticalMargin verticalMargin() const; >+ Layout::UsedHorizontalMargin horizontalMargin() const; > LayoutUnit marginBefore() const; > LayoutUnit marginStart() const; > LayoutUnit marginAfter() const; >@@ -580,6 +581,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/DisplayRun.h b/Source/WebCore/layout/displaytree/DisplayRun.h >new file mode 100644 >index 0000000000000000000000000000000000000000..bfb1cdd0cd779609316ec0a3df3b3b2bad5ac90d >--- /dev/null >+++ b/Source/WebCore/layout/displaytree/DisplayRun.h >@@ -0,0 +1,111 @@ >+/* >+ * 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(Box::Rect logicalRect, Optional<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 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); } >+ >+ struct ExpansionOpportunity { >+ unsigned count { 0 }; >+ ExpansionBehavior behavior { ForbidLeadingExpansion | ForbidTrailingExpansion }; >+ LayoutUnit expansion; >+ }; >+ ExpansionOpportunity& expansionOpportunity() { return m_expansionOpportunity; } >+ >+ void setTextContext(TextContext textContext) { m_textContext.emplace(textContext); } >+ Optional<TextContext>& textContext() { return m_textContext; } >+ Optional<TextContext> textContext() const { return m_textContext; } >+ >+private: >+ Box::Rect m_logicalRect; >+ ExpansionOpportunity m_expansionOpportunity; >+ Optional<TextContext> m_textContext; >+}; >+ >+inline Run::Run(Box::Rect logicalRect, Optional<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_expansionOpportunity = other.m_expansionOpportunity; >+ m_textContext = other.m_textContext; >+} >+ >+} >+} >+#endif >diff --git a/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp b/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp >index e3c1536dcd32a1efed8128d332b118e28bdd9e72..435d0b3f5893b0aaf9f21364186f432d625448bb 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" >@@ -79,16 +79,19 @@ void InlineFormattingContext::layout() const > layoutFormattingContextRoot(*layoutBox, usedValues); > else if (is<Container>(*layoutBox)) { > auto& inlineContainer = downcast<InlineContainer>(*layoutBox); >- computeMargin(inlineContainer, usedValues); >+ computeHorizontalMargin(inlineContainer, usedValues); > computeBorderAndPadding(inlineContainer, usedValues); > } else if (layoutBox->isReplaced()) > computeWidthAndHeightForReplacedInlineBox(*layoutBox, usedValues); > 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 +123,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); > } >@@ -161,7 +164,7 @@ void InlineFormattingContext::computeIntrinsicWidthForFloatBox(const Box& layout > > auto usedHorizontalValues = UsedHorizontalValues { }; > computeBorderAndPadding(layoutBox, usedHorizontalValues); >- computeMargin(layoutBox, usedHorizontalValues); >+ computeHorizontalMargin(layoutBox, usedHorizontalValues); > layoutState.createFormattingContext(layoutBox)->computeIntrinsicWidthConstraints(); > > auto usedVerticalValues = UsedVerticalValues { }; >@@ -178,11 +181,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); >@@ -256,88 +259,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 node. This essentially truns 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 +289,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..2ddf3d63757d8f25f52e3423de9cc236dca157cd 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,17 @@ private: > class LineLayout { > public: > LineLayout(const InlineFormattingContext&); >- void layout(const InlineRunProvider&) const; >+ void layout() const; > > private: >+ LayoutState& layoutState() const { return m_formattingContext.layoutState(); } > 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 commitInlineItemToLine(Line&, const InlineItem&) 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; >+ void computeExpansionOpportunities(Line&, const InlineItem&, bool previousRunIsWhitepace) const; > > private: > static void justifyRuns(Line&); >@@ -91,11 +85,11 @@ private: > void computeIntrinsicWidthForFloatBox(const Box&) 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 7b13ab0b4ebcbd2571fe6c368a8f77016fcaa0e4..d818a1aacffbf7f64911de3313fd3bb833a32bca 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" >@@ -43,151 +42,250 @@ namespace Layout { > > class Line { > public: >- void init(const LayoutPoint& topLeft, LayoutUnit availableWidth, LayoutUnit minimalHeight); >+ Line(const LayoutState&); >+ >+ void reset(const LayoutPoint& topLeft, LayoutUnit availableWidth, LayoutUnit minimumHeight); > void close(); > >- void appendContent(const InlineRunProvider::Run&, const LayoutSize&); >+ void appendTextContent(const InlineTextItem&, LayoutSize); >+ void appendNonTextContent(const InlineItem&, LayoutSize); >+ void appendNonBreakableSpace(const InlineItem&); >+ >+ void adjustLogicalLeft(LayoutUnit); >+ void adjustLogicalRight(LayoutUnit); > >- void adjustLogicalLeft(LayoutUnit delta); >- void adjustLogicalRight(LayoutUnit delta); >+ struct LineItem { >+ Display::Run inlineRun; >+ const InlineItem& inlineItem; >+ }; >+ Vector<LineItem>& lineItems() { return m_lineItems; } > >- bool hasContent() const { return !m_inlineRuns.isEmpty(); } >+ bool hasContent() const; >+ bool isEmpty() const { return m_lineItems.isEmpty(); } >+ bool hasTrailingWhitespace() const { return m_numberOfTrimmableRuns; } >+ LayoutUnit trailingWhitespaceWidth() const; > bool isClosed() const { return m_closed; } > bool isFirstLine() const { return m_isFirstLine; } >- Vector<InlineRun>& runs() { return m_inlineRuns; } >- >- 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; } > >+ LayoutUnit availableWidth() const { return m_lineWidth - m_logicalRect.width(); } > LayoutUnit logicalTop() const { return m_logicalRect.top(); } >+ LayoutUnit logicalLeft() const { return m_logicalRect.left(); } > LayoutUnit logicalBottom() const { return m_logicalRect.bottom(); } >+ LayoutUnit logicalRight() const { return m_logicalRect.right(); } >+ > LayoutUnit logicalHeight() const { return logicalBottom() - logicalTop(); } > > private: >- struct TrailingTrimmableContent { >- LayoutUnit width; >- unsigned length; >- }; >- Optional<TrailingTrimmableContent> m_trailingTrimmableContent; >- Optional<InlineRunProvider::Run::Type> m_lastRunType; >+ const LayoutState& m_layoutState; >+ unsigned m_numberOfTrimmableRuns { 0 }; > bool m_lastRunCanExpand { false }; > > Display::Box::Rect m_logicalRect; >- LayoutUnit m_availableWidth; >+ LayoutUnit m_lineWidth; > >- Vector<InlineRun> m_inlineRuns; >+ Vector<LineItem> m_lineItems; > bool m_isFirstLine { true }; > bool m_closed { true }; > }; > >-void Line::init(const LayoutPoint& topLeft, LayoutUnit availableWidth, LayoutUnit minimalHeight) >+Line::Line(const LayoutState& layoutState) >+ : m_layoutState(layoutState) >+{ >+} >+ >+void Line::reset(const LayoutPoint& topLeft, LayoutUnit availableWidth, LayoutUnit minimumHeight) > { >- m_logicalRect.setTopLeft(topLeft); >- m_logicalRect.setWidth(availableWidth); >- m_logicalRect.setHeight(minimalHeight); >- m_availableWidth = availableWidth; >+ m_logicalRect = { topLeft.y(), topLeft.x(), 0, minimumHeight }; >+ m_lineWidth = availableWidth; > >- m_inlineRuns.clear(); >- m_lastRunType = { }; >+ m_lineItems.clear(); > m_lastRunCanExpand = false; >- m_trailingTrimmableContent = { }; >+ m_numberOfTrimmableRuns = 0; > m_closed = false; > } > > void Line::adjustLogicalLeft(LayoutUnit delta) > { >+ if (!delta) >+ return; > ASSERT(delta > 0); >- >- m_availableWidth -= delta; >- m_logicalRect.shiftLeftTo(m_logicalRect.left() + delta); >- >- for (auto& inlineRun : m_inlineRuns) >- inlineRun.moveHorizontally(delta); >+ // Shrink the line and move the items. >+ m_lineWidth-= delta; >+ m_logicalRect.moveHorizontally(delta); >+ for (auto& lineItem : m_lineItems) >+ lineItem.inlineRun.moveHorizontally(delta); > } > > void Line::adjustLogicalRight(LayoutUnit delta) > { > ASSERT(delta > 0); >+ m_lineWidth-= delta; >+} > >- m_availableWidth -= delta; >- m_logicalRect.shiftRightTo(m_logicalRect.right() - delta); >+static bool isTrimmableContent(const InlineItem& inlineItem) >+{ >+ if (!is<InlineTextItem>(inlineItem)) >+ return false; >+ auto& inlineTextItem = downcast<InlineTextItem>(inlineItem); >+ return inlineTextItem.isWhitespace() && inlineTextItem.style().collapseWhiteSpace(); > } > >-static bool isTrimmableContent(const InlineRunProvider::Run& inlineRun) >+LayoutUnit Line::trailingWhitespaceWidth() const > { >- return inlineRun.isWhitespace() && inlineRun.style().collapseWhiteSpace(); >+ if (isEmpty() || !m_numberOfTrimmableRuns) >+ return { }; >+ LayoutUnit trimmableWidth; >+ auto numberOfTrimmableRuns = m_numberOfTrimmableRuns; >+ auto runIndex = m_lineItems.size() - 1; >+ while (numberOfTrimmableRuns) { >+ auto& lineItem = m_lineItems[runIndex--]; >+ if (lineItem.inlineItem.isContainerStart() || lineItem.inlineItem.isContainerEnd()) >+ continue; >+ trimmableWidth += lineItem.inlineRun.logicalWidth(); >+ --numberOfTrimmableRuns; >+ } >+ return trimmableWidth; > } > >-LayoutUnit Line::contentLogicalRight() const >+bool Line::hasContent() const > { >- if (m_inlineRuns.isEmpty()) >- return m_logicalRect.left(); >+ // 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.inlineRun.logicalWidth()) >+ return true; >+ } >+ return false; >+} > >- return m_inlineRuns.last().logicalRight(); >+void Line::appendNonBreakableSpace(const InlineItem& inlineItem) >+{ >+ ASSERT(!isClosed()); >+ // FIXME height >+ auto logicalRect = Display::Box::Rect { logicalTop(), logicalRight(), inlineItem.width(), 0 }; >+ m_lineItems.append({ Display::Run { logicalRect, { }}, inlineItem }); >+ m_logicalRect.expand(inlineItem.width(), 0); >+ m_lastRunCanExpand = false; > } > >-void Line::appendContent(const InlineRunProvider::Run& run, const LayoutSize& runSize) >+void Line::appendTextContent(const InlineTextItem& inlineItem, LayoutSize runSize) > { > ASSERT(!isClosed()); >+ auto isTrimmable = isTrimmableContent(inlineItem); >+ >+ auto shouldCollapse = [&]() { >+ if (!isTrimmable) >+ return false; >+ // Skip leading whitespace. >+ if (isEmpty()) >+ return true; >+ // Check if the previous run is a whitespace and whether we can collapse it with this run. >+ auto currentIndex = m_lineItems.size() - 1; >+ auto* currentItem = &m_lineItems[currentIndex].inlineItem; >+ // Skip non-conent inline items. >+ while (currentItem->isContainerStart() || currentItem->isContainerEnd()) { >+ if (!currentIndex--) >+ return true; >+ currentItem = &m_lineItems[currentIndex].inlineItem; >+ } >+ return currentItem->isText() && isTrimmableContent(downcast<InlineTextItem>(*currentItem)); >+ }; > >- // 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 }; >- } >+ if (shouldCollapse()) >+ return; > >- 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_lastRunCanExpand = !inlineItem.isCollapsed(); >+ m_numberOfTrimmableRuns = isTrimmable ? m_numberOfTrimmableRuns + 1 : 0; >+ auto runLength = inlineItem.isCollapsed() ? 1 : inlineItem.length(); >+ >+ auto requiresNewRun = isEmpty() || !m_lastRunCanExpand || &m_lineItems.last().inlineItem != &inlineItem; >+ if (requiresNewRun) { >+ auto logicalRect = Display::Box::Rect { logicalTop(), logicalRight(), runSize.width(), runSize.height() }; >+ auto textContext = Display::Run::TextContext { inlineItem.start(), runLength }; >+ auto displayRun = Display::Run(logicalRect, textContext); >+ m_lineItems.append({ displayRun, inlineItem }); >+ m_logicalRect.expand(runSize.width(), 0); > 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()); >+ return; > } > >- 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() }; >+ auto& lastInlineRun = m_lineItems.last().inlineRun; >+ ASSERT(runSize.height() == lastInlineRun.logicalHeight()); >+ lastInlineRun.expandHorizontally(runSize.width()); >+ lastInlineRun.textContext()->expand(runLength); >+ m_logicalRect.expand(runSize.width(), 0); >+} >+ >+void Line::appendNonTextContent(const InlineItem& inlineItem, LayoutSize runSize) >+{ >+ ASSERT(!isClosed()); >+ >+ auto& displayBox = m_layoutState.displayBoxForLayoutBox(inlineItem.layoutBox()); >+ auto horizontalMargin = displayBox.horizontalMargin(); >+ >+ auto logicalRect = Display::Box::Rect { logicalTop(), logicalRight() + horizontalMargin.start, runSize.width(), runSize.height() }; >+ m_lineItems.append({ Display::Run { logicalRect, { }}, inlineItem }); >+ m_logicalRect.setHeight(std::max(runSize.height(), m_logicalRect.height())); >+ m_logicalRect.expand(runSize.width() + horizontalMargin.start + horizontalMargin.end, 0); >+ >+ m_lastRunCanExpand = false; >+ m_numberOfTrimmableRuns = 0; > } > > void Line::close() > { >- 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 removeTrimmableTrailingContent = [&] { >+ ASSERT(m_lineItems.size()); >+ auto lastLineItemIndex = m_lineItems.size() - 1; >+ while (m_numberOfTrimmableRuns) { >+ auto& lastLineItem = m_lineItems[lastLineItemIndex]; >+ if (lastLineItem.inlineItem.isContainerStart() || lastLineItem.inlineItem.isContainerEnd()) { >+ --lastLineItemIndex; >+ continue; >+ } >+ m_logicalRect.expand(-lastLineItem.inlineRun.logicalWidth(), 0); >+ m_lineItems.remove(lastLineItemIndex); >+ --m_numberOfTrimmableRuns; >+ --lastLineItemIndex; >+ } > }; > >- if (!hasContent()) >+ if (isEmpty()) > return; > >- trimTrailingContent(); >+ removeTrimmableTrailingContent(); > m_isFirstLine = false; > m_closed = true; > } > >+struct UncommittedContent { >+ void add(InlineItem&); >+ void reset(); >+ >+ Vector<InlineItem*> inlineItems() { return m_inlineItems; } >+ bool isEmpty() const { return m_inlineItems.isEmpty(); } >+ LayoutUnit width() const { return m_width; } >+ >+private: >+ Vector<InlineItem*> m_inlineItems; >+ LayoutUnit m_width; >+}; >+ >+void UncommittedContent::add(InlineItem& inlineItem) >+{ >+ m_inlineItems.append(&inlineItem); >+ m_width += inlineItem.width(); >+} >+ >+void UncommittedContent::reset() >+{ >+ m_inlineItems.clear(); >+ m_width = 0; >+} >+ > InlineFormattingContext::LineLayout::LineLayout(const InlineFormattingContext& inlineFormattingContext) > : m_formattingContext(inlineFormattingContext) > , m_formattingState(m_formattingContext.formattingState()) >@@ -196,72 +294,71 @@ InlineFormattingContext::LineLayout::LineLayout(const InlineFormattingContext& i > { > } > >-static bool isTrimmableContent(const InlineLineBreaker::Run& run) >-{ >- return run.content.isWhitespace() && run.content.style().collapseWhiteSpace(); >-} >- >-void InlineFormattingContext::LineLayout::layout(const InlineRunProvider& inlineRunProvider) const >+void InlineFormattingContext::LineLayout::layout() const > { >- auto& layoutState = m_formattingContext.layoutState(); > auto floatingContext = FloatingContext { m_floatingState }; >+ Line line(layoutState()); >+ UncommittedContent uncommittedContent; > >- Line line; > initializeNewLine(line); > >- 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; >- >- // 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); >- >- 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); >+ auto commitPendingContent = [&] { >+ for (auto* uncommitted : uncommittedContent.inlineItems()) >+ commitInlineItemToLine(line, *uncommitted); >+ uncommittedContent.reset(); >+ }; > >- generatesInlineRun = false; >+ LineBreaker lineBreaker(layoutState()); >+ auto& inlineContent = m_formattingState.inlineItems(); >+ for (auto& inlineItem : inlineContent) { >+ // 1. Simply add non-breakable spaces to the current line. They don't wrap. >+ // 2. Normal inline boxes either go on the current or wrap/break to the next line. >+ // 3. Floats are special. They constrain the lines instead of being on them. >+ auto availableWidth = line.availableWidth() - uncommittedContent.width(); >+ auto currentLogicalRight = line.logicalRight() + uncommittedContent.width(); >+ // FIXME: Ensure LineContext::trimmableWidth includes uncommitted content if needed. >+ auto breakingContext = lineBreaker.breakingContext(*inlineItem, { availableWidth, currentLogicalRight, line.trailingWhitespaceWidth(), !line.hasContent() }); >+ if (breakingContext.isAtBreakingOpportunity) >+ commitPendingContent(); >+ >+ if (breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Break) { >+ ASSERT_NOT_IMPLEMENTED_YET(); >+ continue; > } > >- // 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; >- >- 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); >- } >+ if (breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Wrap) { >+ closeLine(line, IsLastLine::No); >+ initializeNewLine(line); > } > >- 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 }); >+ if (inlineItem->isFloat()) { >+ auto& floatBox = inlineItem->layoutBox(); >+ computeFloatPosition(floatingContext, line, floatBox); >+ m_floatingState.append(floatBox); >+ // Shrink availble space for current line and move existing inline runs. >+ auto floatBoxWidth = inlineItem->width(); >+ floatBox.isLeftFloatingPositioned() ? line.adjustLogicalLeft(floatBoxWidth) : line.adjustLogicalRight(floatBoxWidth); >+ } else { >+ if (breakingContext.isAtBreakingOpportunity) >+ commitInlineItemToLine(line, *inlineItem); >+ else >+ uncommittedContent.add(*inlineItem); > } >- >- if (isLastRun) >+ } >+ // Process remaining uncommitted content. >+ if (!uncommittedContent.isEmpty()) { >+ if (line.availableWidth() < uncommittedContent.width()) { > closeLine(line, IsLastLine::No); >+ initializeNewLine(line); >+ } >+ commitPendingContent(); > } >- > closeLine(line, IsLastLine::Yes); > } > > void InlineFormattingContext::LineLayout::initializeNewLine(Line& line) const > { >- auto& formattingRootDisplayBox = m_formattingContext.layoutState().displayBoxForLayoutBox(m_formattingRoot); >+ auto& formattingRootDisplayBox = layoutState().displayBoxForLayoutBox(m_formattingRoot); > > auto lineLogicalLeft = formattingRootDisplayBox.contentBoxLeft(); > auto lineLogicalTop = line.isFirstLine() ? formattingRootDisplayBox.contentBoxTop() : line.logicalBottom(); >@@ -290,195 +387,99 @@ void InlineFormattingContext::LineLayout::initializeNewLine(Line& line) const > availableWidth = *floatConstraints.right - lineLogicalLeft; > } > } >- >- line.init({ lineLogicalLeft, lineLogicalTop }, availableWidth, m_formattingRoot.style().computedLineHeight()); >+ line.reset({ lineLogicalLeft, lineLogicalTop }, availableWidth, m_formattingRoot.style().computedLineHeight()); > } > >-void InlineFormattingContext::LineLayout::splitInlineRunIfNeeded(const InlineRun& inlineRun, InlineRuns& splitRuns) const >+void InlineFormattingContext::LineLayout::closeLine(Line& line, IsLastLine isLastLine) 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 = { }; >- }; >- >- for (auto iterator = inlineContent.find(const_cast<InlineItem*>(&inlineRun.inlineItem())); iterator != inlineContent.end() && remaningLength > 0; ++iterator) { >- auto& inlineItem = **iterator; >+ line.close(); >+ if (line.isEmpty()) >+ return; > >- // Skip all non-inflow boxes (floats, out-of-flow positioned elements). They don't participate in the inline run context. >- if (!inlineItem.layoutBox().isInFlow()) >+ alignRuns(m_formattingRoot.style().textAlign(), line, isLastLine); >+ >+ auto& lineItems = line.lineItems(); >+ // 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.isContainerStart() || inlineItem.isBox()) { >+ // Set inline container's logical topleft position -taking relative positioning into account. >+ auto topLeft = inlineRun.logicalTopLeft(); >+ if (layoutBox.isInFlowPositioned()) >+ topLeft += Geometry::inFlowPositionedPositionOffset(layoutState(), layoutBox); >+ displayBox.setTopLeft(topLeft); >+ >+ if (inlineItem.isBox()) >+ m_formattingState.addInlineRun(std::make_unique<Display::Run>(inlineRun)); > continue; >+ } > >- 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(); >+ if (inlineItem.isContainerEnd()) { >+ // Set inline container's width and 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); >+ // FIXME: height >+ displayBox.setContentBoxHeight(line.logicalHeight()); > continue; > } > >- // #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(); >-} >+ if (inlineItem.isHardLineBreak()) >+ continue; > >-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; >+ ASSERT(inlineRun.textContext()); >+ auto& inlineTextItem = downcast<InlineTextItem>(inlineItem); >+ const InlineItem* previousInlineItem = !index ? nullptr : &lineItems[index - 1].inlineItem; >+ auto previousRunHasCollapsedWhitespace = false; >+ if (is<InlineTextItem>(previousInlineItem)) >+ previousRunHasCollapsedWhitespace = downcast<InlineTextItem>(*previousInlineItem).isCollapsed(); >+ >+ auto requiresNewRun = !index || &inlineItem.layoutBox() != &previousInlineItem->layoutBox() || previousRunHasCollapsedWhitespace; >+ 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()); > } >- >- 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()); > } > } > >-void InlineFormattingContext::LineLayout::postProcessInlineRuns(Line& line, IsLastLine isLastLine) const >-{ >- alignRuns(m_formattingRoot.style().textAlign(), line, isLastLine); >- auto firstRunIndex = m_formattingState.inlineRuns().size(); >- createFinalRuns(line); >- >- placeInFlowPositionedChildren(firstRunIndex); >-} >- >-void InlineFormattingContext::LineLayout::closeLine(Line& line, IsLastLine isLastLine) const >-{ >- line.close(); >- if (!line.hasContent()) >- return; >- >- postProcessInlineRuns(line, isLastLine); >-} >- >-void InlineFormattingContext::LineLayout::appendContentToLine(Line& line, const InlineRunProvider::Run& run, const LayoutSize& runSize) const >+void InlineFormattingContext::LineLayout::commitInlineItemToLine(Line& line, const InlineItem& inlineItem) const > { >- auto lastRunType = line.lastRunType(); >- line.appendContent(run, runSize); >+ if (inlineItem.isContainerStart() || inlineItem.isContainerEnd()) >+ return line.appendNonBreakableSpace(inlineItem); >+ >+ auto width = inlineItem.width(); >+ if (is<InlineTextItem>(inlineItem)) >+ line.appendTextContent(downcast<InlineTextItem>(inlineItem), { width, m_formattingRoot.style().computedLineHeight() }); >+ else { >+ auto& displayBox = layoutState().displayBoxForLayoutBox(inlineItem.layoutBox()); >+ line.appendNonTextContent(inlineItem, { width, displayBox.height() }); >+ } > > if (m_formattingRoot.style().textAlign() == TextAlignMode::Justify) >- computeExpansionOpportunities(line, run, lastRunType.valueOr(InlineRunProvider::Run::Type::NonWhitespace)); >+ computeExpansionOpportunities(line, inlineItem, line.hasTrailingWhitespace()); > } > > void InlineFormattingContext::LineLayout::computeFloatPosition(const FloatingContext& floatingContext, Line& line, const Box& floatBox) const > { >- auto& layoutState = m_formattingContext.layoutState(); >- ASSERT(layoutState.hasDisplayBox(floatBox)); >- auto& displayBox = layoutState.displayBoxForLayoutBox(floatBox); >+ ASSERT(layoutState().hasDisplayBox(floatBox)); >+ auto& displayBox = layoutState().displayBoxForLayoutBox(floatBox); > > // Set static position first. >- displayBox.setTopLeft({ line.contentLogicalRight(), line.logicalTop() }); >+ displayBox.setTopLeft({ line.logicalRight(), line.logicalTop() }); > // Float it. > displayBox.setTopLeft(floatingContext.positionForFloat(floatBox)); > } > >-void InlineFormattingContext::LineLayout::placeInFlowPositionedChildren(unsigned fistRunIndex) 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 (auto offset = positionOffset(inlineRun.inlineItem().layoutBox())) { >- inlineRun.moveVertically(offset->height()); >- inlineRun.moveHorizontally(offset->width()); >- } >- } >-} >- > static LayoutUnit adjustedLineLogicalLeft(TextAlignMode align, LayoutUnit lineLogicalLeft, LayoutUnit remainingWidth) > { > switch (align) { >@@ -503,8 +504,8 @@ static LayoutUnit adjustedLineLogicalLeft(TextAlignMode align, LayoutUnit lineLo > > void InlineFormattingContext::LineLayout::justifyRuns(Line& line) > { >- auto& inlineRuns = line.runs(); >- auto& lastInlineRun = inlineRuns.last(); >+ auto& lineItems = line.lineItems(); >+ auto& lastInlineRun = lineItems.last().inlineRun; > > // Adjust (forbid) trailing expansion for the last text run on line. > auto expansionBehavior = lastInlineRun.expansionOpportunity().behavior; >@@ -519,28 +520,29 @@ void InlineFormattingContext::LineLayout::justifyRuns(Line& line) > return; > > auto expansionOpportunities = 0; >- for (auto& inlineRun : inlineRuns) >- expansionOpportunities += inlineRun.expansionOpportunity().count; >+ for (auto& lineItem : lineItems) >+ expansionOpportunities += lineItem.inlineRun.expansionOpportunity().count; > > if (!expansionOpportunities) > return; > > float expansion = widthToDistribute.toFloat() / expansionOpportunities; > LayoutUnit accumulatedExpansion; >- for (auto& inlineRun : inlineRuns) { >+ for (auto& lineItem : lineItems) { >+ auto& inlineRun = lineItem.inlineRun; > auto expansionForRun = inlineRun.expansionOpportunity().count * expansion; > > inlineRun.expansionOpportunity().expansion = expansionForRun; >- inlineRun.setLogicalLeft(inlineRun.logicalLeft() + accumulatedExpansion); >- inlineRun.setLogicalWidth(inlineRun.logicalWidth() + expansionForRun); >+ inlineRun.moveHorizontally(accumulatedExpansion); >+ inlineRun.expandHorizontally(expansionForRun); > accumulatedExpansion += expansionForRun; > } > } > >-void InlineFormattingContext::LineLayout::computeExpansionOpportunities(Line& line, const InlineRunProvider::Run& run, InlineRunProvider::Run::Type lastRunType) const >+void InlineFormattingContext::LineLayout::computeExpansionOpportunities(Line& line, const InlineItem& inlineItem, bool previousRunIsWhitepace) const > { >- auto isExpansionOpportunity = [](auto currentRunIsWhitespace, auto lastRunIsWhitespace) { >- return currentRunIsWhitespace || (!currentRunIsWhitespace && !lastRunIsWhitespace); >+ auto isExpansionOpportunity = [](auto currentRunIsWhitespace, auto previousRunIsWhitepace) { >+ return currentRunIsWhitespace || (!currentRunIsWhitespace && !previousRunIsWhitepace); > }; > > auto expansionBehavior = [](auto isAtExpansionOpportunity) { >@@ -549,9 +551,10 @@ void InlineFormattingContext::LineLayout::computeExpansionOpportunities(Line& li > return expansionBehavior; > }; > >- auto isAtExpansionOpportunity = isExpansionOpportunity(run.isWhitespace(), lastRunType == InlineRunProvider::Run::Type::Whitespace); >+ auto currentRunIsWhitespace = is<InlineTextItem>(inlineItem) ? downcast<InlineTextItem>(inlineItem).isWhitespace() : false; >+ auto isAtExpansionOpportunity = isExpansionOpportunity(currentRunIsWhitespace, previousRunIsWhitepace); > >- auto& currentInlineRun = line.runs().last(); >+ auto& currentInlineRun = line.lineItems().last().inlineRun; > auto& expansionOpportunity = currentInlineRun.expansionOpportunity(); > if (isAtExpansionOpportunity) > ++expansionOpportunity.count; >@@ -567,38 +570,14 @@ void InlineFormattingContext::LineLayout::alignRuns(TextAlignMode textAlign, Lin > return; > } > >- auto lineLogicalLeft = line.contentLogicalLeft(); >+ auto lineLogicalLeft = line.logicalLeft(); > 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; >+ for (auto& lineItem : line.lineItems()) >+ lineItem.inlineRun.moveHorizontally(delta); > } > > } >diff --git a/Source/WebCore/layout/inlineformatting/InlineFormattingState.h b/Source/WebCore/layout/inlineformatting/InlineFormattingState.h >index 662a83c3ebc51ba7b0e3c4eaccf51844e9ed659c..08b1a5f9719239da7e5e6efeaf7bbd2dca417482 100644 >--- a/Source/WebCore/layout/inlineformatting/InlineFormattingState.h >+++ b/Source/WebCore/layout/inlineformatting/InlineFormattingState.h >@@ -27,15 +27,18 @@ > > #if ENABLE(LAYOUT_FORMATTING_CONTEXT) > >+#include "DisplayRun.h" > #include "FormattingState.h" > #include "InlineItem.h" >-#include "InlineRun.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>>; > // InlineFormattingState holds the state for a particular inline formatting context tree. > class InlineFormattingState : public FormattingState { > WTF_MAKE_ISO_ALLOCATED(InlineFormattingState); >@@ -43,15 +46,16 @@ 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); } >+ >+ 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)); } > > private: >- InlineContent m_inlineContent; >+ InlineItems m_inlineItems; > InlineRuns m_inlineRuns; > }; > >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/InlineLineBreaker.cpp b/Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp >index 576a0bb795437e013742a7286943af2481004fec..31c3cd2b971db77acb84cd6e7b72a81dfca06f45 100644 >--- a/Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp >+++ b/Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp >@@ -28,173 +28,103 @@ > > #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) > { >- 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); > } > >-bool InlineLineBreaker::isAtContentEnd() const >+LineBreaker::BreakingContext LineBreaker::breakingContext(InlineItem& inlineItem, LineContext lineContext) > { >- return m_currentRunIndex == m_inlineRuns.size(); >+ 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) }; > } > >-InlineLineBreaker::LineBreakingBehavior InlineLineBreaker::lineBreakingBehavior(const InlineRunProvider::Run& inlineRun, bool lineIsEmpty) >+LineBreaker::BreakingBehavior LineBreaker::wordBreakingBehavior(const InlineTextItem& inlineItem, bool lineIsEmpty) const > { >- // 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 (is<InlineTextItem>(inlineItem)) >+ return textWidth(downcast<InlineTextItem>(inlineItem), contentLogicalLeft); > >- if (inlineRun.isText()) >- return textWidth(inlineRun, contentLogicalLeft); >+ if (inlineItem.isLineBreak()) >+ return 0; > >- 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.marginBox().width(); >+ >+ 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/LayoutReplaced.cpp b/Source/WebCore/layout/layouttree/LayoutReplaced.cpp >index 00cd5d068298b1663acffc9d49f0ffb1b65c4f23..964a6b36b4f53a4350472227d81f471e65ef03a8 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..4cc23395b43465f5dadc6be7c0603c3ccb653e39 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" >@@ -60,6 +61,15 @@ std::unique_ptr<Container> TreeBuilder::createLayoutTree(const RenderView& rende > return initialContainingBlock; > } > >+static Optional<LayoutSize> accumulatedOffsetForInFlowPositionedContinuation(const RenderBlock& 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> { >@@ -115,9 +125,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<RenderBlock>(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())); >@@ -166,11 +182,11 @@ static void outputInlineRuns(TextStream& stream, const LayoutState& layoutState, > while (++printedCharacters <= depth * 2) > stream << " "; > stream << "run"; >- if (inlineRun.textContext()) >- stream << "(" << inlineRun.textContext()->start() << ", " << inlineRun.textContext()->start() + inlineRun.textContext()->length() << ") "; >+ 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() << "]"; >+ stream << "at [" << inlineRun->logicalLeft() << ", " << inlineRun->logicalTop() << "] size [" << inlineRun->logicalWidth() << " " << inlineRun->logicalHeight() << "]"; > stream.nextLine(); > } > } >@@ -186,11 +202,13 @@ static void outputLayoutBox(TextStream& stream, const Box& layoutBox, const Disp > 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 >+ else if (layoutBox.isAnonymous()) >+ stream << "anonymous inline box"; >+ else > stream << "inline box"; >+ >+ if (downcast<InlineBox>(layoutBox).hasTextContent()) >+ stream << " with text content [\"" << downcast<InlineBox>(layoutBox).textContent().utf8().data() << "\"]"; > } else if (is<BlockContainer>(layoutBox)) { > if (!layoutBox.parent()) > stream << "initial "; >@@ -201,10 +219,9 @@ static void outputLayoutBox(TextStream& stream, const Box& layoutBox, const Disp > 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 >+ if (is<InlineContainer>(layoutBox)) >+ stream << " at [" << displayBox->left() << "] width [" << displayBox->width() << "]"; >+ else if (!layoutBox.isAnonymous()) > stream << " at [" << displayBox->left() << " " << displayBox->top() << "] size [" << displayBox->width() << " " << displayBox->height() << "]"; > } > stream << " [" << &layoutBox << "]"; >diff --git a/Tools/LayoutReloaded/misc/LFC-passing-tests.txt b/Tools/LayoutReloaded/misc/LFC-passing-tests.txt >index ced009edd4b28995b230b1da48bd861cc34d23ca..50c7698e0fc9de4dca58dd33476280a663ec1e17 100644 >--- a/Tools/LayoutReloaded/misc/LFC-passing-tests.txt >+++ b/Tools/LayoutReloaded/misc/LFC-passing-tests.txt >@@ -473,7 +473,6 @@ css2.1/t0511-c21-pseud-link-00-e.html > css2.1/t0511-c21-pseud-link-01-e.html > css2.1/t0511-c21-pseud-link-02-e.html > css2.1/t0511-c21-pseud-link-03-e.html >-css2.1/t0602-c13-inh-underlin-00-e.html > css2.1/t0603-c11-import-00-b.html > css2.1/t0803-c5502-imrgn-r-00-b-ag.html > css2.1/t0803-c5502-mrgn-r-02-c.html >@@ -643,7 +642,6 @@ css2.1/t060403-c21-pseu-id-00-e-i.html > css2.1/t090501-c414-flt-00-d.html > css2.1/t090501-c414-flt-02-d-g.html > css2.1/t100303-c412-blockw-00-d-ag.html >-css2.1/t100801-c544-valgn-04-d-agi.html > css2.1/t100801-c548-ln-ht-01-b-ag.html > css2.1/t100801-c548-ln-ht-02-b-ag.html > css2.1/t100801-c548-ln-ht-03-d-ag.html
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