| Differences between
and this patch
- a/Source/WebCore/ChangeLog +27 lines
Lines 1-3 a/Source/WebCore/ChangeLog_sec1
1
2016-09-08  Myles C. Maxfield  <mmaxfield@apple.com>
2
3
        [Cocoa] Improve performance of glyph advance metrics gathering
4
        https://bugs.webkit.org/show_bug.cgi?id=161119
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        Most of the glyphs in a GlyphPage are never read from. Therefore, we can get a performance boost
9
        by not populating as many items in the GlyphPage. Because of the performance characteristics of
10
        CTFontGetGlyphsForCharacters(), a better size for a GlyphPage is 16 items. This, coupled with
11
        using CTFontGetUnsummedAdvancesForGlyphsAndStyle(), causes between a 0.01%-0.5% speedup on PLT.
12
13
        No new tests because there is no behavior change.
14
15
        * platform/graphics/Font.cpp:
16
        (WebCore::Font::initCharWidths):
17
        (WebCore::Font::platformGlyphInit):
18
        (WebCore::createAndFillGlyphPage):
19
        * platform/graphics/Font.h:
20
        (WebCore::Font::widthForGlyph):
21
        * platform/graphics/GlyphMetricsMap.h:
22
        * platform/graphics/GlyphPage.h:
23
        * platform/graphics/cocoa/FontCocoa.mm:
24
        * platform/spi/cocoa/CoreTextSPI.h:
25
        (WebCore::Font::platformWidthForGlyph):
26
        (WebCore::canUseFastGlyphAdvanceGetter): Deleted.
27
1
2016-09-08  Yusuke Suzuki  <utatane.tea@gmail.com>
28
2016-09-08  Yusuke Suzuki  <utatane.tea@gmail.com>
2
29
3
        ScriptRunner should be driven by PendingScript rather than ScriptElement
30
        ScriptRunner should be driven by PendingScript rather than ScriptElement
