Simple line layout: Add support for hyphen: auto.
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 24 Jan 2017 21:38:20 +0000 (21:38 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 24 Jan 2017 21:38:20 +0000 (21:38 +0000)
https://bugs.webkit.org/show_bug.cgi?id=167297
<rdar://problem/30119463>

Reviewed by Antti Koivisto.

Source/WebCore:

Implement hyphen: auto for simple line layout.

Tests: fast/text/simple-line-hyphens-with-text-align.html
       fast/text/simple-line-hyphens-with-word-letter-spacing.html

* platform/text/Hyphenation.h:
(WebCore::enoughWidthForHyphenation):
* rendering/RenderTreeAsText.cpp:
(WebCore::writeSimpleLine):
(WebCore::write):
* rendering/SimpleLineLayout.cpp:
(WebCore::SimpleLineLayout::canUseForStyle):
(WebCore::SimpleLineLayout::LineState::appendFragmentAndCreateRunIfNeeded): Inherit the hyphen attribute from the
run-to-be-appended. Ensure that we don't append additional runs when the last run has hyphen.
(WebCore::SimpleLineLayout::splitFragmentToFitLine): Before calling into the lastHyphenPosition() we need to
ensure that the hyphen would surely fit (even on the splitting position).
(WebCore::SimpleLineLayout::createLineRuns): Probe hypenation for overhanging non-whitespace runs.
(WebCore::SimpleLineLayout::printReason):
* rendering/SimpleLineLayout.h:
(WebCore::SimpleLineLayout::Run::Run):
* rendering/SimpleLineLayoutFlowContents.h:
(WebCore::SimpleLineLayout::FlowContents::Segment::toSegmentPosition):
(WebCore::SimpleLineLayout::FlowContents::Segment::toRenderPosition):
* rendering/SimpleLineLayoutResolver.cpp:
(WebCore::SimpleLineLayout::RunResolver::Run::Run):
(WebCore::SimpleLineLayout::RunResolver::Run::constructStringForHyphenIfNeeded):
(WebCore::SimpleLineLayout::RunResolver::Run::text):
* rendering/SimpleLineLayoutResolver.h:
(WebCore::SimpleLineLayout::RunResolver::Run::hasHyphen):
* rendering/SimpleLineLayoutTextFragmentIterator.cpp:
(WebCore::SimpleLineLayout::TextFragmentIterator::Style::Style):
(WebCore::SimpleLineLayout::TextFragmentIterator::nextBreakablePosition):
(WebCore::SimpleLineLayout::TextFragmentIterator::nextNonWhitespacePosition):
(WebCore::SimpleLineLayout::TextFragmentIterator::textWidth):
(WebCore::SimpleLineLayout::TextFragmentIterator::lastHyphenPosition): We only check the actual run for hyphenation ignoring
the neighboring runs. This might need to be changed in the future.
(WebCore::SimpleLineLayout::TextFragmentIterator::runWidth):
* rendering/SimpleLineLayoutTextFragmentIterator.h:
(WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::TextFragment):
(WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::hasHyphen):
(WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::operator==):
(WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::split):
(WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::splitWithHyphen):
* rendering/line/BreakingContext.h:
(WebCore::tryHyphenating):

LayoutTests:

* fast/text/simple-line-hyphens-with-text-align-expected.html: Added.
* fast/text/simple-line-hyphens-with-text-align.html: Added.
* fast/text/simple-line-hyphens-with-word-letter-spacing-expected.html: Added.
* fast/text/simple-line-hyphens-with-word-letter-spacing.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@211108 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/text/simple-line-hyphens-with-text-align-expected.html [new file with mode: 0644]
LayoutTests/fast/text/simple-line-hyphens-with-text-align.html [new file with mode: 0644]
LayoutTests/fast/text/simple-line-hyphens-with-word-letter-spacing-expected.html [new file with mode: 0644]
LayoutTests/fast/text/simple-line-hyphens-with-word-letter-spacing.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/platform/text/Hyphenation.h
Source/WebCore/rendering/RenderTreeAsText.cpp
Source/WebCore/rendering/SimpleLineLayout.cpp
Source/WebCore/rendering/SimpleLineLayout.h
Source/WebCore/rendering/SimpleLineLayoutFlowContents.h
Source/WebCore/rendering/SimpleLineLayoutResolver.cpp
Source/WebCore/rendering/SimpleLineLayoutResolver.h
Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.cpp
Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.h
Source/WebCore/rendering/line/BreakingContext.h

index 91bbe7c..e7e25cf 100644 (file)
@@ -1,3 +1,16 @@
+2017-01-24  Zalan Bujtas  <zalan@apple.com>
+
+        Simple line layout: Add support for hyphen: auto.
+        https://bugs.webkit.org/show_bug.cgi?id=167297
+        <rdar://problem/30119463>
+
+        Reviewed by Antti Koivisto.
+
+        * fast/text/simple-line-hyphens-with-text-align-expected.html: Added.
+        * fast/text/simple-line-hyphens-with-text-align.html: Added.
+        * fast/text/simple-line-hyphens-with-word-letter-spacing-expected.html: Added.
+        * fast/text/simple-line-hyphens-with-word-letter-spacing.html: Added.
+
 2017-01-24  Ryan Haddad  <ryanhaddad@apple.com>
 
         More modern-media-controls LayoutTest gardening.
diff --git a/LayoutTests/fast/text/simple-line-hyphens-with-text-align-expected.html b/LayoutTests/fast/text/simple-line-hyphens-with-text-align-expected.html
new file mode 100644 (file)
index 0000000..5e167f6
--- /dev/null
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>This tests that simple and normal line layout produce the same lines with hyphens</title>
+<style>
+div {
+  display: inline-block;
+  -webkit-hyphens: auto; 
+  width: 200px;
+  border: 1px solid green;
+}
+</style>
+<script>
+if (internal.settings)
+    internals.settings.setSimpleLineLayoutEnabled(false);
+</script>
+</head>
+<body>
+<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec consequat rhoncus erat, id pellentesque ligula aliquet et. Nam aliquam pellentesque risus. Mauris lorem nunc, sodales pellentesque porttitor ut, pellentesque at felis. Nullam et accumsan leo, in scelerisque massa. Fusce luctus laoreet pretium. Nulla sollicitudin volutpat neque in mattis. Vestibulum non placerat velit. Aenean dui nunc, tincidunt nec tempus et, venenatis vel magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin pretium nisl sit amet lacus varius consequat. Donec congue molestie mauris, a vehicula velit. Nam pellentesque sed arcu congue rutrum. Maecenas pulvinar ex at diam dapibus consectetur ut non nisl. Sed tempus bibendum sodales. Donec nec arcu ligula. Vivamus sit amet aliquet neque, vel volutpat nibh. In purus sem, tincidunt vulputate neque eu, scelerisque hendrerit ex. Donec eu porta lectus, at malesuada magna. Duis ut egestas est. Nullam et libero sit amet lectus tempus pharetra ac id mauris. Ut diam orci, interdum nec suscipit ut, semper nec orci. Fusce sed risus elementum, posuere orci id, aliquam urna. Donec arcu turpis, scelerisque a mauris vel, vehicula convallis ipsum. Phasellus facilisis, magna ut dapibus pretium, sapien mauris viverra enim, ut hendrerit urna dui eu ligula. Nulla vestibulum et nibh quis laoreet. Quisque feugiat arcu ipsum, id mollis quam sagittis at. Morbi tempus, risus molestie ultricies viverra, justo augue facilisis orci, a semper risus dui pellentesque purus. Curabitur facilisis arcu quam, id facilisis turpis aliquam ac. Maecenas efficitur risus pellentesque sem maximus euismod. Proin aliquet justo ac dolor faucibus porttitor. Fusce orci lectus, eleifend at lectus sit amet, pretium ornare felis. Nullam nec ipsum maximus, molestie arcu in, finibus urna. Suspendisse tincidunt feugiat est, in viverra lectus tincidunt quis. Ut eros tortor, tincidunt vel commodo hendrerit, consequat vel neque. Vestibulum enim nibh, accumsan quis viverra ut, iaculis sit amet est. Morbi non lacus at dolor euismod molestie. Integer pulvinar, nibh in volutpat tincidunt, urna odio interdum magna, vitae faucibus felis quam nec est. Proin tellus quam, auctor nec dictum sed, rhoncus nec massa. Mauris ac arcu ac augue porta viverra. Quisque semper eget nisi quis viverra. Donec vitae mauris ipsum. Duis tempor pulvinar viverra. Nam dignissim iaculis felis, eget vestibulum eros. Nulla eget faucibus massa. Integer sollicitudin pretium erat, vel commodo nunc congue non. Nulla in nunc auctor dui efficitur euismod. Sed pharetra sapien erat, a blandit neque porttitor sit amet. Mauris pharetra sodales maximus. Nulla volutpat auctor quam, a elementum risus tristique eu. In ac sodales nibh. Maecenas pharetra orci sem, eu laoreet quam tincidunt non. Mauris in interdum dui. Vivamus et interdum erat. Aliquam nec ante tincidunt, elementum risus in, mattis orci. Sed massa turpis, blandit a rutrum at, dignissim et lectus. Nunc tincidunt orci nibh, id ullamcorper nisl vestibulum vel.</div>
+<div style="text-align: justify">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec consequat rhoncus erat, id pellentesque ligula aliquet et. Nam aliquam pellentesque risus. Mauris lorem nunc, sodales pellentesque porttitor ut, pellentesque at felis. Nullam et accumsan leo, in scelerisque massa. Fusce luctus laoreet pretium. Nulla sollicitudin volutpat neque in mattis. Vestibulum non placerat velit. Aenean dui nunc, tincidunt nec tempus et, venenatis vel magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin pretium nisl sit amet lacus varius consequat. Donec congue molestie mauris, a vehicula velit. Nam pellentesque sed arcu congue rutrum. Maecenas pulvinar ex at diam dapibus consectetur ut non nisl. Sed tempus bibendum sodales. Donec nec arcu ligula. Vivamus sit amet aliquet neque, vel volutpat nibh. In purus sem, tincidunt vulputate neque eu, scelerisque hendrerit ex. Donec eu porta lectus, at malesuada magna. Duis ut egestas est. Nullam et libero sit amet lectus tempus pharetra ac id mauris. Ut diam orci, interdum nec suscipit ut, semper nec orci. Fusce sed risus elementum, posuere orci id, aliquam urna. Donec arcu turpis, scelerisque a mauris vel, vehicula convallis ipsum. Phasellus facilisis, magna ut dapibus pretium, sapien mauris viverra enim, ut hendrerit urna dui eu ligula. Nulla vestibulum et nibh quis laoreet. Quisque feugiat arcu ipsum, id mollis quam sagittis at. Morbi tempus, risus molestie ultricies viverra, justo augue facilisis orci, a semper risus dui pellentesque purus. Curabitur facilisis arcu quam, id facilisis turpis aliquam ac. Maecenas efficitur risus pellentesque sem maximus euismod. Proin aliquet justo ac dolor faucibus porttitor. Fusce orci lectus, eleifend at lectus sit amet, pretium ornare felis. Nullam nec ipsum maximus, molestie arcu in, finibus urna. Suspendisse tincidunt feugiat est, in viverra lectus tincidunt quis. Ut eros tortor, tincidunt vel commodo hendrerit, consequat vel neque. Vestibulum enim nibh, accumsan quis viverra ut, iaculis sit amet est. Morbi non lacus at dolor euismod molestie. Integer pulvinar, nibh in volutpat tincidunt, urna odio interdum magna, vitae faucibus felis quam nec est. Proin tellus quam, auctor nec dictum sed, rhoncus nec massa. Mauris ac arcu ac augue porta viverra. Quisque semper eget nisi quis viverra. Donec vitae mauris ipsum. Duis tempor pulvinar viverra. Nam dignissim iaculis felis, eget vestibulum eros. Nulla eget faucibus massa. Integer sollicitudin pretium erat, vel commodo nunc congue non. Nulla in nunc auctor dui efficitur euismod. Sed pharetra sapien erat, a blandit neque porttitor sit amet. Mauris pharetra sodales maximus. Nulla volutpat auctor quam, a elementum risus tristique eu. In ac sodales nibh. Maecenas pharetra orci sem, eu laoreet quam tincidunt non. Mauris in interdum dui. Vivamus et interdum erat. Aliquam nec ante tincidunt, elementum risus in, mattis orci. Sed massa turpis, blandit a rutrum at, dignissim et lectus. Nunc tincidunt orci nibh, id ullamcorper nisl vestibulum vel.</div>
+<div style="text-align: right">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec consequat rhoncus erat, id pellentesque ligula aliquet et. Nam aliquam pellentesque risus. Mauris lorem nunc, sodales pellentesque porttitor ut, pellentesque at felis. Nullam et accumsan leo, in scelerisque massa. Fusce luctus laoreet pretium. Nulla sollicitudin volutpat neque in mattis. Vestibulum non placerat velit. Aenean dui nunc, tincidunt nec tempus et, venenatis vel magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin pretium nisl sit amet lacus varius consequat. Donec congue molestie mauris, a vehicula velit. Nam pellentesque sed arcu congue rutrum. Maecenas pulvinar ex at diam dapibus consectetur ut non nisl. Sed tempus bibendum sodales. Donec nec arcu ligula. Vivamus sit amet aliquet neque, vel volutpat nibh. In purus sem, tincidunt vulputate neque eu, scelerisque hendrerit ex. Donec eu porta lectus, at malesuada magna. Duis ut egestas est. Nullam et libero sit amet lectus tempus pharetra ac id mauris. Ut diam orci, interdum nec suscipit ut, semper nec orci. Fusce sed risus elementum, posuere orci id, aliquam urna. Donec arcu turpis, scelerisque a mauris vel, vehicula convallis ipsum. Phasellus facilisis, magna ut dapibus pretium, sapien mauris viverra enim, ut hendrerit urna dui eu ligula. Nulla vestibulum et nibh quis laoreet. Quisque feugiat arcu ipsum, id mollis quam sagittis at. Morbi tempus, risus molestie ultricies viverra, justo augue facilisis orci, a semper risus dui pellentesque purus. Curabitur facilisis arcu quam, id facilisis turpis aliquam ac. Maecenas efficitur risus pellentesque sem maximus euismod. Proin aliquet justo ac dolor faucibus porttitor. Fusce orci lectus, eleifend at lectus sit amet, pretium ornare felis. Nullam nec ipsum maximus, molestie arcu in, finibus urna. Suspendisse tincidunt feugiat est, in viverra lectus tincidunt quis. Ut eros tortor, tincidunt vel commodo hendrerit, consequat vel neque. Vestibulum enim nibh, accumsan quis viverra ut, iaculis sit amet est. Morbi non lacus at dolor euismod molestie. Integer pulvinar, nibh in volutpat tincidunt, urna odio interdum magna, vitae faucibus felis quam nec est. Proin tellus quam, auctor nec dictum sed, rhoncus nec massa. Mauris ac arcu ac augue porta viverra. Quisque semper eget nisi quis viverra. Donec vitae mauris ipsum. Duis tempor pulvinar viverra. Nam dignissim iaculis felis, eget vestibulum eros. Nulla eget faucibus massa. Integer sollicitudin pretium erat, vel commodo nunc congue non. Nulla in nunc auctor dui efficitur euismod. Sed pharetra sapien erat, a blandit neque porttitor sit amet. Mauris pharetra sodales maximus. Nulla volutpat auctor quam, a elementum risus tristique eu. In ac sodales nibh. Maecenas pharetra orci sem, eu laoreet quam tincidunt non. Mauris in interdum dui. Vivamus et interdum erat. Aliquam nec ante tincidunt, elementum risus in, mattis orci. Sed massa turpis, blandit a rutrum at, dignissim et lectus. Nunc tincidunt orci nibh, id ullamcorper nisl vestibulum vel.</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/text/simple-line-hyphens-with-text-align.html b/LayoutTests/fast/text/simple-line-hyphens-with-text-align.html
new file mode 100644 (file)
index 0000000..d17cac5
--- /dev/null
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>This tests that simple and normal line layout produce the same lines with hyphens</title>
+<style>
+div {
+  display: inline-block;
+  -webkit-hyphens: auto; 
+  width: 200px;
+  border: 1px solid green;
+}
+</style>
+</head>
+<body>
+<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec consequat rhoncus erat, id pellentesque ligula aliquet et. Nam aliquam pellentesque risus. Mauris lorem nunc, sodales pellentesque porttitor ut, pellentesque at felis. Nullam et accumsan leo, in scelerisque massa. Fusce luctus laoreet pretium. Nulla sollicitudin volutpat neque in mattis. Vestibulum non placerat velit. Aenean dui nunc, tincidunt nec tempus et, venenatis vel magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin pretium nisl sit amet lacus varius consequat. Donec congue molestie mauris, a vehicula velit. Nam pellentesque sed arcu congue rutrum. Maecenas pulvinar ex at diam dapibus consectetur ut non nisl. Sed tempus bibendum sodales. Donec nec arcu ligula. Vivamus sit amet aliquet neque, vel volutpat nibh. In purus sem, tincidunt vulputate neque eu, scelerisque hendrerit ex. Donec eu porta lectus, at malesuada magna. Duis ut egestas est. Nullam et libero sit amet lectus tempus pharetra ac id mauris. Ut diam orci, interdum nec suscipit ut, semper nec orci. Fusce sed risus elementum, posuere orci id, aliquam urna. Donec arcu turpis, scelerisque a mauris vel, vehicula convallis ipsum. Phasellus facilisis, magna ut dapibus pretium, sapien mauris viverra enim, ut hendrerit urna dui eu ligula. Nulla vestibulum et nibh quis laoreet. Quisque feugiat arcu ipsum, id mollis quam sagittis at. Morbi tempus, risus molestie ultricies viverra, justo augue facilisis orci, a semper risus dui pellentesque purus. Curabitur facilisis arcu quam, id facilisis turpis aliquam ac. Maecenas efficitur risus pellentesque sem maximus euismod. Proin aliquet justo ac dolor faucibus porttitor. Fusce orci lectus, eleifend at lectus sit amet, pretium ornare felis. Nullam nec ipsum maximus, molestie arcu in, finibus urna. Suspendisse tincidunt feugiat est, in viverra lectus tincidunt quis. Ut eros tortor, tincidunt vel commodo hendrerit, consequat vel neque. Vestibulum enim nibh, accumsan quis viverra ut, iaculis sit amet est. Morbi non lacus at dolor euismod molestie. Integer pulvinar, nibh in volutpat tincidunt, urna odio interdum magna, vitae faucibus felis quam nec est. Proin tellus quam, auctor nec dictum sed, rhoncus nec massa. Mauris ac arcu ac augue porta viverra. Quisque semper eget nisi quis viverra. Donec vitae mauris ipsum. Duis tempor pulvinar viverra. Nam dignissim iaculis felis, eget vestibulum eros. Nulla eget faucibus massa. Integer sollicitudin pretium erat, vel commodo nunc congue non. Nulla in nunc auctor dui efficitur euismod. Sed pharetra sapien erat, a blandit neque porttitor sit amet. Mauris pharetra sodales maximus. Nulla volutpat auctor quam, a elementum risus tristique eu. In ac sodales nibh. Maecenas pharetra orci sem, eu laoreet quam tincidunt non. Mauris in interdum dui. Vivamus et interdum erat. Aliquam nec ante tincidunt, elementum risus in, mattis orci. Sed massa turpis, blandit a rutrum at, dignissim et lectus. Nunc tincidunt orci nibh, id ullamcorper nisl vestibulum vel.</div>
+<div style="text-align: justify">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec consequat rhoncus erat, id pellentesque ligula aliquet et. Nam aliquam pellentesque risus. Mauris lorem nunc, sodales pellentesque porttitor ut, pellentesque at felis. Nullam et accumsan leo, in scelerisque massa. Fusce luctus laoreet pretium. Nulla sollicitudin volutpat neque in mattis. Vestibulum non placerat velit. Aenean dui nunc, tincidunt nec tempus et, venenatis vel magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin pretium nisl sit amet lacus varius consequat. Donec congue molestie mauris, a vehicula velit. Nam pellentesque sed arcu congue rutrum. Maecenas pulvinar ex at diam dapibus consectetur ut non nisl. Sed tempus bibendum sodales. Donec nec arcu ligula. Vivamus sit amet aliquet neque, vel volutpat nibh. In purus sem, tincidunt vulputate neque eu, scelerisque hendrerit ex. Donec eu porta lectus, at malesuada magna. Duis ut egestas est. Nullam et libero sit amet lectus tempus pharetra ac id mauris. Ut diam orci, interdum nec suscipit ut, semper nec orci. Fusce sed risus elementum, posuere orci id, aliquam urna. Donec arcu turpis, scelerisque a mauris vel, vehicula convallis ipsum. Phasellus facilisis, magna ut dapibus pretium, sapien mauris viverra enim, ut hendrerit urna dui eu ligula. Nulla vestibulum et nibh quis laoreet. Quisque feugiat arcu ipsum, id mollis quam sagittis at. Morbi tempus, risus molestie ultricies viverra, justo augue facilisis orci, a semper risus dui pellentesque purus. Curabitur facilisis arcu quam, id facilisis turpis aliquam ac. Maecenas efficitur risus pellentesque sem maximus euismod. Proin aliquet justo ac dolor faucibus porttitor. Fusce orci lectus, eleifend at lectus sit amet, pretium ornare felis. Nullam nec ipsum maximus, molestie arcu in, finibus urna. Suspendisse tincidunt feugiat est, in viverra lectus tincidunt quis. Ut eros tortor, tincidunt vel commodo hendrerit, consequat vel neque. Vestibulum enim nibh, accumsan quis viverra ut, iaculis sit amet est. Morbi non lacus at dolor euismod molestie. Integer pulvinar, nibh in volutpat tincidunt, urna odio interdum magna, vitae faucibus felis quam nec est. Proin tellus quam, auctor nec dictum sed, rhoncus nec massa. Mauris ac arcu ac augue porta viverra. Quisque semper eget nisi quis viverra. Donec vitae mauris ipsum. Duis tempor pulvinar viverra. Nam dignissim iaculis felis, eget vestibulum eros. Nulla eget faucibus massa. Integer sollicitudin pretium erat, vel commodo nunc congue non. Nulla in nunc auctor dui efficitur euismod. Sed pharetra sapien erat, a blandit neque porttitor sit amet. Mauris pharetra sodales maximus. Nulla volutpat auctor quam, a elementum risus tristique eu. In ac sodales nibh. Maecenas pharetra orci sem, eu laoreet quam tincidunt non. Mauris in interdum dui. Vivamus et interdum erat. Aliquam nec ante tincidunt, elementum risus in, mattis orci. Sed massa turpis, blandit a rutrum at, dignissim et lectus. Nunc tincidunt orci nibh, id ullamcorper nisl vestibulum vel.</div>
+<div style="text-align: right">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec consequat rhoncus erat, id pellentesque ligula aliquet et. Nam aliquam pellentesque risus. Mauris lorem nunc, sodales pellentesque porttitor ut, pellentesque at felis. Nullam et accumsan leo, in scelerisque massa. Fusce luctus laoreet pretium. Nulla sollicitudin volutpat neque in mattis. Vestibulum non placerat velit. Aenean dui nunc, tincidunt nec tempus et, venenatis vel magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin pretium nisl sit amet lacus varius consequat. Donec congue molestie mauris, a vehicula velit. Nam pellentesque sed arcu congue rutrum. Maecenas pulvinar ex at diam dapibus consectetur ut non nisl. Sed tempus bibendum sodales. Donec nec arcu ligula. Vivamus sit amet aliquet neque, vel volutpat nibh. In purus sem, tincidunt vulputate neque eu, scelerisque hendrerit ex. Donec eu porta lectus, at malesuada magna. Duis ut egestas est. Nullam et libero sit amet lectus tempus pharetra ac id mauris. Ut diam orci, interdum nec suscipit ut, semper nec orci. Fusce sed risus elementum, posuere orci id, aliquam urna. Donec arcu turpis, scelerisque a mauris vel, vehicula convallis ipsum. Phasellus facilisis, magna ut dapibus pretium, sapien mauris viverra enim, ut hendrerit urna dui eu ligula. Nulla vestibulum et nibh quis laoreet. Quisque feugiat arcu ipsum, id mollis quam sagittis at. Morbi tempus, risus molestie ultricies viverra, justo augue facilisis orci, a semper risus dui pellentesque purus. Curabitur facilisis arcu quam, id facilisis turpis aliquam ac. Maecenas efficitur risus pellentesque sem maximus euismod. Proin aliquet justo ac dolor faucibus porttitor. Fusce orci lectus, eleifend at lectus sit amet, pretium ornare felis. Nullam nec ipsum maximus, molestie arcu in, finibus urna. Suspendisse tincidunt feugiat est, in viverra lectus tincidunt quis. Ut eros tortor, tincidunt vel commodo hendrerit, consequat vel neque. Vestibulum enim nibh, accumsan quis viverra ut, iaculis sit amet est. Morbi non lacus at dolor euismod molestie. Integer pulvinar, nibh in volutpat tincidunt, urna odio interdum magna, vitae faucibus felis quam nec est. Proin tellus quam, auctor nec dictum sed, rhoncus nec massa. Mauris ac arcu ac augue porta viverra. Quisque semper eget nisi quis viverra. Donec vitae mauris ipsum. Duis tempor pulvinar viverra. Nam dignissim iaculis felis, eget vestibulum eros. Nulla eget faucibus massa. Integer sollicitudin pretium erat, vel commodo nunc congue non. Nulla in nunc auctor dui efficitur euismod. Sed pharetra sapien erat, a blandit neque porttitor sit amet. Mauris pharetra sodales maximus. Nulla volutpat auctor quam, a elementum risus tristique eu. In ac sodales nibh. Maecenas pharetra orci sem, eu laoreet quam tincidunt non. Mauris in interdum dui. Vivamus et interdum erat. Aliquam nec ante tincidunt, elementum risus in, mattis orci. Sed massa turpis, blandit a rutrum at, dignissim et lectus. Nunc tincidunt orci nibh, id ullamcorper nisl vestibulum vel.</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/text/simple-line-hyphens-with-word-letter-spacing-expected.html b/LayoutTests/fast/text/simple-line-hyphens-with-word-letter-spacing-expected.html
new file mode 100644 (file)
index 0000000..23080df
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>This tests that simple and normal line layout produce the same lines with hyphens</title>
+<style>
+div {
+  display: inline-block;
+  -webkit-hyphens: auto; 
+  width: 200px;
+  border: 1px solid green;
+}
+</style>
+<script>
+if (internal.settings)
+    internals.settings.setSimpleLineLayoutEnabled(false);
+</script>
+</head>
+<body>
+<div style="word-spacing: 30px">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec consequat rhoncus erat, id pellentesque ligula aliquet et. Nam aliquam pellentesque risus. Mauris lorem nunc, sodales pellentesque porttitor ut, pellentesque at felis. Nullam et accumsan leo, in scelerisque massa. Fusce luctus laoreet pretium. Nulla sollicitudin volutpat neque in mattis. Vestibulum non placerat velit. Aenean dui nunc, tincidunt nec tempus et, venenatis vel magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin pretium nisl sit amet lacus varius consequat. Donec congue molestie mauris, a vehicula velit. Nam pellentesque sed arcu congue rutrum. Maecenas pulvinar ex at diam dapibus consectetur ut non nisl. Sed tempus bibendum sodales. Donec nec arcu ligula. Vivamus sit amet aliquet neque, vel volutpat nibh. In purus sem, tincidunt vulputate neque eu, scelerisque hendrerit ex. Donec eu porta lectus, at malesuada magna. Duis ut egestas est. Nullam et libero sit amet lectus tempus pharetra ac id mauris. Ut diam orci, interdum nec suscipit ut, semper nec orci. Fusce sed risus elementum, posuere orci id, aliquam urna. Donec arcu turpis, scelerisque a mauris vel, vehicula convallis ipsum. Phasellus facilisis, magna ut dapibus pretium, sapien mauris viverra enim, ut hendrerit urna dui eu ligula. Nulla vestibulum et nibh quis laoreet. Quisque feugiat arcu ipsum, id mollis quam sagittis at. Morbi tempus, risus molestie ultricies viverra, justo augue facilisis orci, a semper risus dui pellentesque purus. Curabitur facilisis arcu quam, id facilisis turpis aliquam ac. Maecenas efficitur risus pellentesque sem maximus euismod. Proin aliquet justo ac dolor faucibus porttitor. Fusce orci lectus, eleifend at lectus sit amet, pretium ornare felis. Nullam nec ipsum maximus, molestie arcu in, finibus urna. Suspendisse tincidunt feugiat est, in viverra lectus tincidunt quis. Ut eros tortor, tincidunt vel commodo hendrerit, consequat vel neque. Vestibulum enim nibh, accumsan quis viverra ut, iaculis sit amet est. Morbi non lacus at dolor euismod molestie. Integer pulvinar, nibh in volutpat tincidunt, urna odio interdum magna, vitae faucibus felis quam nec est. Proin tellus quam, auctor nec dictum sed, rhoncus nec massa. Mauris ac arcu ac augue porta viverra. Quisque semper eget nisi quis viverra. Donec vitae mauris ipsum. Duis tempor pulvinar viverra. Nam dignissim iaculis felis, eget vestibulum eros. Nulla eget faucibus massa. Integer sollicitudin pretium erat, vel commodo nunc congue non. Nulla in nunc auctor dui efficitur euismod. Sed pharetra sapien erat, a blandit neque porttitor sit amet. Mauris pharetra sodales maximus. Nulla volutpat auctor quam, a elementum risus tristique eu. In ac sodales nibh. Maecenas pharetra orci sem, eu laoreet quam tincidunt non. Mauris in interdum dui. Vivamus et interdum erat. Aliquam nec ante tincidunt, elementum risus in, mattis orci. Sed massa turpis, blandit a rutrum at, dignissim et lectus. Nunc tincidunt orci nibh, id ullamcorper nisl vestibulum vel.</div>
+<div style="letter-spacing: 3px">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec consequat rhoncus erat, id pellentesque ligula aliquet et. Nam aliquam pellentesque risus. Mauris lorem nunc, sodales pellentesque porttitor ut, pellentesque at felis. Nullam et accumsan leo, in scelerisque massa. Fusce luctus laoreet pretium. Nulla sollicitudin volutpat neque in mattis. Vestibulum non placerat velit. Aenean dui nunc, tincidunt nec tempus et, venenatis vel magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin pretium nisl sit amet lacus varius consequat. Donec congue molestie mauris, a vehicula velit. Nam pellentesque sed arcu congue rutrum. Maecenas pulvinar ex at diam dapibus consectetur ut non nisl. Sed tempus bibendum sodales. Donec nec arcu ligula. Vivamus sit amet aliquet neque, vel volutpat nibh. In purus sem, tincidunt vulputate neque eu, scelerisque hendrerit ex. Donec eu porta lectus, at malesuada magna. Duis ut egestas est. Nullam et libero sit amet lectus tempus pharetra ac id mauris. Ut diam orci, interdum nec suscipit ut, semper nec orci. Fusce sed risus elementum, posuere orci id, aliquam urna. Donec arcu turpis, scelerisque a mauris vel, vehicula convallis ipsum. Phasellus facilisis, magna ut dapibus pretium, sapien mauris viverra enim, ut hendrerit urna dui eu ligula. Nulla vestibulum et nibh quis laoreet. Quisque feugiat arcu ipsum, id mollis quam sagittis at. Morbi tempus, risus molestie ultricies viverra, justo augue facilisis orci, a semper risus dui pellentesque purus. Curabitur facilisis arcu quam, id facilisis turpis aliquam ac. Maecenas efficitur risus pellentesque sem maximus euismod. Proin aliquet justo ac dolor faucibus porttitor. Fusce orci lectus, eleifend at lectus sit amet, pretium ornare felis. Nullam nec ipsum maximus, molestie arcu in, finibus urna. Suspendisse tincidunt feugiat est, in viverra lectus tincidunt quis. Ut eros tortor, tincidunt vel commodo hendrerit, consequat vel neque. Vestibulum enim nibh, accumsan quis viverra ut, iaculis sit amet est. Morbi non lacus at dolor euismod molestie. Integer pulvinar, nibh in volutpat tincidunt, urna odio interdum magna, vitae faucibus felis quam nec est. Proin tellus quam, auctor nec dictum sed, rhoncus nec massa. Mauris ac arcu ac augue porta viverra. Quisque semper eget nisi quis viverra. Donec vitae mauris ipsum. Duis tempor pulvinar viverra. Nam dignissim iaculis felis, eget vestibulum eros. Nulla eget faucibus massa. Integer sollicitudin pretium erat, vel commodo nunc congue non. Nulla in nunc auctor dui efficitur euismod. Sed pharetra sapien erat, a blandit neque porttitor sit amet. Mauris pharetra sodales maximus. Nulla volutpat auctor quam, a elementum risus tristique eu. In ac sodales nibh. Maecenas pharetra orci sem, eu laoreet quam tincidunt non. Mauris in interdum dui. Vivamus et interdum erat. Aliquam nec ante tincidunt, elementum risus in, mattis orci. Sed massa turpis, blandit a rutrum at, dignissim et lectus. Nunc tincidunt orci nibh, id ullamcorper nisl vestibulum vel.</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/text/simple-line-hyphens-with-word-letter-spacing.html b/LayoutTests/fast/text/simple-line-hyphens-with-word-letter-spacing.html
new file mode 100644 (file)
index 0000000..8f10942
--- /dev/null
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>This tests that simple and normal line layout produce the same lines with hyphens</title>
+<style>
+div {
+  display: inline-block;
+  -webkit-hyphens: auto; 
+  width: 200px;
+  border: 1px solid green;
+}
+</style>
+</head>
+<body>
+<div style="word-spacing: 30px">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec consequat rhoncus erat, id pellentesque ligula aliquet et. Nam aliquam pellentesque risus. Mauris lorem nunc, sodales pellentesque porttitor ut, pellentesque at felis. Nullam et accumsan leo, in scelerisque massa. Fusce luctus laoreet pretium. Nulla sollicitudin volutpat neque in mattis. Vestibulum non placerat velit. Aenean dui nunc, tincidunt nec tempus et, venenatis vel magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin pretium nisl sit amet lacus varius consequat. Donec congue molestie mauris, a vehicula velit. Nam pellentesque sed arcu congue rutrum. Maecenas pulvinar ex at diam dapibus consectetur ut non nisl. Sed tempus bibendum sodales. Donec nec arcu ligula. Vivamus sit amet aliquet neque, vel volutpat nibh. In purus sem, tincidunt vulputate neque eu, scelerisque hendrerit ex. Donec eu porta lectus, at malesuada magna. Duis ut egestas est. Nullam et libero sit amet lectus tempus pharetra ac id mauris. Ut diam orci, interdum nec suscipit ut, semper nec orci. Fusce sed risus elementum, posuere orci id, aliquam urna. Donec arcu turpis, scelerisque a mauris vel, vehicula convallis ipsum. Phasellus facilisis, magna ut dapibus pretium, sapien mauris viverra enim, ut hendrerit urna dui eu ligula. Nulla vestibulum et nibh quis laoreet. Quisque feugiat arcu ipsum, id mollis quam sagittis at. Morbi tempus, risus molestie ultricies viverra, justo augue facilisis orci, a semper risus dui pellentesque purus. Curabitur facilisis arcu quam, id facilisis turpis aliquam ac. Maecenas efficitur risus pellentesque sem maximus euismod. Proin aliquet justo ac dolor faucibus porttitor. Fusce orci lectus, eleifend at lectus sit amet, pretium ornare felis. Nullam nec ipsum maximus, molestie arcu in, finibus urna. Suspendisse tincidunt feugiat est, in viverra lectus tincidunt quis. Ut eros tortor, tincidunt vel commodo hendrerit, consequat vel neque. Vestibulum enim nibh, accumsan quis viverra ut, iaculis sit amet est. Morbi non lacus at dolor euismod molestie. Integer pulvinar, nibh in volutpat tincidunt, urna odio interdum magna, vitae faucibus felis quam nec est. Proin tellus quam, auctor nec dictum sed, rhoncus nec massa. Mauris ac arcu ac augue porta viverra. Quisque semper eget nisi quis viverra. Donec vitae mauris ipsum. Duis tempor pulvinar viverra. Nam dignissim iaculis felis, eget vestibulum eros. Nulla eget faucibus massa. Integer sollicitudin pretium erat, vel commodo nunc congue non. Nulla in nunc auctor dui efficitur euismod. Sed pharetra sapien erat, a blandit neque porttitor sit amet. Mauris pharetra sodales maximus. Nulla volutpat auctor quam, a elementum risus tristique eu. In ac sodales nibh. Maecenas pharetra orci sem, eu laoreet quam tincidunt non. Mauris in interdum dui. Vivamus et interdum erat. Aliquam nec ante tincidunt, elementum risus in, mattis orci. Sed massa turpis, blandit a rutrum at, dignissim et lectus. Nunc tincidunt orci nibh, id ullamcorper nisl vestibulum vel.</div>
+<div style="letter-spacing: 3px">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec consequat rhoncus erat, id pellentesque ligula aliquet et. Nam aliquam pellentesque risus. Mauris lorem nunc, sodales pellentesque porttitor ut, pellentesque at felis. Nullam et accumsan leo, in scelerisque massa. Fusce luctus laoreet pretium. Nulla sollicitudin volutpat neque in mattis. Vestibulum non placerat velit. Aenean dui nunc, tincidunt nec tempus et, venenatis vel magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin pretium nisl sit amet lacus varius consequat. Donec congue molestie mauris, a vehicula velit. Nam pellentesque sed arcu congue rutrum. Maecenas pulvinar ex at diam dapibus consectetur ut non nisl. Sed tempus bibendum sodales. Donec nec arcu ligula. Vivamus sit amet aliquet neque, vel volutpat nibh. In purus sem, tincidunt vulputate neque eu, scelerisque hendrerit ex. Donec eu porta lectus, at malesuada magna. Duis ut egestas est. Nullam et libero sit amet lectus tempus pharetra ac id mauris. Ut diam orci, interdum nec suscipit ut, semper nec orci. Fusce sed risus elementum, posuere orci id, aliquam urna. Donec arcu turpis, scelerisque a mauris vel, vehicula convallis ipsum. Phasellus facilisis, magna ut dapibus pretium, sapien mauris viverra enim, ut hendrerit urna dui eu ligula. Nulla vestibulum et nibh quis laoreet. Quisque feugiat arcu ipsum, id mollis quam sagittis at. Morbi tempus, risus molestie ultricies viverra, justo augue facilisis orci, a semper risus dui pellentesque purus. Curabitur facilisis arcu quam, id facilisis turpis aliquam ac. Maecenas efficitur risus pellentesque sem maximus euismod. Proin aliquet justo ac dolor faucibus porttitor. Fusce orci lectus, eleifend at lectus sit amet, pretium ornare felis. Nullam nec ipsum maximus, molestie arcu in, finibus urna. Suspendisse tincidunt feugiat est, in viverra lectus tincidunt quis. Ut eros tortor, tincidunt vel commodo hendrerit, consequat vel neque. Vestibulum enim nibh, accumsan quis viverra ut, iaculis sit amet est. Morbi non lacus at dolor euismod molestie. Integer pulvinar, nibh in volutpat tincidunt, urna odio interdum magna, vitae faucibus felis quam nec est. Proin tellus quam, auctor nec dictum sed, rhoncus nec massa. Mauris ac arcu ac augue porta viverra. Quisque semper eget nisi quis viverra. Donec vitae mauris ipsum. Duis tempor pulvinar viverra. Nam dignissim iaculis felis, eget vestibulum eros. Nulla eget faucibus massa. Integer sollicitudin pretium erat, vel commodo nunc congue non. Nulla in nunc auctor dui efficitur euismod. Sed pharetra sapien erat, a blandit neque porttitor sit amet. Mauris pharetra sodales maximus. Nulla volutpat auctor quam, a elementum risus tristique eu. In ac sodales nibh. Maecenas pharetra orci sem, eu laoreet quam tincidunt non. Mauris in interdum dui. Vivamus et interdum erat. Aliquam nec ante tincidunt, elementum risus in, mattis orci. Sed massa turpis, blandit a rutrum at, dignissim et lectus. Nunc tincidunt orci nibh, id ullamcorper nisl vestibulum vel.</div>
+</body>
+</html>
index 2bc231c..c2fab6f 100644 (file)
@@ -1,3 +1,57 @@
+2017-01-24  Zalan Bujtas  <zalan@apple.com>
+
+        Simple line layout: Add support for hyphen: auto.
+        https://bugs.webkit.org/show_bug.cgi?id=167297
+        <rdar://problem/30119463>
+
+        Reviewed by Antti Koivisto.
+
+        Implement hyphen: auto for simple line layout. 
+
+        Tests: fast/text/simple-line-hyphens-with-text-align.html
+               fast/text/simple-line-hyphens-with-word-letter-spacing.html
+
+        * platform/text/Hyphenation.h:
+        (WebCore::enoughWidthForHyphenation):
+        * rendering/RenderTreeAsText.cpp:
+        (WebCore::writeSimpleLine):
+        (WebCore::write):
+        * rendering/SimpleLineLayout.cpp:
+        (WebCore::SimpleLineLayout::canUseForStyle):
+        (WebCore::SimpleLineLayout::LineState::appendFragmentAndCreateRunIfNeeded): Inherit the hyphen attribute from the
+        run-to-be-appended. Ensure that we don't append additional runs when the last run has hyphen.
+        (WebCore::SimpleLineLayout::splitFragmentToFitLine): Before calling into the lastHyphenPosition() we need to
+        ensure that the hyphen would surely fit (even on the splitting position).
+        (WebCore::SimpleLineLayout::createLineRuns): Probe hypenation for overhanging non-whitespace runs. 
+        (WebCore::SimpleLineLayout::printReason):
+        * rendering/SimpleLineLayout.h:
+        (WebCore::SimpleLineLayout::Run::Run):
+        * rendering/SimpleLineLayoutFlowContents.h:
+        (WebCore::SimpleLineLayout::FlowContents::Segment::toSegmentPosition):
+        (WebCore::SimpleLineLayout::FlowContents::Segment::toRenderPosition):
+        * rendering/SimpleLineLayoutResolver.cpp:
+        (WebCore::SimpleLineLayout::RunResolver::Run::Run):
+        (WebCore::SimpleLineLayout::RunResolver::Run::constructStringForHyphenIfNeeded):
+        (WebCore::SimpleLineLayout::RunResolver::Run::text):
+        * rendering/SimpleLineLayoutResolver.h:
+        (WebCore::SimpleLineLayout::RunResolver::Run::hasHyphen):
+        * rendering/SimpleLineLayoutTextFragmentIterator.cpp:
+        (WebCore::SimpleLineLayout::TextFragmentIterator::Style::Style):
+        (WebCore::SimpleLineLayout::TextFragmentIterator::nextBreakablePosition):
+        (WebCore::SimpleLineLayout::TextFragmentIterator::nextNonWhitespacePosition):
+        (WebCore::SimpleLineLayout::TextFragmentIterator::textWidth):
+        (WebCore::SimpleLineLayout::TextFragmentIterator::lastHyphenPosition): We only check the actual run for hyphenation ignoring
+        the neighboring runs. This might need to be changed in the future.
+        (WebCore::SimpleLineLayout::TextFragmentIterator::runWidth):
+        * rendering/SimpleLineLayoutTextFragmentIterator.h:
+        (WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::TextFragment):
+        (WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::hasHyphen):
+        (WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::operator==):
+        (WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::split):
+        (WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::splitWithHyphen):
+        * rendering/line/BreakingContext.h:
+        (WebCore::tryHyphenating):
+
 2017-01-24  Matt Rajca  <mrajca@apple.com>
 
         Pass down website autoplay policies to media elements
index 38f2af1..27f4305 100644 (file)
 
 namespace WebCore {
 
+inline static bool enoughWidthForHyphenation(float availableWidth, float fontPixelSize)
+{
+    // If the maximum width available for the prefix before the hyphen is small, then it is very unlikely
+    // that an hyphenation opportunity exists, so do not bother to look for it.
+    return availableWidth > fontPixelSize * 5 / 4;
+
+}
 bool canHyphenate(const AtomicString& localeIdentifier);
 size_t lastHyphenLocation(StringView, size_t beforeIndex, const AtomicString& localeIdentifier);
 
index 0b621c1..34b9de4 100644 (file)
@@ -493,18 +493,23 @@ static void writeTextRun(TextStream& ts, const RenderText& o, const InlineTextBo
     ts << "\n";
 }
 
-static void writeSimpleLine(TextStream& ts, const RenderText& o, const FloatRect& rect, StringView text)
+static void writeSimpleLine(TextStream& ts, const RenderText& renderText, const SimpleLineLayout::RunResolver::Run& run)
 {
+    auto rect = run.rect();
     int x = rect.x();
     int y = rect.y();
     int logicalWidth = ceilf(rect.x() + rect.width()) - x;
 
-    if (is<RenderTableCell>(*o.containingBlock()))
-        y -= floorToInt(downcast<RenderTableCell>(*o.containingBlock()).intrinsicPaddingBefore());
-        
+    if (is<RenderTableCell>(*renderText.containingBlock()))
+        y -= floorToInt(downcast<RenderTableCell>(*renderText.containingBlock()).intrinsicPaddingBefore());
+
     ts << "text run at (" << x << "," << y << ") width " << logicalWidth;
-    ts << ": "
-        << quoteAndEscapeNonPrintables(text);
+    if (run.hasHyphen()) {
+        ts << ": " << quoteAndEscapeNonPrintables(run.text().substring(0, run.text().length() - 1));
+        ts << " + hyphen string " << quoteAndEscapeNonPrintables(renderText.style().hyphenString().string());
+    } else
+        ts << ": " << quoteAndEscapeNonPrintables(run.text());
+
     ts << "\n";
 }
 
@@ -555,7 +560,7 @@ void write(TextStream& ts, const RenderObject& o, int indent, RenderAsTextBehavi
             auto resolver = runResolver(downcast<RenderBlockFlow>(*text.parent()), *layout);
             for (const auto& run : resolver.rangeForRenderer(text)) {
                 writeIndent(ts, indent + 1);
-                writeSimpleLine(ts, text, run.rect(), run.text());
+                writeSimpleLine(ts, text, run);
             }
         } else {
             for (auto* box = text.firstTextBox(); box; box = box->nextTextBox()) {
index e88258d..749cb98 100644 (file)
@@ -33,6 +33,7 @@
 #include "HitTestLocation.h"
 #include "HitTestRequest.h"
 #include "HitTestResult.h"
+#include "Hyphenation.h"
 #include "InlineTextBox.h"
 #include "LineWidth.h"
 #include "Logging.h"
@@ -85,7 +86,7 @@ enum AvoidanceReason_ : uint64_t {
     FlowHasRTLOrdering                    = 1LLU  << 20,
     FlowHasLineAlignEdges                 = 1LLU  << 21,
     FlowHasLineSnap                       = 1LLU  << 22,
-    FlowHasHypensAuto                     = 1LLU  << 23,
+    FlowHasHypensLimit                    = 1LLU  << 23,
     FlowHasTextEmphasisFillOrMark         = 1LLU  << 24,
     FlowHasTextShadow                     = 1LLU  << 25,
     FlowHasPseudoFirstLine                = 1LLU  << 26,
@@ -236,8 +237,10 @@ static AvoidanceReasonFlags canUseForStyle(const RenderStyle& style, IncludeReas
         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasLineAlignEdges, reasons, includeReasons);
     if (style.lineSnap() != LineSnapNone)
         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasLineSnap, reasons, includeReasons);
-    if (style.hyphens() == HyphensAuto)
-        SET_REASON_AND_RETURN_IF_NEEDED(FlowHasHypensAuto, reasons, includeReasons);
+    if (style.hyphenationLimitBefore() != RenderStyle::initialHyphenationLimitBefore()
+        || style.hyphenationLimitAfter() != RenderStyle::initialHyphenationLimitAfter()
+        || style.hyphenationLimitLines() != RenderStyle::initialHyphenationLimitLines())
+        SET_REASON_AND_RETURN_IF_NEEDED(FlowHasHypensLimit, reasons, includeReasons);
     if (style.textEmphasisFill() != TextEmphasisFillFilled || style.textEmphasisMark() != TextEmphasisMarkNone)
         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasTextEmphasisFillOrMark, reasons, includeReasons);
     if (style.textShadow())
@@ -453,7 +456,7 @@ public:
         unsigned endPosition = fragment.isCollapsed() ? fragment.start() + 1 : fragment.end();
         // New line needs new run.
         if (!m_runsWidth)
-            runs.append(Run(fragment.start(), endPosition, m_runsWidth, m_runsWidth + fragment.width(), false));
+            runs.append(Run(fragment.start(), endPosition, m_runsWidth, m_runsWidth + fragment.width(), false, fragment.hasHyphen()));
         else {
             const auto& lastFragment = m_fragments.last();
             // Advance last completed fragment when the previous fragment is all set (including multiple parts across renderers)
@@ -470,11 +473,13 @@ public:
                 return;
             }
             if (lastFragment.isLastInRenderer() || lastFragment.isCollapsed())
-                runs.append(Run(fragment.start(), endPosition, m_runsWidth, m_runsWidth + fragment.width(), false));
+                runs.append(Run(fragment.start(), endPosition, m_runsWidth, m_runsWidth + fragment.width(), false, fragment.hasHyphen()));
             else {
                 Run& lastRun = runs.last();
                 lastRun.end = endPosition;
                 lastRun.logicalRight += fragment.width();
+                ASSERT(!lastRun.hasHyphen);
+                lastRun.hasHyphen = fragment.hasHyphen();
             }
         }
         m_fragments.append(fragment);
@@ -623,8 +628,26 @@ static TextFragmentIterator::TextFragment splitFragmentToFitLine(TextFragmentIte
         return availableWidth < textFragmentIterator.textWidth(start, index + 1, 0);
     });
     unsigned splitPosition = (*it);
-    if (keepAtLeastOneCharacter && splitPosition == fragmentToSplit.start())
-        ++splitPosition;
+    auto& style = textFragmentIterator.style();
+    // Does first character fit this line?
+    if (splitPosition == fragmentToSplit.start()) {
+        if (keepAtLeastOneCharacter)
+            ++splitPosition;
+    } else if (style.shouldHyphenate && enoughWidthForHyphenation(availableWidth, style.font.pixelSize())) {
+        // We might be able to fit the hyphen at the split position.
+        auto splitPositionWithHyphen = splitPosition;
+        // Find a splitting position where hyphen surely fits.
+        auto leftSideWidth = textFragmentIterator.textWidth(start, splitPosition, 0);
+        while (leftSideWidth + style.hyphenStringWidth > availableWidth) {
+            if (--splitPositionWithHyphen <= start)
+                break; // No space for hyphen.
+            leftSideWidth -= textFragmentIterator.textWidth(splitPositionWithHyphen, splitPositionWithHyphen + 1, 0);
+        }
+        if (splitPositionWithHyphen > start) {
+            if (auto hyphenPosition = textFragmentIterator.lastHyphenPosition(fragmentToSplit, splitPositionWithHyphen + 1))
+                return fragmentToSplit.splitWithHyphen(*hyphenPosition, textFragmentIterator);
+        }
+    }
     return fragmentToSplit.split(splitPosition, textFragmentIterator);
 }
 
