Changeset 211228 in webkit


Ignore:
Timestamp:
Jan 26, 2017 1:19:38 PM (7 years ago)
Author:
Alan Bujtas
Message:

Simple line layout: Add support for -webkit-hyphenate-limit-lines
https://bugs.webkit.org/show_bug.cgi?id=167446
<rdar://problem/30194030>

Reviewed by Antti Koivisto.

Source/WebCore:

Now we can set the limit on the number of lines that a word can split across through hyphenation.

Tests: fast/text/simple-line-layout-hyphen-limit-lines.html

fast/text/simple-line-layout-hyphen-limit-lines2.html

  • rendering/SimpleLineLayout.cpp:

(WebCore::SimpleLineLayout::canUseForStyle):
(WebCore::SimpleLineLayout::splitFragmentToFitLine):
(WebCore::SimpleLineLayout::printReason):

  • rendering/SimpleLineLayoutTextFragmentIterator.cpp:

(WebCore::SimpleLineLayout::TextFragmentIterator::Style::Style):

  • rendering/SimpleLineLayoutTextFragmentIterator.h:

(WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::TextFragment):
(WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::wrappingWithHyphenCounter):
(WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::splitWithHyphen): The right side of the split has +1 on the wrapping counter.

LayoutTests:

  • fast/text/simple-line-layout-hyphen-limit-lines-expected.html: Added.
  • fast/text/simple-line-layout-hyphen-limit-lines.html: Added.
  • fast/text/simple-line-layout-hyphen-limit-lines2-expected.html: Added.
  • fast/text/simple-line-layout-hyphen-limit-lines2.html: Added.
  • platform/mac/fast/text/hyphenate-limit-lines-expected.txt: progression
