Commit 940f5872 authored by antti@apple.com's avatar antti@apple.com
Browse files

Simple line layout

https://bugs.webkit.org/show_bug.cgi?id=122458

Reviewed by Darin Adler.

Line box based inline layout is powerful but also rather slow and memory intensive. Simple line layout
is a compact alternative data structure and fast code path to cover common cases without requiring line
boxes.
        
This patch handles a case single left-aligned text renderer inside flow with no floats. Even this very basic
case is sufficiently common to handle up to 25% of all text lines on some popular new sites. The decision
which path to use is made per block flow (paragraph).
        
Simple line layout aims to produce pixel-exact rendering result when compared to the line box layout.
        
The goal is to handle everything that requires line level access in cases that allow use of simple lines.
This is not quite the case yet. For example selections and outline painting are not supported. In these
cases we seamlessly switch to the line boxes.

The simple line data structure currently uses 12 bytes per line. Lineboxes take ~160 bytes minimum per line.
Laying out the lines is also several times faster as is iterating over them.

* CMakeLists.txt:
* GNUmakefile.list.am:
* WebCore.vcxproj/WebCore.vcxproj:
* WebCore.xcodeproj/project.pbxproj:
* dom/Position.cpp:
(WebCore::Position::upstream):
(WebCore::Position::downstream):
(WebCore::Position::getInlineBoxAndOffset):
        
    Creating positions within a simple line flow causes switch to line boxes.

* editing/TextIterator.cpp:
(WebCore::TextIterator::handleTextNode):
        
    TextIterator traverses line boxes if available. In case simple line case we need to replicate the
    same results (for compatibility but especially to avoid changing test results). This is done here
    by just traversing the string without actually using the layout.

* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::RenderBlock):
(WebCore::RenderBlock::layoutShapeInsideInfo):
* rendering/RenderBlock.h:
* rendering/RenderBlockFlow.cpp:
(WebCore::RenderBlockFlow::layoutInlineChildren):
        
    Select the layout path to use.

(WebCore::RenderBlockFlow::deleteLines):
(WebCore::RenderBlockFlow::hitTestInlineChildren):
(WebCore::RenderBlockFlow::adjustForBorderFit):
(WebCore::RenderBlockFlow::firstLineBaseline):
(WebCore::RenderBlockFlow::inlineBlockBaseline):
(WebCore::RenderBlockFlow::inlineSelectionGaps):
(WebCore::RenderBlockFlow::clearTruncation):
(WebCore::RenderBlockFlow::positionForPointWithInlineChildren):
(WebCore::RenderBlockFlow::addFocusRingRectsForInlineChildren):
(WebCore::RenderBlockFlow::paintInlineChildren):
(WebCore::RenderBlockFlow::hasLines):
(WebCore::RenderBlockFlow::layoutSimpleLines):
        
    Do simple layout.

(WebCore::RenderBlockFlow::deleteLineBoxesBeforeSimpleLineLayout):
(WebCore::RenderBlockFlow::ensureLineBoxes):
        
    This function switches from simple lines to line boxes. The switching can be done outside normal layout.
    This is used to cover some cases that are not yet supported by simple lines (like selections).

* rendering/RenderBlockFlow.h:
(WebCore::RenderBlockFlow::simpleLines):
* rendering/RenderBlockLineLayout.cpp:
(WebCore::RenderBlockFlow::layoutLineBoxes):
        
    Rename the line box layout function.

(WebCore::RenderBlockFlow::addOverflowFromInlineChildren):
* rendering/RenderText.cpp:
(WebCore::RenderText::deleteLineBoxesBeforeSimpleLineLayout):
(WebCore::RenderText::absoluteRects):
(WebCore::RenderText::absoluteRectsForRange):
(WebCore::RenderText::absoluteQuadsClippedToEllipsis):
(WebCore::RenderText::absoluteQuads):
(WebCore::RenderText::absoluteQuadsForRange):
(WebCore::RenderText::positionForPoint):
(WebCore::RenderText::knownToHaveNoOverflowAndNoFallbackFonts):
(WebCore::RenderText::setSelectionState):
(WebCore::RenderText::setTextWithOffset):
(WebCore::RenderText::ensureLineBoxes):
(WebCore::RenderText::simpleLines):
(WebCore::RenderText::linesBoundingBox):
(WebCore::RenderText::linesVisualOverflowBoundingBox):
(WebCore::RenderText::selectionRectForRepaint):
(WebCore::RenderText::caretMinOffset):
(WebCore::RenderText::caretMaxOffset):
(WebCore::RenderText::countRenderedCharacterOffsetsUntil):
(WebCore::RenderText::containsRenderedCharacterOffset):
(WebCore::RenderText::containsCaretOffset):
(WebCore::RenderText::hasRenderedText):
* rendering/RenderText.h:
* rendering/RenderTreeAsText.cpp:
(WebCore::RenderTreeAsText::writeRenderObject):
(WebCore::writeSimpleLine):
(WebCore::write):
* rendering/SimpleLineLayout.cpp: Added.
(WebCore::SimpleLineLayout::canUseFor):
        
    This check for the cases supported by the simple line layout path.