@@ -736,8 +759,20 @@ static bool createLineRuns(LineState& line, const LineState& previousLine, Layou
                 line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
                 break;
             }
-            // Non-breakable non-whitespace first fragment. Add it to the current line. -it overflows though.
             ASSERT(fragment.type() == TextFragmentIterator::TextFragment::NonWhitespace);
+            // Find out if this non-whitespace fragment has a hyphen where we can break.
+            if (style.shouldHyphenate) {
+                auto fragmentToSplit = fragment;
+                // Split and check if we actually ended up with a hyphen.
+                auto overflowFragment = splitFragmentToFitLine(fragmentToSplit, line.availableWidth() - line.width(), emptyLine, textFragmentIterator);
+                if (fragmentToSplit.hasHyphen()) {
+                    line.setOverflowedFragment(overflowFragment);
+                    line.appendFragmentAndCreateRunIfNeeded(fragmentToSplit, runs);
+                    break;
+                }
+                // No hyphen, no split.
+            }
+            // Non-breakable non-whitespace first fragment. Add it to the current line. -it overflows though.
             if (emptyLine) {
                 forceFragmentToLine(line, textFragmentIterator, runs, fragment);
                 break;
@@ -956,8 +991,8 @@ static void printReason(AvoidanceReason reason, TextStream& stream)
     case FlowHasLineSnap:
         stream << "-webkit-line-snap property";
         break;
-    case FlowHasHypensAuto:
-        stream << "hyphen: auto";
+    case FlowHasHypensLimit:
+        stream << "hyphen-limit-* property";
         break;
     case FlowHasTextEmphasisFillOrMark:
         stream << "text-emphasis (fill/mark)";
index f655438..b288e04 100644 (file)
@@ -46,17 +46,19 @@ struct Run {
 #if COMPILER(MSVC)
     Run() { }
 #endif
-    Run(unsigned start, unsigned end, float logicalLeft, float logicalRight, bool isEndOfLine)
-        : start(start)
-        , end(end)
+    Run(unsigned start, unsigned end, float logicalLeft, float logicalRight, bool isEndOfLine, bool hasHyphen)
+        : end(end)
+        , start(start)
         , isEndOfLine(isEndOfLine)
+        , hasHyphen(hasHyphen)
         , logicalLeft(logicalLeft)
         , logicalRight(logicalRight)
     { }
 
-    unsigned start;
-    unsigned end : 31;
+    unsigned end;
+    unsigned start : 30;
     unsigned isEndOfLine : 1;
+    unsigned hasHyphen : 1;
     float logicalLeft;
     float logicalRight;
     // TODO: Move these optional items out of SimpleLineLayout::Run to a supplementary structure.
index e80198c..bb331ec 100644 (file)
@@ -37,6 +37,12 @@ public:
     FlowContents(const RenderBlockFlow&);
 
     struct Segment {
+        unsigned toSegmentPosition(unsigned position) const
+        {
+            ASSERT(position >= start);
+            return position - start;
+        }
+        unsigned toRenderPosition(unsigned position) const { return start + position; }
         unsigned start;
         unsigned end;
         String text;
index a4b61ae..eca5f13 100644 (file)
@@ -47,6 +47,19 @@ static FloatSize lineSize(float logicalLeft, float logicalRight, float height)
 RunResolver::Run::Run(const Iterator& iterator)
     : m_iterator(iterator)
 {
+    constructStringForHyphenIfNeeded();
+}
+
+void RunResolver::Run::constructStringForHyphenIfNeeded()
+{
+    auto& run = m_iterator.simpleRun();
+    if (!run.hasHyphen)
+        return;
+    // Empty runs should not have hyphen.
+    ASSERT(run.start < run.end);
+    auto& segment = m_iterator.resolver().m_flowContents.segmentForRun(run.start, run.end);
+    auto text = StringView(segment.text).substring(segment.toSegmentPosition(run.start), run.end - run.start);
+    m_textWithHyphen = makeString(text, m_iterator.resolver().flow().style().hyphenString());
 }
 
 FloatRect RunResolver::Run::rect() const
@@ -69,12 +82,14 @@ FloatRect RunResolver::Run::rect() const
 
 StringView RunResolver::Run::text() const
 {
+    if (m_textWithHyphen)
+        return StringView(*m_textWithHyphen);
     auto& run = m_iterator.simpleRun();
     ASSERT(run.start < run.end);
     auto& segment = m_iterator.resolver().m_flowContents.segmentForRun(run.start, run.end);
     // We currently split runs on segment boundaries (different RenderObject).
     ASSERT(run.end <= segment.end);
-    return StringView(segment.text).substring(run.start - segment.start, run.end - run.start);
+    return StringView(segment.text).substring(segment.toSegmentPosition(run.start), run.end - run.start);
 }
 
 RunResolver::Iterator::Iterator(const RunResolver& resolver, unsigned runIndex, unsigned lineIndex)
index db6dd1d..84c768b 100644 (file)
@@ -65,13 +65,16 @@ public:
         int baselinePosition() const;
         StringView text() const;
         bool isEndOfLine() const;
+        bool hasHyphen() const { return m_iterator.simpleRun().hasHyphen; }
 
         unsigned lineIndex() const;
 
     private:
         float computeBaselinePosition() const;
+        void constructStringForHyphenIfNeeded();
 
         const Iterator& m_iterator;
+        std::optional<String> m_textWithHyphen;
     };
 
     class Iterator {
index e9ac6ed..a6d5e72 100644 (file)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "SimpleLineLayoutTextFragmentIterator.h"
 
+#include "Hyphenation.h"
 #include "RenderBlockFlow.h"
 #include "RenderChildIterator.h"
 #include "SimpleLineLayoutFlowContents.h"
@@ -46,6 +47,8 @@ TextFragmentIterator::Style::Style(const RenderStyle& style)
     , spaceWidth(font.width(TextRun(StringView(&space, 1))))
     , wordSpacing(font.wordSpacing())
     , tabWidth(collapseWhitespace ? 0 : style.tabSize())
+    , shouldHyphenate(style.hyphens() == HyphensAuto && canHyphenate(style.locale()))
+    , hyphenStringWidth(shouldHyphenate ? font.width(TextRun(style.hyphenString())) : 0)
     , locale(style.locale())
 {
 }
@@ -143,8 +146,7 @@ unsigned TextFragmentIterator::nextBreakablePosition(const FlowContents::Segment
         m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter);
         m_lineBreakIterator.resetStringAndReleaseIterator(segment.text, m_style.locale, LineBreakIteratorMode::Default);
     }
-    unsigned segmentPosition = startPosition - segment.start;
-    return segment.start + nextBreakablePositionInSegment(m_lineBreakIterator, segmentPosition, m_style.breakNBSP, m_style.keepAllWordsForCJK);
+    return segment.toRenderPosition(nextBreakablePositionInSegment(m_lineBreakIterator, segment.toSegmentPosition(startPosition), m_style.breakNBSP, m_style.keepAllWordsForCJK));
 }
 
 template <typename CharacterType>
@@ -154,7 +156,7 @@ unsigned TextFragmentIterator::nextNonWhitespacePosition(const FlowContents::Seg
     const auto* text = segment.text.characters<CharacterType>();
     unsigned position = startPosition;
     for (; position < segment.end; ++position) {
-        auto character = text[position - segment.start];
+        auto character = text[segment.toSegmentPosition(position)];
         bool isWhitespace = character == ' ' || character == '\t' || (!m_style.preserveNewline && character == '\n');
         if (!isWhitespace)
             return position;
@@ -170,10 +172,28 @@ float TextFragmentIterator::textWidth(unsigned from, unsigned to, float xPositio
     if (!m_style.font.size())
         return 0;
     if (m_style.font.isFixedPitch() || (from == segment.start && to == segment.end))
-        return downcast<RenderText>(segment.renderer).width(from - segment.start, to - from, m_style.font, xPosition, nullptr, nullptr);
+        return downcast<RenderText>(segment.renderer).width(segment.toSegmentPosition(from), to - from, m_style.font, xPosition, nullptr, nullptr);
     return runWidth(segment, from, to, xPosition);
 }
 
+std::optional<unsigned> TextFragmentIterator::lastHyphenPosition(const TextFragmentIterator::TextFragment& run, unsigned beforeIndex) const
+{
+    ASSERT(run.start() < beforeIndex);
+    auto& segment = *m_currentSegment;
+    ASSERT(segment.start <= beforeIndex && beforeIndex <= segment.end);
+    ASSERT(is<RenderText>(segment.renderer));
+    if (!m_style.shouldHyphenate || run.type() != TextFragment::NonWhitespace)
+        return std::nullopt;
+    
+    auto runStart = segment.toSegmentPosition(run.start());
+    auto before = segment.toSegmentPosition(beforeIndex) - runStart;
+    auto substringForHyphenation = StringView(segment.text).substring(runStart, run.end() - run.start());
+    auto hyphenLocation = lastHyphenLocation(substringForHyphenation, before, m_style.locale);
+    if (hyphenLocation)
+        return segment.toRenderPosition(hyphenLocation + runStart);
+    return std::nullopt;
+}
+
 unsigned TextFragmentIterator::skipToNextPosition(PositionType positionType, unsigned startPosition, float& width, float xPosition, bool& overlappingFragment)
 {
     overlappingFragment = false;
@@ -219,8 +239,8 @@ float TextFragmentIterator::runWidth(const FlowContents::Segment& segment, unsig
     ASSERT(startPosition <= endPosition);
     if (startPosition == endPosition)
         return 0;
-    unsigned segmentFrom = startPosition - segment.start;
-    unsigned segmentTo = endPosition - segment.start;
+    unsigned segmentFrom = segment.toSegmentPosition(startPosition);
+    unsigned segmentTo = segment.toSegmentPosition(endPosition);
     bool measureWithEndSpace = m_style.collapseWhitespace && segmentTo < segment.text.length() && segment.text[segmentTo] == ' ';
     if (measureWithEndSpace)
         ++segmentTo;
index 8ca8843..ad78499 100644 (file)
@@ -43,7 +43,7 @@ public:
     public:
         enum Type { ContentEnd, SoftLineBreak, HardLineBreak, Whitespace, NonWhitespace };
         TextFragment() = default;
-        TextFragment(unsigned start, unsigned end, float width, Type type, bool isLastInRenderer = false, bool overlapsToNextRenderer = false, bool isCollapsed = false, bool isCollapsible = false)
+        TextFragment(unsigned start, unsigned end, float width, Type type, bool isLastInRenderer = false, bool overlapsToNextRenderer = false, bool isCollapsed = false, bool isCollapsible = false, bool hasHyphen = false)
             : m_start(start)
             , m_end(end)
             , m_width(width)
@@ -52,6 +52,7 @@ public:
             , m_overlapsToNextRenderer(overlapsToNextRenderer)
             , m_isCollapsed(isCollapsed)
             , m_isCollapsible(isCollapsible)
+            , m_hasHyphen(hasHyphen)
         {
         }
 
@@ -64,9 +65,11 @@ public:
         bool isLineBreak() const { return m_type == SoftLineBreak || m_type == HardLineBreak; }
         bool isCollapsed() const { return m_isCollapsed; }
         bool isCollapsible() const { return m_isCollapsible; }
+        bool hasHyphen() const { return m_hasHyphen; }
 
         bool isEmpty() const { return start() == end() && !isLineBreak(); }
         TextFragment split(unsigned splitPosition, const TextFragmentIterator&);
+        TextFragment splitWithHyphen(unsigned hyphenPosition, const TextFragmentIterator&);
         bool operator==(const TextFragment& other) const
         {
             return m_start == other.m_start
@@ -76,7 +79,8 @@ public:
                 && m_isLastInRenderer == other.m_isLastInRenderer
                 && m_overlapsToNextRenderer == other.m_overlapsToNextRenderer
                 && m_isCollapsed == other.m_isCollapsed
-                && m_isCollapsible == other.m_isCollapsible;
+                && m_isCollapsible == other.m_isCollapsible
+                && m_hasHyphen == other.m_hasHyphen;
         }
 
     private:
@@ -88,10 +92,14 @@ public:
         bool m_overlapsToNextRenderer { false };
         bool m_isCollapsed { false };
         bool m_isCollapsible { false };
+        bool m_hasHyphen { false };
     };
     TextFragment nextTextFragment(float xPosition = 0);
     void revertToEndOfFragment(const TextFragment&);
+
+    // FIXME: These functions below should be decoupled from the text iterator.
     float textWidth(unsigned startPosition, unsigned endPosition, float xPosition) const;
+    std::optional<unsigned> lastHyphenPosition(const TextFragmentIterator::TextFragment& run, unsigned beforeIndex) const;
 
     struct Style {
         explicit Style(const RenderStyle&);
@@ -108,6 +116,8 @@ public:
         float spaceWidth;
         float wordSpacing;
         unsigned tabWidth;
+        bool shouldHyphenate;
+        float hyphenStringWidth;
         AtomicString locale;
     };
     const Style& style() const { return m_style; }
@@ -142,13 +152,23 @@ inline TextFragmentIterator::TextFragment TextFragmentIterator::TextFragment::sp
         fragment.m_isCollapsed = false;
     };
 
-    TextFragment newFragment(*this);
+    TextFragment rightSide(*this);
     m_end = splitPosition;
     updateFragmentProperties(*this);
 
-    newFragment.m_start = splitPosition;
-    updateFragmentProperties(newFragment);
-    return newFragment;
+    rightSide.m_start = splitPosition;
+    updateFragmentProperties(rightSide);
+    return rightSide;
+}
+
+inline TextFragmentIterator::TextFragment TextFragmentIterator::TextFragment::splitWithHyphen(unsigned hyphenPosition,
+    const TextFragmentIterator& textFragmentIterator)
+{
+    ASSERT(textFragmentIterator.style().shouldHyphenate);
+    auto rightSide = split(hyphenPosition, textFragmentIterator);
+    m_hasHyphen = true;
+    m_width += textFragmentIterator.style().hyphenStringWidth;
+    return rightSide;
 }
 
 inline bool TextFragmentIterator::isSoftLineBreak(unsigned position) const
index ed7611e..541ca57 100644 (file)
@@ -687,9 +687,7 @@ inline void tryHyphenating(RenderText& text, const FontCascade& font, const Atom
     int hyphenWidth = measureHyphenWidth(text, font);
 
     float maxPrefixWidth = availableWidth - xPos - hyphenWidth - lastSpaceWordSpacing;
-    // If the maximum width available for the prefix before the hyphen is small, then it is very unlikely
-    // that an hyphenation opportunity exists, so do not bother to look for it.
-    if (maxPrefixWidth <= font.pixelSize() * 5 / 4)
+    if (!enoughWidthForHyphenation(maxPrefixWidth, font.pixelSize()))
         return;
 
     const RenderStyle& style = text.style();