Location:
trunk
Files:
4 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r211222 r211228  
     12017-01-26  Zalan Bujtas  <zalan@apple.com>
     2
     3        Simple line layout: Add support for -webkit-hyphenate-limit-lines
     4        https://bugs.webkit.org/show_bug.cgi?id=167446
     5        <rdar://problem/30194030>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        * fast/text/simple-line-layout-hyphen-limit-lines-expected.html: Added.
     10        * fast/text/simple-line-layout-hyphen-limit-lines.html: Added.
     11        * fast/text/simple-line-layout-hyphen-limit-lines2-expected.html: Added.
     12        * fast/text/simple-line-layout-hyphen-limit-lines2.html: Added.
     13        * platform/mac/fast/text/hyphenate-limit-lines-expected.txt: progression
     14
    1152017-01-26  Zalan Bujtas  <zalan@apple.com>
    216
  • trunk/LayoutTests/platform/mac/fast/text/hyphenate-limit-lines-expected.txt

    r177774 r211228  
    1 layer at (0,0) size 785x1066
     1layer at (0,0) size 785x1035
    22  RenderView at (0,0) size 785x600
    3 layer at (0,0) size 785x1066
    4   RenderBlock {HTML} at (0,0) size 785x1066
     3layer at (0,0) size 785x1035
     4  RenderBlock {HTML} at (0,0) size 785x1035
    55    RenderBody {BODY} at (8,8) size 769x584
    66      RenderBlock (floating) {DIV} at (4,0) size 202x498 [border: (1px solid #ADD8E6)]
     
    4848          text run at (1,466) width 109: "vented by "
    4949          text run at (109,466) width 61: "Plato."
    50       RenderBlock (floating) {DIV} at (424,0) size 202x529 [border: (1px solid #ADD8E6)]
    51         RenderText {#text} at (1,1) size 200x527
     50      RenderBlock (floating) {DIV} at (424,0) size 202x498 [border: (1px solid #ADD8E6)]
     51        RenderText {#text} at (1,1) size 200x496
    5252          text run at (1,1) width 200: "also the division of"
    5353          text run at (1,32) width 200: "the mind into the"
     
    5858          text run at (1,156) width 200: "pleasures and de" + hyphen string "-"
    5959          text run at (1,187) width 200: "sires into neces" + hyphen string "-"
    60           text run at (1,218) width 200: "sary and"
    61           text run at (1,249) width 154: "unnecessary\x{2014}"
     60          text run at (1,218) width 108: "sary and "
     61          text run at (108,218) width 93: "unneces" + hyphen string "-"
     62          text run at (1,249) width 200: "sary\x{2014}these and"
     63          text run at (1,280) width 200: "other great forms"
     64          text run at (1,311) width 200: "of thought are all"
     65          text run at (1,342) width 129: "of them "
     66          text run at (129,342) width 72: "to be"
     67          text run at (1,373) width 200: "found in the Re" + hyphen string "-"
     68          text run at (1,404) width 200: "public, and were"
     69          text run at (1,435) width 200: "probably first in" + hyphen string "-"
     70          text run at (1,466) width 109: "vented by "
     71          text run at (109,466) width 61: "Plato."
     72      RenderBlock (floating) {DIV} at (4,498) size 202x498 [border: (1px solid #ADD8E6)]
     73        RenderText {#text} at (1,1) size 200x496
     74          text run at (1,1) width 200: "also the division of"
     75          text run at (1,32) width 200: "the mind into the"
     76          text run at (1,63) width 200: "rational, concupis" + hyphen string "-"
     77          text run at (1,94) width 112: "cent, and "
     78          text run at (112,94) width 89: "irascible"
     79          text run at (1,125) width 200: "elements, or of"
     80          text run at (1,156) width 200: "pleasures and de" + hyphen string "-"
     81          text run at (1,187) width 200: "sires into neces" + hyphen string "-"
     82          text run at (1,218) width 108: "sary and "
     83          text run at (108,218) width 93: "unneces" + hyphen string "-"
     84          text run at (1,249) width 200: "sary\x{2014}these and"
     85          text run at (1,280) width 200: "other great forms"
     86          text run at (1,311) width 200: "of thought are all"
     87          text run at (1,342) width 129: "of them "
     88          text run at (129,342) width 72: "to be"
     89          text run at (1,373) width 200: "found in the Re" + hyphen string "-"
     90          text run at (1,404) width 200: "public, and were"
     91          text run at (1,435) width 200: "probably first in" + hyphen string "-"
     92          text run at (1,466) width 109: "vented by "
     93          text run at (109,466) width 61: "Plato."
     94      RenderBlock (floating) {DIV} at (214,498) size 202x529 [border: (1px solid #ADD8E6)]
     95        RenderText {#text} at (1,1) size 200x527
     96          text run at (1,1) width 200: "also the division of"
     97          text run at (1,32) width 200: "the mind into the"
     98          text run at (1,63) width 86: "rational,"
     99          text run at (1,94) width 200: "concupiscent, and"
     100          text run at (1,125) width 200: "irascible elements,"
     101          text run at (1,156) width 200: "or of pleasures and"
     102          text run at (1,187) width 200: "desires into"
     103          text run at (1,218) width 200: "necessary and"
     104          text run at (1,249) width 200: "unnecessary\x{2014}"
    62105          text run at (1,280) width 200: "these and other"
    63106          text run at (1,311) width 200: "great forms of"
     
    69112          text run at (1,466) width 200: "first invented by"
    70113          text run at (1,497) width 60: "Plato."
    71       RenderBlock (floating) {DIV} at (4,529) size 202x498 [border: (1px solid #ADD8E6)]
    72         RenderText {#text} at (1,1) size 200x496
    73           text run at (1,1) width 200: "also the division of"
    74           text run at (1,32) width 200: "the mind into the"
    75           text run at (1,63) width 200: "rational, concupis" + hyphen string "-"
    76           text run at (1,94) width 112: "cent, and "
    77           text run at (112,94) width 89: "irascible"
    78           text run at (1,125) width 200: "elements, or of"
    79           text run at (1,156) width 200: "pleasures and de" + hyphen string "-"
    80           text run at (1,187) width 200: "sires into"
    81           text run at (1,218) width 166: "necessary and "
    82           text run at (166,218) width 35: "un" + hyphen string "-"
    83           text run at (1,249) width 181: "necessary\x{2014}these"
    84           text run at (1,280) width 200: "and other great"
    85           text run at (1,311) width 200: "forms of thought"
    86           text run at (1,342) width 180: "are all of them "
    87           text run at (180,342) width 21: "to"
    88           text run at (1,373) width 200: "be found in the"
    89           text run at (1,404) width 200: "Republic, and"
    90           text run at (1,435) width 200: "were probably first"
    91           text run at (1,466) width 129: "invented by "
    92           text run at (129,466) width 61: "Plato."
    93       RenderBlock (floating) {DIV} at (214,529) size 202x529 [border: (1px solid #ADD8E6)]
    94         RenderText {#text} at (1,1) size 200x527
    95           text run at (1,1) width 200: "also the division of"
    96           text run at (1,32) width 200: "the mind into the"
    97           text run at (1,63) width 86: "rational,"
    98           text run at (1,94) width 200: "concupiscent, and"
    99           text run at (1,125) width 200: "irascible elements,"
    100           text run at (1,156) width 200: "or of pleasures and"
    101           text run at (1,187) width 200: "desires into"
    102           text run at (1,218) width 200: "necessary and"
    103           text run at (1,249) width 154: "unnecessary\x{2014}"
    104           text run at (1,280) width 200: "these and other"
    105           text run at (1,311) width 200: "great forms of"
    106           text run at (1,342) width 200: "thought are all of"
    107           text run at (1,373) width 67: "them "
    108           text run at (67,373) width 134: "to be found"
    109           text run at (1,404) width 200: "in the Republic,"
    110           text run at (1,435) width 200: "and were probably"
    111           text run at (1,466) width 200: "first invented by"
    112           text run at (1,497) width 60: "Plato."
  • trunk/Source/WebCore/ChangeLog

    r211227 r211228  
     12017-01-26  Zalan Bujtas  <zalan@apple.com>
     2
     3        Simple line layout: Add support for -webkit-hyphenate-limit-lines
     4        https://bugs.webkit.org/show_bug.cgi?id=167446
     5        <rdar://problem/30194030>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        Now we can set the limit on the number of lines that a word can split across through hyphenation.
     10
     11        Tests: fast/text/simple-line-layout-hyphen-limit-lines.html
     12               fast/text/simple-line-layout-hyphen-limit-lines2.html
     13
     14        * rendering/SimpleLineLayout.cpp:
     15        (WebCore::SimpleLineLayout::canUseForStyle):
     16        (WebCore::SimpleLineLayout::splitFragmentToFitLine):
     17        (WebCore::SimpleLineLayout::printReason):
     18        * rendering/SimpleLineLayoutTextFragmentIterator.cpp:
     19        (WebCore::SimpleLineLayout::TextFragmentIterator::Style::Style):
     20        * rendering/SimpleLineLayoutTextFragmentIterator.h:
     21        (WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::TextFragment):
     22        (WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::wrappingWithHyphenCounter):
     23        (WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::splitWithHyphen): The right side of the split has +1 on the wrapping counter.
     24
    1252017-01-26  Wenson Hsieh  <wenson_hsieh@apple.com>
    226
  • trunk/Source/WebCore/rendering/SimpleLineLayout.cpp

    r211222 r211228  
    8787    FlowHasLineAlignEdges                 = 1LLU  << 21,
    8888    FlowHasLineSnap                       = 1LLU  << 22,
    89     FlowHasHypensLineLimit                = 1LLU  << 23,
    90     FlowHasTextEmphasisFillOrMark         = 1LLU  << 24,
    91     FlowHasTextShadow                     = 1LLU  << 25,
    92     FlowHasPseudoFirstLine                = 1LLU  << 26,
    93     FlowHasPseudoFirstLetter              = 1LLU  << 27,
    94     FlowHasTextCombine                    = 1LLU  << 28,
    95     FlowHasTextFillBox                    = 1LLU  << 29,
    96     FlowHasBorderFitLines                 = 1LLU  << 30,
    97     FlowHasNonAutoLineBreak               = 1LLU  << 31,
    98     FlowHasNonAutoTrailingWord            = 1LLU  << 32,
    99     FlowHasSVGFont                        = 1LLU  << 33,
    100     FlowTextIsEmpty                       = 1LLU  << 34,
    101     FlowTextHasSoftHyphen                 = 1LLU  << 35,
    102     FlowTextHasDirectionCharacter         = 1LLU  << 36,
    103     FlowIsMissingPrimaryFont              = 1LLU  << 37,
    104     FlowFontIsMissingGlyph                = 1LLU  << 38,
    105     FlowTextIsCombineText                 = 1LLU  << 39,
    106     FlowTextIsRenderCounter               = 1LLU  << 40,
    107     FlowTextIsRenderQuote                 = 1LLU  << 41,
    108     FlowTextIsTextFragment                = 1LLU  << 42,
    109     FlowTextIsSVGInlineText               = 1LLU  << 43,
    110     FlowFontIsNotSimple                   = 1LLU  << 44,
    111     FeatureIsDisabled                     = 1LLU  << 45,
    112     FlowHasNoParent                       = 1LLU  << 46,
    113     FlowHasNoChild                        = 1LLU  << 47,
    114     FlowChildIsSelected                   = 1LLU  << 48,
    115     FlowHasHangingPunctuation             = 1LLU  << 49,
    116     EndOfReasons                          = 1LLU  << 50
     89    FlowHasTextEmphasisFillOrMark         = 1LLU  << 23,
     90    FlowHasTextShadow                     = 1LLU  << 24,
     91    FlowHasPseudoFirstLine                = 1LLU  << 25,
     92    FlowHasPseudoFirstLetter              = 1LLU  << 26,
     93    FlowHasTextCombine                    = 1LLU  << 27,
     94    FlowHasTextFillBox                    = 1LLU  << 28,
     95    FlowHasBorderFitLines                 = 1LLU  << 29,
     96    FlowHasNonAutoLineBreak               = 1LLU  << 30,
     97    FlowHasNonAutoTrailingWord            = 1LLU  << 31,
     98    FlowHasSVGFont                        = 1LLU  << 32,
     99    FlowTextIsEmpty                       = 1LLU  << 33,
     100    FlowTextHasSoftHyphen                 = 1LLU  << 34,
     101    FlowTextHasDirectionCharacter         = 1LLU  << 35,
     102    FlowIsMissingPrimaryFont              = 1LLU  << 36,
     103    FlowFontIsMissingGlyph                = 1LLU  << 37,
     104    FlowTextIsCombineText                 = 1LLU  << 38,
     105    FlowTextIsRenderCounter               = 1LLU  << 39,
     106    FlowTextIsRenderQuote                 = 1LLU  << 40,
     107    FlowTextIsTextFragment                = 1LLU  << 41,
     108    FlowTextIsSVGInlineText               = 1LLU  << 42,
     109    FlowFontIsNotSimple                   = 1LLU  << 43,
     110    FeatureIsDisabled                     = 1LLU  << 44,
     111    FlowHasNoParent                       = 1LLU  << 45,
     112    FlowHasNoChild                        = 1LLU  << 46,
     113    FlowChildIsSelected                   = 1LLU  << 47,
     114    FlowHasHangingPunctuation             = 1LLU  << 48,
     115    EndOfReasons                          = 1LLU  << 49
    117116};
    118117const unsigned NoReason = 0;
     
    238237    if (style.lineSnap() != LineSnapNone)
    239238        SET_REASON_AND_RETURN_IF_NEEDED(FlowHasLineSnap, reasons, includeReasons);
    240     if (style.hyphenationLimitLines() != RenderStyle::initialHyphenationLimitLines())
    241         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasHypensLineLimit, reasons, includeReasons);
    242239    if (style.textEmphasisFill() != TextEmphasisFillFilled || style.textEmphasisMark() != TextEmphasisMarkNone)
    243240        SET_REASON_AND_RETURN_IF_NEEDED(FlowHasTextEmphasisFillOrMark, reasons, includeReasons);
     
    618615}
    619616
     617static std::optional<unsigned> hyphenPositionForFragment(unsigned splitPosition, TextFragmentIterator::TextFragment& fragmentToSplit,
     618    const TextFragmentIterator& textFragmentIterator, float availableWidth)
     619{
     620    auto& style = textFragmentIterator.style();
     621    bool shouldHyphenate = style.shouldHyphenate && (!style.hyphenLimitLines || fragmentToSplit.wrappingWithHyphenCounter() < *style.hyphenLimitLines);
     622    if (!shouldHyphenate)
     623        return std::nullopt;
     624
     625    if (!enoughWidthForHyphenation(availableWidth, style.font.pixelSize()))
     626        return std::nullopt;
     627
     628    // We might be able to fit the hyphen at the split position.
     629    auto splitPositionWithHyphen = splitPosition;
     630    // Find a splitting position where hyphen surely fits.
     631    unsigned start = fragmentToSplit.start();
     632    auto leftSideWidth = textFragmentIterator.textWidth(start, splitPosition, 0);
     633    while (leftSideWidth + style.hyphenStringWidth > availableWidth) {
     634        if (--splitPositionWithHyphen <= start)
     635            return std::nullopt; // No space for hyphen.
     636        leftSideWidth -= textFragmentIterator.textWidth(splitPositionWithHyphen, splitPositionWithHyphen + 1, 0);
     637    }
     638    ASSERT(splitPositionWithHyphen > start);
     639    return textFragmentIterator.lastHyphenPosition(fragmentToSplit, splitPositionWithHyphen + 1);
     640}
     641
    620642static TextFragmentIterator::TextFragment splitFragmentToFitLine(TextFragmentIterator::TextFragment& fragmentToSplit, float availableWidth, bool keepAtLeastOneCharacter, const TextFragmentIterator& textFragmentIterator)
    621643{
     
    627649    });
    628650    unsigned splitPosition = (*it);
    629     auto& style = textFragmentIterator.style();
    630651    // Does first character fit this line?
    631     if (splitPosition == fragmentToSplit.start()) {
     652    if (splitPosition == start) {
    632653        if (keepAtLeastOneCharacter)
    633654            ++splitPosition;
    634     } else if (style.shouldHyphenate && enoughWidthForHyphenation(availableWidth, style.font.pixelSize())) {
    635         // We might be able to fit the hyphen at the split position.
    636         auto splitPositionWithHyphen = splitPosition;
    637         // Find a splitting position where hyphen surely fits.
    638         auto leftSideWidth = textFragmentIterator.textWidth(start, splitPosition, 0);
    639         while (leftSideWidth + style.hyphenStringWidth > availableWidth) {
    640             if (--splitPositionWithHyphen <= start)
    641                 break; // No space for hyphen.
    642             leftSideWidth -= textFragmentIterator.textWidth(splitPositionWithHyphen, splitPositionWithHyphen + 1, 0);
    643         }
    644         if (splitPositionWithHyphen > start) {
    645             if (auto hyphenPosition = textFragmentIterator.lastHyphenPosition(fragmentToSplit, splitPositionWithHyphen + 1))
    646                 return fragmentToSplit.splitWithHyphen(*hyphenPosition, textFragmentIterator);
    647         }
    648     }
     655    } else if (auto hyphenPosition = hyphenPositionForFragment(splitPosition, fragmentToSplit, textFragmentIterator, availableWidth))
     656        return fragmentToSplit.splitWithHyphen(*hyphenPosition, textFragmentIterator);
    649657    return fragmentToSplit.split(splitPosition, textFragmentIterator);
    650658}
     
    990998        stream << "-webkit-line-snap property";
    991999        break;
    992     case FlowHasHypensLineLimit:
    993         stream << "-webkit-hyphenate-limit-lines property";
    994         break;
    9951000    case FlowHasTextEmphasisFillOrMark:
    9961001        stream << "text-emphasis (fill/mark)";
  • trunk/Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.cpp

    r211222 r211228  
    5454    , locale(style.locale())
    5555{
     56    if (style.hyphenationLimitLines() > -1)
     57        hyphenLimitLines = style.hyphenationLimitLines();
    5658}
    5759
  • trunk/Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.h

    r211222 r211228  
    4444        enum Type { ContentEnd, SoftLineBreak, HardLineBreak, Whitespace, NonWhitespace };
    4545        TextFragment() = default;
    46         TextFragment(unsigned start, unsigned end, float width, Type type, bool isLastInRenderer = false, bool overlapsToNextRenderer = false, bool isCollapsed = false, bool isCollapsible = false, bool hasHyphen = false)
     46        TextFragment(unsigned start, unsigned end, float width, Type type, bool isLastInRenderer = false, bool overlapsToNextRenderer = false, bool isCollapsed = false, bool isCollapsible = false)
    4747            : m_start(start)
    4848            , m_end(end)
     
    5353            , m_isCollapsed(isCollapsed)
    5454            , m_isCollapsible(isCollapsible)
    55             , m_hasHyphen(hasHyphen)
    5655        {
    5756        }
     
    6766        bool isCollapsible() const { return m_isCollapsible; }
    6867        bool hasHyphen() const { return m_hasHyphen; }
     68        unsigned wrappingWithHyphenCounter() const { return m_hyphenationCounter; }
    6969
    7070        bool isEmpty() const { return start() == end() && !isLineBreak(); }
     
    9494        bool m_isCollapsible { false };
    9595        bool m_hasHyphen { false };
     96        unsigned m_hyphenationCounter { 0 };
    9697    };
    9798    TextFragment nextTextFragment(float xPosition = 0);
     
    122123        unsigned hyphenLimitAfter;
    123124        AtomicString locale;
     125        std::optional<unsigned> hyphenLimitLines;
    124126    };
    125127    const Style& style() const { return m_style; }
     
    169171    ASSERT(textFragmentIterator.style().shouldHyphenate);
    170172    auto rightSide = split(hyphenPosition, textFragmentIterator);
     173    rightSide.m_hyphenationCounter = m_hyphenationCounter + 1;
    171174    m_hasHyphen = true;
    172175    m_width += textFragmentIterator.style().hyphenStringWidth;
Note: See TracChangeset for help on using the changeset viewer.