Diff
Modified: trunk/LayoutTests/ChangeLog (176395 => 176396)
--- trunk/LayoutTests/ChangeLog 2014-11-20 15:20:37 UTC (rev 176395)
+++ trunk/LayoutTests/ChangeLog 2014-11-20 15:22:02 UTC (rev 176396)
@@ -1,3 +1,19 @@
+2014-11-20 Zalan Bujtas <[email protected]>
+
+ Simple line layout: Introduce text fragment continuation.
+ https://bugs.webkit.org/show_bug.cgi?id=138274
+
+ Rebaseline for simple line layout's multiple rendere support.
+
+ Reviewed by Antti Koivisto.
+
+ * fast/text/simple-lines-multiple-renderers-expected.html: Added.
+ * fast/text/simple-lines-multiple-renderers.html: Added.
+ * fast/tokenizer/script_extra_close-expected.txt: Multiple tab characters should collapse into a single whitespace. This
+ needs fixing in complex line layout.
+ * tables/mozilla/bugs/bug157890-expected.txt: no-op endofline run is added by complex inline layout
+ when multiple text content is injected through JS into a <pre>. This requires fixing complex line layout.
+
2014-11-19 Myles C. Maxfield <[email protected]>
[OS X] Upright vertical text is completely broken for multi-code-unit codepoints
Added: trunk/LayoutTests/fast/text/simple-lines-multiple-renderers-expected.html (0 => 176396)
--- trunk/LayoutTests/fast/text/simple-lines-multiple-renderers-expected.html (rev 0)
+++ trunk/LayoutTests/fast/text/simple-lines-multiple-renderers-expected.html 2014-11-20 15:22:02 UTC (rev 176396)
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>This tests that simple line layout is applied on multiple sibling text renderers.</title>
+<script>
+ if (window.internals)
+ internals.settings.setSimpleLineLayoutDebugBordersEnabled(true);
+</script>
+</head>
+<body>
+<div id=container>
+</div>
+<script>
+ var container = document.getElementById("container");
+ container.appendChild(document.createTextNode("Quo usque tandem abutere, Catilina, patientia nostra? quam diu etiam\n"));
+ container.appendChild(document.createTextNode("furor iste tuus nos eludet? quem ad finem sese effrenata iactabit\n"));
+ container.appendChild(document.createTextNode("audacia? Nihilne te nocturnum praesidium Palati, nihil urbis vigiliae,\n"));
+ container.appendChild(document.createTextNode("nihil timor populi, nihil concursus bonorum omnium, nihil hic munitissimus\n"));
+ container.appendChild(document.createTextNode("habendi senatus locus, nihil horum ora voltusque moverunt? Patere tua\n"));
+ container.appendChild(document.createTextNode("consilia non sentis, constrictam iam horum omnium scientia teneri\n"));
+ container.appendChild(document.createTextNode("coniurationem tuam non vides? Quid proxima, quid superiore nocte egeris,\n"));
+ container.appendChild(document.createTextNode("ubi fueris, quos convocaveris, quid consilii ceperis, quem nostrum\n"));
+ container.appendChild(document.createTextNode("ignorare arbitraris? O tempora, o mores!\n"));
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/fast/text/simple-lines-multiple-renderers.html (0 => 176396)
--- trunk/LayoutTests/fast/text/simple-lines-multiple-renderers.html (rev 0)
+++ trunk/LayoutTests/fast/text/simple-lines-multiple-renderers.html 2014-11-20 15:22:02 UTC (rev 176396)
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>This tests that simple line layout is applied on multiple sibling text renderers.</title>
+<script>
+ if (window.internals)
+ internals.settings.setSimpleLineLayoutDebugBordersEnabled(true);
+</script>
+</head>
+<body>
+<div>
+ Quo usque tandem abutere, Catilina, patientia nostra? quam diu etiam
+ furor iste tuus nos eludet? quem ad finem sese effrenata iactabit
+ audacia? Nihilne te nocturnum praesidium Palati, nihil urbis vigiliae,
+ nihil timor populi, nihil concursus bonorum omnium, nihil hic munitissimus
+ habendi senatus locus, nihil horum ora voltusque moverunt? Patere tua
+ consilia non sentis, constrictam iam horum omnium scientia teneri
+ coniurationem tuam non vides? Quid proxima, quid superiore nocte egeris,
+ ubi fueris, quos convocaveris, quid consilii ceperis, quem nostrum
+ ignorare arbitraris? O tempora, o mores!
+</div>
+</body>
+</html>
Modified: trunk/LayoutTests/fast/tokenizer/script_extra_close-expected.txt (176395 => 176396)
--- trunk/LayoutTests/fast/tokenizer/script_extra_close-expected.txt 2014-11-20 15:20:37 UTC (rev 176395)
+++ trunk/LayoutTests/fast/tokenizer/script_extra_close-expected.txt 2014-11-20 15:22:02 UTC (rev 176396)
@@ -1 +1 @@
-TEST... PASSED. This text should show up.
+TEST... PASSED. This text should show up.
Modified: trunk/LayoutTests/tables/mozilla/bugs/bug157890-expected.txt (176395 => 176396)
--- trunk/LayoutTests/tables/mozilla/bugs/bug157890-expected.txt 2014-11-20 15:20:37 UTC (rev 176395)
+++ trunk/LayoutTests/tables/mozilla/bugs/bug157890-expected.txt 2014-11-20 15:22:02 UTC (rev 176396)
@@ -71,10 +71,8 @@
RenderBlock {PRE} at (0,13) size 784x450
RenderText {#text} at (0,0) size 216x15
text run at (0,0) width 216: "Specified table width: 25px"
- text run at (216,0) width 0: " "
RenderText {#text} at (0,15) size 216x15
text run at (0,15) width 216: "Actual table width: 25px"
- text run at (216,15) width 0: " "
RenderText {#text} at (0,30) size 168x15
text run at (0,30) width 168: "Specified TD widths: "
RenderText {#text} at (168,30) size 32x15
@@ -111,8 +109,7 @@
text run at (648,30) width 32: "1px "
RenderText {#text} at (680,30) size 32x15
text run at (680,30) width 32: "8px "
- RenderText {#text} at (712,30) size 0x15
- text run at (712,30) width 0: " "
+ RenderText {#text} at (0,0) size 0x0
RenderText {#text} at (0,45) size 168x15
text run at (0,45) width 168: "Actual TD widths: "
RenderText {#text} at (168,45) size 32x15
@@ -149,15 +146,12 @@
text run at (648,45) width 32: "1px "
RenderText {#text} at (680,45) size 32x15
text run at (680,45) width 32: "8px "
- RenderText {#text} at (712,45) size 712x30
- text run at (712,45) width 0: " "
+ RenderText {#text} at (0,60) size 0x15
text run at (0,60) width 0: " "
RenderText {#text} at (0,75) size 216x15
text run at (0,75) width 216: "Specified table width: 12px"
- text run at (216,75) width 0: " "
RenderText {#text} at (0,90) size 216x15
text run at (0,90) width 216: "Actual table width: 12px"
- text run at (216,90) width 0: " "
RenderText {#text} at (0,105) size 168x15
text run at (0,105) width 168: "Specified TD widths: "
RenderText {#text} at (168,105) size 32x15
@@ -170,8 +164,7 @@
text run at (264,105) width 32: "1px "
RenderText {#text} at (296,105) size 32x15
text run at (296,105) width 32: "8px "
- RenderText {#text} at (328,105) size 0x15
- text run at (328,105) width 0: " "
+ RenderText {#text} at (0,0) size 0x0
RenderText {#text} at (0,120) size 168x15
text run at (0,120) width 168: "Actual TD widths: "
RenderText {#text} at (168,120) size 32x15
@@ -184,15 +177,12 @@
text run at (264,120) width 32: "1px "
RenderText {#text} at (296,120) size 32x15
text run at (296,120) width 32: "8px "
- RenderText {#text} at (328,120) size 328x30
- text run at (328,120) width 0: " "
+ RenderText {#text} at (0,135) size 0x15
text run at (0,135) width 0: " "
RenderText {#text} at (0,150) size 216x15
text run at (0,150) width 216: "Specified table width: 13px"
- text run at (216,150) width 0: " "
RenderText {#text} at (0,165) size 216x15
text run at (0,165) width 216: "Actual table width: 13px"
- text run at (216,165) width 0: " "
RenderText {#text} at (0,180) size 168x15
text run at (0,180) width 168: "Specified TD widths: "
RenderText {#text} at (168,180) size 32x15
@@ -205,8 +195,7 @@
text run at (264,180) width 32: "1px "
RenderText {#text} at (296,180) size 32x15
text run at (296,180) width 32: "8px "
- RenderText {#text} at (328,180) size 0x15
- text run at (328,180) width 0: " "
+ RenderText {#text} at (0,0) size 0x0
RenderText {#text} at (0,195) size 168x15
text run at (0,195) width 168: "Actual TD widths: "
RenderText {#text} at (168,195) size 32x15
@@ -219,15 +208,12 @@
text run at (264,195) width 32: "1px "
RenderText {#text} at (296,195) size 32x15
text run at (296,195) width 32: "8px "
- RenderText {#text} at (328,195) size 328x30
- text run at (328,195) width 0: " "
+ RenderText {#text} at (0,210) size 0x15
text run at (0,210) width 0: " "
RenderText {#text} at (0,225) size 216x15
text run at (0,225) width 216: "Specified table width: 24px"
- text run at (216,225) width 0: " "
RenderText {#text} at (0,240) size 216x15
text run at (0,240) width 216: "Actual table width: 24px"
- text run at (216,240) width 0: " "
RenderText {#text} at (0,255) size 168x15
text run at (0,255) width 168: "Specified TD widths: "
RenderText {#text} at (168,255) size 32x15
@@ -240,8 +226,7 @@
text run at (264,255) width 32: "1px "
RenderText {#text} at (296,255) size 32x15
text run at (296,255) width 32: "8px "
- RenderText {#text} at (328,255) size 0x15
- text run at (328,255) width 0: " "
+ RenderText {#text} at (0,0) size 0x0
RenderText {#text} at (0,270) size 168x15
text run at (0,270) width 168: "Actual TD widths: "
RenderText {#text} at (168,270) size 32x15
@@ -254,15 +239,12 @@
text run at (264,270) width 32: "2px "
RenderText {#text} at (296,270) size 40x15
text run at (296,270) width 40: "16px "
- RenderText {#text} at (336,270) size 336x30
- text run at (336,270) width 0: " "
+ RenderText {#text} at (0,285) size 0x15
text run at (0,285) width 0: " "
RenderText {#text} at (0,300) size 216x15
text run at (0,300) width 216: "Specified table width: 25px"
- text run at (216,300) width 0: " "
RenderText {#text} at (0,315) size 216x15
text run at (0,315) width 216: "Actual table width: 25px"
- text run at (216,315) width 0: " "
RenderText {#text} at (0,330) size 168x15
text run at (0,330) width 168: "Specified TD widths: "
RenderText {#text} at (168,330) size 32x15
@@ -275,8 +257,7 @@
text run at (264,330) width 32: "1px "
RenderText {#text} at (296,330) size 32x15
text run at (296,330) width 32: "8px "
- RenderText {#text} at (328,330) size 0x15
- text run at (328,330) width 0: " "
+ RenderText {#text} at (0,0) size 0x0
RenderText {#text} at (0,345) size 168x15
text run at (0,345) width 168: "Actual TD widths: "
RenderText {#text} at (168,345) size 32x15
@@ -289,15 +270,12 @@
text run at (264,345) width 32: "2px "
RenderText {#text} at (296,345) size 40x15
text run at (296,345) width 40: "16px "
- RenderText {#text} at (336,345) size 336x30
- text run at (336,345) width 0: " "
+ RenderText {#text} at (0,360) size 0x15
text run at (0,360) width 0: " "
RenderText {#text} at (0,375) size 216x15
text run at (0,375) width 216: "Specified table width: 17px"
- text run at (216,375) width 0: " "
RenderText {#text} at (0,390) size 216x15
text run at (0,390) width 216: "Actual table width: 17px"
- text run at (216,390) width 0: " "
RenderText {#text} at (0,405) size 168x15
text run at (0,405) width 168: "Specified TD widths: "
RenderText {#text} at (168,405) size 32x15
@@ -320,8 +298,7 @@
text run at (424,405) width 32: "10% "
RenderText {#text} at (456,405) size 32x15
text run at (456,405) width 32: "10% "
- RenderText {#text} at (488,405) size 0x15
- text run at (488,405) width 0: " "
+ RenderText {#text} at (0,0) size 0x0
RenderText {#text} at (0,420) size 168x15
text run at (0,420) width 168: "Actual TD widths: "
RenderText {#text} at (168,420) size 32x15
@@ -344,6 +321,5 @@
text run at (424,420) width 32: "1px "
RenderText {#text} at (456,420) size 32x15
text run at (456,420) width 32: "1px "
- RenderText {#text} at (488,420) size 488x30
- text run at (488,420) width 0: " "
+ RenderText {#text} at (0,435) size 0x15
text run at (0,435) width 0: " "
Modified: trunk/Source/WebCore/ChangeLog (176395 => 176396)
--- trunk/Source/WebCore/ChangeLog 2014-11-20 15:20:37 UTC (rev 176395)
+++ trunk/Source/WebCore/ChangeLog 2014-11-20 15:22:02 UTC (rev 176396)
@@ -1,3 +1,49 @@
+2014-11-20 Zalan Bujtas <[email protected]>
+
+ Simple line layout: Introduce text fragment continuation.
+ https://bugs.webkit.org/show_bug.cgi?id=138274
+
+ This patch extends simple line layout coverage to multiple text renderers.
+ When a particular render flow has multiple text renderers (but not any other type)
+ then we use simple line layout to process and paint the content. -other, existing requirements still apply
+ so that for example if the content requires decoration, we bail out of simple line layout.
+
+ FlowContent now supports multiple renderes. It continuously reads content from sibling renderers
+ so that the simple line layout parser sees it as one monolithic block of content. Run positions
+ are all relative to the block and they get resolved to renderer's positions on demand.
+ (painting, computing bounding rects etc)
+
+ Reviewed by Antti Koivisto.
+
+ Performance test already been added for the multiple rendere use case,
+ correctness is covered by existing test cases.
+ Test: fast/text/simple-lines-mutliple-renderers.html
+
+ * rendering/SimpleLineLayout.cpp:
+ (WebCore::SimpleLineLayout::canUseFor): Check if children are all 8bit RenderTexts.
+ (WebCore::SimpleLineLayout::removeTrailingWhitespace): Move the endofline check right before where we might overflow using end position.
+ (WebCore::SimpleLineLayout::initializeNewLine):
+ (WebCore::SimpleLineLayout::closeLineEndingAndAdjustRuns):
+ (WebCore::SimpleLineLayout::splitRunsAtRendererBoundary): Split runs at renderers' boundary to be in sync with inline text renderering.
+ (WebCore::SimpleLineLayout::createTextRuns):
+ (WebCore::SimpleLineLayout::create):
+ * rendering/SimpleLineLayoutFlowContents.cpp:
+ (WebCore::SimpleLineLayout::FlowContents::FlowContents):
+ (WebCore::SimpleLineLayout::FlowContents::findNextBreakablePosition):
+ (WebCore::SimpleLineLayout::FlowContents::findNextNonWhitespacePosition):
+ (WebCore::SimpleLineLayout::FlowContents::textWidth): Do not measure text across renderers. It could produce different width value due to
+ ligature which later can produce unexpected line breaks and out sync renderering in general.
+ (WebCore::SimpleLineLayout::FlowContents::renderer):
+ (WebCore::SimpleLineLayout::FlowContents::resolveRendererPositions):
+ (WebCore::SimpleLineLayout::FlowContents::appendNextRendererContentIfNeeded): Read the next renderer content if needed.
+ (WebCore::SimpleLineLayout::FlowContents::nextNonWhitespacePosition):
+ (WebCore::SimpleLineLayout::FlowContents::runWidth):
+ * rendering/SimpleLineLayoutFlowContents.h:
+ (WebCore::SimpleLineLayout::FlowContents::isNewlineCharacter):
+ (WebCore::SimpleLineLayout::FlowContents::isEndOfContent):
+ * rendering/SimpleLineLayoutResolver.cpp:
+ (WebCore::SimpleLineLayout::RunResolver::Run::text):
+
2014-11-20 [email protected] <[email protected]>
[WinCairo] Compile error when GStreamer is enabled.
Modified: trunk/Source/WebCore/rendering/SimpleLineLayout.cpp (176395 => 176396)
--- trunk/Source/WebCore/rendering/SimpleLineLayout.cpp 2014-11-20 15:20:37 UTC (rev 176395)
+++ trunk/Source/WebCore/rendering/SimpleLineLayout.cpp 2014-11-20 15:22:02 UTC (rev 176396)
@@ -37,6 +37,7 @@
#include "LineWidth.h"
#include "PaintInfo.h"
#include "RenderBlockFlow.h"
+#include "RenderChildIterator.h"
#include "RenderStyle.h"
#include "RenderText.h"
#include "RenderTextControl.h"
@@ -93,14 +94,12 @@
return false;
if (!flow.firstChild())
return false;
- // This currently covers <blockflow>#text</blockflow> case.
+ // This currently covers <blockflow>#text</blockflow> and mutiple (sibling) RenderText cases.
// The <blockflow><inline>#text</inline></blockflow> case is also popular and should be relatively easy to cover.
- if (flow.firstChild() != flow.lastChild())
- return false;
- if (!is<RenderText>(flow.firstChild()))
- return false;
- if (!downcast<RenderText>(*flow.firstChild()).text()->is8Bit())
- return false;
+ for (const auto& renderer : childrenOfType<RenderObject>(flow)) {
+ if (!is<RenderText>(renderer) || !downcast<RenderText>(renderer).text()->is8Bit())
+ return false;
+ }
if (!flow.isHorizontalWritingMode())
return false;
if (flow.flowThreadState() != RenderObject::NotInsideFlowThread)
@@ -406,10 +405,8 @@
lineState.removeCommittedTrailingWhitespace();
}
- if (flowContents.isEndOfContent(lineState.position))
- return;
// If we skipped any whitespace and now the line end is a "preserved" newline, skip the newline too as we are wrapping the line here already.
- if (lastPosition != lineState.position && style.preserveNewline && flowContents.isNewlineCharacter(lineState.position))
+ if (lastPosition != lineState.position && style.preserveNewline && !flowContents.isEndOfContent(lineState.position) && flowContents.isNewlineCharacter(lineState.position))
++lineState.position;
}
@@ -471,7 +468,7 @@
return fragmentForNextLine;
}
-static TextFragment nextFragment(unsigned previousFragmentEnd, FlowContents& flowContents, float xPosition)
+static TextFragment nextFragment(unsigned previousFragmentEnd, const FlowContents& flowContents, float xPosition)
{
// A fragment can have
// 1. new line character when preserveNewline is on (not considered as whitespace) or
@@ -510,7 +507,7 @@
return fragment;
}
-static bool createLineRuns(LineState& lineState, Layout::RunVector& lineRuns, FlowContents& flowContents)
+static bool createLineRuns(LineState& lineState, Layout::RunVector& lineRuns, const FlowContents& flowContents)
{
const auto& style = flowContents.style();
bool lineCanBeWrapped = style.wrapLines || style.breakWordOnOverflow;
@@ -586,6 +583,34 @@
++lineCount;
}
+static void splitRunsAtRendererBoundary(Layout::RunVector& lineRuns, const FlowContents& flowContents)
+{
+ if (!lineRuns.size())
+ return;
+
+ unsigned runIndex = 0;
+ do {
+ const Run& run = lineRuns.at(runIndex);
+ ASSERT(run.start != run.end);
+ const RenderText* startRenderer = flowContents.renderer(run.start);
+ const RenderText* endRenderer = flowContents.renderer(run.end - 1);
+ if (startRenderer == endRenderer)
+ continue;
+ // This run overlaps multiple renderers. Split it up.
+ unsigned rendererStartPosition = 0;
+ unsigned rendererEndPosition = 0;
+ bool found = flowContents.resolveRendererPositions(*startRenderer, rendererStartPosition, rendererEndPosition);
+ ASSERT_UNUSED(found, found);
+
+ // 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, rendererEndPosition, run.logicalLeft);
+ lineRuns.insert(runIndex, Run(run.start, rendererEndPosition, run.logicalLeft, logicalRightOfLeftRun, false));
+ Run& rightSideRun = lineRuns.at(runIndex + 1);
+ rightSideRun.start = rendererEndPosition;
+ rightSideRun.logicalLeft = logicalRightOfLeftRun;
+ } while (++runIndex < lineRuns.size());
+}
+
static void updateLineConstrains(const RenderBlockFlow& flow, float& availableWidth, float& logicalLeftOffset)
{
LayoutUnit height = flow.logicalHeight();
@@ -610,6 +635,9 @@
isEndOfContent = createLineRuns(lineState, runs, flowContents);
closeLineEndingAndAdjustRuns(lineState, runs, lineCount, flowContents);
} while (!isEndOfContent);
+
+ if (flow.firstChild() != flow.lastChild())
+ splitRunsAtRendererBoundary(runs, flowContents);
ASSERT(!lineState.uncommittedWidth);
}
@@ -617,11 +645,12 @@
{
unsigned lineCount = 0;
Layout::RunVector runs;
- RenderText& textRenderer = downcast<RenderText>(*flow.firstChild());
- ASSERT(!textRenderer.firstTextBox());
createTextRuns(runs, flow, lineCount);
- textRenderer.clearNeedsLayout();
+ for (auto& renderer : childrenOfType<RenderObject>(flow)) {
+ ASSERT(is<RenderText>(renderer));
+ renderer.clearNeedsLayout();
+ }
return Layout::create(runs, lineCount);
}
Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp (176395 => 176396)
--- trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp 2014-11-20 15:20:37 UTC (rev 176395)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp 2014-11-20 15:22:02 UTC (rev 176396)
@@ -27,6 +27,8 @@
#include "SimpleLineLayoutFlowContents.h"
#include "RenderBlockFlow.h"
+#include "RenderChildIterator.h"
+#include "RenderText.h"
namespace WebCore {
namespace SimpleLineLayout {
@@ -35,21 +37,135 @@
: m_flow(flow)
, m_style(flow.style())
, m_lineBreakIterator(downcast<RenderText>(*flow.firstChild()).text(), flow.style().locale())
+ , m_lastRendererIndex(0)
{
+ unsigned startPosition = 0;
+ for (const RenderText* textRenderer = downcast<RenderText>(m_flow.firstChild()); textRenderer; textRenderer = downcast<RenderText>(textRenderer->nextSibling())) {
+ unsigned contentLength = textRenderer->text()->length();
+ m_textRanges.append(std::make_pair(startPosition, textRenderer));
+ startPosition += contentLength;
+ }
+ // End item.
+ const RenderText* closingNullItem = nullptr;
+ m_textRanges.append(std::make_pair(startPosition, closingNullItem));
}
-unsigned FlowContents::findNextBreakablePosition(unsigned position)
+unsigned FlowContents::findNextBreakablePosition(unsigned position) const
{
String string = m_lineBreakIterator.string();
- return nextBreakablePosition<LChar, false>(m_lineBreakIterator, string.characters8(), string.length(), position);
+ unsigned breakablePosition = nextBreakablePosition<LChar, false>(m_lineBreakIterator, string.characters8(), string.length(), position);
+ if (appendNextRendererContentIfNeeded(breakablePosition))
+ return findNextBreakablePosition(position);
+ ASSERT(breakablePosition >= position);
+ return breakablePosition;
}
unsigned FlowContents::findNextNonWhitespacePosition(unsigned position, unsigned& spaceCount) const
{
+ unsigned nonWhitespacePosition = nextNonWhitespacePosition(position, spaceCount);
+ if (appendNextRendererContentIfNeeded(nonWhitespacePosition))
+ return findNextNonWhitespacePosition(position, spaceCount);
+ ASSERT(nonWhitespacePosition >= position);
+ return nonWhitespacePosition;
+}
+
+float FlowContents::textWidth(unsigned from, unsigned to, float xPosition) const
+{
+ unsigned rendererStart = 0;
+ const RenderText* textRenderer = renderer(from, &rendererStart);
+ ASSERT(textRenderer);
+ // Resolved positions are relative to the renderers.
+ unsigned absoluteStart = from - rendererStart;
+ unsigned absoluteEnd = to - rendererStart;
+ if ((m_style.font.isFixedPitch() && textRenderer == renderer(to)) || (!absoluteStart && absoluteEnd == textRenderer->text()->length()))
+ return textRenderer->width(absoluteStart, to - from, m_style.font, xPosition, nullptr, nullptr);
+
+ // We need to split up the text and measure renderers individually due to ligature.
+ float textWidth = 0;
+ unsigned fragmentEnd = 0;
+ do {
+ fragmentEnd = std::min(to, rendererStart + textRenderer->text()->length());
+ unsigned absoluteFragmentEnd = fragmentEnd - rendererStart;
+ absoluteStart = from - rendererStart;
+ textWidth += runWidth(*textRenderer, absoluteStart, absoluteFragmentEnd, xPosition + textWidth);
+ from = fragmentEnd;
+ if (fragmentEnd < to)
+ textRenderer = renderer(fragmentEnd, &rendererStart);
+ } while (fragmentEnd < to && textRenderer);
+ return textWidth;
+}
+
+const RenderText* FlowContents::renderer(unsigned position, unsigned* rendererStartPosition) const
+{
+ unsigned arraySize = m_textRanges.size();
+ // Take advantage of the usage pattern.
+ if (position >= m_textRanges.at(m_lastRendererIndex).first && m_lastRendererIndex + 1 < arraySize && position < m_textRanges.at(m_lastRendererIndex + 1).first) {
+ if (rendererStartPosition)
+ *rendererStartPosition = m_textRanges.at(m_lastRendererIndex).first;
+ return m_textRanges.at(m_lastRendererIndex).second;
+ }
+ unsigned left = 0;
+ unsigned right = arraySize - 1;
+ ASSERT(arraySize);
+ ASSERT(position >= 0);
+ while (left < right) {
+ unsigned middle = (left + right) / 2;
+ unsigned endPosition = m_textRanges.at(middle + 1).first;
+ if (position > endPosition)
+ left = middle + 1;
+ else if (position < endPosition)
+ right = middle;
+ else {
+ right = middle + 1;
+ break;
+ }
+ }
+ if (rendererStartPosition)
+ *rendererStartPosition = m_textRanges.at(right).first;
+ return m_textRanges.at(right).second;
+}
+
+bool FlowContents::resolveRendererPositions(const RenderText& renderer, unsigned& startPosition, unsigned& endPosition) const
+{
+ unsigned arraySize = m_textRanges.size();
+ if (!arraySize)
+ return false;
+
+ unsigned index = 0;
+ do {
+ auto range = m_textRanges.at(index);
+ if (range.second == &renderer) {
+ startPosition = range.first;
+ ASSERT(index + 1 < arraySize);
+ endPosition = m_textRanges.at(index + 1).first;
+ return true;
+ }
+ } while (++index < arraySize);
+ return false;
+}
+
+bool FlowContents::appendNextRendererContentIfNeeded(unsigned position) const
+{
String string = m_lineBreakIterator.string();
+ if (position < string.length())
+ return false;
+
+ // Content needs to be requested sequentially.
+ ASSERT(position == string.length());
+ const RenderText* nextRenderer = renderer(position);
+ if (!nextRenderer)
+ return false;
+
+ ++m_lastRendererIndex;
+ m_lineBreakIterator.resetStringAndReleaseIterator(string + String(nextRenderer->text()), m_flow.style().locale());
+ return true;
+}
+
+unsigned FlowContents::nextNonWhitespacePosition(unsigned position, unsigned& spaceCount) const
+{
+ String string = m_lineBreakIterator.string();
unsigned length = string.length();
const LChar* text = string.characters8();
- spaceCount = 0;
for (; position < length; ++position) {
bool isSpace = text[position] == ' ';
if (!(isSpace || text[position] == '\t' || (!m_style.preserveNewline && text[position] == '\n')))
@@ -60,35 +176,15 @@
return length;
}
-float FlowContents::textWidth(unsigned from, unsigned to, float xPosition) const
+float FlowContents::runWidth(const RenderText& renderer, unsigned from, unsigned to, float xPosition) const
{
- String string = m_lineBreakIterator.string();
- unsigned length = string.length();
- if (m_style.font.isFixedPitch() || (!from && to == length)) {
- const RenderText& renderer = downcast<RenderText>(*m_flow.firstChild());
- return renderer.width(from, to - from, m_style.font, xPosition, nullptr, nullptr);
- }
-
+ ASSERT(from < to);
+ String string = renderer.text();
TextRun run(string.characters8() + from, to - from);
run.setXPos(xPosition);
- run.setCharactersLength(length - from);
run.setTabSize(!!m_style.tabWidth, m_style.tabWidth);
- ASSERT(run.charactersLength() >= run.length());
return m_style.font.width(run);
}
-bool FlowContents::resolveRendererPositions(const RenderText& renderer, unsigned& startPosition, unsigned& endPosition) const
-{
- ASSERT(&renderer == downcast<RenderText>(m_flow.firstChild()));
- startPosition = 0;
- endPosition = renderer.text()->length();
- return true;
}
-
-const RenderText& FlowContents::renderer(unsigned) const
-{
- return downcast<RenderText>(*m_flow.firstChild());
}
-
-}
-}
Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h (176395 => 176396)
--- trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h 2014-11-20 15:20:37 UTC (rev 176395)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h 2014-11-20 15:22:02 UTC (rev 176396)
@@ -40,7 +40,7 @@
public:
FlowContents(const RenderBlockFlow&);
- unsigned findNextBreakablePosition(unsigned position);
+ unsigned findNextBreakablePosition(unsigned position) const;
unsigned findNextNonWhitespacePosition(unsigned position, unsigned& spaceCount) const;
float textWidth(unsigned from, unsigned to, float xPosition) const;
@@ -49,7 +49,7 @@
bool isEndOfContent(unsigned position) const;
bool resolveRendererPositions(const RenderText&, unsigned& startPosition, unsigned& endPosition) const;
- const RenderText& renderer(unsigned position) const;
+ const RenderText* renderer(unsigned position, unsigned* startPosition = nullptr) const;
class Style {
public:
@@ -77,23 +77,27 @@
const Style& style() const { return m_style; }
private:
+ bool appendNextRendererContentIfNeeded(unsigned position) const;
unsigned nextNonWhitespacePosition(unsigned position, unsigned& spaceCount) const;
- float runWidth(unsigned from, unsigned to, float xPosition) const;
+ float runWidth(const RenderText&, unsigned from, unsigned to, float xPosition) const;
const RenderBlockFlow& m_flow;
- Style m_style;
- LazyLineBreakIterator m_lineBreakIterator;
+ const Style m_style;
+ mutable LazyLineBreakIterator m_lineBreakIterator;
+ Vector<std::pair<unsigned, const RenderText*>> m_textRanges;
+ mutable unsigned m_lastRendererIndex;
};
inline bool FlowContents::isNewlineCharacter(unsigned position) const
{
- ASSERT(m_lineBreakIterator.string().length() > position);
+ appendNextRendererContentIfNeeded(position);
+ ASSERT(position < m_lineBreakIterator.string().length());
return m_lineBreakIterator.string().at(position) == '\n';
}
inline bool FlowContents::isEndOfContent(unsigned position) const
{
- return position >= m_lineBreakIterator.string().length();
+ return position >= m_lineBreakIterator.string().length() && !renderer(position);
}
}
Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutResolver.cpp (176395 => 176396)
--- trunk/Source/WebCore/rendering/SimpleLineLayoutResolver.cpp 2014-11-20 15:20:37 UTC (rev 176395)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutResolver.cpp 2014-11-20 15:22:02 UTC (rev 176396)
@@ -76,9 +76,11 @@
{
auto& resolver = m_iterator.resolver();
auto& run = m_iterator.simpleRun();
- const auto& renderer = resolver.m_flowContents.renderer(run.start);
- ASSERT(renderer.is8Bit());
- return StringView(renderer.characters8(), renderer.textLength()).substring(run.start, run.end - run.start);
+ unsigned rendererOffset = 0;
+ const auto* renderer = resolver.m_flowContents.renderer(run.start, &rendererOffset);
+ ASSERT(renderer);
+ ASSERT(renderer->is8Bit());
+ return StringView(renderer->characters8(), renderer->textLength()).substring(run.start - rendererOffset, run.end - run.start);
}
RunResolver::Iterator::Iterator(const RunResolver& resolver, unsigned runIndex, unsigned lineIndex)