(WebCore::SimpleLineLayout::isWhitespace):
(WebCore::SimpleLineLayout::skipWhitespaces):
(WebCore::SimpleLineLayout::textWidth):
(WebCore::SimpleLineLayout::createLines):
        
    The main layout functions that breaks text to lines. It only handles the cases allowed by 
    SimpleLineLayout::canUseFor. What it handles it aims to break exactly as line box layout does.

* rendering/SimpleLineLayout.h: Added.
* rendering/SimpleLineLayoutFunctions.cpp: Added.
(WebCore::SimpleLineLayout::paintFlow):
(WebCore::SimpleLineLayout::hitTestFlow):
(WebCore::SimpleLineLayout::collectFlowOverflow):
(WebCore::SimpleLineLayout::computeTextBoundingBox):
* rendering/SimpleLineLayoutFunctions.h: Added.
(WebCore::SimpleLineLayout::computeFlowHeight):
(WebCore::SimpleLineLayout::computeFlowFirstLineBaseline):
(WebCore::SimpleLineLayout::computeFlowLastLineBaseline):
(WebCore::SimpleLineLayout::findTextCaretMinimumOffset):
(WebCore::SimpleLineLayout::findTextCaretMaximumOffset):
(WebCore::SimpleLineLayout::containsTextCaretOffset):
(WebCore::SimpleLineLayout::isTextRendered):
(WebCore::SimpleLineLayout::lineHeightFromFlow):
        
    Support functions called from RenderBlockFlow and RenderText. They are equivalent to
    similar line box functions.

(WebCore::SimpleLineLayout::baselineFromFlow):
* rendering/SimpleLineLayoutResolver.h: Added.
(WebCore::SimpleLineLayout::Resolver::Line::Line):
(WebCore::SimpleLineLayout::Resolver::Line::rect):
(WebCore::SimpleLineLayout::Resolver::Line::baseline):
(WebCore::SimpleLineLayout::Resolver::Line::text):
(WebCore::SimpleLineLayout::Resolver::Iterator::Iterator):
(WebCore::SimpleLineLayout::Resolver::Iterator::operator++):
(WebCore::SimpleLineLayout::Resolver::Iterator::operator--):
(WebCore::SimpleLineLayout::Resolver::Iterator::operator==):
(WebCore::SimpleLineLayout::Resolver::Iterator::operator!=):
(WebCore::SimpleLineLayout::Resolver::Iterator::operator*):
        
    Lazy iterator for deriving line metrics. This keeps the line data structure small as
    we don't need to keep easily derived values around.

