Title: [159030] trunk
Revision
159030
Author
[email protected]
Date
2013-11-10 14:17:32 -0800 (Sun, 10 Nov 2013)

Log Message

Implement white-space property on simple line layout path
https://bugs.webkit.org/show_bug.cgi?id=124122

Source/WebCore: 

Reviewed by Andreas Kling.
        
Support all values of the white-space property and the tab-size property.

Tests: fast/forms/basic-textareas-simple-lines.html
       fast/text/embed-at-end-of-pre-wrap-line-simple-lines.html
       fast/text/whitespace/pre-wrap-line-test-simple-lines.html
       fast/text/whitespace/pre-wrap-long-word-simple-lines.html
       fast/text/whitespace/pre-wrap-spaces-after-newline-simple-lines.html

* rendering/SimpleLineLayout.cpp:
(WebCore::SimpleLineLayout::canUseFor):
(WebCore::SimpleLineLayout::isWhitespace):
(WebCore::SimpleLineLayout::skipWhitespaces):
(WebCore::SimpleLineLayout::textWidth):
(WebCore::SimpleLineLayout::measureWord):
(WebCore::SimpleLineLayout::createTextRuns):
* rendering/SimpleLineLayoutFunctions.cpp:
(WebCore::SimpleLineLayout::paintDebugBorders):
(WebCore::SimpleLineLayout::paintFlow):

LayoutTests: 

Reviewed by Andreas Kling.
        
The simple line layout produces slightly different runs in some pre-wrap cases compared
to the line box path (with less unnecessary boxes). To keep the test coverage this patch forces the
existing render tree dump based tests to use line boxes. It also adds new ref tests for
the same cases where the test uses the simple line path and the ref is forced on the line box path.
This ensures that the paths produce pixel-identical results.

* fast/forms/basic-textareas-simple-lines-expected.html: Added.
* fast/forms/basic-textareas-simple-lines.html: Added.
* fast/forms/basic-textareas.html:
* fast/text/embed-at-end-of-pre-wrap-line-simple-lines-expected.html: Added.
* fast/text/embed-at-end-of-pre-wrap-line-simple-lines.html: Added.
* fast/text/embed-at-end-of-pre-wrap-line.html:
* fast/text/whitespace/pre-wrap-line-test-simple-lines-expected.html: Added.
* fast/text/whitespace/pre-wrap-line-test-simple-lines.html: Added.
* fast/text/whitespace/pre-wrap-line-test.html:
* fast/text/whitespace/pre-wrap-long-word-simple-lines-expected.html: Added.
* fast/text/whitespace/pre-wrap-long-word-simple-lines.html: Added. New simple test for overflowing lines which was only covered by the very large basic-textareas.html.
* fast/text/whitespace/pre-wrap-spaces-after-newline-simple-lines-expected.html: Added.
* fast/text/whitespace/pre-wrap-spaces-after-newline-simple-lines.html: Added.
* fast/text/whitespace/pre-wrap-spaces-after-newline.html:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (159029 => 159030)


