Changeset 205396 in webkit


Ignore:
Timestamp:
Sep 2, 2016 10:52:44 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

    r205392 r205396  
     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  Zalan Bujtas  <zalan@apple.com>
    224
  • trunk/LayoutTests/platform/mac/css2.1/t051202-c26-psudo-nest-00-c-expected.txt

    r205382 r205396  
    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

    r205382 r205396  
    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

    r205392 r205396  
     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  Zalan Bujtas  <zalan@apple.com>
    266
  • trunk/Source/WebCore/platform/graphics/GlyphBuffer.h

    r205382 r205396  
    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

    r205382 r205396  
    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

    r205382 r205396  
    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                    }
     
    326310    if (m_run.is8Bit()) {
    327311        String stringFor8BitRun = String::make16BitFrom8BitSource(m_run.characters8(), m_run.length());
    328         cp = stringFor8BitRun.characters16();
    329         m_stringsFor8BitRuns.append(stringFor8BitRun);
     312        m_stringsFor8BitRuns.append(WTFMove(stringFor8BitRun));
     313        cp = m_stringsFor8BitRuns.last().characters16();
    330314    } else
    331315        cp = m_run.characters16();
     
    429413    }
    430414
     415    ASSERT(m_end >= indexOfFontTransition);
    431416    unsigned itemLength = m_end - indexOfFontTransition;
    432417    if (itemLength) {
     
    464449
    465450    m_glyphEndOffsets.grow(m_glyphCount);
    466     for (size_t i = 0; i < m_glyphCount; ++i) {
     451    for (unsigned i = 0; i < m_glyphCount; ++i) {
    467452        CFIndex nextMappedIndex = m_indexEnd;
    468453        for (size_t j = indexAt(i) + 1; j < m_stringLength; ++j) {
     
    531516}
    532517
     518float ComplexTextController::runWidthSoFarFraction(unsigned glyphStartOffset, unsigned glyphEndOffset, unsigned oldCharacterInCurrentGlyph, GlyphIterationStyle iterationStyle) const
     519{
     520    // FIXME: Instead of dividing the glyph's advance equally between the characters, this
     521    // could use the glyph's "ligature carets". This is available in CoreText via CTFontGetLigatureCaretPositions().
     522    if (glyphStartOffset == glyphEndOffset) {
     523        // When there are multiple glyphs per character we need to advance by the full width of the glyph.
     524        ASSERT(m_characterInCurrentGlyph == oldCharacterInCurrentGlyph);
     525        return 1;
     526    }
     527
     528    if (iterationStyle == ByWholeGlyphs) {
     529        if (!oldCharacterInCurrentGlyph)
     530            return 1;
     531        return 0;
     532    }
     533
     534    return static_cast<float>(m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset);
     535}
     536
    533537void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer, GlyphIterationStyle iterationStyle, HashSet<const Font*>* fallbackFonts)
    534538{
    535     if (static_cast<int>(offset) > m_end)
     539    if (offset > m_end)
    536540        offset = m_end;
    537541
     
    563567        // account the text direction.
    564568        if (glyphBuffer && !leftmostGlyph) {
    565             glyphBuffer->setInitialAdvance(complexTextRun.initialAdvance());
     569            CGSize initialAdvance = complexTextRun.initialAdvance();
     570#if USE_LAYOUT_SPECIFIC_ADVANCES
     571            unsigned index = ltr ? 0 : m_glyphOrigins.size() - 1;
     572            initialAdvance.width += m_glyphOrigins[index].x;
     573            initialAdvance.height += m_glyphOrigins[index].y;
     574#endif
     575            glyphBuffer->setInitialAdvance(initialAdvance);
     576
    566577            glyphBuffer->setLeadingExpansion(m_leadingExpansion);
    567578        }
     
    578589                glyphEndOffset = complexTextRun.endOffsetAt(g);
    579590
    580             CGSize adjustedAdvance = m_adjustedAdvances[k];
     591            CGSize adjustedBaseAdvance = m_adjustedBaseAdvances[k];
    581592
    582593            if (glyphStartOffset + complexTextRun.stringLocation() >= m_currentCharacter)
    583594                return;
    584595
    585             if (glyphBuffer && !m_characterInCurrentGlyph)
    586                 glyphBuffer->add(m_adjustedGlyphs[k], &complexTextRun.font(), adjustedAdvance, complexTextRun.indexAt(m_glyphInCurrentRun));
     596            if (glyphBuffer && !m_characterInCurrentGlyph) {
     597                GlyphBufferAdvance paintAdvance = adjustedBaseAdvance;
     598#if USE_LAYOUT_SPECIFIC_ADVANCES
     599                if (k + 1 < m_adjustedBaseAdvances.size()) {
     600                    paintAdvance.setWidth(paintAdvance.width() + m_glyphOrigins[k + 1].x - m_glyphOrigins[k].x);
     601                    paintAdvance.setHeight(paintAdvance.height() - m_glyphOrigins[k + 1].y + m_glyphOrigins[k].y);
     602                }
     603#endif
     604                glyphBuffer->add(m_adjustedGlyphs[k], &complexTextRun.font(), paintAdvance, complexTextRun.indexAt(m_glyphInCurrentRun));
     605            }
    587606
    588607            unsigned oldCharacterInCurrentGlyph = m_characterInCurrentGlyph;
    589608            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);
     609            m_runWidthSoFar += adjustedBaseAdvance.width * runWidthSoFarFraction(glyphStartOffset, glyphEndOffset, oldCharacterInCurrentGlyph, iterationStyle);
    602610
    603611            if (glyphEndOffset + complexTextRun.stringLocation() > m_currentCharacter)
     
    618626        m_glyphInCurrentRun = 0;
    619627    }
    620     if (!m_run.ltr() && m_numGlyphsSoFar == m_adjustedAdvances.size())
    621         m_runWidthSoFar += m_finalRoundingWidth;
    622628}
    623629
     
    657663    bool runForbidsLeadingExpansion = (m_run.expansionBehavior() & LeadingExpansionMask) == ForbidLeadingExpansion;
    658664    bool runForbidsTrailingExpansion = (m_run.expansionBehavior() & TrailingExpansionMask) == ForbidTrailingExpansion;
     665
    659666    // We are iterating in glyph order, not string order. Compare this to WidthIterator::advanceInternal()
    660667    for (size_t r = 0; r < runCount; ++r) {
     
    665672        // Represent the initial advance for a text run by adjusting the advance
    666673        // 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();
     674        if (r && m_adjustedBaseAdvances.size()) {
     675            CGSize previousAdvance = m_adjustedBaseAdvances.last();
    669676            previousAdvance.width += complexTextRun.initialAdvance().width;
    670677            previousAdvance.height -= complexTextRun.initialAdvance().height;
    671             m_adjustedAdvances[m_adjustedAdvances.size() - 1] = previousAdvance;
     678            m_adjustedBaseAdvances[m_adjustedBaseAdvances.size() - 1] = previousAdvance;
    672679        }
    673680        widthSinceLastCommit += complexTextRun.initialAdvance().width;
     
    677684
    678685        const CGGlyph* glyphs = complexTextRun.glyphs();
    679         const CGSize* advances = complexTextRun.advances();
     686        const CGSize* advances = complexTextRun.baseAdvances();
    680687
    681688        bool lastRun = r + 1 == runCount;
     
    751758                            m_expansion -= m_expansionPerOpportunity;
    752759                            m_totalWidth += m_expansionPerOpportunity;
    753                             if (m_adjustedAdvances.isEmpty())
     760                            if (m_adjustedBaseAdvances.isEmpty())
    754761                                m_leadingExpansion = m_expansionPerOpportunity;
    755762                            else
    756                                 m_adjustedAdvances.last().width += m_expansionPerOpportunity;
     763                                m_adjustedBaseAdvances.last().width += m_expansionPerOpportunity;
    757764                        }
    758765                        if (expandRight) {
     
    778785
    779786            advance.height *= -1;
    780             m_adjustedAdvances.append(advance);
     787            m_adjustedBaseAdvances.append(advance);
     788#if USE_LAYOUT_SPECIFIC_ADVANCES
     789            m_glyphOrigins.append(complexTextRun.glyphOrigins()[i]);
     790#endif
    781791            m_adjustedGlyphs.append(glyph);
    782792           
  • trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.h

    r205382 r205396  
    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    Vector<String> m_stringsFor8BitRuns;
     176
     177    HashSet<const Font*>* m_fallbackFonts { nullptr };
     178
     179    const FontCascade& m_font;
     180    const TextRun& m_run;
    163181 
    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;
     182    unsigned m_currentCharacter { 0 };
     183    unsigned m_end { 0 };
     184
     185    float m_totalWidth { 0 };
     186    float m_runWidthSoFar { 0 };
     187    unsigned m_numGlyphsSoFar { 0 };
     188    unsigned m_currentRun { 0 };
     189    unsigned m_glyphInCurrentRun { 0 };
     190    unsigned m_characterInCurrentGlyph { 0 };
     191    float m_expansion { 0 };
     192    float m_expansionPerOpportunity { 0 };
     193    float m_leadingExpansion { 0 };
     194
     195    float m_minGlyphBoundingBoxX { std::numeric_limits<float>::max() };
     196    float m_maxGlyphBoundingBoxX { std::numeric_limits<float>::min() };
     197    float m_minGlyphBoundingBoxY { std::numeric_limits<float>::max() };
     198    float m_maxGlyphBoundingBoxY { std::numeric_limits<float>::min() };
     199
     200    bool m_isLTROnly { true };
     201    bool m_mayUseNaturalWritingDirection { false };
     202    bool m_forTextEmphasis { false };
    187203};
    188204
  • trunk/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.mm

    r205382 r205396  
    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

    r205382 r205396  
    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.