Soft hyphen is not shown when it is placed at the end of an inline element
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 18 Feb 2016 23:48:19 +0000 (23:48 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 18 Feb 2016 23:48:19 +0000 (23:48 +0000)
https://bugs.webkit.org/show_bug.cgi?id=153980

Reviewed by David Hyatt.

This patch handles the case when the character at the breaking position does not fit the
line and soft-hyphen, as the first breaking opportunity, is followed by this overflowing character.
(foo&shy;bar where b overflows the line).
In such cases we don't yet have an item in the breaking history so we need to take a look at
the current context instead.

Source/WebCore:

Test: fast/text/soft-hyphen-as-first-breaking-opportunity.html

* rendering/line/BreakingContext.h:
(WebCore::BreakingContext::InlineIteratorHistory::nextBreakablePosition):
(WebCore::BreakingContext::handleText):

LayoutTests:

* fast/text/soft-hyphen-as-first-breaking-opportunity-expected.html: Added.
* fast/text/soft-hyphen-as-first-breaking-opportunity.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/fast/text/soft-hyphen-as-first-breaking-opportunity-expected.html [new file with mode: 0644]
LayoutTests/fast/text/soft-hyphen-as-first-breaking-opportunity.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/line/BreakingContext.h

index 8649f15..be68160 100644 (file)
@@ -1,3 +1,19 @@
+2016-02-18  Zalan Bujtas  <zalan@apple.com>
+
+        Soft hyphen is not shown when it is placed at the end of an inline element
+        https://bugs.webkit.org/show_bug.cgi?id=153980
+
+        Reviewed by David Hyatt.
+
+        This patch handles the case when the character at the breaking position does not fit the
+        line and soft-hyphen, as the first breaking opportunity, is followed by this overflowing character.
+        (foo&shy;bar where b overflows the line).
+        In such cases we don't yet have an item in the breaking history so we need to take a look at
+        the current context instead.    
+
+        * fast/text/soft-hyphen-as-first-breaking-opportunity-expected.html: Added.
+        * fast/text/soft-hyphen-as-first-breaking-opportunity.html: Added.
+
 2016-02-18  Ryan Haddad  <ryanhaddad@apple.com>
 
         Rebaseline imported/w3c/web-platform-tests/html/dom/interfaces.html for ios-simulator after r196770
diff --git a/LayoutTests/fast/text/soft-hyphen-as-first-breaking-opportunity-expected.html b/LayoutTests/fast/text/soft-hyphen-as-first-breaking-opportunity-expected.html
new file mode 100644 (file)
index 0000000..0d7c4ce
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>This tests that soft-hyphen is placed correctly when it is the first breaking opportunity.</title>
+<style>
+.wrap {
+    width: 200px;
+    border: 1px solid;
+}
+.soft-hyphen {
+    color: red;
+}
+</style>
+</head>
+<body>
+<h2>No extra element.</h2>
+<div class="wrap">mmmmmmmmmmmmmm-mmmmmmmmmmmmmm
+</div>
+<h2>Soft hyphen inside a styled span.</h2>
+<div class="wrap">mmmmmmmmmmmmmm<span class="soft-hyphen">-</span>mmmmmmmmmmmmmm
+</div>
+<h2>Soft hyphen at the end of a styled span with text in it.</h2>
+<div class="wrap">mmmmmmmmmmmmm<span class="soft-hyphen">m-</span>mmmmmmmmmmmmmm
+</div>
+<h2>Soft hyphen at the start of a styled span with text in it.</h2>
+<div class="wrap">mmmmmmmmmmmmmm<span class="soft-hyphen">-m</span>mmmmmmmmmmmmm
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/text/soft-hyphen-as-first-breaking-opportunity.html b/LayoutTests/fast/text/soft-hyphen-as-first-breaking-opportunity.html
new file mode 100644 (file)
index 0000000..101f074
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>This tests that soft-hyphen is placed correctly when it is the first breaking opportunity.</title>
+<style>
+.wrap {
+    width: 200px;
+    border: 1px solid;
+}
+.soft-hyphen {
+    color: red;
+}
+</style>
+</head>
+<body>
+<h2>No extra element.</h2>
+<div class="wrap">mmmmmmmmmmmmmm&shy;mmmmmmmmmmmmmm
+</div>
+<h2>Soft hyphen inside a styled span.</h2>
+<div class="wrap">mmmmmmmmmmmmmm<span class="soft-hyphen">&shy;</span>mmmmmmmmmmmmmm
+</div>
+<h2>Soft hyphen at the end of a styled span with text in it.</h2>
+<div class="wrap">mmmmmmmmmmmmm<span class="soft-hyphen">m&shy;</span>mmmmmmmmmmmmmm
+</div>
+<h2>Soft hyphen at the start of a styled span with text in it.</h2>
+<div class="wrap">mmmmmmmmmmmmmm<span class="soft-hyphen">&shy;m</span>mmmmmmmmmmmmm
+</div>
+</body>
+</html>
index 625880a..6ba898f 100644 (file)
@@ -1,3 +1,22 @@
+2016-02-18  Zalan Bujtas  <zalan@apple.com>
+
+        Soft hyphen is not shown when it is placed at the end of an inline element
+        https://bugs.webkit.org/show_bug.cgi?id=153980
+
+        Reviewed by David Hyatt.
+
+        This patch handles the case when the character at the breaking position does not fit the
+        line and soft-hyphen, as the first breaking opportunity, is followed by this overflowing character.
+        (foo&shy;bar where b overflows the line).
+        In such cases we don't yet have an item in the breaking history so we need to take a look at
+        the current context instead.    
+
+        Test: fast/text/soft-hyphen-as-first-breaking-opportunity.html
+
+        * rendering/line/BreakingContext.h:
+        (WebCore::BreakingContext::InlineIteratorHistory::nextBreakablePosition):
+        (WebCore::BreakingContext::handleText):
+
 2016-02-18  Andreas Kling  <akling@apple.com>
 
         Fake memory pressure handler should log detailed memory breakdown.
index b44c5a2..c1f9476 100644 (file)
@@ -200,6 +200,7 @@ private:
 
         RenderObject* renderer() const { return this->at(0).renderer(); }
         unsigned offset() const { return this->at(0).offset(); }
+        int nextBreakablePosition() const { return this->at(0).nextBreakablePosition(); }
         bool atTextParagraphSeparator() const { return this->at(0).atTextParagraphSeparator(); }
         UChar previousInSameNode() const { return this->at(0).previousInSameNode(); }
         const InlineIterator& get(size_t i) const { return this->at(i); };
@@ -776,6 +777,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
     // Non-zero only when kerning is enabled and TextLayout isn't used, in which case we measure
     // words with their trailing space, then subtract its width.
     HashSet<const Font*> fallbackFonts;
+    UChar lastCharacterFromPreviousRenderText = m_renderTextInfo.lineBreakIterator.lastCharacter();
     UChar lastCharacter = m_renderTextInfo.lineBreakIterator.lastCharacter();
     UChar secondToLastCharacter = m_renderTextInfo.lineBreakIterator.secondToLastCharacter();
     WordTrailingSpace wordTrailingSpace(renderText, style, textLayout);
@@ -903,8 +905,33 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
                         m_lineInfo.setPreviousLineBrokeCleanly(true);
                         wordMeasurement.endOffset = m_lineBreakHistory.offset();
                     }
