Changeset 205373 in webkit


Ignore:
Timestamp:
Sep 2, 2016 2:43:45 PM (8 years ago)
Author:
mmaxfield@apple.com
Message:

[Cocoa] Distinguish between paint advances and base advances
https://bugs.webkit.org/show_bug.cgi?id=160892

Reviewed by Simon Fraser.

Source/WebCore:

This patch introduces the concept of a layout (or "base") advance which is distinct
from a painting advance. In extremely complicated scripts such as Urdu, it is common
for a glyph advance to be negative in the horizontal direction, and have large advances
in the vertical direction. In particular, in cursive scripts, the glyph placement is
only indirectly related to where the actual characters lie. Conceptually, these glyph
locations are correct for painting, but are not correct when performing width
measurements.

In many text engines, glyph shaping actually can be split into two phases: adjusting
advances, and then placing glyphs relative to those advances. The secondary glyph
placement step is much more context-sensitive than the first step. In addition, when
multiple glyphs combine to form a character, it is common for one glyph to own the
full base advance for the character, and for the other glyphs in the character to
have zero base advances. (Then, in the glyph placement phase, the other glyphs get
placed all around.)

Because of the context-insensitivity of the base advances, it is valuable to use
these for text measurement. Then, when we want to paint, we should add in the extra
origins. This dramatically improves the layout of complex fonts like Noto Nastaliq.

This patch migrates WebKit to use this two-phase shaping.

No new tests just yet, because I have to create a font which exercises the
advanced glyph placement support.

  • platform/graphics/GlyphBuffer.h:

(WebCore::GlyphBufferAdvance::setHeight):
(WebCore::GlyphBufferAdvance::setWidth): Deleted.

  • platform/graphics/TextRun.h:

(WebCore::TextRun::TextRun):
(WebCore::TextRun::shouldDisableLayoutSpecificAdvances):
(WebCore::TextRun::setShouldDisableLayoutSpecificAdvances):
(WebCore::TextRun::spacingDisabled): Deleted.
(WebCore::TextRun::setCharacterScanForCodePath): Deleted.

  • platform/graphics/cocoa/FontCascadeCocoa.mm:

(WebCore::FontCascade::getGlyphsAndAdvancesForComplexText):

  • platform/graphics/mac/ComplexTextController.cpp:

(WebCore::ComplexTextController::ComplexTextController):
(WebCore::ComplexTextController::offsetForPosition):
(WebCore::ComplexTextController::collectComplexTextRuns):
(WebCore::ComplexTextController::ComplexTextRun::setIsNonMonotonic):
(WebCore::ComplexTextController::runWidthSoFarFraction):
(WebCore::ComplexTextController::advance):
(WebCore::ComplexTextController::adjustGlyphsAndAdvances):

  • platform/graphics/mac/ComplexTextController.h:

(WebCore::ComplexTextController::ComplexTextRun::create):
(WebCore::ComplexTextController::ComplexTextRun::baseAdvances):
(WebCore::ComplexTextController::ComplexTextRun::glyphOrigins):
(WebCore::ComplexTextController::useLayoutSpecificAdvances):
(WebCore::ComplexTextController::finalRoundingWidth): Deleted.
(WebCore::ComplexTextController::ComplexTextRun::advances): Deleted.

  • platform/graphics/mac/ComplexTextControllerCoreText.mm:

(SOFT_LINK):
(WebCore::ComplexTextController::ComplexTextRun::ComplexTextRun):
(WebCore::ComplexTextController::collectComplexTextRunsForCharacters):

  • platform/spi/cocoa/CoreTextSPI.h:

LayoutTests:

Update tests. There are some expected (small) changes in metrics due to this patch.

  • platform/mac-elcapitan/css2.1/t051202-c26-psudo-nest-00-c-expected.png: Copied from LayoutTests/platform/mac/css2.1/t051202-c26-psudo-nest-00-c-expected.png.
  • platform/mac-elcapitan/css2.1/t051202-c26-psudo-nest-00-c-expected.txt: Copied from LayoutTests/platform/mac/css2.1/t051202-c26-psudo-nest-00-c-expected.txt.
  • platform/mac-elcapitan/css2.1/t1508-c527-font-00-b-expected.png: Copied from LayoutTests/platform/mac/css2.1/t1508-c527-font-00-b-expected.png.
  • platform/mac-elcapitan/css2.1/t1508-c527-font-00-b-expected.txt: Added.
  • platform/mac-elcapitan/fast/inline/absolute-positioned-inline-in-centred-block-expected.png: Copied from LayoutTests/platform/mac/fast/inline/absolute-positioned-inline-in-centred-block-expected.png.
  • platform/mac-elcapitan/fast/inline/absolute-positioned-inline-in-centred-block-expected.txt: Copied from LayoutTests/platform/mac/fast/inline/absolute-positioned-inline-in-centred-block-expected.txt.
  • platform/mac/css2.1/t051202-c26-psudo-nest-00-c-expected.png:
  • platform/mac/css2.1/t051202-c26-psudo-nest-00-c-expected.txt:
  • platform/mac/css2.1/t1508-c527-font-00-b-expected.png:
  • platform/mac/css2.1/t1508-c527-font-00-b-expected.txt: Added.
  • platform/mac/fast/inline/absolute-positioned-inline-in-centred-block-expected.png:
  • platform/mac/fast/inline/absolute-positioned-inline-in-centred-block-expected.txt:
