Diff
Modified: trunk/Source/WebCore/CMakeLists.txt (179283 => 179284)
--- trunk/Source/WebCore/CMakeLists.txt 2015-01-28 21:27:39 UTC (rev 179283)
+++ trunk/Source/WebCore/CMakeLists.txt 2015-01-28 21:37:40 UTC (rev 179284)
@@ -2352,6 +2352,7 @@
rendering/ScrollBehavior.cpp
rendering/SimpleLineLayout.cpp
rendering/SimpleLineLayoutFlowContents.cpp
+ rendering/SimpleLineLayoutFlowContentsIterator.cpp
rendering/SimpleLineLayoutFunctions.cpp
rendering/SimpleLineLayoutResolver.cpp
rendering/TextAutosizer.cpp
Modified: trunk/Source/WebCore/ChangeLog (179283 => 179284)
--- trunk/Source/WebCore/ChangeLog 2015-01-28 21:27:39 UTC (rev 179283)
+++ trunk/Source/WebCore/ChangeLog 2015-01-28 21:37:40 UTC (rev 179284)
@@ -1,3 +1,76 @@
+2015-01-28 Zalan Bujtas <[email protected]>
+
+ Simple line layout: Move FlowContents iterator interface to FlowContentsIterator.
+ https://bugs.webkit.org/show_bug.cgi?id=140944
+
+ Reviewed by Antti Koivisto.
+
+ This patch cleans up FlowContents's interface by moving the iterator functionality
+ to this new FlowContentsIterator class.
+
+ No change in functionality.
+
+ * CMakeLists.txt:
+ * WebCore.vcxproj/WebCore.vcxproj:
+ * WebCore.vcxproj/WebCore.vcxproj.filters:
+ * WebCore.xcodeproj/project.pbxproj:
+ * rendering/SimpleLineLayout.cpp:
+ (WebCore::SimpleLineLayout::LineState::addUncommitted):
+ (WebCore::SimpleLineLayout::LineState::addUncommittedWhitespace):
+ (WebCore::SimpleLineLayout::preWrap):
+ (WebCore::SimpleLineLayout::removeTrailingWhitespace):
+ (WebCore::SimpleLineLayout::splitFragmentToFitLine):
+ (WebCore::SimpleLineLayout::firstFragment):
+ (WebCore::SimpleLineLayout::createLineRuns):
+ (WebCore::SimpleLineLayout::closeLineEndingAndAdjustRuns):
+ (WebCore::SimpleLineLayout::splitRunsAtRendererBoundary):
+ (WebCore::SimpleLineLayout::createTextRuns):
+ * rendering/SimpleLineLayoutFlowContents.cpp:
+ (WebCore::SimpleLineLayout::FlowContents::FlowContents):
+ (WebCore::SimpleLineLayout::FlowContents::Style::Style): Deleted.
+ (WebCore::SimpleLineLayout::FlowContents::nextTextFragment): Deleted.
+ (WebCore::SimpleLineLayout::nextBreakablePosition): Deleted.
+ (WebCore::SimpleLineLayout::FlowContents::findNextBreakablePosition): Deleted.
+ (WebCore::SimpleLineLayout::findNextNonWhitespace): Deleted.
+ (WebCore::SimpleLineLayout::FlowContents::findNextNonWhitespacePosition): Deleted.
+ (WebCore::SimpleLineLayout::FlowContents::textWidth): Deleted.
+ (WebCore::SimpleLineLayout::FlowContents::runWidth): Deleted.
+ * rendering/SimpleLineLayoutFlowContents.h:
+ (WebCore::SimpleLineLayout::FlowContents::Iterator::Iterator):
+ (WebCore::SimpleLineLayout::FlowContents::Iterator::operator*):
+ (WebCore::SimpleLineLayout::FlowContents::begin):
+ (WebCore::SimpleLineLayout::FlowContents::end):
+ (WebCore::SimpleLineLayout::FlowContents::length):
+ (WebCore::SimpleLineLayout::FlowContents::Iterator::operator++):
+ (WebCore::SimpleLineLayout::FlowContents::Iterator::operator==):
+ (WebCore::SimpleLineLayout::FlowContents::Iterator::operator!=):
+ (WebCore::SimpleLineLayout::FlowContents::segmentIndexForPosition):
+ (WebCore::SimpleLineLayout::FlowContents::TextFragment::TextFragment): Deleted.
+ (WebCore::SimpleLineLayout::FlowContents::TextFragment::isEmpty): Deleted.
+ (WebCore::SimpleLineLayout::FlowContents::hasOneSegment): Deleted.
+ (WebCore::SimpleLineLayout::FlowContents::style): Deleted.
+ (WebCore::SimpleLineLayout::FlowContents::characterAt): Deleted.
+ (WebCore::SimpleLineLayout::FlowContents::isLineBreak): Deleted.
+ (WebCore::SimpleLineLayout::FlowContents::isEnd): Deleted.
+ * rendering/SimpleLineLayoutFlowContentsIterator.cpp: Copied from Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp.
+ (WebCore::SimpleLineLayout::FlowContentsIterator::Style::Style):
+ (WebCore::SimpleLineLayout::FlowContentsIterator::FlowContentsIterator):
+ (WebCore::SimpleLineLayout::FlowContentsIterator::nextTextFragment):
+ (WebCore::SimpleLineLayout::FlowContentsIterator::textWidth):
+ (WebCore::SimpleLineLayout::nextBreakablePosition):
+ (WebCore::SimpleLineLayout::FlowContentsIterator::findNextBreakablePosition):
+ (WebCore::SimpleLineLayout::findNextNonWhitespace):
+ (WebCore::SimpleLineLayout::FlowContentsIterator::findNextNonWhitespacePosition):
+ (WebCore::SimpleLineLayout::FlowContentsIterator::runWidth):
+ * rendering/SimpleLineLayoutFlowContentsIterator.h: Copied from Source/WebCore/rendering/SimpleLineLayoutFlowContents.h.
+ (WebCore::SimpleLineLayout::FlowContentsIterator::TextFragment::TextFragment):
+ (WebCore::SimpleLineLayout::FlowContentsIterator::TextFragment::isEmpty):
+ (WebCore::SimpleLineLayout::FlowContentsIterator::style):
+ (WebCore::SimpleLineLayout::FlowContentsIterator::segmentForPosition):
+ (WebCore::SimpleLineLayout::FlowContentsIterator::characterAt):
+ (WebCore::SimpleLineLayout::FlowContentsIterator::isLineBreak):
+ (WebCore::SimpleLineLayout::FlowContentsIterator::isEnd):
+
2015-01-28 Beth Dakin <[email protected]>
Remove Mountain Lion code from WebCore
Modified: trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj (179283 => 179284)
--- trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj 2015-01-28 21:27:39 UTC (rev 179283)
+++ trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj 2015-01-28 21:37:40 UTC (rev 179284)
@@ -11582,6 +11582,7 @@
<ClCompile Include="..\rendering\SelectionSubtreeRoot.cpp" />
<ClCompile Include="..\rendering\SimpleLineLayout.cpp" />
<ClCompile Include="..\rendering\SimpleLineLayoutFlowContents.cpp" />
+ <ClCompile Include="..\rendering\SimpleLineLayoutFlowContentsIterator.cpp" />
<ClCompile Include="..\rendering\SimpleLineLayoutFunctions.cpp" />
<ClCompile Include="..\rendering\SimpleLineLayoutResolver.cpp" />
<ClCompile Include="..\rendering\TextPaintStyle.cpp" />
Modified: trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters (179283 => 179284)
--- trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters 2015-01-28 21:27:39 UTC (rev 179283)
+++ trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters 2015-01-28 21:37:40 UTC (rev 179284)
@@ -6775,6 +6775,9 @@
<ClCompile Include="..\rendering\SimpleLineLayoutFlowContents.cpp">
<Filter>rendering</Filter>
</ClCompile>
+ <ClCompile Include="..\rendering\SimpleLineLayoutFlowContentsIterator.cpp">
+ <Filter>rendering</Filter>
+ </ClCompile>
<ClCompile Include="..\rendering\SimpleLineLayoutFunctions.cpp">
<Filter>rendering</Filter>
</ClCompile>
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (179283 => 179284)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2015-01-28 21:27:39 UTC (rev 179283)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2015-01-28 21:37:40 UTC (rev 179284)
@@ -2096,6 +2096,8 @@
580371611A66F00A00BAF519 /* ClipRect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5803715F1A66F00A00BAF519 /* ClipRect.cpp */; };
580371621A66F00A00BAF519 /* ClipRect.h in Headers */ = {isa = PBXBuildFile; fileRef = 580371601A66F00A00BAF519 /* ClipRect.h */; settings = {ATTRIBUTES = (Private, ); }; };
580371641A66F1D300BAF519 /* LayerFragment.h in Headers */ = {isa = PBXBuildFile; fileRef = 580371631A66F1D300BAF519 /* LayerFragment.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 582CB0531A78A14B00AFFCC4 /* SimpleLineLayoutFlowContentsIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 582CB0521A78A14B00AFFCC4 /* SimpleLineLayoutFlowContentsIterator.h */; };
+ 582CB0551A78A2B200AFFCC4 /* SimpleLineLayoutFlowContentsIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 582CB0541A78A2B200AFFCC4 /* SimpleLineLayoutFlowContentsIterator.cpp */; };
585D6DFC1A15355600FA4F12 /* SimpleLineLayoutResolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 585D6DFB1A15355600FA4F12 /* SimpleLineLayoutResolver.cpp */; };
585D6E031A1A792E00FA4F12 /* SimpleLineLayoutFlowContents.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 585D6E011A1A792E00FA4F12 /* SimpleLineLayoutFlowContents.cpp */; };
585D6E041A1A792E00FA4F12 /* SimpleLineLayoutFlowContents.h in Headers */ = {isa = PBXBuildFile; fileRef = 585D6E021A1A792E00FA4F12 /* SimpleLineLayoutFlowContents.h */; };
@@ -9232,6 +9234,8 @@
5803715F1A66F00A00BAF519 /* ClipRect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClipRect.cpp; sourceTree = "<group>"; };
580371601A66F00A00BAF519 /* ClipRect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClipRect.h; sourceTree = "<group>"; };
580371631A66F1D300BAF519 /* LayerFragment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LayerFragment.h; sourceTree = "<group>"; };
+ 582CB0521A78A14B00AFFCC4 /* SimpleLineLayoutFlowContentsIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleLineLayoutFlowContentsIterator.h; sourceTree = "<group>"; };
+ 582CB0541A78A2B200AFFCC4 /* SimpleLineLayoutFlowContentsIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleLineLayoutFlowContentsIterator.cpp; sourceTree = "<group>"; };
585D6DFB1A15355600FA4F12 /* SimpleLineLayoutResolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleLineLayoutResolver.cpp; sourceTree = "<group>"; };
585D6E011A1A792E00FA4F12 /* SimpleLineLayoutFlowContents.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleLineLayoutFlowContents.cpp; sourceTree = "<group>"; };
585D6E021A1A792E00FA4F12 /* SimpleLineLayoutFlowContents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleLineLayoutFlowContents.h; sourceTree = "<group>"; };
@@ -22604,6 +22608,8 @@
E4C91A0D1802343100A17F6D /* TextPaintStyle.h */,
37FC96DA1104ED71003E1FAD /* TrailingFloatsRootInlineBox.h */,
BCA257141293C010007A263D /* VerticalPositionCache.h */,
+ 582CB0521A78A14B00AFFCC4 /* SimpleLineLayoutFlowContentsIterator.h */,
+ 582CB0541A78A2B200AFFCC4 /* SimpleLineLayoutFlowContentsIterator.cpp */,
);
path = rendering;
sourceTree = "<group>";
@@ -23543,6 +23549,7 @@
379E61CC126CA5C400B63E8D /* BaseCheckableInputType.h in Headers */,
F5E0C65C1643C42C00D6CB69 /* BaseChooserOnlyDateAndTimeInputType.h in Headers */,
C33EE5C514FB49610002095A /* BaseClickableWithKeyInputType.h in Headers */,
+ 582CB0531A78A14B00AFFCC4 /* SimpleLineLayoutFlowContentsIterator.h in Headers */,
F59C96001255B23F000623C0 /* BaseDateAndTimeInputType.h in Headers */,
F55B3DAE1251F12D003EF269 /* BaseTextInputType.h in Headers */,
FBD6AF8A15EF25DF008B7110 /* BasicShapeFunctions.h in Headers */,
@@ -29506,6 +29513,7 @@
BC2441C40E8B65D00055320F /* ScrollView.cpp in Sources */,
E45390450EAFD637003695C8 /* ScrollViewIOS.mm in Sources */,
9353676B09AED88B00D35CD6 /* ScrollViewMac.mm in Sources */,
+ 582CB0551A78A2B200AFFCC4 /* SimpleLineLayoutFlowContentsIterator.cpp in Sources */,
F55B3DD11251F12D003EF269 /* SearchInputType.cpp in Sources */,
976F36EA14686225005E93B4 /* SecurityContext.cpp in Sources */,
BCD0E0FA0E972C3500265DEA /* SecurityOrigin.cpp in Sources */,
Modified: trunk/Source/WebCore/rendering/SimpleLineLayout.cpp (179283 => 179284)
--- trunk/Source/WebCore/rendering/SimpleLineLayout.cpp 2015-01-28 21:27:39 UTC (rev 179283)
+++ trunk/Source/WebCore/rendering/SimpleLineLayout.cpp 2015-01-28 21:37:40 UTC (rev 179284)
@@ -44,6 +44,7 @@
#include "RenderView.h"
#include "Settings.h"
#include "SimpleLineLayoutFlowContents.h"
+#include "SimpleLineLayoutFlowContentsIterator.h"
#include "SimpleLineLayoutFunctions.h"
#include "Text.h"
#include "TextPaintStyle.h"
@@ -247,7 +248,7 @@
m_newUncommittedSegment = true;
}
- void addUncommitted(const FlowContents::TextFragment& fragment)
+ void addUncommitted(const FlowContentsIterator::TextFragment& fragment)
{
// Start a new uncommitted segment.
if (m_newUncommittedSegment) {
@@ -256,13 +257,13 @@
}
uncommittedWidth += fragment.width;
uncommittedEnd = fragment.end;
- uncomittedTrailingWhitespaceWidth = fragment.type == FlowContents::TextFragment::Whitespace ? fragment.width : 0;
- uncomittedTrailingWhitespaceLength = fragment.type == FlowContents::TextFragment::Whitespace ? fragment.end - fragment.start : 0;
+ uncomittedTrailingWhitespaceWidth = fragment.type == FlowContentsIterator::TextFragment::Whitespace ? fragment.width : 0;
+ uncomittedTrailingWhitespaceLength = fragment.type == FlowContentsIterator::TextFragment::Whitespace ? fragment.end - fragment.start : 0;
}
void addUncommittedWhitespace(float whitespaceWidth)
{
- addUncommitted(FlowContents::TextFragment(uncommittedEnd, uncommittedEnd + 1, whitespaceWidth, true));
+ addUncommitted(FlowContentsIterator::TextFragment(uncommittedEnd, uncommittedEnd + 1, whitespaceWidth, true));
}
bool hasWhitespaceOnly() const
@@ -301,25 +302,25 @@
bool m_firstCharacterFits { false };
bool m_newUncommittedSegment { true };
- FlowContents::TextFragment overflowedFragment;
+ FlowContentsIterator::TextFragment overflowedFragment;
private:
float uncomittedTrailingWhitespaceWidth { 0 };
unsigned uncomittedTrailingWhitespaceLength { 0 };
};
-static bool preWrap(const FlowContents::Style& style)
+static bool preWrap(const FlowContentsIterator::Style& style)
{
return style.wrapLines && !style.collapseWhitespace;
}
-static void removeTrailingWhitespace(LineState& lineState, Layout::RunVector& lineRuns, const FlowContents& flowContents)
+static void removeTrailingWhitespace(LineState& lineState, Layout::RunVector& lineRuns, const FlowContentsIterator& flowContentsIterator)
{
if (!lineState.committedTrailingWhitespaceLength)
return;
// Remove collapsed whitespace, or non-collapsed pre-wrap whitespace, unless it's the only content on the line -so removing the whitesapce would produce an empty line.
- const auto& style = flowContents.style();
+ const auto& style = flowContentsIterator.style();
bool collapseWhitespace = style.collapseWhitespace | preWrap(style);
if (!collapseWhitespace)
return;
@@ -345,14 +346,14 @@
availableWidth = std::max<float>(0, logicalRightOffset - logicalLeftOffset);
}
-static FlowContents::TextFragment splitFragmentToFitLine(FlowContents::TextFragment& fragmentToSplit, float availableWidth, bool keepAtLeastOneCharacter, const FlowContents& flowContents)
+static FlowContentsIterator::TextFragment splitFragmentToFitLine(FlowContentsIterator::TextFragment& fragmentToSplit, float availableWidth, bool keepAtLeastOneCharacter, const FlowContentsIterator& flowContentsIterator)
{
// Fast path for single char fragments.
if (fragmentToSplit.start + 1 == fragmentToSplit.end) {
if (keepAtLeastOneCharacter)
- return FlowContents::TextFragment();
+ return FlowContentsIterator::TextFragment();
- FlowContents::TextFragment fragmentForNextLine(fragmentToSplit);
+ FlowContentsIterator::TextFragment fragmentForNextLine(fragmentToSplit);
fragmentToSplit.end = fragmentToSplit.start;
fragmentToSplit.width = 0;
return fragmentForNextLine;
@@ -364,7 +365,7 @@
float width = 0;
while (left < right) {
unsigned middle = (left + right) / 2;
- width = flowContents.textWidth(fragmentToSplit.start, middle + 1, 0);
+ width = flowContentsIterator.textWidth(fragmentToSplit.start, middle + 1, 0);
if (availableWidth > width)
left = middle + 1;
else if (availableWidth < width)
@@ -377,48 +378,48 @@
if (keepAtLeastOneCharacter && right == fragmentToSplit.start)
++right;
- FlowContents::TextFragment fragmentForNextLine(fragmentToSplit);
+ FlowContentsIterator::TextFragment fragmentForNextLine(fragmentToSplit);
fragmentToSplit.end = right;
- fragmentToSplit.width = fragmentToSplit.isEmpty() ? 0 : flowContents.textWidth(fragmentToSplit.start, fragmentToSplit.end, 0);
+ fragmentToSplit.width = fragmentToSplit.isEmpty() ? 0 : flowContentsIterator.textWidth(fragmentToSplit.start, fragmentToSplit.end, 0);
fragmentForNextLine.start = fragmentToSplit.end;
fragmentForNextLine.width -= fragmentToSplit.width;
return fragmentForNextLine;
}
-static FlowContents::TextFragment firstFragment(FlowContents& flowContents, const LineState& previousLine)
+static FlowContentsIterator::TextFragment firstFragment(FlowContentsIterator& flowContentsIterator, const LineState& previousLine)
{
// Handle overflowed fragment from previous line.
- FlowContents::TextFragment firstFragment = previousLine.overflowedFragment;
- const auto& style = flowContents.style();
+ FlowContentsIterator::TextFragment firstFragment = previousLine.overflowedFragment;
+ const auto& style = flowContentsIterator.style();
if (firstFragment.isEmpty())
- firstFragment = flowContents.nextTextFragment();
+ firstFragment = flowContentsIterator.nextTextFragment();
else {
// Special overflow pre-wrap whitespace handling: ignore the overflowed whitespace if we managed to fit at least one character on the previous line.
// When the line is too short to fit one character (thought it still stays on the line) we continue with the overflow whitespace content on this line.
- if (firstFragment.type == FlowContents::TextFragment::Whitespace && preWrap(style) && previousLine.m_firstCharacterFits) {
- firstFragment = flowContents.nextTextFragment();
+ if (firstFragment.type == FlowContentsIterator::TextFragment::Whitespace && preWrap(style) && previousLine.m_firstCharacterFits) {
+ firstFragment = flowContentsIterator.nextTextFragment();
// If skipping the whitespace puts us on a hard newline, skip the newline too as we already wrapped the line.
- if (firstFragment.type == FlowContents::TextFragment::LineBreak)
- firstFragment = flowContents.nextTextFragment();
+ if (firstFragment.type == FlowContentsIterator::TextFragment::LineBreak)
+ firstFragment = flowContentsIterator.nextTextFragment();
}
}
// Check if we need to skip the leading whitespace.
- if (style.collapseWhitespace && firstFragment.type == FlowContents::TextFragment::Whitespace)
- firstFragment = flowContents.nextTextFragment();
+ if (style.collapseWhitespace && firstFragment.type == FlowContentsIterator::TextFragment::Whitespace)
+ firstFragment = flowContentsIterator.nextTextFragment();
return firstFragment;
}
-static bool createLineRuns(LineState& line, const LineState& previousLine, Layout::RunVector& lineRuns, FlowContents& flowContents)
+static bool createLineRuns(LineState& line, const LineState& previousLine, Layout::RunVector& lineRuns, FlowContentsIterator& flowContentsIterator)
{
- const auto& style = flowContents.style();
+ const auto& style = flowContentsIterator.style();
bool lineCanBeWrapped = style.wrapLines || style.breakWordOnOverflow;
- auto fragment = firstFragment(flowContents, previousLine);
+ auto fragment = firstFragment(flowContentsIterator, previousLine);
while (!fragment.isEmpty()) {
// Hard linebreak.
- if (fragment.type == FlowContents::TextFragment::LineBreak) {
+ if (fragment.type == FlowContentsIterator::TextFragment::LineBreak) {
// Add the new line fragment only if there's nothing on the line. (otherwise the extra new line character would show up at the end of the content.)
if (!line.width())
line.addUncommitted(fragment);
@@ -432,10 +433,10 @@
// 4. Non-whitespace fragment when there's already another fragment on the line gets pushed to the next line.
bool emptyLine = !line.width();
// Whitespace fragment.
- if (fragment.type == FlowContents::TextFragment::Whitespace) {
+ if (fragment.type == FlowContentsIterator::TextFragment::Whitespace) {
if (!style.collapseWhitespace) {
// Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
- line.overflowedFragment = splitFragmentToFitLine(fragment, line.availableWidth - line.width(), emptyLine, flowContents);
+ line.overflowedFragment = splitFragmentToFitLine(fragment, line.availableWidth - line.width(), emptyLine, flowContentsIterator);
line.addUncommitted(fragment);
}
// When whitespace collapse is on, whitespace that doesn't fit is simply skipped.
@@ -444,7 +445,7 @@
// Non-whitespace fragment. (!style.wrapLines: bug138102(preserve existing behavior)
if ((emptyLine && style.breakWordOnOverflow) || !style.wrapLines) {
// Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
- line.overflowedFragment = splitFragmentToFitLine(fragment, line.availableWidth - line.width(), emptyLine, flowContents);
+ line.overflowedFragment = splitFragmentToFitLine(fragment, line.availableWidth - line.width(), emptyLine, flowContentsIterator);
line.addUncommitted(fragment);
break;
}
@@ -465,22 +466,22 @@
} else
line.addUncommitted(fragment);
// Find the next text fragment.
- fragment = flowContents.nextTextFragment(line.width());
+ fragment = flowContentsIterator.nextTextFragment(line.width());
}
line.commitAndCreateRun(lineRuns);
return fragment.isEmpty() && line.overflowedFragment.isEmpty();
}
-static void closeLineEndingAndAdjustRuns(LineState& line, Layout::RunVector& runs, unsigned previousRunCount, unsigned& lineCount, const FlowContents& flowContents)
+static void closeLineEndingAndAdjustRuns(LineState& line, Layout::RunVector& runs, unsigned previousRunCount, unsigned& lineCount, const FlowContentsIterator& flowContentsIterator)
{
if (previousRunCount == runs.size())
return;
ASSERT(runs.size());
- removeTrailingWhitespace(line, runs, flowContents);
+ removeTrailingWhitespace(line, runs, flowContentsIterator);
if (!runs.size())
return;
// Adjust runs' position by taking line's alignment into account.
- if (float lineLogicalLeft = computeLineLeft(flowContents.style().textAlign, line.availableWidth, line.committedWidth, line.logicalLeftOffset)) {
+ if (float lineLogicalLeft = computeLineLeft(flowContentsIterator.style().textAlign, line.availableWidth, line.committedWidth, line.logicalLeftOffset)) {
for (unsigned i = previousRunCount; i < runs.size(); ++i) {
runs[i].logicalLeft += lineLogicalLeft;
runs[i].logicalRight += lineLogicalLeft;
@@ -490,24 +491,21 @@
++lineCount;
}
-static void splitRunsAtRendererBoundary(Layout::RunVector& lineRuns, const FlowContents& flowContents)
+static void splitRunsAtRendererBoundary(Layout::RunVector& lineRuns, const FlowContentsIterator& flowContentsIterator)
{
// FIXME: We should probably split during run construction instead of as a separate pass.
if (lineRuns.isEmpty())
return;
- if (flowContents.hasOneSegment())
- return;
-
unsigned runIndex = 0;
do {
const Run& run = lineRuns.at(runIndex);
ASSERT(run.start != run.end);
- auto& startSegment = flowContents.segmentForPosition(run.start);
+ auto& startSegment = flowContentsIterator.segmentForPosition(run.start);
if (run.end <= startSegment.end)
continue;
// This run overlaps multiple renderers. Split it up.
// Split run at the renderer's boundary and create a new run for the left side, while use the current run as the right side.
- float logicalRightOfLeftRun = run.logicalLeft + flowContents.textWidth(run.start, startSegment.end, run.logicalLeft);
+ float logicalRightOfLeftRun = run.logicalLeft + flowContentsIterator.textWidth(run.start, startSegment.end, run.logicalLeft);
lineRuns.insert(runIndex, Run(run.start, startSegment.end, run.logicalLeft, logicalRightOfLeftRun, false));
Run& rightSideRun = lineRuns.at(runIndex + 1);
rightSideRun.start = startSegment.end;
@@ -521,7 +519,7 @@
LayoutUnit lineHeight = lineHeightFromFlow(flow);
LineState line;
bool isEndOfContent = false;
- FlowContents flowContents = FlowContents(flow);
+ FlowContentsIterator flowContentsIterator = FlowContentsIterator(flow);
do {
flow.setLogicalHeight(lineHeight * lineCount + borderAndPaddingBefore);
@@ -529,11 +527,12 @@
unsigned previousRunCount = runs.size();
line = LineState();
updateLineConstrains(flow, line.availableWidth, line.logicalLeftOffset);
- isEndOfContent = createLineRuns(line, previousLine, runs, flowContents);
- closeLineEndingAndAdjustRuns(line, runs, previousRunCount, lineCount, flowContents);
+ isEndOfContent = createLineRuns(line, previousLine, runs, flowContentsIterator);
+ closeLineEndingAndAdjustRuns(line, runs, previousRunCount, lineCount, flowContentsIterator);
} while (!isEndOfContent);
- splitRunsAtRendererBoundary(runs, flowContents);
+ if (flow.firstChild() != flow.lastChild())
+ splitRunsAtRendererBoundary(runs, flowContentsIterator);
ASSERT(!line.uncommittedWidth);
}
Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp (179283 => 179284)
--- trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp 2015-01-28 21:27:39 UTC (rev 179283)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp 2015-01-28 21:37:40 UTC (rev 179284)
@@ -33,19 +33,6 @@
namespace WebCore {
namespace SimpleLineLayout {
-FlowContents::Style::Style(const RenderStyle& style)
- : font(style.fontCascade())
- , textAlign(style.textAlign())
- , collapseWhitespace(style.collapseWhiteSpace())
- , preserveNewline(style.preserveNewline())
- , wrapLines(style.autoWrap())
- , breakWordOnOverflow(style.overflowWrap() == BreakOverflowWrap && (wrapLines || preserveNewline))
- , spaceWidth(font.width(TextRun(&space, 1)))
- , tabWidth(collapseWhitespace ? 0 : style.tabSize())
- , locale(style.locale())
-{
-}
-
static Vector<FlowContents::Segment> initializeSegments(const RenderBlockFlow& flow)
{
Vector<FlowContents::Segment, 8> segments;
@@ -59,141 +46,11 @@
}
FlowContents::FlowContents(const RenderBlockFlow& flow)
- : m_style(flow.style())
- , m_segments(initializeSegments(flow))
- , m_lineBreakIterator(m_segments[0].text, flow.style().locale())
+ : m_segments(initializeSegments(flow))
, m_lastSegmentIndex(0)
{
}
-FlowContents::TextFragment FlowContents::nextTextFragment(float xPosition)
-{
- // A fragment can either be
- // 1. new line character when preserveNewline is on (not considered as whitespace) or
- // 2. whitespace (collasped, non-collapsed multi or single) or
- // 3. non-whitespace characters.
- // 4. empty, indicating content end.
- TextFragment fragment;
- fragment.start = m_position;
- if (isEnd(fragment.start)) {
- fragment.end = fragment.start;
- return fragment;
- }
- if (isLineBreak(fragment.start)) {
- fragment.type = TextFragment::LineBreak;
- fragment.end = fragment.start + 1;
- m_position = fragment.end;
- return fragment;
- }
-
- unsigned spaceCount = 0;
- unsigned whitespaceEnd = findNextNonWhitespacePosition(fragment.start, spaceCount);
- ASSERT(fragment.start <= whitespaceEnd);
- if (fragment.start != whitespaceEnd) {
- fragment.type = TextFragment::Whitespace;
- fragment.end = whitespaceEnd;
- bool multipleWhitespace = fragment.start + 1 < fragment.end;
- fragment.isCollapsed = multipleWhitespace && m_style.collapseWhitespace;
- fragment.isBreakable = !fragment.isCollapsed && multipleWhitespace;
- if (fragment.isCollapsed)
- fragment.width = m_style.spaceWidth;
- else {
- unsigned fragmentLength = fragment.end - fragment.start;
- if (fragmentLength == spaceCount)
- fragment.width = fragmentLength * m_style.spaceWidth;
- else
- fragment.width = textWidth(fragment.start, fragment.end, xPosition);
- }
- m_position = fragment.end;
- return fragment;
- }
-
- fragment.type = TextFragment::NonWhitespace;
- fragment.isBreakable = m_style.breakWordOnOverflow;
- fragment.end = findNextBreakablePosition(fragment.start + 1);
- fragment.width = textWidth(fragment.start, fragment.end, xPosition);
- m_position = fragment.end;
- return fragment;
-}
-
-template <typename CharacterType>
-static unsigned nextBreakablePosition(LazyLineBreakIterator& lineBreakIterator, const FlowContents::Segment& segment, unsigned position)
-{
- const auto* characters = segment.text.characters<CharacterType>();
- unsigned segmentLength = segment.end - segment.start;
- unsigned segmentPosition = position - segment.start;
- return nextBreakablePositionNonLoosely<CharacterType, NBSPBehavior::IgnoreNBSP>(lineBreakIterator, characters, segmentLength, segmentPosition);
-}
-
-unsigned FlowContents::findNextBreakablePosition(unsigned position) const
-{
- while (!isEnd(position)) {
- auto& segment = segmentForPosition(position);
- if (segment.text.impl() != m_lineBreakIterator.string().impl()) {
- UChar lastCharacter = segment.start > 0 ? characterAt(segment.start - 1) : 0;
- UChar secondToLastCharacter = segment.start > 1 ? characterAt(segment.start - 2) : 0;
- m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter);
- m_lineBreakIterator.resetStringAndReleaseIterator(segment.text, m_style.locale, LineBreakIteratorModeUAX14);
- }
-
- unsigned breakable = segment.text.is8Bit() ? nextBreakablePosition<LChar>(m_lineBreakIterator, segment, position) : nextBreakablePosition<UChar>(m_lineBreakIterator, segment, position);
- position = segment.start + breakable;
- if (position < segment.end)
- break;
- }
- return position;
-}
-
-template <typename CharacterType>
-static bool findNextNonWhitespace(const FlowContents::Segment& segment, const FlowContents::Style& style, unsigned& position, unsigned& spaceCount)
-{
- const auto* text = segment.text.characters<CharacterType>();
- for (; position < segment.end; ++position) {
- auto character = text[position - segment.start];
- bool isSpace = character == ' ';
- bool isWhitespace = isSpace || character == '\t' || (!style.preserveNewline && character == '\n');
- if (!isWhitespace)
- return true;
- if (isSpace)
- ++spaceCount;
- }
- return false;
-}
-
-unsigned FlowContents::findNextNonWhitespacePosition(unsigned position, unsigned& spaceCount) const
-{
- for (unsigned i = segmentIndexForPosition(position); i < m_segments.size(); ++i) {
- bool foundNonWhitespace = m_segments[i].text.is8Bit() ? findNextNonWhitespace<LChar>(m_segments[i], m_style, position, spaceCount) :
- findNextNonWhitespace<UChar>(m_segments[i], m_style, position, spaceCount);
- if (foundNonWhitespace)
- break;
- }
- return position;
-}
-
-float FlowContents::textWidth(unsigned from, unsigned to, float xPosition) const
-{
- const auto& fromSegment = segmentForPosition(from);
-
- if ((m_style.font.isFixedPitch() && fromSegment.end >= to) || (from == fromSegment.start && to == fromSegment.end))
- return fromSegment.renderer.width(from - fromSegment.start, to - from, m_style.font, xPosition, nullptr, nullptr);
-
- const auto* segment = &fromSegment;
- float textWidth = 0;
- unsigned fragmentEnd = 0;
- while (true) {
- fragmentEnd = std::min(to, segment->end);
- textWidth += segment->text.is8Bit() ? runWidth<LChar>(segment->text, from - segment->start, fragmentEnd - segment->start, xPosition + textWidth) :
- runWidth<UChar>(segment->text, from - segment->start, fragmentEnd - segment->start, xPosition + textWidth);
- if (fragmentEnd == to)
- break;
- from = fragmentEnd;
- segment = &segmentForPosition(fragmentEnd);
- };
-
- return textWidth;
-}
-
unsigned FlowContents::segmentIndexForPositionSlow(unsigned position) const
{
auto it = std::lower_bound(m_segments.begin(), m_segments.end(), position, [](const Segment& segment, unsigned position) {
@@ -215,21 +72,5 @@
return m_segments.last();
}
-template <typename CharacterType>
-float FlowContents::runWidth(const String& text, unsigned from, unsigned to, float xPosition) const
-{
- ASSERT(from < to);
- bool measureWithEndSpace = m_style.collapseWhitespace && to < text.length() && text[to] == ' ';
- if (measureWithEndSpace)
- ++to;
- TextRun run(text.characters<CharacterType>() + from, to - from);
- run.setXPos(xPosition);
- run.setTabSize(!!m_style.tabWidth, m_style.tabWidth);
- float width = m_style.font.width(run);
- if (measureWithEndSpace)
- width -= m_style.spaceWidth;
- return width;
}
-
}
-}
Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h (179283 => 179284)
--- trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h 2015-01-28 21:27:39 UTC (rev 179283)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h 2015-01-28 21:37:40 UTC (rev 179284)
@@ -26,10 +26,7 @@
#ifndef SimpleLineLayoutFlowContents_h
#define SimpleLineLayoutFlowContents_h
-#include "FontCascade.h"
-#include "RenderStyle.h"
-#include "TextBreakIterator.h"
-#include "break_lines.h"
+#include "RenderText.h"
namespace WebCore {
class RenderBlockFlow;
@@ -40,32 +37,6 @@
public:
FlowContents(const RenderBlockFlow&);
- struct TextFragment {
- TextFragment() = default;
- TextFragment(unsigned textStart, unsigned textEnd, float textWidth, bool isWhitespaceOnly)
- : start(textStart)
- , end(textEnd)
- , type(isWhitespaceOnly ? Whitespace : NonWhitespace)
- , width(textWidth)
- {
- }
-
- bool isEmpty() const
- {
- return start == end;
- }
-
- enum Type { LineBreak, Whitespace, NonWhitespace };
- unsigned start = 0;
- unsigned end = 0;
- Type type = NonWhitespace;
- bool isCollapsed = false;
- bool isBreakable = false;
- float width = 0;
- };
- TextFragment nextTextFragment(float xPosition = 0);
- float textWidth(unsigned from, unsigned to, float xPosition) const;
-
struct Segment {
unsigned start;
unsigned end;
@@ -75,64 +46,57 @@
const Segment& segmentForPosition(unsigned) const;
const Segment& segmentForRenderer(const RenderText&) const;
- bool hasOneSegment() const { return m_segments.size() == 1; }
- unsigned length() const { return m_segments.last().end; };
+ class Iterator {
+ public:
+ Iterator(const FlowContents& flowContents, unsigned segmentIndex)
+ : m_flowContents(flowContents)
+ , m_segmentIndex(segmentIndex)
+ {
+ }
- struct Style {
- explicit Style(const RenderStyle&);
+ Iterator& operator++();
+ bool operator==(const Iterator& other) const;
+ bool operator!=(const Iterator& other) const;
+ const Segment& operator*() const { return m_flowContents.m_segments[m_segmentIndex]; }
- const FontCascade& font;
- ETextAlign textAlign;
- bool collapseWhitespace;
- bool preserveNewline;
- bool wrapLines;
- bool breakWordOnOverflow;
- float spaceWidth;
- unsigned tabWidth;
- AtomicString locale;
+ private:
+ const FlowContents& m_flowContents;
+ unsigned m_segmentIndex;
};
- const Style& style() const { return m_style; }
-private:
- unsigned findNextNonWhitespacePosition(unsigned position, unsigned& spaceCount) const;
- unsigned findNextBreakablePosition(unsigned position) const;
- bool isLineBreak(unsigned position) const;
- bool isEnd(unsigned position) const;
+ Iterator begin() const { return Iterator(*this, 0); }
+ Iterator end() const { return Iterator(*this, m_segments.size()); }
+
+ unsigned length() const { return m_segments.last().end; };
+
unsigned segmentIndexForPosition(unsigned position) const;
+
+private:
unsigned segmentIndexForPositionSlow(unsigned position) const;
- UChar characterAt(unsigned position) const;
- template <typename CharacterType> float runWidth(const String&, unsigned from, unsigned to, float xPosition) const;
-
- const Style m_style;
const Vector<Segment, 8> m_segments;
- mutable LazyLineBreakIterator m_lineBreakIterator;
mutable unsigned m_lastSegmentIndex;
- unsigned m_position { 0 };
};
-inline UChar FlowContents::characterAt(unsigned position) const
+inline FlowContents::Iterator& FlowContents::Iterator::operator++()
{
- auto& segment = segmentForPosition(position);
- return segment.text[position - segment.start];
+ ++m_segmentIndex;
+ return *this;
}
-inline bool FlowContents::isLineBreak(unsigned position) const
+inline bool FlowContents::Iterator::operator==(const FlowContents::Iterator& other) const
{
- if (isEnd(position))
- return false;
- return m_style.preserveNewline && characterAt(position) == '\n';
+ return m_segmentIndex == other.m_segmentIndex;
}
-inline bool FlowContents::isEnd(unsigned position) const
+inline bool FlowContents::Iterator::operator!=(const FlowContents::Iterator& other) const
{
- return position >= length();
+ return !(*this == other);
}
inline unsigned FlowContents::segmentIndexForPosition(unsigned position) const
{
- ASSERT(!isEnd(position));
auto& lastSegment = m_segments[m_lastSegmentIndex];
if (lastSegment.start <= position && position < lastSegment.end)
return m_lastSegmentIndex;
Copied: trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContentsIterator.cpp (from rev 179283, trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp) (0 => 179284)
--- trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContentsIterator.cpp (rev 0)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContentsIterator.cpp 2015-01-28 21:37:40 UTC (rev 179284)
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2015 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 "SimpleLineLayoutFlowContentsIterator.h"
+
+#include "RenderBlockFlow.h"
+#include "RenderChildIterator.h"
+#include "RenderText.h"
+#include "SimpleLineLayoutFlowContents.h"
+
+namespace WebCore {
+namespace SimpleLineLayout {
+
+FlowContentsIterator::Style::Style(const RenderStyle& style)
+ : font(style.fontCascade())
+ , textAlign(style.textAlign())
+ , collapseWhitespace(style.collapseWhiteSpace())
+ , preserveNewline(style.preserveNewline())
+ , wrapLines(style.autoWrap())
+ , breakWordOnOverflow(style.overflowWrap() == BreakOverflowWrap && (wrapLines || preserveNewline))
+ , spaceWidth(font.width(TextRun(&space, 1)))
+ , tabWidth(collapseWhitespace ? 0 : style.tabSize())
+ , locale(style.locale())
+{
+}
+
+FlowContentsIterator::FlowContentsIterator(const RenderBlockFlow& flow)
+ : m_flowContents(flow)
+ , m_lineBreakIterator((*m_flowContents.begin()).text, flow.style().locale())
+ , m_style(flow.style())
+{
+}
+
+FlowContentsIterator::TextFragment FlowContentsIterator::nextTextFragment(float xPosition)
+{
+ // A fragment can either be
+ // 1. new line character when preserveNewline is on (not considered as whitespace) or
+ // 2. whitespace (collasped, non-collapsed multi or single) or
+ // 3. non-whitespace characters.
+ // 4. empty, indicating content end.
+ TextFragment fragment;
+ fragment.start = m_position;
+ if (isEnd(fragment.start)) {
+ fragment.end = fragment.start;
+ return fragment;
+ }
+ if (isLineBreak(fragment.start)) {
+ fragment.type = TextFragment::LineBreak;
+ fragment.end = fragment.start + 1;
+ m_position = fragment.end;
+ return fragment;
+ }
+
+ unsigned spaceCount = 0;
+ unsigned whitespaceEnd = findNextNonWhitespacePosition(fragment.start, spaceCount);
+ ASSERT(fragment.start <= whitespaceEnd);
+ if (fragment.start != whitespaceEnd) {
+ fragment.type = TextFragment::Whitespace;
+ fragment.end = whitespaceEnd;
+ bool multipleWhitespace = fragment.start + 1 < fragment.end;
+ fragment.isCollapsed = multipleWhitespace && m_style.collapseWhitespace;
+ fragment.isBreakable = !fragment.isCollapsed && multipleWhitespace;
+ if (fragment.isCollapsed)
+ fragment.width = m_style.spaceWidth;
+ else {
+ unsigned fragmentLength = fragment.end - fragment.start;
+ if (fragmentLength == spaceCount)
+ fragment.width = fragmentLength * m_style.spaceWidth;
+ else
+ fragment.width = textWidth(fragment.start, fragment.end, xPosition);
+ }
+ m_position = fragment.end;
+ return fragment;
+ }
+
+ fragment.type = TextFragment::NonWhitespace;
+ fragment.isBreakable = m_style.breakWordOnOverflow;
+ fragment.end = findNextBreakablePosition(fragment.start + 1);
+ fragment.width = textWidth(fragment.start, fragment.end, xPosition);
+ m_position = fragment.end;
+ return fragment;
+}
+
+float FlowContentsIterator::textWidth(unsigned from, unsigned to, float xPosition) const
+{
+ const auto& fromSegment = m_flowContents.segmentForPosition(from);
+ if ((m_style.font.isFixedPitch() && fromSegment.end >= to) || (from == fromSegment.start && to == fromSegment.end))
+ return fromSegment.renderer.width(from - fromSegment.start, to - from, m_style.font, xPosition, nullptr, nullptr);
+
+ const auto* segment = &fromSegment;
+ float textWidth = 0;
+ unsigned fragmentEnd = 0;
+ while (true) {
+ fragmentEnd = std::min(to, segment->end);
+ textWidth += segment->text.is8Bit() ? runWidth<LChar>(segment->text, from - segment->start, fragmentEnd - segment->start, xPosition + textWidth) :
+ runWidth<UChar>(segment->text, from - segment->start, fragmentEnd - segment->start, xPosition + textWidth);
+ if (fragmentEnd == to)
+ break;
+ from = fragmentEnd;
+ segment = &m_flowContents.segmentForPosition(fragmentEnd);
+ };
+
+ return textWidth;
+}
+
+template <typename CharacterType>
+static unsigned nextBreakablePosition(LazyLineBreakIterator& lineBreakIterator, const FlowContents::Segment& segment, unsigned position)
+{
+ const auto* characters = segment.text.characters<CharacterType>();
+ unsigned segmentLength = segment.end - segment.start;
+ unsigned segmentPosition = position - segment.start;
+ return nextBreakablePositionNonLoosely<CharacterType, NBSPBehavior::IgnoreNBSP>(lineBreakIterator, characters, segmentLength, segmentPosition);
+}
+
+unsigned FlowContentsIterator::findNextBreakablePosition(unsigned position) const
+{
+ while (!isEnd(position)) {
+ auto& segment = m_flowContents.segmentForPosition(position);
+ if (segment.text.impl() != m_lineBreakIterator.string().impl()) {
+ UChar lastCharacter = segment.start > 0 ? characterAt(segment.start - 1) : 0;
+ UChar secondToLastCharacter = segment.start > 1 ? characterAt(segment.start - 2) : 0;
+ m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter);
+ m_lineBreakIterator.resetStringAndReleaseIterator(segment.text, m_style.locale, LineBreakIteratorModeUAX14);
+ }
+
+ unsigned breakable = segment.text.is8Bit() ? nextBreakablePosition<LChar>(m_lineBreakIterator, segment, position) : nextBreakablePosition<UChar>(m_lineBreakIterator, segment, position);
+ position = segment.start + breakable;
+ if (position < segment.end)
+ break;
+ }
+ return position;
+}
+
+template <typename CharacterType>
+static bool findNextNonWhitespace(const FlowContents::Segment& segment, const FlowContentsIterator::Style& style, unsigned& position, unsigned& spaceCount)
+{
+ const auto* text = segment.text.characters<CharacterType>();
+ for (; position < segment.end; ++position) {
+ auto character = text[position - segment.start];
+ bool isSpace = character == ' ';
+ bool isWhitespace = isSpace || character == '\t' || (!style.preserveNewline && character == '\n');
+ if (!isWhitespace)
+ return true;
+ if (isSpace)
+ ++spaceCount;
+ }
+ return false;
+}
+
+unsigned FlowContentsIterator::findNextNonWhitespacePosition(unsigned position, unsigned& spaceCount) const
+{
+ FlowContents::Iterator it(m_flowContents, m_flowContents.segmentIndexForPosition(position));
+ for (auto end = m_flowContents.end(); it != end; ++it) {
+ bool foundNonWhitespace = (*it).text.is8Bit() ? findNextNonWhitespace<LChar>(*it, m_style, position, spaceCount) : findNextNonWhitespace<UChar>(*it, m_style, position, spaceCount);
+ if (foundNonWhitespace)
+ break;
+ }
+ return position;
+}
+
+template <typename CharacterType>
+float FlowContentsIterator::runWidth(const String& text, unsigned from, unsigned to, float xPosition) const
+{
+ ASSERT(from < to);
+ bool measureWithEndSpace = m_style.collapseWhitespace && to < text.length() && text[to] == ' ';
+ if (measureWithEndSpace)
+ ++to;
+ TextRun run(text.characters<CharacterType>() + from, to - from);
+ run.setXPos(xPosition);
+ run.setTabSize(!!m_style.tabWidth, m_style.tabWidth);
+ float width = m_style.font.width(run);
+ if (measureWithEndSpace)
+ width -= m_style.spaceWidth;
+ return width;
+}
+
+}
+}
Copied: trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContentsIterator.h (from rev 179283, trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h) (0 => 179284)
--- trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContentsIterator.h (rev 0)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContentsIterator.h 2015-01-28 21:37:40 UTC (rev 179284)
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef SimpleLineLayoutFlowContentsIterator_h
+#define SimpleLineLayoutFlowContentsIterator_h
+
+#include "RenderStyle.h"
+#include "SimpleLineLayoutFlowContents.h"
+#include "TextBreakIterator.h"
+#include "break_lines.h"
+
+namespace WebCore {
+class RenderBlockFlow;
+
+namespace SimpleLineLayout {
+
+class FlowContentsIterator {
+public:
+ FlowContentsIterator(const RenderBlockFlow&);
+
+ struct TextFragment {
+ TextFragment() = default;
+ TextFragment(unsigned textStart, unsigned textEnd, float textWidth, bool isWhitespaceOnly)
+ : start(textStart)
+ , end(textEnd)
+ , type(isWhitespaceOnly ? Whitespace : NonWhitespace)
+ , width(textWidth)
+ {
+ }
+
+ bool isEmpty() const
+ {
+ return start == end;
+ }
+
+ enum Type { LineBreak, Whitespace, NonWhitespace };
+ unsigned start { 0 };
+ unsigned end {0 };
+ Type type { NonWhitespace };
+ bool isCollapsed { false };
+ bool isBreakable { false };
+ float width { 0 };
+ };
+ TextFragment nextTextFragment(float xPosition = 0);
+ float textWidth(unsigned from, unsigned to, float xPosition) const;
+
+ struct Style {
+ explicit Style(const RenderStyle&);
+
+ const FontCascade& font;
+ ETextAlign textAlign;
+ bool collapseWhitespace;
+ bool preserveNewline;
+ bool wrapLines;
+ bool breakWordOnOverflow;
+ float spaceWidth;
+ unsigned tabWidth;
+ AtomicString locale;
+ };
+ const Style& style() const { return m_style; }
+ // FIXME: remove splitRunsAtRendererBoundary()
+ const FlowContents::Segment& segmentForPosition(unsigned position) const { return m_flowContents.segmentForPosition(position); };
+
+private:
+ unsigned findNextNonWhitespacePosition(unsigned position, unsigned& spaceCount) const;
+ unsigned findNextBreakablePosition(unsigned position) const;
+ UChar characterAt(unsigned position) const;
+ bool isLineBreak(unsigned position) const;
+ bool isEnd(unsigned position) const;
+ template <typename CharacterType> float runWidth(const String&, unsigned from, unsigned to, float xPosition) const;
+
+ FlowContents m_flowContents;
+ mutable LazyLineBreakIterator m_lineBreakIterator;
+ const Style m_style;
+ unsigned m_position { 0 };
+};
+
+inline UChar FlowContentsIterator::characterAt(unsigned position) const
+{
+ auto& segment = m_flowContents.segmentForPosition(position);
+ return segment.text[position - segment.start];
+}
+
+inline bool FlowContentsIterator::isLineBreak(unsigned position) const
+{
+ if (isEnd(position))
+ return false;
+ return m_style.preserveNewline && characterAt(position) == '\n';
+}
+
+inline bool FlowContentsIterator::isEnd(unsigned position) const
+{
+ return position >= m_flowContents.length();
+}
+
+}
+}
+
+#endif