-                    if (m_lineBreakHistory.offset() && downcast<RenderText>(m_lineBreakHistory.renderer()) && downcast<RenderText>(*m_lineBreakHistory.renderer()).textLength() && downcast<RenderText>(*m_lineBreakHistory.renderer()).characterAt(m_lineBreakHistory.offset() - 1) == softHyphen && style.hyphens() != HyphensNone)
-                        hyphenated = true;
+                    // Check if the last breaking position is a soft-hyphen.
+                    if (!hyphenated && style.hyphens() != HyphensNone) {
+                        Optional<int> lastBreakingPositon;
+                        const RenderObject* rendererAtBreakingPosition = nullptr;
+                        if (m_lineBreakHistory.offset() || m_lineBreakHistory.nextBreakablePosition() > -1) {
+                            lastBreakingPositon = m_lineBreakHistory.offset();
+                            rendererAtBreakingPosition = m_lineBreakHistory.renderer();
+                        } else if (m_current.nextBreakablePosition() > -1 && (unsigned)m_current.nextBreakablePosition() <= m_current.offset()) {
+                            // We might just be right after the soft-hyphen
+                            lastBreakingPositon = m_current.nextBreakablePosition();
+                            rendererAtBreakingPosition = m_current.renderer();
+                        }
+                        if (lastBreakingPositon) {
+                            Optional<UChar> characterBeforeBreakingPosition;
+                            // When last breaking position points to the start of the current context, we need to look at the last character from
+                            // the previous non-empty text renderer.
+                            if (!lastBreakingPositon.value())
+                                characterBeforeBreakingPosition = lastCharacterFromPreviousRenderText;
+                            else if (is<RenderText>(rendererAtBreakingPosition)) {
+                                const auto& textRenderer = downcast<RenderText>(*rendererAtBreakingPosition);
+                                ASSERT(textRenderer.textLength() > (unsigned)(lastBreakingPositon.value() - 1));
+                                characterBeforeBreakingPosition = textRenderer.characterAt(lastBreakingPositon.value() - 1);
+                            }
+                            if (characterBeforeBreakingPosition)
+                                hyphenated = characterBeforeBreakingPosition.value() == softHyphen;
+                        }
+                    }
                     if (m_lineBreakHistory.offset() && m_lineBreakHistory.offset() != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) {
                         if (charWidth) {
                             wordMeasurement.endOffset = m_lineBreakHistory.offset();