Location:
trunk
Files:
4 added
13 edited
5 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r205372 r205373  
     12016-09-02  Myles C. Maxfield  <mmaxfield@apple.com>
     2
     3        [Cocoa] Distinguish between paint advances and base advances
     4        https://bugs.webkit.org/show_bug.cgi?id=160892
     5
     6        Reviewed by Simon Fraser.
     7
     8        Update tests. There are some expected (small) changes in metrics due to this patch.
     9
     10        * platform/mac-elcapitan/css2.1/t051202-c26-psudo-nest-00-c-expected.png: Copied from LayoutTests/platform/mac/css2.1/t051202-c26-psudo-nest-00-c-expected.png.
     11        * platform/mac-elcapitan/css2.1/t051202-c26-psudo-nest-00-c-expected.txt: Copied from LayoutTests/platform/mac/css2.1/t051202-c26-psudo-nest-00-c-expected.txt.
     12        * platform/mac-elcapitan/css2.1/t1508-c527-font-00-b-expected.png: Copied from LayoutTests/platform/mac/css2.1/t1508-c527-font-00-b-expected.png.
     13        * platform/mac-elcapitan/css2.1/t1508-c527-font-00-b-expected.txt: Added.
     14        * platform/mac-elcapitan/fast/inline/absolute-positioned-inline-in-centred-block-expected.png: Copied from LayoutTests/platform/mac/fast/inline/absolute-positioned-inline-in-centred-block-expected.png.
     15        * platform/mac-elcapitan/fast/inline/absolute-positioned-inline-in-centred-block-expected.txt: Copied from LayoutTests/platform/mac/fast/inline/absolute-positioned-inline-in-centred-block-expected.txt.
     16        * platform/mac/css2.1/t051202-c26-psudo-nest-00-c-expected.png:
     17        * platform/mac/css2.1/t051202-c26-psudo-nest-00-c-expected.txt:
     18        * platform/mac/css2.1/t1508-c527-font-00-b-expected.png:
     19        * platform/mac/css2.1/t1508-c527-font-00-b-expected.txt: Added.
     20        * platform/mac/fast/inline/absolute-positioned-inline-in-centred-block-expected.png:
     21        * platform/mac/fast/inline/absolute-positioned-inline-in-centred-block-expected.txt:
     22
    1232016-09-02  Chris Dumez  <cdumez@apple.com>
    224
  • trunk/LayoutTests/platform/mac/css2.1/t051202-c26-psudo-nest-00-c-expected.txt

    r177774 r205373  
    5757          RenderText {#text} at (130,15) size 111x18
    5858            text run at (130,15) width 111: "two characters"
    59         RenderText {#text} at (240,15) size 452x18
    60           text run at (240,15) width 121: " in this paragraph "
    61           text run at (360,15) width 332: "(a double-quote mark and a capital 'T') should be "
    62         RenderInline {STRONG} at (0,0) size 89x18
    63           RenderText {#text} at (691,15) size 89x18
    64             text run at (691,15) width 45: "200% "
    65             text run at (735,15) width 45: "bigger"
     59        RenderText {#text} at (240,15) size 451x18
     60          text run at (240,15) width 120: " in this paragraph "
     61          text run at (359,15) width 332: "(a double-quote mark and a capital 'T') should be "
     62        RenderInline {STRONG} at (0,0) size 90x18
     63          RenderText {#text} at (690,15) size 90x18
     64            text run at (690,15) width 45: "200% "
     65            text run at (734,15) width 46: "bigger"
    6666        RenderText {#text} at (0,37) size 223x18
    6767          text run at (0,37) width 223: "than the rest of the paragraph, and "
  • trunk/LayoutTests/platform/mac/fast/inline/absolute-positioned-inline-in-centred-block-expected.txt

    r180441 r205373  
    77layer at (250,562) size 303x28
    88  RenderBlock (positioned) {FONT} at (250,562) size 303x28
    9     RenderText {#text} at (0,0) size 303x28
    10       text run at (0,0) width 303: "Hello World, And Stuff!"
     9    RenderText {#text} at (0,0) size 302x28
     10      text run at (0,0) width 302: "Hello World, And Stuff!"
  • trunk/Source/WebCore/ChangeLog

    r205372 r205373  
     12016-09-02  Myles C. Maxfield  <mmaxfield@apple.com>
     2
     3        [Cocoa] Distinguish between paint advances and base advances
     4        https://bugs.webkit.org/show_bug.cgi?id=160892
     5
     6        Reviewed by Simon Fraser.
     7
     8        This patch introduces the concept of a layout (or "base") advance which is distinct
     9        from a painting advance. In extremely complicated scripts such as Urdu, it is common
     10        for a glyph advance to be negative in the horizontal direction, and have large advances
     11        in the vertical direction. In particular, in cursive scripts, the glyph placement is
     12        only indirectly related to where the actual characters lie. Conceptually, these glyph
     13        locations are correct for painting, but are not correct when performing width
     14        measurements.
     15
     16        In many text engines, glyph shaping actually can be split into two phases: adjusting
     17        advances, and then placing glyphs relative to those advances. The secondary glyph
     18        placement step is much more context-sensitive than the first step. In addition, when
     19        multiple glyphs combine to form a character, it is common for one glyph to own the
     20        full base advance for the character, and for the other glyphs in the character to
     21        have zero base advances. (Then, in the glyph placement phase, the other glyphs get
     22        placed all around.)
     23
     24        Because of the context-insensitivity of the base advances, it is valuable to use
     25        these for text measurement. Then, when we want to paint, we should add in the extra
     26        origins. This dramatically improves the layout of complex fonts like Noto Nastaliq.
     27
     28        This patch migrates WebKit to use this two-phase shaping.
     29
     30        No new tests just yet, because I have to create a font which exercises the
     31        advanced glyph placement support.
     32
     33        * platform/graphics/GlyphBuffer.h:
     34        (WebCore::GlyphBufferAdvance::setHeight):
     35        (WebCore::GlyphBufferAdvance::setWidth): Deleted.
     36        * platform/graphics/TextRun.h:
     37        (WebCore::TextRun::TextRun):
     38        (WebCore::TextRun::shouldDisableLayoutSpecificAdvances):
     39        (WebCore::TextRun::setShouldDisableLayoutSpecificAdvances):
     40        (WebCore::TextRun::spacingDisabled): Deleted.
     41        (WebCore::TextRun::setCharacterScanForCodePath): Deleted.
     42        * platform/graphics/cocoa/FontCascadeCocoa.mm:
     43        (WebCore::FontCascade::getGlyphsAndAdvancesForComplexText):
     44        * platform/graphics/mac/ComplexTextController.cpp:
     45        (WebCore::ComplexTextController::ComplexTextController):
     46        (WebCore::ComplexTextController::offsetForPosition):
     47        (WebCore::ComplexTextController::collectComplexTextRuns):
     48        (WebCore::ComplexTextController::ComplexTextRun::setIsNonMonotonic):
     49        (WebCore::ComplexTextController::runWidthSoFarFraction):
     50        (WebCore::ComplexTextController::advance):
     51        (WebCore::ComplexTextController::adjustGlyphsAndAdvances):
     52        * platform/graphics/mac/ComplexTextController.h:
     53        (WebCore::ComplexTextController::ComplexTextRun::create):
     54        (WebCore::ComplexTextController::ComplexTextRun::baseAdvances):
     55        (WebCore::ComplexTextController::ComplexTextRun::glyphOrigins):
     56        (WebCore::ComplexTextController::useLayoutSpecificAdvances):
     57        (WebCore::ComplexTextController::finalRoundingWidth): Deleted.
     58        (WebCore::ComplexTextController::ComplexTextRun::advances): Deleted.
     59        * platform/graphics/mac/ComplexTextControllerCoreText.mm:
     60        (SOFT_LINK):
     61        (WebCore::ComplexTextController::ComplexTextRun::ComplexTextRun):
     62        (WebCore::ComplexTextController::collectComplexTextRunsForCharacters):
     63        * platform/spi/cocoa/CoreTextSPI.h:
     64
    1652016-09-02  Chris Dumez  <cdumez@apple.com>
    266
  • trunk/Source/WebCore/platform/graphics/GlyphBuffer.h

    r204400 r205373  
    6868
    6969    void setWidth(CGFloat width) { this->CGSize::width = width; }
     70    void setHeight(CGFloat height) { this->CGSize::height = height; }
    7071    CGFloat width() const { return this->CGSize::width; }
    7172    CGFloat height() const { return this->CGSize::height; }
  • trunk/Source/WebCore/platform/graphics/cocoa/FontCascadeCocoa.mm

    r204858 r205373  
    515515
    516516    if (run.rtl()) {
    517         initialAdvance = controller.totalWidth() + controller.finalRoundingWidth() - afterWidth + controller.leadingExpansion();
     517        initialAdvance = controller.totalWidth() - afterWidth + controller.leadingExpansion();
    518518        glyphBuffer.reverse(0, glyphBuffer.size());
    519519    } else
  • trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp

    r205282 r205373  
    108108
    109109ComplexTextController::ComplexTextController(const FontCascade& font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const Font*>* fallbackFonts, bool forTextEmphasis)
    110     : m_font(font)
     110    : m_fallbackFonts(fallbackFonts)
     111    , m_font(font)
    111112    , m_run(run)
    112     , m_isLTROnly(true)
     113    , m_end(run.length())
     114    , m_expansion(run.expansion())
    113115    , m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection)
    114116    , m_forTextEmphasis(forTextEmphasis)
    115     , m_currentCharacter(0)
    116     , m_end(run.length())
    117     , m_totalWidth(0)
    118     , m_runWidthSoFar(0)
    119     , m_numGlyphsSoFar(0)
    120     , m_currentRun(0)
    121     , m_glyphInCurrentRun(0)
    122     , m_characterInCurrentGlyph(0)
    123     , m_finalRoundingWidth(0)
    124     , m_expansion(run.expansion())
    125     , m_leadingExpansion(0)
    126     , m_fallbackFonts(fallbackFonts)
    127     , m_minGlyphBoundingBoxX(std::numeric_limits<float>::max())
    128     , m_maxGlyphBoundingBoxX(std::numeric_limits<float>::min())
    129     , m_minGlyphBoundingBoxY(std::numeric_limits<float>::max())
    130     , m_maxGlyphBoundingBoxY(std::numeric_limits<float>::min())
    131     , m_lastRoundingGlyph(0)
    132117{
    133118    if (!m_expansion)
     
    159144}
    160145
    161 int ComplexTextController::offsetForPosition(float h, bool includePartialGlyphs)
     146unsigned ComplexTextController::offsetForPosition(float h, bool includePartialGlyphs)
    162147{
    163148    if (h >= m_totalWidth)
     
    177162        for (unsigned j = 0; j < complexTextRun.glyphCount(); ++j) {
    178163            size_t index = offsetIntoAdjustedGlyphs + j;
    179             CGFloat adjustedAdvance = m_adjustedAdvances[index].width;
     164            CGFloat adjustedAdvance = m_adjustedBaseAdvances[index].width;
    180165            if (!index)
    181166                adjustedAdvance += complexTextRun.initialAdvance().width;
     
    189174
    190175                // FIXME: Instead of dividing the glyph's advance equally between the characters, this
    191                 // could use the glyph's "ligature carets". However, there is no Core Text API to get the
    192                 // ligature carets.
     176                // could use the glyph's "ligature carets". This is available in CoreText via CTFontGetLigatureCaretPositions().
    193177                CFIndex hitIndex = hitGlyphStart + (hitGlyphEnd - hitGlyphStart) * (m_run.ltr() ? x / adjustedAdvance : 1 - x / adjustedAdvance);
    194178                int stringLength = complexTextRun.stringLength();
     
    218202                    int firstGlyphBeforeCluster = j - 1;
    219203                    while (firstGlyphBeforeCluster >= 0 && complexTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) {
    220                         CGFloat width = m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width;
     204                        CGFloat width = m_adjustedBaseAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width;
    221205                        clusterWidth += width;
    222206                        x += width;
     
    225209                    unsigned firstGlyphAfterCluster = j + 1;
    226210                    while (firstGlyphAfterCluster < complexTextRun.glyphCount() && complexTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) {
    227                         clusterWidth += m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphAfterCluster].width;
     211                        clusterWidth += m_adjustedBaseAdvances[offsetIntoAdjustedGlyphs + firstGlyphAfterCluster].width;
    228212                        firstGlyphAfterCluster++;
    229213                    }
     
    324308    const UChar* cp;
    325309
     310    Vector<String> stringsFor8BitRuns;
    326311    if (m_run.is8Bit()) {
    327312        String stringFor8BitRun = String::make16BitFrom8BitSource(m_run.characters8(), m_run.length());
    328         cp = stringFor8BitRun.characters16();
    329         m_stringsFor8BitRuns.append(stringFor8BitRun);
     313        stringsFor8BitRuns.append(WTFMove(stringFor8BitRun));
     314        cp = stringsFor8BitRuns.last().characters16();
    330315    } else
    331316        cp = m_run.characters16();
     
    429414    }
    430415
     416    ASSERT(m_end >= indexOfFontTransition);
    431417    unsigned itemLength = m_end - indexOfFontTransition;
    432418    if (itemLength) {
     
    464450
    465451    m_glyphEndOffsets.grow(m_glyphCount);
    466     for (size_t i = 0; i < m_glyphCount; ++i) {
     452    for (unsigned i = 0; i < m_glyphCount; ++i) {
    467453        CFIndex nextMappedIndex = m_indexEnd;
    468454        for (size_t j = indexAt(i) + 1; j < m_stringLength; ++j) {
     
    531517}
    532518
     519float ComplexTextController::runWidthSoFarFraction(unsigned glyphStartOffset, unsigned glyphEndOffset, unsigned oldCharacterInCurrentGlyph, GlyphIterationStyle iterationStyle) const
     520{
     521    // FIXME: Instead of dividing the glyph's advance equally between the characters, this
     522    // could use the glyph's "ligature carets". This is available in CoreText via CTFontGetLigatureCaretPositions().
     523    if (glyphStartOffset == glyphEndOffset) {
     524        // When there are multiple glyphs per character we need to advance by the full width of the glyph.
     525        ASSERT(m_characterInCurrentGlyph == oldCharacterInCurrentGlyph);
     526        return 1;
     527    }
     528
     529    if (iterationStyle == ByWholeGlyphs) {
     530        if (!oldCharacterInCurrentGlyph)
     531            return 1;
     532        return 0;
     533    }
     534
     535    return static_cast<float>(m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset);
     536}
     537
    533538void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer, GlyphIterationStyle iterationStyle, HashSet<const Font*>* fallbackFonts)
    534539{
    535     if (static_cast<int>(offset) > m_end)
     540    if (offset > m_end)
    536541        offset = m_end;
    537542
     
    563568        // account the text direction.
    564569        if (glyphBuffer && !leftmostGlyph) {
    565             glyphBuffer->setInitialAdvance(complexTextRun.initialAdvance());
     570            CGSize initialAdvance = complexTextRun.initialAdvance();
     571#if USE_LAYOUT_SPECIFIC_ADVANCES
     572            unsigned index = ltr ? 0 : m_glyphOrigins.size() - 1;
     573            initialAdvance.width += m_glyphOrigins[index].x;
     574            initialAdvance.height += m_glyphOrigins[index].y;
     575#endif
     576            glyphBuffer->setInitialAdvance(initialAdvance);
     577
    566578            glyphBuffer->setLeadingExpansion(m_leadingExpansion);
    567579        }
     
    578590                glyphEndOffset = complexTextRun.endOffsetAt(g);
    579591
    580             CGSize adjustedAdvance = m_adjustedAdvances[k];
     592            CGSize adjustedBaseAdvance = m_adjustedBaseAdvances[k];
    581593
    582594            if (glyphStartOffset + complexTextRun.stringLocation() >= m_currentCharacter)
    583595                return;
    584596
    585             if (glyphBuffer && !m_characterInCurrentGlyph)
    586                 glyphBuffer->add(m_adjustedGlyphs[k], &complexTextRun.font(), adjustedAdvance, complexTextRun.indexAt(m_glyphInCurrentRun));
     597            if (glyphBuffer && !m_characterInCurrentGlyph) {
     598                GlyphBufferAdvance paintAdvance = adjustedBaseAdvance;
     599#if USE_LAYOUT_SPECIFIC_ADVANCES
     600                if (k + 1 < m_adjustedBaseAdvances.size()) {
     601                    paintAdvance.setWidth(paintAdvance.width() + m_glyphOrigins[k + 1].x - m_glyphOrigins[k].x);
     602                    paintAdvance.setHeight(paintAdvance.height() - m_glyphOrigins[k + 1].y + m_glyphOrigins[k].y);
     603                }
     604#endif
     605                glyphBuffer->add(m_adjustedGlyphs[k], &complexTextRun.font(), paintAdvance, complexTextRun.indexAt(m_glyphInCurrentRun));
     606            }
    587607
    588608            unsigned oldCharacterInCurrentGlyph = m_characterInCurrentGlyph;
    589609            m_characterInCurrentGlyph = std::min(m_currentCharacter - complexTextRun.stringLocation(), glyphEndOffset) - glyphStartOffset;
    590             // FIXME: Instead of dividing the glyph's advance equally between the characters, this
    591             // could use the glyph's "ligature carets". However, there is no Core Text API to get the
    592             // ligature carets.
    593             if (glyphStartOffset == glyphEndOffset) {
    594                 // When there are multiple glyphs per character we need to advance by the full width of the glyph.
    595                 ASSERT(m_characterInCurrentGlyph == oldCharacterInCurrentGlyph);
    596                 m_runWidthSoFar += adjustedAdvance.width;
    597             } else if (iterationStyle == ByWholeGlyphs) {
    598                 if (!oldCharacterInCurrentGlyph)
    599                     m_runWidthSoFar += adjustedAdvance.width;
    600             } else
    601                 m_runWidthSoFar += adjustedAdvance.width * (m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset);
     610            m_runWidthSoFar += adjustedBaseAdvance.width * runWidthSoFarFraction(glyphStartOffset, glyphEndOffset, oldCharacterInCurrentGlyph, iterationStyle);
    602611
    603612            if (glyphEndOffset + complexTextRun.stringLocation() > m_currentCharacter)
     
    618627        m_glyphInCurrentRun = 0;
    619628    }
    620     if (!m_run.ltr() && m_numGlyphsSoFar == m_adjustedAdvances.size())
    621         m_runWidthSoFar += m_finalRoundingWidth;
    622629}
    623630
     
    657664    bool runForbidsLeadingExpansion = (m_run.expansionBehavior() & LeadingExpansionMask) == ForbidLeadingExpansion;
    658665    bool runForbidsTrailingExpansion = (m_run.expansionBehavior() & TrailingExpansionMask) == ForbidTrailingExpansion;
     666
    659667    // We are iterating in glyph order, not string order. Compare this to WidthIterator::advanceInternal()
    660668    for (size_t r = 0; r < runCount; ++r) {
     
    665673        // Represent the initial advance for a text run by adjusting the advance
    666674        // of the last glyph of the previous text run in the glyph buffer.
    667         if (r && m_adjustedAdvances.size()) {
    668             CGSize previousAdvance = m_adjustedAdvances.last();
     675        if (r && m_adjustedBaseAdvances.size()) {
     676            CGSize previousAdvance = m_adjustedBaseAdvances.last();
    669677            previousAdvance.width += complexTextRun.initialAdvance().width;
    670678            previousAdvance.height -= complexTextRun.initialAdvance().height;
    671             m_adjustedAdvances[m_adjustedAdvances.size() - 1] = previousAdvance;
     679            m_adjustedBaseAdvances[m_adjustedBaseAdvances.size() - 1] = previousAdvance;
    672680        }
    673681        widthSinceLastCommit += complexTextRun.initialAdvance().width;
     
    677685
    678686        const CGGlyph* glyphs = complexTextRun.glyphs();
    679         const CGSize* advances = complexTextRun.advances();
     687        const CGSize* advances = complexTextRun.baseAdvances();
    680688
    681689        bool lastRun = r + 1 == runCount;
     
    751759                            m_expansion -= m_expansionPerOpportunity;
    752760                            m_totalWidth += m_expansionPerOpportunity;
    753                             if (m_adjustedAdvances.isEmpty())
     761                            if (m_adjustedBaseAdvances.isEmpty())
    754762                                m_leadingExpansion = m_expansionPerOpportunity;
    755763                            else
    756                                 m_adjustedAdvances.last().width += m_expansionPerOpportunity;
     764                                m_adjustedBaseAdvances.last().width += m_expansionPerOpportunity;
    757765                        }
    758766                        if (expandRight) {
     
    778786
    779787            advance.height *= -1;
    780             m_adjustedAdvances.append(advance);
     788            m_adjustedBaseAdvances.append(advance);
     789#if USE_LAYOUT_SPECIFIC_ADVANCES
     790            m_glyphOrigins.append(complexTextRun.glyphOrigins()[i]);
     791#endif
    781792            m_adjustedGlyphs.append(glyph);
    782793           
  • trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.h

    r204466 r205373  
    3333#include <wtf/text/WTFString.h>
    3434
     35#define USE_LAYOUT_SPECIFIC_ADVANCES ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000))
     36
    3537typedef unsigned short CGGlyph;
    3638
     
    5759
    5860    // Compute the character offset for a given x coordinate.
    59     int offsetForPosition(float x, bool includePartialGlyphs);
     61    unsigned offsetForPosition(float x, bool includePartialGlyphs);
    6062
    6163    // Returns the width of everything we've consumed so far.
     
    6365
    6466    float totalWidth() const { return m_totalWidth; }
    65 
    66     float finalRoundingWidth() const { return m_finalRoundingWidth; }
    6767
    6868    float minGlyphBoundingBoxX() const { return m_minGlyphBoundingBoxX; }
     
    9696        CFIndex endOffsetAt(size_t i) const { ASSERT(!m_isMonotonic); return m_glyphEndOffsets[i]; }
    9797        const CGGlyph* glyphs() const { return m_glyphs; }
     98
     99        /*
     100         *                                              X (Paint glyph position)   X (Paint glyph position)   X (Paint glyph position)
     101         *                                             7                          7                          7
     102         *                                            /                          /                          /
     103         *                                           / (Glyph origin)           / (Glyph origin)           / (Glyph origin)
     104         *                                          /                          /                          /
     105         *                                         /                          /                          /
     106         *                X-----------------------X--------------------------X--------------------------X---->...
     107         * (text position ^)  (initial advance)          (base advance)             (base advance)
     108         */
    98109        CGSize initialAdvance() const { return m_initialAdvance; }
    99         const CGSize* advances() const { return m_advances; }
     110        const CGSize* baseAdvances() const { return m_baseAdvances; }
     111        const CGPoint* glyphOrigins() const { return m_glyphOrigins.data(); }
    100112        bool isLTR() const { return m_isLTR; }
    101113        bool isMonotonic() const { return m_isMonotonic; }
     
    106118        ComplexTextRun(const Font&, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr);
    107119
    108         unsigned m_glyphCount;
     120        Vector<CGSize, 64> m_baseAdvancesVector;
     121        Vector<CGPoint, 64> m_glyphOrigins;
     122        Vector<CGGlyph, 64> m_glyphsVector;
     123        Vector<CFIndex, 64> m_glyphEndOffsets;
     124        Vector<CFIndex, 64> m_coreTextIndicesVector;
     125        CGSize m_initialAdvance;
    109126        const Font& m_font;
    110127        const UChar* m_characters;
    111         unsigned m_stringLocation;
    112128        size_t m_stringLength;
    113         Vector<CFIndex, 64> m_coreTextIndicesVector;
    114129        const CFIndex* m_coreTextIndices;
     130        const CGGlyph* m_glyphs;
     131        const CGSize* m_baseAdvances;
    115132        CFIndex m_indexBegin;
    116133        CFIndex m_indexEnd;
    117         Vector<CFIndex, 64> m_glyphEndOffsets;
    118         Vector<CGGlyph, 64> m_glyphsVector;
    119         const CGGlyph* m_glyphs;
    120         CGSize m_initialAdvance;
    121         Vector<CGSize, 64> m_advancesVector;
    122         const CGSize* m_advances;
     134        unsigned m_glyphCount;
     135        unsigned m_stringLocation;
    123136        bool m_isLTR;
    124137        bool m_isMonotonic;
     
    136149    unsigned incrementCurrentRun(unsigned& leftmostGlyph);
    137150
    138     // The initial capacity of these vectors was selected as being the smallest power of two greater than
    139     // the average (3.5) plus one standard deviation (7.5) of nonzero sizes used on Arabic Wikipedia.
    140     Vector<unsigned, 16> m_runIndices;
    141     Vector<unsigned, 16> m_glyphCountFromStartToIndex;
    142 
    143     const FontCascade& m_font;
    144     const TextRun& m_run;
    145     bool m_isLTROnly;
    146     bool m_mayUseNaturalWritingDirection;
    147     bool m_forTextEmphasis;
    148 
    149     Vector<String> m_stringsFor8BitRuns;
     151    float runWidthSoFarFraction(unsigned glyphStartOffset, unsigned glyphEndOffset, unsigned oldCharacterInCurrentGlyph, GlyphIterationStyle) const;
     152
     153    Vector<CGSize, 256> m_adjustedBaseAdvances;
     154    Vector<CGPoint, 256> m_glyphOrigins;
     155    Vector<CGGlyph, 256> m_adjustedGlyphs;
     156
    150157    Vector<UChar, 256> m_smallCapsBuffer;
    151158
     
    157164    // its Line. ComplexTextRun::glyphs() and ComplexTextRun::advances() refer to glyphs relative to the ComplexTextRun.
    158165    // The length of the entire TextRun is m_run.length()
     166    Vector<RefPtr<ComplexTextRun>, 16> m_complexTextRuns;
     167
     168    // The initial capacity of these vectors was selected as being the smallest power of two greater than
     169    // the average (3.5) plus one standard deviation (7.5) of nonzero sizes used on Arabic Wikipedia.
     170    Vector<unsigned, 16> m_runIndices;
     171    Vector<unsigned, 16> m_glyphCountFromStartToIndex;
     172
    159173    Vector<RetainPtr<CTLineRef>> m_coreTextLines;
    160     Vector<RefPtr<ComplexTextRun>, 16> m_complexTextRuns;
    161     Vector<CGSize, 256> m_adjustedAdvances;
    162     Vector<CGGlyph, 256> m_adjustedGlyphs;
     174
     175    HashSet<const Font*>* m_fallbackFonts { nullptr };
     176
     177    const FontCascade& m_font;
     178    const TextRun& m_run;
    163179 
    164     unsigned m_currentCharacter;
    165     int m_end;
    166 
    167     CGFloat m_totalWidth;
    168 
    169     float m_runWidthSoFar;
    170     unsigned m_numGlyphsSoFar;
    171     size_t m_currentRun;
    172     unsigned m_glyphInCurrentRun;
    173     unsigned m_characterInCurrentGlyph;
    174     float m_finalRoundingWidth;
    175     float m_expansion;
    176     float m_expansionPerOpportunity;
    177     float m_leadingExpansion;
    178 
    179     HashSet<const Font*>* m_fallbackFonts;
    180 
    181     float m_minGlyphBoundingBoxX;
    182     float m_maxGlyphBoundingBoxX;
    183     float m_minGlyphBoundingBoxY;
    184     float m_maxGlyphBoundingBoxY;
    185 
    186     unsigned m_lastRoundingGlyph;
     180    unsigned m_currentCharacter { 0 };
     181    unsigned m_end { 0 };
     182
     183    float m_totalWidth { 0 };
     184    float m_runWidthSoFar { 0 };
     185    unsigned m_numGlyphsSoFar { 0 };
     186    unsigned m_currentRun { 0 };
     187    unsigned m_glyphInCurrentRun { 0 };
     188    unsigned m_characterInCurrentGlyph { 0 };
     189    float m_expansion { 0 };
     190    float m_expansionPerOpportunity { 0 };
     191    float m_leadingExpansion { 0 };
     192
     193    float m_minGlyphBoundingBoxX { std::numeric_limits<float>::max() };
     194    float m_maxGlyphBoundingBoxX { std::numeric_limits<float>::min() };
     195    float m_minGlyphBoundingBoxY { std::numeric_limits<float>::max() };
     196    float m_maxGlyphBoundingBoxY { std::numeric_limits<float>::min() };
     197
     198    bool m_isLTROnly { true };
     199    bool m_mayUseNaturalWritingDirection { false };
     200    bool m_forTextEmphasis { false };
    187201};
    188202
  • trunk/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.mm

    r203330 r205373  
    3030#include "FontCache.h"
    3131#include "FontCascade.h"
     32#include "SoftLinking.h"
    3233#include "TextRun.h"
    3334#include "WebCoreSystemInterface.h"
     
    3940#include <ApplicationServices/ApplicationServices.h>
    4041#endif
     42
     43#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101100) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED < 90000)
     44SOFT_LINK_FRAMEWORK(CoreText);
     45SOFT_LINK(CoreText, CTRunGetBaseAdvancesAndOrigins, void, (CTRunRef run, CFRange range, CGSize baseAdvances[], CGPoint origins[]), (run, range, baseAdvances, origins))
     46#endif
     47
    4148
    4249// Note: CTFontDescriptorRefs can live forever in caches inside CoreText, so this object can too.
     
    101108
    102109ComplexTextController::ComplexTextRun::ComplexTextRun(CTRunRef ctRun, const Font& font, const UChar* characters, unsigned stringLocation, size_t stringLength, CFRange runRange)
    103     : m_font(font)
     110    : m_initialAdvance(CTRunGetInitialAdvance(ctRun))
     111    , m_font(font)
    104112    , m_characters(characters)
    105     , m_stringLocation(stringLocation)
    106113    , m_stringLength(stringLength)
    107114    , m_indexBegin(runRange.location)
    108115    , m_indexEnd(runRange.location + runRange.length)
    109     , m_initialAdvance(CTRunGetInitialAdvance(ctRun))
     116    , m_stringLocation(stringLocation)
    110117    , m_isLTR(!(CTRunGetStatus(ctRun) & kCTRunStatusRightToLeft))
    111118    , m_isMonotonic(true)
     
    126133    }
    127134
    128     m_advances = CTRunGetAdvancesPtr(ctRun);
    129     if (!m_advances) {
    130         m_advancesVector.grow(m_glyphCount);
    131         CTRunGetAdvances(ctRun, CFRangeMake(0, 0), m_advancesVector.data());
    132         m_advances = m_advancesVector.data();
    133     }
     135#if USE_LAYOUT_SPECIFIC_ADVANCES
     136    m_baseAdvancesVector.grow(m_glyphCount);
     137    m_glyphOrigins.grow(m_glyphCount);
     138    CTRunGetBaseAdvancesAndOrigins(ctRun, CFRangeMake(0, 0), m_baseAdvancesVector.data(), m_glyphOrigins.data());
     139    m_baseAdvances = m_baseAdvancesVector.data();
     140#else
     141    m_baseAdvances = CTRunGetAdvancesPtr(ctRun);
     142    if (!m_baseAdvances) {
     143        m_baseAdvancesVector.grow(m_glyphCount);
     144        CTRunGetAdvances(ctRun, CFRangeMake(0, 0), m_baseAdvancesVector.data());
     145        m_baseAdvances = m_baseAdvancesVector.data();
     146    }
     147#endif
    134148}
    135149
     
    137151// glyphs from LastResort. We want to use the primary font's missing glyph in order to match the fast text code path.
    138152ComplexTextController::ComplexTextRun::ComplexTextRun(const Font& font, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr)
    139     : m_font(font)
     153    : m_initialAdvance(CGSizeZero)
     154    , m_font(font)
    140155    , m_characters(characters)
    141     , m_stringLocation(stringLocation)
    142156    , m_stringLength(stringLength)
    143157    , m_indexBegin(0)
    144158    , m_indexEnd(stringLength)
    145     , m_initialAdvance(CGSizeZero)
     159    , m_stringLocation(stringLocation)
    146160    , m_isLTR(ltr)
    147161    , m_isMonotonic(true)
     
    151165    while (r < m_stringLength) {
    152166        m_coreTextIndicesVector.uncheckedAppend(r);
    153         if (U_IS_LEAD(m_characters[r]) && r + 1 < m_stringLength && U_IS_TRAIL(m_characters[r + 1]))
    154             r += 2;
    155         else
    156             r++;
     167        UChar32 character;
     168        U16_NEXT(m_characters, r, m_stringLength, character);
    157169    }
    158170    m_glyphCount = m_coreTextIndicesVector.size();
     
    166178    m_glyphsVector.fill(0, m_glyphCount);
    167179    m_glyphs = m_glyphsVector.data();
    168     m_advancesVector.fill(CGSizeMake(m_font.widthForGlyph(0), 0), m_glyphCount);
    169     m_advances = m_advancesVector.data();
     180    m_baseAdvancesVector.fill(CGSizeMake(m_font.widthForGlyph(0), 0), m_glyphCount);
     181    m_baseAdvances = m_baseAdvancesVector.data();
    170182}
    171183
  • trunk/Source/WebCore/platform/spi/cocoa/CoreTextSPI.h

    r205282 r205373  
    6969CGSize CTRunGetInitialAdvance(CTRunRef run);
    7070CTLineRef CTLineCreateWithUniCharProvider(CTUniCharProviderCallback provide, CTUniCharDisposeCallback dispose, void* refCon);
     71void CTRunGetBaseAdvancesAndOrigins(CTRunRef, CFRange, CGSize baseAdvances[], CGPoint origins[]);
    7172CTTypesetterRef CTTypesetterCreateWithUniCharProviderAndOptions(CTUniCharProviderCallback provide, CTUniCharDisposeCallback dispose, void* refCon, CFDictionaryRef options);
    7273bool CTFontGetVerticalGlyphsForCharacters(CTFontRef, const UniChar characters[], CGGlyph glyphs[], CFIndex count);
Note: See TracChangeset for help on using the changeset viewer.