(WebCore::SimpleLineLayout::Resolver::Resolver):
(WebCore::SimpleLineLayout::Resolver::size):
(WebCore::SimpleLineLayout::Resolver::begin):
(WebCore::SimpleLineLayout::Resolver::end):
(WebCore::SimpleLineLayout::Resolver::last):
(WebCore::SimpleLineLayout::Resolver::operator[]):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@157950 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent c9465abd
......@@ -2175,6 +2175,8 @@ set(WebCore_SOURCES
rendering/RenderWidget.cpp
rendering/RootInlineBox.cpp
rendering/ScrollBehavior.cpp
rendering/SimpleLineLayout.cpp
rendering/SimpleLineLayoutFunctions.cpp
rendering/TextAutosizer.cpp
rendering/TextPaintStyle.cpp
rendering/break_lines.cpp
......
2013-10-24 Antti Koivisto <antti@apple.com>
Simple line layout
https://bugs.webkit.org/show_bug.cgi?id=122458
Reviewed by Darin Adler.
Line box based inline layout is powerful but also rather slow and memory intensive. Simple line layout
is a compact alternative data structure and fast code path to cover common cases without requiring line
boxes.
This patch handles a case single left-aligned text renderer inside flow with no floats. Even this very basic
case is sufficiently common to handle up to 25% of all text lines on some popular new sites. The decision
which path to use is made per block flow (paragraph).
Simple line layout aims to produce pixel-exact rendering result when compared to the line box layout.
The goal is to handle everything that requires line level access in cases that allow use of simple lines.
This is not quite the case yet. For example selections and outline painting are not supported. In these
cases we seamlessly switch to the line boxes.
The simple line data structure currently uses 12 bytes per line. Lineboxes take ~160 bytes minimum per line.
Laying out the lines is also several times faster as is iterating over them.
* CMakeLists.txt:
* GNUmakefile.list.am:
* WebCore.vcxproj/WebCore.vcxproj:
* WebCore.xcodeproj/project.pbxproj:
* dom/Position.cpp:
(WebCore::Position::upstream):
(WebCore::Position::downstream):
(WebCore::Position::getInlineBoxAndOffset):
Creating positions within a simple line flow causes switch to line boxes.
* editing/TextIterator.cpp:
(WebCore::TextIterator::handleTextNode):
TextIterator traverses line boxes if available. In case simple line case we need to replicate the
same results (for compatibility but especially to avoid changing test results). This is done here
by just traversing the string without actually using the layout.
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::RenderBlock):
(WebCore::RenderBlock::layoutShapeInsideInfo):
* rendering/RenderBlock.h:
* rendering/RenderBlockFlow.cpp:
(WebCore::RenderBlockFlow::layoutInlineChildren):
Select the layout path to use.
(WebCore::RenderBlockFlow::deleteLines):
(WebCore::RenderBlockFlow::hitTestInlineChildren):
(WebCore::RenderBlockFlow::adjustForBorderFit):
(WebCore::RenderBlockFlow::firstLineBaseline):
(WebCore::RenderBlockFlow::inlineBlockBaseline):
(WebCore::RenderBlockFlow::inlineSelectionGaps):
(WebCore::RenderBlockFlow::clearTruncation):
(WebCore::RenderBlockFlow::positionForPointWithInlineChildren):
(WebCore::RenderBlockFlow::addFocusRingRectsForInlineChildren):
(WebCore::RenderBlockFlow::paintInlineChildren):
(WebCore::RenderBlockFlow::hasLines):
(WebCore::RenderBlockFlow::layoutSimpleLines):
Do simple layout.
(WebCore::RenderBlockFlow::deleteLineBoxesBeforeSimpleLineLayout):
(WebCore::RenderBlockFlow::ensureLineBoxes):
This function switches from simple lines to line boxes. The switching can be done outside normal layout.
This is used to cover some cases that are not yet supported by simple lines (like selections).
* rendering/RenderBlockFlow.h:
(WebCore::RenderBlockFlow::simpleLines):
* rendering/RenderBlockLineLayout.cpp:
(WebCore::RenderBlockFlow::layoutLineBoxes):
Rename the line box layout function.
(WebCore::RenderBlockFlow::addOverflowFromInlineChildren):
* rendering/RenderText.cpp:
(WebCore::RenderText::deleteLineBoxesBeforeSimpleLineLayout):
(WebCore::RenderText::absoluteRects):
(WebCore::RenderText::absoluteRectsForRange):
(WebCore::RenderText::absoluteQuadsClippedToEllipsis):
(WebCore::RenderText::absoluteQuads):
(WebCore::RenderText::absoluteQuadsForRange):
(WebCore::RenderText::positionForPoint):
(WebCore::RenderText::knownToHaveNoOverflowAndNoFallbackFonts):
(WebCore::RenderText::setSelectionState):
(WebCore::RenderText::setTextWithOffset):
(WebCore::RenderText::ensureLineBoxes):
(WebCore::RenderText::simpleLines):
(WebCore::RenderText::linesBoundingBox):
(WebCore::RenderText::linesVisualOverflowBoundingBox):
(WebCore::RenderText::selectionRectForRepaint):
(WebCore::RenderText::caretMinOffset):
(WebCore::RenderText::caretMaxOffset):
(WebCore::RenderText::countRenderedCharacterOffsetsUntil):
(WebCore::RenderText::containsRenderedCharacterOffset):
(WebCore::RenderText::containsCaretOffset):
(WebCore::RenderText::hasRenderedText):
* rendering/RenderText.h:
* rendering/RenderTreeAsText.cpp:
(WebCore::RenderTreeAsText::writeRenderObject):
(WebCore::writeSimpleLine):
(WebCore::write):
* rendering/SimpleLineLayout.cpp: Added.
(WebCore::SimpleLineLayout::canUseFor):
This check for the cases supported by the simple line layout path.
(WebCore::SimpleLineLayout::isWhitespace):
(WebCore::SimpleLineLayout::skipWhitespaces):
(WebCore::SimpleLineLayout::textWidth):
(WebCore::SimpleLineLayout::createLines):
The main layout functions that breaks text to lines. It only handles the cases allowed by
SimpleLineLayout::canUseFor. What it handles it aims to break exactly as line box layout does.
* rendering/SimpleLineLayout.h: Added.
* rendering/SimpleLineLayoutFunctions.cpp: Added.
(WebCore::SimpleLineLayout::paintFlow):
(WebCore::SimpleLineLayout::hitTestFlow):
(WebCore::SimpleLineLayout::collectFlowOverflow):
(WebCore::SimpleLineLayout::computeTextBoundingBox):
* rendering/SimpleLineLayoutFunctions.h: Added.
(WebCore::SimpleLineLayout::computeFlowHeight):
(WebCore::SimpleLineLayout::computeFlowFirstLineBaseline):
(WebCore::SimpleLineLayout::computeFlowLastLineBaseline):
(WebCore::SimpleLineLayout::findTextCaretMinimumOffset):
(WebCore::SimpleLineLayout::findTextCaretMaximumOffset):
(WebCore::SimpleLineLayout::containsTextCaretOffset):
(WebCore::SimpleLineLayout::isTextRendered):
(WebCore::SimpleLineLayout::lineHeightFromFlow):
Support functions called from RenderBlockFlow and RenderText. They are equivalent to
similar line box functions.
(WebCore::SimpleLineLayout::baselineFromFlow):
* rendering/SimpleLineLayoutResolver.h: Added.
(WebCore::SimpleLineLayout::Resolver::Line::Line):
(WebCore::SimpleLineLayout::Resolver::Line::rect):
(WebCore::SimpleLineLayout::Resolver::Line::baseline):
(WebCore::SimpleLineLayout::Resolver::Line::text):
(WebCore::SimpleLineLayout::Resolver::Iterator::Iterator):
(WebCore::SimpleLineLayout::Resolver::Iterator::operator++):
(WebCore::SimpleLineLayout::Resolver::Iterator::operator--):
(WebCore::SimpleLineLayout::Resolver::Iterator::operator==):
(WebCore::SimpleLineLayout::Resolver::Iterator::operator!=):
(WebCore::SimpleLineLayout::Resolver::Iterator::operator*):
Lazy iterator for deriving line metrics. This keeps the line data structure small as
we don't need to keep easily derived values around.
(WebCore::SimpleLineLayout::Resolver::Resolver):
(WebCore::SimpleLineLayout::Resolver::size):
(WebCore::SimpleLineLayout::Resolver::begin):
(WebCore::SimpleLineLayout::Resolver::end):
(WebCore::SimpleLineLayout::Resolver::last):
(WebCore::SimpleLineLayout::Resolver::operator[]):
2013-10-24 Myles C. Maxfield <mmaxfield@apple.com>
Gaps between underlines in adjacent underlined text runs
......
......@@ -4483,6 +4483,11 @@ webcore_sources += \
Source/WebCore/rendering/RootInlineBox.h \
Source/WebCore/rendering/ScrollBehavior.cpp \
Source/WebCore/rendering/ScrollBehavior.h \
Source/WebCore/rendering/SimpleLineLayout.cpp \
Source/WebCore/rendering/SimpleLineLayout.h \
Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp \
Source/WebCore/rendering/SimpleLineLayoutFunctions.h \
Source/WebCore/rendering/SimpleLineLayoutResolver.h \
Source/WebCore/rendering/TextAutosizer.cpp \
Source/WebCore/rendering/TextAutosizer.h \
Source/WebCore/rendering/TextPaintStyle.cpp \
......
......@@ -10912,6 +10912,8 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\rendering\SimpleLineLayout.cpp" />
<ClCompile Include="..\rendering\SimpleLineLayoutFunctions.cpp" />
<ClCompile Include="..\rendering\TextPaintStyle.cpp" />
<ClCompile Include="..\rendering\shapes\PolygonShape.cpp" />
<ClCompile Include="..\rendering\shapes\RasterShape.cpp" />
......@@ -19682,6 +19684,9 @@
<ClInclude Include="..\rendering\RenderWidget.h" />
<ClInclude Include="..\rendering\RootInlineBox.h" />
<ClInclude Include="..\rendering\ScrollBehavior.h" />
<ClInclude Include="..\rendering\SimpleLineLayout.h" />
<ClInclude Include="..\rendering\SimpleLineLayoutFunctions.h" />
<ClInclude Include="..\rendering\SimpleLineLayoutResolver.h" />
<ClInclude Include="..\rendering\svg\SVGMarkerData.h" />
<ClInclude Include="..\rendering\svg\SVGPathData.h" />
<ClInclude Include="..\rendering\svg\SVGRenderingContext.h" />
......@@ -5681,6 +5681,8 @@
E47B4BE90E71241600038854 /* CachedResourceHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E47B4BE70E71241600038854 /* CachedResourceHandle.cpp */; };
E47E276516036ED200EE2AFB /* DocumentStyleSheetCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = E47E276416036ED200EE2AFB /* DocumentStyleSheetCollection.h */; settings = {ATTRIBUTES = (Private, ); }; };
E47E276816036EDC00EE2AFB /* DocumentStyleSheetCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E47E276716036EDC00EE2AFB /* DocumentStyleSheetCollection.cpp */; };
E48944A2180B57D800F165D8 /* SimpleLineLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E48944A0180B57D800F165D8 /* SimpleLineLayout.cpp */; };
E48944A3180B57D800F165D8 /* SimpleLineLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = E48944A1180B57D800F165D8 /* SimpleLineLayout.h */; settings = {ATTRIBUTES = (Private, ); }; };
E4946EAE156E64DD00D3297F /* StyleRuleImport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4946EAC156E64DD00D3297F /* StyleRuleImport.cpp */; };
E4946EAF156E64DD00D3297F /* StyleRuleImport.h in Headers */ = {isa = PBXBuildFile; fileRef = E4946EAD156E64DD00D3297F /* StyleRuleImport.h */; };
E49BD9FA131FD2ED003C56F0 /* CSSValuePool.h in Headers */ = {isa = PBXBuildFile; fileRef = E49BD9F9131FD2ED003C56F0 /* CSSValuePool.h */; settings = {ATTRIBUTES = (Private, ); }; };
......@@ -5717,6 +5719,9 @@
E4D988B617BFEB210084FB88 /* TextNodeTraversal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4D988B517BFEB210084FB88 /* TextNodeTraversal.cpp */; };
E4DEAA1717A93DC3000E0430 /* StyleResolveTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4DEAA1517A93DC3000E0430 /* StyleResolveTree.cpp */; };
E4DEAA1817A93DC3000E0430 /* StyleResolveTree.h in Headers */ = {isa = PBXBuildFile; fileRef = E4DEAA1617A93DC3000E0430 /* StyleResolveTree.h */; settings = {ATTRIBUTES = (Private, ); }; };
E4E9B1191810916F003ACCDF /* SimpleLineLayoutResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = E4E9B1181810916F003ACCDF /* SimpleLineLayoutResolver.h */; };
E4E9B11B18145692003ACCDF /* SimpleLineLayoutFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4E9B11A18145692003ACCDF /* SimpleLineLayoutFunctions.cpp */; };
E4E9B11D1814569C003ACCDF /* SimpleLineLayoutFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = E4E9B11C1814569C003ACCDF /* SimpleLineLayoutFunctions.h */; };
E4F9EEF2156D9FFA00D23E7E /* StyleSheetContents.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4F9EEF0156D84C400D23E7E /* StyleSheetContents.cpp */; };
E4F9EEF3156DA00700D23E7E /* StyleSheetContents.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F9EEF1156D84C400D23E7E /* StyleSheetContents.h */; };
E51A81DF17298D7700BFCA61 /* JSPerformance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E51A81DE17298D7700BFCA61 /* JSPerformance.cpp */; };
......@@ -12669,6 +12674,8 @@
E47B4BE70E71241600038854 /* CachedResourceHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CachedResourceHandle.cpp; sourceTree = "<group>"; };
E47E276416036ED200EE2AFB /* DocumentStyleSheetCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DocumentStyleSheetCollection.h; sourceTree = "<group>"; };
E47E276716036EDC00EE2AFB /* DocumentStyleSheetCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentStyleSheetCollection.cpp; sourceTree = "<group>"; };
E48944A0180B57D800F165D8 /* SimpleLineLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleLineLayout.cpp; sourceTree = "<group>"; };
E48944A1180B57D800F165D8 /* SimpleLineLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleLineLayout.h; sourceTree = "<group>"; };
E4946EAC156E64DD00D3297F /* StyleRuleImport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StyleRuleImport.cpp; sourceTree = "<group>"; };
E4946EAD156E64DD00D3297F /* StyleRuleImport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StyleRuleImport.h; sourceTree = "<group>"; };
E49BD9F9131FD2ED003C56F0 /* CSSValuePool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSValuePool.h; sourceTree = "<group>"; };
......@@ -12722,6 +12729,9 @@
E4D988B517BFEB210084FB88 /* TextNodeTraversal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextNodeTraversal.cpp; sourceTree = "<group>"; };
E4DEAA1517A93DC3000E0430 /* StyleResolveTree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StyleResolveTree.cpp; sourceTree = "<group>"; };
E4DEAA1617A93DC3000E0430 /* StyleResolveTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StyleResolveTree.h; sourceTree = "<group>"; };
E4E9B1181810916F003ACCDF /* SimpleLineLayoutResolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleLineLayoutResolver.h; sourceTree = "<group>"; };
E4E9B11A18145692003ACCDF /* SimpleLineLayoutFunctions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleLineLayoutFunctions.cpp; sourceTree = "<group>"; };
E4E9B11C1814569C003ACCDF /* SimpleLineLayoutFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleLineLayoutFunctions.h; sourceTree = "<group>"; };
E4F9EEF0156D84C400D23E7E /* StyleSheetContents.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StyleSheetContents.cpp; sourceTree = "<group>"; };
E4F9EEF1156D84C400D23E7E /* StyleSheetContents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StyleSheetContents.h; sourceTree = "<group>"; };
E51A81DE17298D7700BFCA61 /* JSPerformance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPerformance.cpp; sourceTree = "<group>"; };
......@@ -20768,6 +20778,11 @@
5D925B650F64D4DD00B847F0 /* ScrollBehavior.cpp */,
5D925B660F64D4DD00B847F0 /* ScrollBehavior.h */,
A8CFF04C0A154F09000A4234 /* TableLayout.h */,
E48944A0180B57D800F165D8 /* SimpleLineLayout.cpp */,
E48944A1180B57D800F165D8 /* SimpleLineLayout.h */,
E4E9B11A18145692003ACCDF /* SimpleLineLayoutFunctions.cpp */,
E4E9B11C1814569C003ACCDF /* SimpleLineLayoutFunctions.h */,
E4E9B1181810916F003ACCDF /* SimpleLineLayoutResolver.h */,
E4C91A0F1802343900A17F6D /* TextPaintStyle.cpp */,
E4C91A0D1802343100A17F6D /* TextPaintStyle.h */,
37FC96DA1104ED71003E1FAD /* TrailingFloatsRootInlineBox.h */,
......@@ -22573,6 +22588,7 @@
A80D67080E9E9DEB00E420F0 /* GraphicsContextPlatformPrivateCG.h in Headers */,
0F580B0D0F12A2690051D689 /* GraphicsLayer.h in Headers */,
499B3ED7128CD31400E726C2 /* GraphicsLayerCA.h in Headers */,
E4E9B1191810916F003ACCDF /* SimpleLineLayoutResolver.h in Headers */,
0F580B0E0F12A2690051D689 /* GraphicsLayerClient.h in Headers */,
CDAB6D2E17C814EE00C60B34 /* JSMediaControlsHost.h in Headers */,
1AC69593161A1E53003732CB /* GraphicsLayerFactory.h in Headers */,
......@@ -23633,6 +23649,7 @@
49D5DC2E0F423A73008F20FD /* PerspectiveTransformOperation.h in Headers */,
D0FF2A5E11F8C45A007E74E0 /* PingLoader.h in Headers */,
377C4CDF1014E9F600B9AE42 /* PlaceholderDocument.h in Headers */,
E4E9B11D1814569C003ACCDF /* SimpleLineLayoutFunctions.h in Headers */,
499B3EDD128DB50200E726C2 /* PlatformCAAnimation.h in Headers */,
0F13163E16ED0CC80035CC04 /* PlatformCAFilters.h in Headers */,
499B3EC5128CCC4700E726C2 /* PlatformCALayer.h in Headers */,
......@@ -23819,6 +23836,7 @@
0854B0171255E4E600B9CDD0 /* RenderSVGInlineText.h in Headers */,
CD3A496217A9D01B00274E42 /* SourceBuffer.h in Headers */,
436708CB12D9CA4B00044234 /* RenderSVGModelObject.h in Headers */,
E48944A3180B57D800F165D8 /* SimpleLineLayout.h in Headers */,
ADDF1AD71257CD9A0003A759 /* RenderSVGPath.h in Headers */,
A10BB5851484E3A700B2E87A /* RenderSVGRect.h in Headers */,
436708CD12D9CA4B00044234 /* RenderSVGResource.h in Headers */,
......@@ -26603,6 +26621,7 @@
15C77094100D3CA8005BA267 /* JSValidityState.cpp in Sources */,
BE8EF04A171C9014009B48C3 /* JSVideoTrack.cpp in Sources */,
BE6DF70B171CA2C500DD52B8 /* JSVideoTrackCustom.cpp in Sources */,
E4E9B11B18145692003ACCDF /* SimpleLineLayoutFunctions.cpp in Sources */,
BE8EF04C171C9014009B48C3 /* JSVideoTrackList.cpp in Sources */,
BE6DF70D171CA2C500DD52B8 /* JSVideoTrackListCustom.cpp in Sources */,
078E093317D16B0600420AA1 /* MediaStreamCenter.cpp in Sources */,
......@@ -26845,6 +26864,7 @@
F3820892147D35F90010BC06 /* PageConsoleAgent.cpp in Sources */,
F34742DC134362F000531BC2 /* PageDebuggerAgent.cpp in Sources */,
9302B0BD0D79F82900C7EE83 /* PageGroup.cpp in Sources */,
E48944A2180B57D800F165D8 /* SimpleLineLayout.cpp in Sources */,
7A674BDB0F9EBF4E006CF099 /* PageGroupLoadDeferrer.cpp in Sources */,
1C26497C0D7E24EC00BD10F2 /* PageMac.cpp in Sources */,
FBDB619D16D6034600BB3394 /* PageRuleCollector.cpp in Sources */,
......@@ -644,7 +644,12 @@ Position Position::upstream(EditingBoundaryCrossingRule rule) const
}
// return current position if it is in rendered text
if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
if (renderer->isText()) {
auto& textRenderer = toRenderText(*renderer);
textRenderer.ensureLineBoxes();
if (!textRenderer.firstTextBox())
continue;
if (currentNode != startNode) {
// This assertion fires in layout tests in the case-transform.html test because
// of a mix-up between offsets in the text in the DOM tree with text in the
......@@ -655,9 +660,8 @@ Position Position::upstream(EditingBoundaryCrossingRule rule) const
}
unsigned textOffset = currentPos.offsetInLeafNode();
RenderText* textRenderer = toRenderText(renderer);
InlineTextBox* lastTextBox = textRenderer->lastTextBox();
for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
auto lastTextBox = textRenderer.lastTextBox();
for (auto box = textRenderer.firstTextBox(); box; box = box->nextTextBox()) {
if (textOffset <= box->start() + box->len()) {
if (textOffset > box->start())
return currentPos;
......@@ -676,7 +680,7 @@ Position Position::upstream(EditingBoundaryCrossingRule rule) const
otherBox = otherBox->nextLeafChild();
if (!otherBox)
break;
if (otherBox == lastTextBox || (&otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() > textOffset))
if (otherBox == lastTextBox || (&otherBox->renderer() == &textRenderer && static_cast<InlineTextBox*>(otherBox)->start() > textOffset))
continuesOnNextLine = false;
}
......@@ -685,7 +689,7 @@ Position Position::upstream(EditingBoundaryCrossingRule rule) const
otherBox = otherBox->prevLeafChild();
if (!otherBox)
break;
if (otherBox == lastTextBox || (&otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() > textOffset))
if (otherBox == lastTextBox || (&otherBox->renderer() == &textRenderer && static_cast<InlineTextBox*>(otherBox)->start() > textOffset))
continuesOnNextLine = false;
}
......@@ -772,16 +776,20 @@ Position Position::downstream(EditingBoundaryCrossingRule rule) const
}
// return current position if it is in rendered text
if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
if (renderer->isText()) {
auto& textRenderer = toRenderText(*renderer);
textRenderer.ensureLineBoxes();
if (!textRenderer.firstTextBox())
continue;
if (currentNode != startNode) {
ASSERT(currentPos.atStartOfNode());
return createLegacyEditingPosition(currentNode, renderer->caretMinOffset());
}
unsigned textOffset = currentPos.offsetInLeafNode();
RenderText* textRenderer = toRenderText(renderer);
InlineTextBox* lastTextBox = textRenderer->lastTextBox();
for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
auto lastTextBox = textRenderer.lastTextBox();
for (auto box = textRenderer.firstTextBox(); box; box = box->nextTextBox()) {
if (textOffset <= box->end()) {
if (textOffset >= box->start())
return currentPos;
......@@ -800,7 +808,7 @@ Position Position::downstream(EditingBoundaryCrossingRule rule) const
otherBox = otherBox->nextLeafChild();
if (!otherBox)
break;
if (otherBox == lastTextBox || (&otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() >= textOffset))
if (otherBox == lastTextBox || (&otherBox->renderer() == &textRenderer && static_cast<InlineTextBox*>(otherBox)->start() >= textOffset))
continuesOnNextLine = false;
}
......@@ -809,7 +817,7 @@ Position Position::downstream(EditingBoundaryCrossingRule rule) const
otherBox = otherBox->prevLeafChild();
if (!otherBox)
break;
if (otherBox == lastTextBox || (&otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() >= textOffset))
if (otherBox == lastTextBox || (&otherBox->renderer() == &textRenderer && static_cast<InlineTextBox*>(otherBox)->start() >= textOffset))
continuesOnNextLine = false;
}
......@@ -1154,7 +1162,8 @@ void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDi
if (renderer->isBR())
inlineBox = !caretOffset ? toRenderLineBreak(renderer)->inlineBoxWrapper() : nullptr;
else if (renderer->isText()) {
RenderText* textRenderer = toRenderText(renderer);
auto textRenderer = toRenderText(renderer);
textRenderer->ensureLineBoxes();
InlineTextBox* box;
InlineTextBox* candidate = 0;
......
......@@ -521,6 +521,36 @@ bool TextIterator::handleTextNode()
return true;
}
if (renderer->simpleLines()) {
if (renderer->style()->visibility() != VISIBLE && !m_ignoresStyleVisibility)
return true;
// This code aims to produce same results as handleTextBox() below so test results don't change. It does not make much logical sense.
unsigned runEnd = m_offset;
unsigned runStart = m_offset;
while (runEnd < str.length() && (isCollapsibleWhitespace(str[runEnd]) || str[runEnd] == '\t'))
++runEnd;
bool addSpaceForPrevious = m_lastTextNodeEndedWithCollapsedSpace && m_lastCharacter && !isCollapsibleWhitespace(m_lastCharacter);
if (runEnd > runStart || addSpaceForPrevious) {
if (runEnd == str.length()) {
m_lastTextNodeEndedWithCollapsedSpace = true;
return true;
}
bool addSpaceForCurrent = runStart || (m_lastCharacter && !isCollapsibleWhitespace(m_lastCharacter));
if (addSpaceForCurrent || addSpaceForPrevious) {
emitCharacter(' ', m_node, 0, runStart, runEnd);
m_offset = runEnd;
return false;
}
runStart = runEnd;
}
while (runEnd < str.length() && !isCollapsibleWhitespace(str[runEnd]))
++runEnd;
if (runStart < str.length())
emitText(m_node, renderer, runStart, runEnd);
m_offset = runEnd;
return runEnd == str.length();
}
if (renderer->firstTextBox())
m_textBox = renderer->firstTextBox();
......
......@@ -152,6 +152,7 @@ RenderBlock::RenderBlock(Element& element, unsigned baseTypeFlags)
, m_beingDestroyed(false)
, m_hasMarkupTruncation(false)
, m_hasBorderOrPaddingLogicalWidthChanged(false)
, m_forceLineBoxLayout(false)
#if ENABLE(IOS_TEXT_AUTOSIZING)
, m_widthForTextAutosizing(-1)
, m_lineCountForTextAutosizing(NOT_SET)
......@@ -167,6 +168,7 @@ RenderBlock::RenderBlock(Document& document, unsigned baseTypeFlags)
, m_beingDestroyed(false)
, m_hasMarkupTruncation(false)
, m_hasBorderOrPaddingLogicalWidthChanged(false)
, m_forceLineBoxLayout(false)
#if ENABLE(IOS_TEXT_AUTOSIZING)
, m_widthForTextAutosizing(-1)
, m_lineCountForTextAutosizing(NOT_SET)
......@@ -1383,6 +1385,10 @@ void RenderBlock::markShapeInsideDescendantsForLayout()
ShapeInsideInfo* RenderBlock::layoutShapeInsideInfo() const
{
// This may be called outside layout when switching from SimpleLineLayout to line boxes. This case never has shape info.
if (!view().layoutState())
return nullptr;
ShapeInsideInfo* shapeInsideInfo = view().layoutState()->shapeInsideInfo();
if (!shapeInsideInfo && flowThreadContainingBlock() && allowsShapeInsideInfoSharing()) {
......
......@@ -751,12 +751,13 @@ public:
protected:
OwnPtr<RenderBlockRareData> m_rareData;
mutable signed m_lineHeight : 27;
mutable signed m_lineHeight : 26;
unsigned m_hasMarginBeforeQuirk : 1; // Note these quirk values can't be put in RenderBlockRareData since they are set too frequently.
unsigned m_hasMarginAfterQuirk : 1;
unsigned m_beingDestroyed : 1;
unsigned m_hasMarkupTruncation : 1;
unsigned m_hasBorderOrPaddingLogicalWidthChanged : 1;
unsigned m_forceLineBoxLayout : 1;
#if ENABLE(IOS_TEXT_AUTOSIZING)
int m_widthForTextAutosizing;
......
......@@ -33,7 +33,9 @@
#include "RenderFlowThread.h"
#include "RenderLayer.h"
#include "RenderNamedFlowFragment.h"
#include "RenderText.h"
#include "RenderView.h"
#include "SimpleLineLayoutFunctions.h"
#include "VerticalPositionCache.h"
#include "VisiblePosition.h"
......@@ -518,6 +520,19 @@ void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& max
handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
}
void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
{
bool canUseSimpleLineLayout = !m_forceLineBoxLayout && SimpleLineLayout::canUseFor(*this);
if (canUseSimpleLineLayout) {
deleteLineBoxesBeforeSimpleLineLayout();
layoutSimpleLines(repaintLogicalTop, repaintLogicalBottom);
return;
}
m_simpleLines = nullptr;
layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
}
void RenderBlockFlow::layoutBlockChild(RenderBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
{
LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
......@@ -1632,7 +1647,11 @@ void RenderBlockFlow::deleteLines()
if (containsFloats())
m_floatingObjects->clearLineBoxTreePointers();
m_lineBoxes.deleteLineBoxTree(renderArena());
if (m_simpleLines) {
ASSERT(!m_lineBoxes.firstLineBox());
m_simpleLines = nullptr;
} else
m_lineBoxes.deleteLineBoxTree(renderArena());
RenderBlock::deleteLines();
}
......@@ -2413,6 +2432,10 @@ bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult
bool RenderBlockFlow::hitTestInlineChildren(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
{
ASSERT(childrenInline());
if (m_simpleLines)
return SimpleLineLayout::hitTestFlow(*this, *m_simpleLines, request, result, locationInContainer, accumulatedOffset, hitTestAction);
return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
}
......@@ -2424,6 +2447,8 @@ void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutU
// We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
// for either overflow or translations via relative positioning.
if (childrenInline()) {
const_cast<RenderBlockFlow&>(*this).ensureLineBoxes();
for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
if (box->firstChild())
left = min(left, x + static_cast<LayoutUnit>(box->firstChild()->x()));
......@@ -2512,10 +2537,14 @@ int RenderBlockFlow::firstLineBaseline() const
if (!childrenInline())
return RenderBlock::firstLineBaseline();
if (firstLineBox())
return firstLineBox()->logicalTop() + firstLineStyle()->fontMetrics().ascent(firstRootBox()->baselineType());
if (!hasLines())
return -1;
return -1;
if (m_simpleLines)
return SimpleLineLayout::computeFlowFirstLineBaseline(*this, *m_simpleLines);
ASSERT(firstLineBox());
return firstLineBox()->logicalTop() + firstLineStyle()->fontMetrics().ascent(firstRootBox()->baselineType());
}
int RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
......@@ -2535,6 +2564,9 @@ int RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
+ (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
}
if (m_simpleLines)
return SimpleLineLayout::computeFlowLastLineBaseline(*this, *m_simpleLines);
bool isFirstLine = lastLineBox() == firstLineBox();
RenderStyle* style = isFirstLine ? firstLineStyle() : this->style();
return lastLineBox()->logicalTop() + style->fontMetrics().ascent(lastRootBox()->baselineType());
......@@ -2543,6 +2575,8 @@ int RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
ASSERT(!m_simpleLines);
GapRects result;
bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
......@@ -2752,6 +2786,8 @@ void RenderBlockFlow::clearTruncation()
return;
if (childrenInline() && hasMarkupTruncation()) {
ensureLineBoxes();
setHasMarkupTruncation(false);
for (auto box = firstRootBox(); box; box = box->nextRootBox())
box->clearTruncation();
......@@ -2793,6 +2829,8 @@ VisiblePosition RenderBlockFlow::positionForPointWithInlineChildren(const Layout
{
ASSERT(childrenInline());
ensureLineBoxes();
if (!firstRootBox())
return createVisiblePosition(0, DOWNSTREAM);
......@@ -2879,6 +2917,10 @@ VisiblePosition RenderBlockFlow::positionForPointWithInlineChildren(const Layout
void RenderBlockFlow::addFocusRingRectsForInlineChildren(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
{
ASSERT(childrenInline());
ensureLineBoxes();
for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
LayoutUnit top = max<LayoutUnit>(curr->lineTop(), curr->top());
LayoutUnit bottom = min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
......@@ -2891,6 +2933,11 @@ void RenderBlockFlow::addFocusRingRectsForInlineChildren(Vector<IntRect>& rects,
void RenderBlockFlow::paintInlineChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
ASSERT(childrenInline());
if (m_simpleLines) {
SimpleLineLayout::paintFlow(*this, *m_simpleLines, paintInfo, paintOffset);
return;
}