- a/Source/WebCore/platform/graphics/Font.cpp -22 / +32 lines
Lines 81-92 Font::Font(const FontPlatformData& platformData, bool isCustomFont, bool isLoadi a/Source/WebCore/platform/graphics/Font.cpp_sec1
81
// Estimates of avgCharWidth and maxCharWidth for platforms that don't support accessing these values from the font.
81
// Estimates of avgCharWidth and maxCharWidth for platforms that don't support accessing these values from the font.
82
void Font::initCharWidths()
82
void Font::initCharWidths()
83
{
83
{
84
    auto* glyphPageZero = glyphPage(0);
84
    auto* glyphPageZero = glyphPage('0' / GlyphPage::size);
85
85
86
    // Treat the width of a '0' as the avgCharWidth.
86
    // Treat the width of a '0' as the avgCharWidth.
87
    if (m_avgCharWidth <= 0.f && glyphPageZero) {
87
    if (m_avgCharWidth <= 0.f && glyphPageZero) {
88
        static const UChar32 digitZeroChar = '0';
88
        Glyph digitZeroGlyph = glyphPageZero->glyphDataForCharacter('0').glyph;
89
        Glyph digitZeroGlyph = glyphPageZero->glyphDataForCharacter(digitZeroChar).glyph;
90
        if (digitZeroGlyph)
89
        if (digitZeroGlyph)
91
            m_avgCharWidth = widthForGlyph(digitZeroGlyph);
90
            m_avgCharWidth = widthForGlyph(digitZeroGlyph);
92
    }
91
    }
Lines 102-123 void Font::initCharWidths() a/Source/WebCore/platform/graphics/Font.cpp_sec2
102
void Font::platformGlyphInit()
101
void Font::platformGlyphInit()
103
{
102
{
104
    auto* glyphPageZero = glyphPage(0);
103
    auto* glyphPageZero = glyphPage(0);
105
    if (!glyphPageZero) {
104
    auto* glyphPageCharacterZero = glyphPage('0' / GlyphPage::size);
106
        determinePitch();
105
    auto* glyphPageSpace = glyphPage(space / GlyphPage::size);
107
        return;
108
    }
109
106
110
    // Ask for the glyph for 0 to avoid paging in ZERO WIDTH SPACE. Control characters, including 0,
107
    // Ask for the glyph for 0 to avoid paging in ZERO WIDTH SPACE. Control characters, including 0,
111
    // are mapped to the ZERO WIDTH SPACE glyph.
108
    // are mapped to the ZERO WIDTH SPACE glyph.
112
    m_zeroWidthSpaceGlyph = glyphPageZero->glyphDataForCharacter(0).glyph;
109
    if (glyphPageZero)
110
        m_zeroWidthSpaceGlyph = glyphPageZero->glyphDataForCharacter(0).glyph;
113
111
114
    // Nasty hack to determine if we should round or ceil space widths.
112
    // Nasty hack to determine if we should round or ceil space widths.
115
    // If the font is monospace or fake monospace we ceil to ensure that 
113
    // If the font is monospace or fake monospace we ceil to ensure that 
116
    // every character and the space are the same width. Otherwise we round.
114
    // every character and the space are the same width. Otherwise we round.
117
    m_spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph;
115
    if (glyphPageSpace)
116
        m_spaceGlyph = glyphPageSpace->glyphDataForCharacter(space).glyph;
118
    float width = widthForGlyph(m_spaceGlyph);
117
    float width = widthForGlyph(m_spaceGlyph);
119
    m_spaceWidth = width;
118
    m_spaceWidth = width;
120
    m_zeroGlyph = glyphPageZero->glyphDataForCharacter('0').glyph;
119
    if (glyphPageCharacterZero)
120
        m_zeroGlyph = glyphPageCharacterZero->glyphDataForCharacter('0').glyph;
121
    m_fontMetrics.setZeroWidth(widthForGlyph(m_zeroGlyph));
121
    m_fontMetrics.setZeroWidth(widthForGlyph(m_zeroGlyph));
122
    determinePitch();
122
    determinePitch();
123
    m_adjustedSpaceWidth = m_treatAsFixedPitch ? ceilf(width) : roundf(width);
123
    m_adjustedSpaceWidth = m_treatAsFixedPitch ? ceilf(width) : roundf(width);
Lines 152-158 static RefPtr<GlyphPage> createAndFillGlyphPage(unsigned pageNumber, const Font& a/Source/WebCore/platform/graphics/Font.cpp_sec3
152
    // FIXME: Times New Roman contains Arabic glyphs, but Core Text doesn't know how to shape them. See <rdar://problem/9823975>.
152
    // FIXME: Times New Roman contains Arabic glyphs, but Core Text doesn't know how to shape them. See <rdar://problem/9823975>.
153
    // Once we have the fix for <rdar://problem/9823975> then remove this code together with Font::shouldNotBeUsedForArabic()
153
    // Once we have the fix for <rdar://problem/9823975> then remove this code together with Font::shouldNotBeUsedForArabic()
154
    // in <rdar://problem/12096835>.
154
    // in <rdar://problem/12096835>.
155
    if (pageNumber == 6 && font.shouldNotBeUsedForArabic())
155
    if (pageNumber >= 0x60 && pageNumber < 0x70 && font.shouldNotBeUsedForArabic())
156
        return nullptr;
156
        return nullptr;
157
#endif
157
#endif
158
158
Lines 165-195 static RefPtr<GlyphPage> createAndFillGlyphPage(unsigned pageNumber, const Font& a/Source/WebCore/platform/graphics/Font.cpp_sec4
165
        for (unsigned i = 0; i < GlyphPage::size; i++)
165
        for (unsigned i = 0; i < GlyphPage::size; i++)
166
            buffer[i] = start + i;
166
            buffer[i] = start + i;
167
167
168
        static_assert(GlyphPage::size == 16 && !(GlyphPage::size & (GlyphPage::size - 1)), "createAndFillGlyphPage() assumes GlyphPage::size is 16.");
168
        if (!start) {
169
        if (!start) {
169
            // Control characters must not render at all.
170
            // Control characters must not render at all.
170
            for (unsigned i = 0; i < 0x20; ++i)
171
            for (unsigned i = 0; i < 0x10; ++i)
171
                buffer[i] = zeroWidthSpace;
172
            for (unsigned i = 0x7F; i < 0xA0; i++)
173
                buffer[i] = zeroWidthSpace;
172
                buffer[i] = zeroWidthSpace;
174
            buffer[softHyphen] = zeroWidthSpace;
175
176
            // \n, \t, and nonbreaking space must render as a space.
173
            // \n, \t, and nonbreaking space must render as a space.
177
            buffer[(int)'\n'] = ' ';
174
            buffer[static_cast<int>('\t')] = space;
178
            buffer[(int)'\t'] = ' ';
175
            buffer[static_cast<int>('\n')] = space;
179
            buffer[noBreakSpace] = ' ';
176
        } else if (pageNumber == 1) {
177
            // Control characters must not render at all.
178
            for (unsigned i = 0; i < 0x10; ++i)
179
                buffer[i] = zeroWidthSpace;
180
        } else if (start == (0x7F & ~(GlyphPage::size - 1))) {
181
            buffer[0x7F - start] = zeroWidthSpace;
182
        } else if (pageNumber >= 8 && pageNumber < 10) {
183
            for (unsigned i = 0; i < GlyphPage::size; ++i)
184
                buffer[i] = zeroWidthSpace;
185
        } else if (pageNumber == 10) {
186
            buffer[softHyphen - start] = zeroWidthSpace;
187
            buffer[noBreakSpace - start] = space;
180
        } else if (start == (leftToRightMark & ~(GlyphPage::size - 1))) {
188
        } else if (start == (leftToRightMark & ~(GlyphPage::size - 1))) {
181
            // LRM, RLM, LRE, RLE, ZWNJ, ZWJ, and PDF must not render at all.
189
            // LRM, RLM, LRE, RLE, ZWNJ, ZWJ, and PDF must not render at all.
182
            buffer[leftToRightMark - start] = zeroWidthSpace;
190
            buffer[leftToRightMark - start] = zeroWidthSpace;
183
            buffer[rightToLeftMark - start] = zeroWidthSpace;
191
            buffer[rightToLeftMark - start] = zeroWidthSpace;
192
            buffer[zeroWidthNonJoiner - start] = zeroWidthSpace;
193
            buffer[zeroWidthJoiner - start] = zeroWidthSpace;
194
        } else if (start == (leftToRightEmbed & ~(GlyphPage::size - 1))) {
184
            buffer[leftToRightEmbed - start] = zeroWidthSpace;
195
            buffer[leftToRightEmbed - start] = zeroWidthSpace;
185
            buffer[rightToLeftEmbed - start] = zeroWidthSpace;
196
            buffer[rightToLeftEmbed - start] = zeroWidthSpace;
186
            buffer[leftToRightOverride - start] = zeroWidthSpace;
197
            buffer[leftToRightOverride - start] = zeroWidthSpace;
187
            buffer[rightToLeftOverride - start] = zeroWidthSpace;
198
            buffer[rightToLeftOverride - start] = zeroWidthSpace;
199
            buffer[popDirectionalFormatting - start] = zeroWidthSpace;
200
        } else if (start == (leftToRightIsolate & ~(GlyphPage::size - 1))) {
188
            buffer[leftToRightIsolate - start] = zeroWidthSpace;
201
            buffer[leftToRightIsolate - start] = zeroWidthSpace;
189
            buffer[rightToLeftIsolate - start] = zeroWidthSpace;
202
            buffer[rightToLeftIsolate - start] = zeroWidthSpace;
190
            buffer[zeroWidthNonJoiner - start] = zeroWidthSpace;
191
            buffer[zeroWidthJoiner - start] = zeroWidthSpace;
192
            buffer[popDirectionalFormatting - start] = zeroWidthSpace;
193
            buffer[popDirectionalIsolate - start] = zeroWidthSpace;
203
            buffer[popDirectionalIsolate - start] = zeroWidthSpace;
194
            buffer[firstStrongIsolate - start] = zeroWidthSpace;
204
            buffer[firstStrongIsolate - start] = zeroWidthSpace;
195
        } else if (start == (objectReplacementCharacter & ~(GlyphPage::size - 1))) {
205
        } else if (start == (objectReplacementCharacter & ~(GlyphPage::size - 1))) {
- a/Source/WebCore/platform/graphics/Font.h -2 / +2 lines
Lines 337-349 ALWAYS_INLINE float Font::widthForGlyph(Glyph glyph) const a/Source/WebCore/platform/graphics/Font.h_sec1
337
        return width;
337
        return width;
338
338
339
#if ENABLE(OPENTYPE_VERTICAL)
339
#if ENABLE(OPENTYPE_VERTICAL)
340
    if (m_verticalData)
340
    if (m_verticalData) {
341
#if USE(CG) || USE(CAIRO)
341
#if USE(CG) || USE(CAIRO)
342
        width = m_verticalData->advanceHeight(this, glyph) + m_syntheticBoldOffset;
342
        width = m_verticalData->advanceHeight(this, glyph) + m_syntheticBoldOffset;
343
#else
343
#else
344
        width = m_verticalData->advanceHeight(this, glyph);
344
        width = m_verticalData->advanceHeight(this, glyph);
345
#endif
345
#endif
346
    else
346
    } else
347
#endif
347
#endif
348
        width = platformWidthForGlyph(glyph);
348
        width = platformWidthForGlyph(glyph);
349
349
- a/Source/WebCore/platform/graphics/GlyphMetricsMap.h -1 / +1 lines
Lines 54-60 private: a/Source/WebCore/platform/graphics/GlyphMetricsMap.h_sec1
54
    class GlyphMetricsPage {
54
    class GlyphMetricsPage {
55
        WTF_MAKE_FAST_ALLOCATED;
55
        WTF_MAKE_FAST_ALLOCATED;
56
    public:
56
    public:
57
        static const size_t size = 256; // Usually covers Latin-1 in a single page.
57
        static const size_t size = 16;
58
58
59
        GlyphMetricsPage() = default;
59
        GlyphMetricsPage() = default;
60
        explicit GlyphMetricsPage(const T& initialValue)
60
        explicit GlyphMetricsPage(const T& initialValue)
- a/Source/WebCore/platform/graphics/GlyphPage.h -2 / +2 lines
Lines 57-63 struct GlyphData { a/Source/WebCore/platform/graphics/GlyphPage.h_sec1
57
57
58
// A GlyphPage contains a fixed-size set of GlyphData mappings for a contiguous
58
// A GlyphPage contains a fixed-size set of GlyphData mappings for a contiguous
59
// range of characters in the Unicode code space. GlyphPages are indexed
59
// range of characters in the Unicode code space. GlyphPages are indexed
60
// starting from 0 and incrementing for each 256 glyphs.
60
// starting from 0 and incrementing for each "size" number of glyphs.
61
class GlyphPage : public RefCounted<GlyphPage> {
61
class GlyphPage : public RefCounted<GlyphPage> {
62
public:
62
public:
63
    static Ref<GlyphPage> create(const Font& font)
63
    static Ref<GlyphPage> create(const Font& font)
Lines 72-78 public: a/Source/WebCore/platform/graphics/GlyphPage.h_sec2
72
72
73
    static unsigned count() { return s_count; }
73
    static unsigned count() { return s_count; }
74
74
75
    static const size_t size = 256; // Covers Latin-1 in a single page.
75
    static const size_t size = 16;
76
    static unsigned indexForCharacter(UChar32 c) { return c % GlyphPage::size; }
76
    static unsigned indexForCharacter(UChar32 c) { return c % GlyphPage::size; }
77
77
78
    GlyphData glyphDataForCharacter(UChar32 c) const
78
    GlyphData glyphDataForCharacter(UChar32 c) const
- a/Source/WebCore/platform/graphics/cocoa/FontCocoa.mm -1 / +17 lines
Lines 596-601 FloatRect Font::platformBoundsForGlyph(Glyph glyph) const a/Source/WebCore/platform/graphics/cocoa/FontCocoa.mm_sec1
596
    return boundingBox;
596
    return boundingBox;
597
}
597
}
598
598
599
#if !((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000))
599
static inline Optional<CGSize> advanceForColorBitmapFont(const FontPlatformData& platformData, Glyph glyph)
600
static inline Optional<CGSize> advanceForColorBitmapFont(const FontPlatformData& platformData, Glyph glyph)
600
{
601
{
601
    CTFontRef font = platformData.font();
602
    CTFontRef font = platformData.font();
Lines 617-632 static inline bool canUseFastGlyphAdvanceGetter(const FontPlatformData& platform a/Source/WebCore/platform/graphics/cocoa/FontCocoa.mm_sec2
617
    }
618
    }
618
    return true;
619
    return true;
619
}
620
}
621
#endif
620
622
621
float Font::platformWidthForGlyph(Glyph glyph) const
623
float Font::platformWidthForGlyph(Glyph glyph) const
622
{
624
{
623
    CGSize advance = CGSizeZero;
625
    CGSize advance = CGSizeZero;
624
    bool horizontal = platformData().orientation() == Horizontal;
626
    bool horizontal = platformData().orientation() == Horizontal;
627
    CGFontRenderingStyle style = kCGFontRenderingStyleAntialiasing | kCGFontRenderingStyleSubpixelPositioning | kCGFontRenderingStyleSubpixelQuantization | kCGFontAntialiasingStyleUnfiltered;
628
629
#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000)
630
    if (platformData().size()) {
631
        CTFontOrientation orientation = horizontal || m_isBrokenIdeographFallback ? kCTFontOrientationHorizontal : kCTFontOrientationVertical;
632
        // FIXME: Remove this special-casing when <rdar://problem/28197291> is fixed.
633
        if (CTFontIsAppleColorEmoji(m_platformData.ctFont()))
634
            CTFontGetAdvancesForGlyphs(m_platformData.ctFont(), orientation, &glyph, &advance, 1);
635
        else
636
            CTFontGetUnsummedAdvancesForGlyphsAndStyle(m_platformData.ctFont(), orientation, style, &glyph, &advance, 1);
637
    }
638
639
#else
640
625
    bool populatedAdvance = false;
641
    bool populatedAdvance = false;
626
    if ((horizontal || m_isBrokenIdeographFallback) && canUseFastGlyphAdvanceGetter(this->platformData(), glyph, advance, populatedAdvance)) {
642
    if ((horizontal || m_isBrokenIdeographFallback) && canUseFastGlyphAdvanceGetter(this->platformData(), glyph, advance, populatedAdvance)) {
627
        float pointSize = platformData().size();
643
        float pointSize = platformData().size();
628
        CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize);
644
        CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize);
629
        CGFontRenderingStyle style = kCGFontRenderingStyleAntialiasing | kCGFontRenderingStyleSubpixelPositioning | kCGFontRenderingStyleSubpixelQuantization | kCGFontAntialiasingStyleUnfiltered;
630
        if (!CGFontGetGlyphAdvancesForStyle(platformData().cgFont(), &m, style, &glyph, 1, &advance)) {
645
        if (!CGFontGetGlyphAdvancesForStyle(platformData().cgFont(), &m, style, &glyph, 1, &advance)) {
631
            RetainPtr<CFStringRef> fullName = adoptCF(CGFontCopyFullName(platformData().cgFont()));
646
            RetainPtr<CFStringRef> fullName = adoptCF(CGFontCopyFullName(platformData().cgFont()));
632
            LOG_ERROR("Unable to cache glyph widths for %@ %f", fullName.get(), pointSize);
647
            LOG_ERROR("Unable to cache glyph widths for %@ %f", fullName.get(), pointSize);
Lines 634-639 float Font::platformWidthForGlyph(Glyph glyph) const a/Source/WebCore/platform/graphics/cocoa/FontCocoa.mm_sec3
634
        }
649
        }
635
    } else if (!populatedAdvance && platformData().size())
650
    } else if (!populatedAdvance && platformData().size())
636
        CTFontGetAdvancesForGlyphs(m_platformData.ctFont(), horizontal ? kCTFontOrientationHorizontal : kCTFontOrientationVertical, &glyph, &advance, 1);
651
        CTFontGetAdvancesForGlyphs(m_platformData.ctFont(), horizontal ? kCTFontOrientationHorizontal : kCTFontOrientationVertical, &glyph, &advance, 1);
652
#endif
637
653
638
    return advance.width + m_syntheticBoldOffset;
654
    return advance.width + m_syntheticBoldOffset;
639
}
655
}
- a/Source/WebCore/platform/spi/cocoa/CoreTextSPI.h +1 lines
Lines 71-76 CTLineRef CTLineCreateWithUniCharProvider(CTUniCharProviderCallback provide, CTU a/Source/WebCore/platform/spi/cocoa/CoreTextSPI.h_sec1
71
void CTRunGetBaseAdvancesAndOrigins(CTRunRef, CFRange, CGSize baseAdvances[], CGPoint origins[]);
71
void CTRunGetBaseAdvancesAndOrigins(CTRunRef, CFRange, CGSize baseAdvances[], CGPoint origins[]);
72
CTTypesetterRef CTTypesetterCreateWithUniCharProviderAndOptions(CTUniCharProviderCallback provide, CTUniCharDisposeCallback dispose, void* refCon, CFDictionaryRef options);
72
CTTypesetterRef CTTypesetterCreateWithUniCharProviderAndOptions(CTUniCharProviderCallback provide, CTUniCharDisposeCallback dispose, void* refCon, CFDictionaryRef options);
73
bool CTFontGetVerticalGlyphsForCharacters(CTFontRef, const UniChar characters[], CGGlyph glyphs[], CFIndex count);
73
bool CTFontGetVerticalGlyphsForCharacters(CTFontRef, const UniChar characters[], CGGlyph glyphs[], CFIndex count);
74
void CTFontGetUnsummedAdvancesForGlyphsAndStyle(CTFontRef, CTFontOrientation, CGFontRenderingStyle, const CGGlyph[], CGSize advances[], CFIndex count);
74
75
75
CTFontDescriptorRef CTFontDescriptorCreateForUIType(CTFontUIFontType, CGFloat size, CFStringRef language);
76
CTFontDescriptorRef CTFontDescriptorCreateForUIType(CTFontUIFontType, CGFloat size, CFStringRef language);
76
CTFontDescriptorRef CTFontDescriptorCreateWithTextStyle(CFStringRef style, CFStringRef size, CFStringRef language);
77
CTFontDescriptorRef CTFontDescriptorCreateWithTextStyle(CFStringRef style, CFStringRef size, CFStringRef language);

Return to Bug 161119