--- trunk/LayoutTests/ChangeLog	2013-11-10 20:59:09 UTC (rev 159029)
+++ trunk/LayoutTests/ChangeLog	2013-11-10 22:17:32 UTC (rev 159030)
@@ -1,3 +1,31 @@
+2013-11-10  Antti Koivisto  <[email protected]>
+
+        Implement white-space property on simple line layout path
+        https://bugs.webkit.org/show_bug.cgi?id=124122
+
+        Reviewed by Andreas Kling.
+        
+        The simple line layout produces slightly different runs in some pre-wrap cases compared
+        to the line box path (with less unnecessary boxes). To keep the test coverage this patch forces the
+        existing render tree dump based tests to use line boxes. It also adds new ref tests for
+        the same cases where the test uses the simple line path and the ref is forced on the line box path.
+        This ensures that the paths produce pixel-identical results.
+
+        * fast/forms/basic-textareas-simple-lines-expected.html: Added.
+        * fast/forms/basic-textareas-simple-lines.html: Added.
+        * fast/forms/basic-textareas.html:
+        * fast/text/embed-at-end-of-pre-wrap-line-simple-lines-expected.html: Added.
+        * fast/text/embed-at-end-of-pre-wrap-line-simple-lines.html: Added.
+        * fast/text/embed-at-end-of-pre-wrap-line.html:
+        * fast/text/whitespace/pre-wrap-line-test-simple-lines-expected.html: Added.
+        * fast/text/whitespace/pre-wrap-line-test-simple-lines.html: Added.
+        * fast/text/whitespace/pre-wrap-line-test.html:
+        * fast/text/whitespace/pre-wrap-long-word-simple-lines-expected.html: Added.
+        * fast/text/whitespace/pre-wrap-long-word-simple-lines.html: Added. New simple test for overflowing lines which was only covered by the very large basic-textareas.html.
+        * fast/text/whitespace/pre-wrap-spaces-after-newline-simple-lines-expected.html: Added.
+        * fast/text/whitespace/pre-wrap-spaces-after-newline-simple-lines.html: Added.
+        * fast/text/whitespace/pre-wrap-spaces-after-newline.html:
+
 2013-11-10  Andreas Kling  <[email protected]>
 
         Optimize baselines: svg/*

Added: trunk/LayoutTests/fast/forms/basic-textareas-simple-lines-expected.html (0 => 159030)


--- trunk/LayoutTests/fast/forms/basic-textareas-simple-lines-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/basic-textareas-simple-lines-expected.html	2013-11-10 22:17:32 UTC (rev 159030)
@@ -0,0 +1,104 @@
+<html>
+<body>
+<script>
+// Force line box path.
+if (window.internals)
+    internals.settings.setSimpleLineLayoutEnabled(false);
+var docToAppendTo;
+function addTextarea(properties, opt_innerHTML) {
+    var title = docToAppendTo.createTextNode();
+    title.nodeValue = '';
+    var wrapper = docToAppendTo.createElement('div');
+    wrapper.style.cssText = 'display:inline-block;border:1px solid blue;font-size:12px;';
+    var textarea = docToAppendTo.createElement('textarea');
+    for (property in properties) {
+        var value = properties[property];
+        title.nodeValue += property + ': "' + value + '", ';
+        if (property == 'wrap')
+            textarea.setAttribute(property, value);
+        else if (property == 'style')
+            textarea.style.cssText = value;
+        else
+            textarea[property] = value;
+    }
+    textarea.innerHTML = opt_innerHTML ||
+        "Lorem ipsum  dolor ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuv";
+
+    var span = document.createElement('span');
+    span.style.cssText = 'display:inline-block;width:80px;';
+    span.appendChild(title);
+    wrapper.appendChild(span);
+    wrapper.appendChild(document.createElement('br'));
+    wrapper.appendChild(textarea)
+    docToAppendTo.body.appendChild(wrapper);
+}
+
+function addAllTextareas(iframe, compatMode) {
+    iframe.style.cssText = 'width:100%;border:0;'
+    docToAppendTo = iframe.contentWindow.document;
+
+    docToAppendTo.body.style.cssText = 'margin:0';
+
+    if (docToAppendTo.compatMode != compatMode)
+        testFailed('This document should be in ' + compatMode + ' mode.');
+
+    var compatModeTitle = docToAppendTo.createElement('div');
+    compatModeTitle.innerHTML = 'CompatMode: ' + docToAppendTo.compatMode;
+    compatModeTitle.style.cssText = 'margin:5px 0;font-weight:bold;';
+    docToAppendTo.body.appendChild(compatModeTitle);
+
+    addTextarea({}, 'Lorem ipsum dolor');
+    addTextarea({disabled: 'true'});
+    addTextarea({style: 'padding:10px'});
+    addTextarea({style: 'padding:0px'});
+    addTextarea({style: 'margin:10px'});
+    addTextarea({style: 'margin:0px'});
+    addTextarea({style: 'width:60px'});
+    addTextarea({style: 'width:60px; padding:20px'});
+    addTextarea({style: 'width:60px; padding:0'});
+    addTextarea({style: 'height:60px'});
+    addTextarea({style: 'width:60px; height:60px'});
+    addTextarea({style: 'overflow:hidden'});
+    addTextarea({style: 'overflow:scroll'});
+    addTextarea({style: 'overflow:hidden; width:60px; height:60px'});
+    addTextarea({style: 'overflow:scroll; width:60px; height:60px'});
+    addTextarea({cols: 5, style: 'width:60px; height:60px'});
+    addTextarea({rows: 4, style: 'width:60px; height:60px'});
+    addTextarea({cols: 5, rows: 4, style: 'width:60px; height:60px'});
+    addTextarea({cols: 3});
+    addTextarea({rows: 3});
+    addTextarea({cols: 7});
+    addTextarea({rows: 7});
+    addTextarea({cols: 5, rows: 4});
+    addTextarea({wrap: 'off'});
+    addTextarea({wrap: 'hard'});
+    addTextarea({wrap: 'soft'});
+    addTextarea({style: 'white-space:normal'});
+    addTextarea({style: 'white-space:pre'});
+    addTextarea({style: 'white-space:prewrap'});
+    addTextarea({style: 'white-space:nowrap'});
+    addTextarea({style: 'white-space:pre-line'});
+    addTextarea({style: 'word-wrap:normal'});
+    addTextarea({wrap: 'off', style: 'white-space:pre-wrap'});
+
+    iframe.style.height = docToAppendTo.body.offsetHeight + 5 + 'px';
+}
+
+document.body.style.margin = 0;
+
+var standardsIframe = document.createElement('iframe');
+// Reference a page with a doctype so it's standards mode.
+standardsIframe.src = '';
+standardsIframe._onload_ = function(e) {
+    addAllTextareas(e.target, 'CSS1Compat');
+}
+document.body.appendChild(standardsIframe);
+
+var quirksIframe = document.createElement('iframe');
+quirksIframe._onload_ = function(e) {
+    addAllTextareas(e.target, 'BackCompat');
+}
+document.body.appendChild(quirksIframe);
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/fast/forms/basic-textareas-simple-lines.html (0 => 159030)


--- trunk/LayoutTests/fast/forms/basic-textareas-simple-lines.html	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/basic-textareas-simple-lines.html	2013-11-10 22:17:32 UTC (rev 159030)
@@ -0,0 +1,101 @@
+<html>
+<body>
+<script>
+var docToAppendTo;
+function addTextarea(properties, opt_innerHTML) {
+    var title = docToAppendTo.createTextNode();
+    title.nodeValue = '';
+    var wrapper = docToAppendTo.createElement('div');
+    wrapper.style.cssText = 'display:inline-block;border:1px solid blue;font-size:12px;';
+    var textarea = docToAppendTo.createElement('textarea');
+    for (property in properties) {
+        var value = properties[property];
+        title.nodeValue += property + ': "' + value + '", ';
+        if (property == 'wrap')
+            textarea.setAttribute(property, value);
+        else if (property == 'style')
+            textarea.style.cssText = value;
+        else
+            textarea[property] = value;
+    }
+    textarea.innerHTML = opt_innerHTML ||
+        "Lorem ipsum  dolor ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuv";
+
+    var span = document.createElement('span');
+    span.style.cssText = 'display:inline-block;width:80px;';
+    span.appendChild(title);
+    wrapper.appendChild(span);
+    wrapper.appendChild(document.createElement('br'));
+    wrapper.appendChild(textarea)
+    docToAppendTo.body.appendChild(wrapper);
+}
+
+function addAllTextareas(iframe, compatMode) {
+    iframe.style.cssText = 'width:100%;border:0;'
+    docToAppendTo = iframe.contentWindow.document;
+
+    docToAppendTo.body.style.cssText = 'margin:0';
+
+    if (docToAppendTo.compatMode != compatMode)
+        testFailed('This document should be in ' + compatMode + ' mode.');
+
+    var compatModeTitle = docToAppendTo.createElement('div');
+    compatModeTitle.innerHTML = 'CompatMode: ' + docToAppendTo.compatMode;
+    compatModeTitle.style.cssText = 'margin:5px 0;font-weight:bold;';
+    docToAppendTo.body.appendChild(compatModeTitle);
+
+    addTextarea({}, 'Lorem ipsum dolor');
+    addTextarea({disabled: 'true'});
+    addTextarea({style: 'padding:10px'});
+    addTextarea({style: 'padding:0px'});
+    addTextarea({style: 'margin:10px'});
+    addTextarea({style: 'margin:0px'});
+    addTextarea({style: 'width:60px'});
+    addTextarea({style: 'width:60px; padding:20px'});
+    addTextarea({style: 'width:60px; padding:0'});
+    addTextarea({style: 'height:60px'});
+    addTextarea({style: 'width:60px; height:60px'});
+    addTextarea({style: 'overflow:hidden'});
+    addTextarea({style: 'overflow:scroll'});
+    addTextarea({style: 'overflow:hidden; width:60px; height:60px'});
+    addTextarea({style: 'overflow:scroll; width:60px; height:60px'});
+    addTextarea({cols: 5, style: 'width:60px; height:60px'});
+    addTextarea({rows: 4, style: 'width:60px; height:60px'});
+    addTextarea({cols: 5, rows: 4, style: 'width:60px; height:60px'});
+    addTextarea({cols: 3});
+    addTextarea({rows: 3});
+    addTextarea({cols: 7});
+    addTextarea({rows: 7});
+    addTextarea({cols: 5, rows: 4});
+    addTextarea({wrap: 'off'});
+    addTextarea({wrap: 'hard'});
+    addTextarea({wrap: 'soft'});
+    addTextarea({style: 'white-space:normal'});
+    addTextarea({style: 'white-space:pre'});
+    addTextarea({style: 'white-space:prewrap'});
+    addTextarea({style: 'white-space:nowrap'});
+    addTextarea({style: 'white-space:pre-line'});
+    addTextarea({style: 'word-wrap:normal'});
+    addTextarea({wrap: 'off', style: 'white-space:pre-wrap'});
+
+    iframe.style.height = docToAppendTo.body.offsetHeight + 5 + 'px';
+}
+
+document.body.style.margin = 0;
+
+var standardsIframe = document.createElement('iframe');
+// Reference a page with a doctype so it's standards mode.
+standardsIframe.src = '';
+standardsIframe._onload_ = function(e) {
+    addAllTextareas(e.target, 'CSS1Compat');
+}
+document.body.appendChild(standardsIframe);
+
+var quirksIframe = document.createElement('iframe');
+quirksIframe._onload_ = function(e) {
+    addAllTextareas(e.target, 'BackCompat');
+}
+document.body.appendChild(quirksIframe);
+</script>
+</body>
+</html>

Modified: trunk/LayoutTests/fast/forms/basic-textareas.html (159029 => 159030)


--- trunk/LayoutTests/fast/forms/basic-textareas.html	2013-11-10 20:59:09 UTC (rev 159029)
+++ trunk/LayoutTests/fast/forms/basic-textareas.html	2013-11-10 22:17:32 UTC (rev 159030)
@@ -1,6 +1,9 @@
 <html>
 <body>
 <script>
+// Force line box path.
+if (window.internals)
+    internals.settings.setSimpleLineLayoutEnabled(false);
 var docToAppendTo;
 function addTextarea(properties, opt_innerHTML) {
     var title = docToAppendTo.createTextNode();

Added: trunk/LayoutTests/fast/text/embed-at-end-of-pre-wrap-line-simple-lines-expected.html (0 => 159030)


--- trunk/LayoutTests/fast/text/embed-at-end-of-pre-wrap-line-simple-lines-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/text/embed-at-end-of-pre-wrap-line-simple-lines-expected.html	2013-11-10 22:17:32 UTC (rev 159030)
@@ -0,0 +1,15 @@
+<script>
+// Force line box path.
+if (window.internals)
+    internals.settings.setSimpleLineLayoutEnabled(false);
+</script>
+<style>
+    div { white-space: pre-wrap; border: 1px solid; padding: 4px; width: 70px; margin: 8px 0; }
+</style>
+<p>
+    The following boxes should be identical.
+</p>
+<div>Lorem....... <span style="direction: rtl; unicode-bidi: bidi-override;">muspi</span>
+</div>
+<div>Lorem....... ipsum
+</div>

Added: trunk/LayoutTests/fast/text/embed-at-end-of-pre-wrap-line-simple-lines.html (0 => 159030)


--- trunk/LayoutTests/fast/text/embed-at-end-of-pre-wrap-line-simple-lines.html	                        (rev 0)
+++ trunk/LayoutTests/fast/text/embed-at-end-of-pre-wrap-line-simple-lines.html	2013-11-10 22:17:32 UTC (rev 159030)
@@ -0,0 +1,10 @@
+<style>
+    div { white-space: pre-wrap; border: 1px solid; padding: 4px; width: 70px; margin: 8px 0; }
+</style>
+<p>
+    The following boxes should be identical.
+</p>
+<div>Lorem....... <span style="direction: rtl; unicode-bidi: bidi-override;">muspi</span>
+</div>
+<div>Lorem....... ipsum
+</div>

Modified: trunk/LayoutTests/fast/text/embed-at-end-of-pre-wrap-line.html (159029 => 159030)


--- trunk/LayoutTests/fast/text/embed-at-end-of-pre-wrap-line.html	2013-11-10 20:59:09 UTC (rev 159029)
+++ trunk/LayoutTests/fast/text/embed-at-end-of-pre-wrap-line.html	2013-11-10 22:17:32 UTC (rev 159030)
@@ -1,3 +1,8 @@
+<script>
+// Force line box path.
+if (window.internals)
+    internals.settings.setSimpleLineLayoutEnabled(false);
+</script>
 <style>
     div { white-space: pre-wrap; border: 1px solid; padding: 4px; width: 70px; margin: 8px 0; }
 </style>

Added: trunk/LayoutTests/fast/text/whitespace/pre-wrap-line-test-simple-lines-expected.html (0 => 159030)


--- trunk/LayoutTests/fast/text/whitespace/pre-wrap-line-test-simple-lines-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/text/whitespace/pre-wrap-line-test-simple-lines-expected.html	2013-11-10 22:17:32 UTC (rev 159030)
@@ -0,0 +1,6 @@
+<script>
+// Force line box path.
+if (window.internals)
+    internals.settings.setSimpleLineLayoutEnabled(false);
+</script>
+<table><tr><td><div style="white-space:pre-wrap">Three cheers    for OldVet and the letter he wrote to Senator Dodd (see above Comment).  We all need to be proactive and contact our senators and representatives to let them know our strong feelings on this subject.  I would lose what little faith I have left in our government if they engineered a tax payer bailout. 

Added: trunk/LayoutTests/fast/text/whitespace/pre-wrap-line-test-simple-lines.html (0 => 159030)


--- trunk/LayoutTests/fast/text/whitespace/pre-wrap-line-test-simple-lines.html	                        (rev 0)
+++ trunk/LayoutTests/fast/text/whitespace/pre-wrap-line-test-simple-lines.html	2013-11-10 22:17:32 UTC (rev 159030)
@@ -0,0 +1,2 @@
+									
+<table><tr><td><div style="white-space:pre-wrap">Three cheers    for OldVet and the letter he wrote to Senator Dodd (see above Comment).  We all need to be proactive and contact our senators and representatives to let them know our strong feelings on this subject.  I would lose what little faith I have left in our government if they engineered a tax payer bailout. 

Modified: trunk/LayoutTests/fast/text/whitespace/pre-wrap-line-test.html (159029 => 159030)


--- trunk/LayoutTests/fast/text/whitespace/pre-wrap-line-test.html	2013-11-10 20:59:09 UTC (rev 159029)
+++ trunk/LayoutTests/fast/text/whitespace/pre-wrap-line-test.html	2013-11-10 22:17:32 UTC (rev 159030)
@@ -1,2 +1,6 @@
-									
+<script>
+// Force line box path.
+if (window.internals)
+    internals.settings.setSimpleLineLayoutEnabled(false);
+</script>
 <table><tr><td><div style="white-space:pre-wrap">Three cheers    for OldVet and the letter he wrote to Senator Dodd (see above Comment).  We all need to be proactive and contact our senators and representatives to let them know our strong feelings on this subject.  I would lose what little faith I have left in our government if they engineered a tax payer bailout. 

Added: trunk/LayoutTests/fast/text/whitespace/pre-wrap-long-word-simple-lines-expected.html (0 => 159030)


--- trunk/LayoutTests/fast/text/whitespace/pre-wrap-long-word-simple-lines-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/text/whitespace/pre-wrap-long-word-simple-lines-expected.html	2013-11-10 22:17:32 UTC (rev 159030)
@@ -0,0 +1,8 @@
+<script>
+// Force line box path.
+if (window.internals)
+    internals.settings.setSimpleLineLayoutEnabled(false);
+</script>
+<div style="position:relative; white-space:pre-wrap; width:180px; border:1px solid blue">
+    Lorem ipsum  dolor ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuv
+</div>

Added: trunk/LayoutTests/fast/text/whitespace/pre-wrap-long-word-simple-lines.html (0 => 159030)


--- trunk/LayoutTests/fast/text/whitespace/pre-wrap-long-word-simple-lines.html	                        (rev 0)
+++ trunk/LayoutTests/fast/text/whitespace/pre-wrap-long-word-simple-lines.html	2013-11-10 22:17:32 UTC (rev 159030)
@@ -0,0 +1,3 @@
+<div style="position:relative; white-space:pre-wrap; width:180px; border:1px solid blue">
+    Lorem ipsum  dolor ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuv
+</div>

Added: trunk/LayoutTests/fast/text/whitespace/pre-wrap-spaces-after-newline-simple-lines-expected.html (0 => 159030)


--- trunk/LayoutTests/fast/text/whitespace/pre-wrap-spaces-after-newline-simple-lines-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/text/whitespace/pre-wrap-spaces-after-newline-simple-lines-expected.html	2013-11-10 22:17:32 UTC (rev 159030)
@@ -0,0 +1,34 @@
+<script>
+// Force line box path.
+if (window.internals)
+    internals.settings.setSimpleLineLayoutEnabled(false);
+</script>
+<style>
+    pre { white-space: pre-wrap; background: silver; width: 7ex; }
+</style>
+<p>
+    Test for
+    <i><a href=""
+    white-space: pre-wrap collapses leading whitespace following a newline</i>.
+</p>
+<hr>
+<p>Here <code>bar</code> should be right under <code>foo</code>:</p>
+<pre>foo      bar</pre>
+<p>Here <code>bar</code> should be on the right hand side of the second line:</p>
+<pre>foo<br>   bar</pre>
+<pre>foo    <br>   bar</pre>
+<pre>foo
+   bar</pre>
+<pre>foo 
+   bar</pre>
+<pre>foo  
+   bar</pre>
+<pre>foo   
+   bar</pre>
+<pre>foo    
+   bar</pre>
+<p>Here <code>bar</code> should be on the right hand side of the third line:</p>
+<pre>foo<br>
+   bar</pre>
+<pre>foo baz
+   bar</pre>

Added: trunk/LayoutTests/fast/text/whitespace/pre-wrap-spaces-after-newline-simple-lines.html (0 => 159030)


--- trunk/LayoutTests/fast/text/whitespace/pre-wrap-spaces-after-newline-simple-lines.html	                        (rev 0)
+++ trunk/LayoutTests/fast/text/whitespace/pre-wrap-spaces-after-newline-simple-lines.html	2013-11-10 22:17:32 UTC (rev 159030)
@@ -0,0 +1,29 @@
+<style>
+    pre { white-space: pre-wrap; background: silver; width: 7ex; }
+</style>
+<p>
+    Test for
+    <i><a href=""
+    white-space: pre-wrap collapses leading whitespace following a newline</i>.
+</p>
+<hr>
+<p>Here <code>bar</code> should be right under <code>foo</code>:</p>
+<pre>foo      bar</pre>
+<p>Here <code>bar</code> should be on the right hand side of the second line:</p>
+<pre>foo<br>   bar</pre>
+<pre>foo    <br>   bar</pre>
+<pre>foo
+   bar</pre>
+<pre>foo 
+   bar</pre>
+<pre>foo  
+   bar</pre>
+<pre>foo   
+   bar</pre>
+<pre>foo    
+   bar</pre>
+<p>Here <code>bar</code> should be on the right hand side of the third line:</p>
+<pre>foo<br>
+   bar</pre>
+<pre>foo baz
+   bar</pre>

Modified: trunk/LayoutTests/fast/text/whitespace/pre-wrap-spaces-after-newline.html (159029 => 159030)


--- trunk/LayoutTests/fast/text/whitespace/pre-wrap-spaces-after-newline.html	2013-11-10 20:59:09 UTC (rev 159029)
+++ trunk/LayoutTests/fast/text/whitespace/pre-wrap-spaces-after-newline.html	2013-11-10 22:17:32 UTC (rev 159030)
@@ -1,3 +1,8 @@
+<script>
+// Force line box path.
+if (window.internals)
+    internals.settings.setSimpleLineLayoutEnabled(false);
+</script>
 <style>
     pre { white-space: pre-wrap; background: silver; width: 7ex; }
 </style>

Modified: trunk/LayoutTests/platform/mac/compositing/repaint/invalidations-on-composited-layers-expected.txt (159029 => 159030)


--- trunk/LayoutTests/platform/mac/compositing/repaint/invalidations-on-composited-layers-expected.txt	2013-11-10 20:59:09 UTC (rev 159029)
+++ trunk/LayoutTests/platform/mac/compositing/repaint/invalidations-on-composited-layers-expected.txt	2013-11-10 22:17:32 UTC (rev 159030)
@@ -1,5 +1,6 @@
 (repaint rects
   (rect 8 13 784 15)
+  (rect 8 13 784 15)
   (rect 8 413 784 28)
   (rect 0 421 800 28)
 )

Modified: trunk/Source/WebCore/ChangeLog (159029 => 159030)


--- trunk/Source/WebCore/ChangeLog	2013-11-10 20:59:09 UTC (rev 159029)
+++ trunk/Source/WebCore/ChangeLog	2013-11-10 22:17:32 UTC (rev 159030)
@@ -1,3 +1,29 @@
+2013-11-10  Antti Koivisto  <[email protected]>
+
+        Implement white-space property on simple line layout path
+        https://bugs.webkit.org/show_bug.cgi?id=124122
+
+        Reviewed by Andreas Kling.
+        
+        Support all values of the white-space property and the tab-size property.
+
+        Tests: fast/forms/basic-textareas-simple-lines.html
+               fast/text/embed-at-end-of-pre-wrap-line-simple-lines.html
+               fast/text/whitespace/pre-wrap-line-test-simple-lines.html
+               fast/text/whitespace/pre-wrap-long-word-simple-lines.html
+               fast/text/whitespace/pre-wrap-spaces-after-newline-simple-lines.html
+
+        * rendering/SimpleLineLayout.cpp:
+        (WebCore::SimpleLineLayout::canUseFor):
+        (WebCore::SimpleLineLayout::isWhitespace):
+        (WebCore::SimpleLineLayout::skipWhitespaces):
+        (WebCore::SimpleLineLayout::textWidth):
+        (WebCore::SimpleLineLayout::measureWord):
+        (WebCore::SimpleLineLayout::createTextRuns):
+        * rendering/SimpleLineLayoutFunctions.cpp:
+        (WebCore::SimpleLineLayout::paintDebugBorders):
+        (WebCore::SimpleLineLayout::paintFlow):
+
 2013-11-10  Sergio Correia  <[email protected]>
 
         Fix EFL build after r159027

Modified: trunk/Source/WebCore/rendering/SimpleLineLayout.cpp (159029 => 159030)


--- trunk/Source/WebCore/rendering/SimpleLineLayout.cpp	2013-11-10 20:59:09 UTC (rev 159029)
+++ trunk/Source/WebCore/rendering/SimpleLineLayout.cpp	2013-11-10 22:17:32 UTC (rev 159030)
@@ -130,9 +130,6 @@
     // Non-visible overflow should be pretty easy to support.
     if (style.overflowX() != OVISIBLE || style.overflowY() != OVISIBLE)
         return false;
-    // Pre/no-wrap would be very helpful to support.
-    if (style.whiteSpace() != NORMAL)
-        return false;
     if (!style.textIndent().isZero())
         return false;
     if (style.wordSpacing() || style.letterSpacing())
@@ -197,35 +194,51 @@
     return true;
 }
 
-static inline bool isWhitespace(UChar character)
+static inline bool isWhitespace(UChar character, bool preserveNewline)
 {
-    return character == ' ' || character == '\t' || character == '\n';
+    return character == ' ' || character == '\t' || (!preserveNewline && character == '\n');
 }
 
 template <typename CharacterType>
-static inline unsigned skipWhitespaces(const CharacterType* text, unsigned offset, unsigned length)
+static inline unsigned skipWhitespaces(const CharacterType* text, unsigned offset, unsigned length, bool preserveNewline)
 {
     for (; offset < length; ++offset) {
-        if (!isWhitespace(text[offset]))
+        if (!isWhitespace(text[offset], preserveNewline))
             return offset;
     }
     return length;
 }
 
 template <typename CharacterType>
-static float textWidth(const RenderText& renderText, const CharacterType* text, unsigned textLength, unsigned from, unsigned to, float xPosition, const RenderStyle& style)
+static float textWidth(const RenderText& renderText, const CharacterType* text, unsigned textLength, unsigned from, unsigned to, float xPosition, const Font& font, float tabWidth)
 {
-    if (style.font().isFixedPitch() || (!from && to == textLength))
-        return renderText.width(from, to - from, style.font(), xPosition, nullptr, nullptr);
-    // FIXME: Add templated UChar/LChar paths.
+    if (font.isFixedPitch() || (!from && to == textLength))
+        return renderText.width(from, to - from, font, xPosition, nullptr, nullptr);
+
     TextRun run(text + from, to - from);
     run.setXPos(xPosition);
     run.setCharactersLength(textLength - from);
+    run.setTabSize(!!tabWidth, tabWidth);
+
     ASSERT(run.charactersLength() >= run.length());
 
-    return style.font().width(run);
+    return font.width(run);
 }
 
+template <typename CharacterType>
+static float measureWord(const RenderText& textRenderer, const CharacterType* text, unsigned textLength, unsigned start, unsigned end, float lineWidth, bool collapseWhitespace, const Font& font, float tabWidth, float spaceWidth)
+{
+    if (text[start] == ' ' && end == start + 1)
+        return spaceWidth;
+
+    bool measureWithEndSpace = collapseWhitespace && end < textLength && text[end] == ' ';
+    if (measureWithEndSpace)
+        ++end;
+    float width = textWidth(textRenderer, text, textLength, start, end, lineWidth, font, collapseWhitespace ? 0 : tabWidth);
+
+    return measureWithEndSpace ? width - spaceWidth : width;
+}
+
 static float computeLineLeft(ETextAlign textAlign, float remainingWidth)
 {
     switch (textAlign) {
@@ -261,17 +274,24 @@
 {
     const RenderStyle& style = flow.style();
 
-    ETextAlign textAlign = style.textAlign();
-    float wordTrailingSpaceWidth = style.font().width(TextRun(&space, 1));
+    // These properties are supported.
+    const Font& font = style.font();
+    unsigned tabWidth = style.tabSize();
+    ETextAlign textAlign = style.textAlign(); // Not 'justify'.
+    bool collapseWhitespace = style.collapseWhiteSpace();
+    bool preserveNewline = style.preserveNewline();
+    bool wrapLines = style.autoWrap();
 
     const CharacterType* text = textRenderer.text()->getCharacters<CharacterType>();
     const unsigned textLength = textRenderer.textLength();
 
+    float spaceWidth = font.width(TextRun(&space, 1));
     LazyLineBreakIterator lineBreakIterator(textRenderer.text(), style.locale());
 
     unsigned lineEnd = 0;
     while (lineEnd < textLength) {
-        lineEnd = skipWhitespaces(text, lineEnd, textLength);
+        if (collapseWhitespace)
+            lineEnd = skipWhitespaces(text, lineEnd, textLength, preserveNewline);
         unsigned lineStart = lineEnd;
         unsigned wordEnd = lineEnd;
         LineWidth lineWidth(flow, false, DoNotIndentText);
@@ -280,33 +300,63 @@
         lineRuns.uncheckedAppend(Run(lineStart, 0));
 
         while (wordEnd < textLength) {
-            ASSERT(!isWhitespace(text[wordEnd]));
+            ASSERT(!collapseWhitespace || !isWhitespace(text[wordEnd], preserveNewline));
 
-            bool wordIsPrecededByWhitespace = wordEnd > lineStart && isWhitespace(text[wordEnd - 1]);
-            unsigned wordStart = wordIsPrecededByWhitespace ? wordEnd - 1 : wordEnd;
+            unsigned wordStart = wordEnd;
 
-            wordEnd = nextBreakablePosition<CharacterType, false>(lineBreakIterator, text, textLength, wordEnd + 1);
+            if (preserveNewline && text[wordStart] == '\n') {
+                ++wordEnd;
+                // FIXME: This creates a dedicated run for newline. This is wasteful and unnecessary but it keeps test results unchanged.
+                if (wordStart > lineStart)
+                    lineRuns.append(Run(lineEnd, lineRuns.last().right));
+                lineRuns.last().right = lineRuns.last().left;
+                lineRuns.last().textLength = 1;
+                lineEnd = wordEnd;
+                break;
+            }
 
-            bool measureWithEndSpace = wordEnd < textLength && text[wordEnd] == ' ';
-            unsigned wordMeasureEnd = measureWithEndSpace ? wordEnd + 1 : wordEnd;
+            if (!collapseWhitespace && isWhitespace(text[wordStart], preserveNewline))
+                wordEnd = wordStart + 1;
+            else
+                wordEnd = nextBreakablePosition<CharacterType, false>(lineBreakIterator, text, textLength, wordStart + 1);
 
-            float wordWidth = textWidth(textRenderer, text, textLength, wordStart, wordMeasureEnd, lineWidth.committedWidth(), style);
+            bool wordIsPrecededByWhitespace = collapseWhitespace && wordStart > lineStart && isWhitespace(text[wordStart - 1], preserveNewline);
+            if (wordIsPrecededByWhitespace)
+                --wordStart;
 
-            if (measureWithEndSpace)
-                wordWidth -= wordTrailingSpaceWidth;
+            float wordWidth = measureWord(textRenderer, text, textLength, wordStart, wordEnd, lineWidth.committedWidth(), collapseWhitespace, font, tabWidth, spaceWidth);
 
             lineWidth.addUncommittedWidth(wordWidth);
 
-            // Move to the next line if the current one is full and we have something on it.
-            if (!lineWidth.fitsOnLine() && lineWidth.committedWidth())
-                break;
+            if (wrapLines) {
+                // Move to the next line if the current one is full and we have something on it.
+                if (!lineWidth.fitsOnLine() && lineWidth.committedWidth())
+                    break;
 
+                // This is for white-space: pre-wrap which requires special handling for end line whitespace.
+                if (!collapseWhitespace && lineWidth.fitsOnLine() && wordEnd < textLength && isWhitespace(text[wordEnd], preserveNewline)) {
+                    // Look ahead to see if the next whitespace would fit.
+                    float whitespaceWidth = textWidth(textRenderer, text, textLength, wordEnd, wordEnd + 1, lineWidth.committedWidth(), font, tabWidth);
+                    if (!lineWidth.fitsOnLineIncludingExtraWidth(whitespaceWidth)) {
+                        // If not eat away the rest of the whitespace on the line.
+                        unsigned whitespaceEnd = skipWhitespaces(text, wordEnd, textLength, preserveNewline);
+                        // Include newline to this run too.
+                        if (whitespaceEnd < textLength && text[whitespaceEnd] == '\n')
+                            ++whitespaceEnd;
+                        lineRuns.last().textLength = whitespaceEnd - lineRuns.last().textOffset;
+                        lineRuns.last().right = lineWidth.availableWidth();
+                        lineEnd = whitespaceEnd;
+                        break;
+                    }
+                }
+            }
+
             if (wordStart > lineEnd) {
                 // There were more than one consecutive whitespace.
                 ASSERT(wordIsPrecededByWhitespace);
                 // Include space to the end of the previous run.
                 lineRuns.last().textLength++;
-                lineRuns.last().right += wordTrailingSpaceWidth;
+                lineRuns.last().right += spaceWidth;
                 // Start a new run on the same line.
                 lineRuns.append(Run(wordStart + 1, lineRuns.last().right));
             }
@@ -317,9 +367,10 @@
             lineRuns.last().textLength = wordEnd - lineRuns.last().textOffset;
 
             lineEnd = wordEnd;
-            wordEnd = skipWhitespaces(text, wordEnd, textLength);
+            if (collapseWhitespace)
+                wordEnd = skipWhitespaces(text, wordEnd, textLength, preserveNewline);
 
-            if (!lineWidth.fitsOnLine()) {
+            if (wrapLines && !lineWidth.fitsOnLine()) {
                 // The first run on the line overflows.
                 ASSERT(lineRuns.size() == 1);
                 break;
@@ -328,12 +379,13 @@
         if (lineStart == lineEnd)
             continue;
 
+        lineRuns.last().isEndOfLine = true;
+
         adjustRunOffsets(lineRuns, textAlign, lineWidth.committedWidth(), lineWidth.availableWidth());
 
         for (unsigned i = 0; i < lineRuns.size(); ++i)
             runs.append(lineRuns[i]);
 
-        runs.last().isEndOfLine = true;
         ++lineCount;
     }
 }

Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp (159029 => 159030)


--- trunk/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp	2013-11-10 20:59:09 UTC (rev 159029)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp	2013-11-10 22:17:32 UTC (rev 159030)
@@ -50,6 +50,8 @@
 
 static void paintDebugBorders(GraphicsContext& context, const LayoutRect& borderRect, const LayoutPoint& paintOffset)
 {
+    if (borderRect.isEmpty())
+        return;
     GraphicsContextStateSaver stateSaver(context);
     context.setStrokeColor(Color(0, 255, 0), ColorSpaceDeviceRGB);
     context.setFillColor(Color::transparent, ColorSpaceDeviceRGB);
@@ -80,7 +82,9 @@
     auto resolver = runResolver(flow, layout);
     for (auto it = resolver.begin(), end = resolver.end(); it != end; ++it) {
         auto run = *it;
-        context.drawText(font, TextRun(run.text()), run.baseline() + paintOffset);
+        TextRun textRun(run.text());
+        textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize());
+        context.drawText(font, textRun, run.baseline() + paintOffset);
         if (debugBordersEnabled)
             paintDebugBorders(context, run.rect(), paintOffset);
     }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to