| Differences between
and this patch
- a/Source/WebCore/ChangeLog +27 lines
Lines 1-3 a/Source/WebCore/ChangeLog_sec1
1
2016-08-25  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
        No new tests (OOPS!).
9
10
        * platform/graphics/Font.cpp:
11
        (WebCore::Font::platformGlyphInit):
12
        * platform/graphics/Font.h:
13
        (WebCore::Font::widthForGlyph):
14
        * platform/graphics/GlyphPage.h:
15
        (WebCore::GlyphData::GlyphData):
16
        (WebCore::GlyphPage::advanceForCharacter):
17
        (WebCore::GlyphPage::glyphDataForIndex):
18
        (WebCore::GlyphPage::advanceForIndex):
19
        (WebCore::GlyphPage::setGlyphForIndex):
20
        * platform/graphics/WidthIterator.cpp:
21
        (WebCore::WidthIterator::advanceInternal):
22
        * platform/graphics/cocoa/FontCocoa.mm:
23
        (WebCore::Font::platformWidthForGlyph):
24
        * platform/graphics/mac/GlyphPageMac.cpp:
25
        (WebCore::GlyphPage::fill):
26
        * platform/spi/cocoa/CoreTextSPI.h:
27
1
2016-08-25  Wenson Hsieh  <wenson_hsieh@apple.com>
28
2016-08-25  Wenson Hsieh  <wenson_hsieh@apple.com>
2
29
3
        Dragging against the end of the inline media scrubber causes the media scrubber to hide
30
        Dragging against the end of the inline media scrubber causes the media scrubber to hide
- a/Source/WebCore/platform/graphics/Font.cpp -18 / +30 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-108 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);
105
    auto* glyphPageSpace = glyphPage(space / GlyphPage::size);
106
    if (!glyphPageZero || !glyphPageCharacterZero || !glyphPageSpace) {
106
        determinePitch();
107
        determinePitch();
107
        return;
108
        return;
108
    }
109
    }
Lines 114-123 void Font::platformGlyphInit() a/Source/WebCore/platform/graphics/Font.cpp_sec3
114
    // Nasty hack to determine if we should round or ceil space widths.
115
    // 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 
116
    // 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.
117
    // every character and the space are the same width. Otherwise we round.
117
    m_spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph;
118
    m_spaceGlyph = glyphPageSpace->glyphDataForCharacter(space).glyph;
118
    float width = widthForGlyph(m_spaceGlyph);
119
    float width = widthForGlyph(m_spaceGlyph);
119
    m_spaceWidth = width;
120
    m_spaceWidth = width;
120
    m_zeroGlyph = glyphPageZero->glyphDataForCharacter('0').glyph;
121
    m_zeroGlyph = glyphPageCharacterZero->glyphDataForCharacter('0').glyph;
121
    m_fontMetrics.setZeroWidth(widthForGlyph(m_zeroGlyph));
122
    m_fontMetrics.setZeroWidth(widthForGlyph(m_zeroGlyph));
122
    determinePitch();
123
    determinePitch();
123
    m_adjustedSpaceWidth = m_treatAsFixedPitch ? ceilf(width) : roundf(width);
124
    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_sec4
152
    // FIXME: Times New Roman contains Arabic glyphs, but Core Text doesn't know how to shape them. See <rdar://problem/9823975>.
153
    // 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()
154
    // Once we have the fix for <rdar://problem/9823975> then remove this code together with Font::shouldNotBeUsedForArabic()
154
    // in <rdar://problem/12096835>.
155
    // in <rdar://problem/12096835>.
155
    if (pageNumber == 6 && font.shouldNotBeUsedForArabic())
156
    if (pageNumber >= 0x60 && pageNumber < 0x70 && && font.shouldNotBeUsedForArabic())
156
        return nullptr;
157
        return nullptr;
157
#endif
158
#endif
158
159
Lines 165-197 static RefPtr<GlyphPage> createAndFillGlyphPage(unsigned pageNumber, const Font& a/Source/WebCore/platform/graphics/Font.cpp_sec5
165
        for (unsigned i = 0; i < GlyphPage::size; i++)
166
        for (unsigned i = 0; i < GlyphPage::size; i++)
166
            buffer[i] = start + i;
167
            buffer[i] = start + i;
167
168
169
        static_assert(GlyphPage::size == 16 && !(GlyphPage::size & (GlyphPage::size - 1)), "createAndFillGlyphPage() assumes GlyphPage::size is 16.");
168
        if (!start) {
170
        if (!start) {
169
            // Control characters must not render at all.
171
            // Control characters must not render at all.
170
            for (unsigned i = 0; i < 0x20; ++i)
172
            for (unsigned i = 0; i < 0x10; ++i)
171
                buffer[i] = zeroWidthSpace;
172
            for (unsigned i = 0x7F; i < 0xA0; i++)
173
                buffer[i] = zeroWidthSpace;
173
                buffer[i] = zeroWidthSpace;
174
            buffer[softHyphen] = zeroWidthSpace;
175
176
            // \n, \t, and nonbreaking space must render as a space.
174
            // \n, \t, and nonbreaking space must render as a space.
177
            buffer[(int)'\n'] = ' ';
175
            buffer[static_cast<int>('\t')] = space;
178
            buffer[(int)'\t'] = ' ';
176
            buffer[static_cast<int>('\n')] = space;
179
            buffer[noBreakSpace] = ' ';
177
        } else if (start == 1) {
178
            // Control characters must not render at all.
179
            for (unsigned i = 0; i < 0x10; ++i)
180
                buffer[i] = zeroWidthSpace;
181
        } else if (start == (0x7F & ~(GlyphPage::size - 1))) {
182
            buffer[0x7F - start] = zeroWidthSpace;
183
        } else if (pageNumber >= 8 && pageNumber < 10) {
184
            for (unsigned i = 0; i < GlyphPage::size; ++i)
185
                buffer[i] = zeroWidthSpace;
186
        } else if (pageNumber == 10) {
187
            buffer[softHyphen - start] = zeroWidthSpace;
188
            buffer[noBreakSpace - start] = space;
180
        } else if (start == (leftToRightMark & ~(GlyphPage::size - 1))) {
189
        } else if (start == (leftToRightMark & ~(GlyphPage::size - 1))) {
181
            // LRM, RLM, LRE, RLE, ZWNJ, ZWJ, and PDF must not render at all.
190
            // LRM, RLM, LRE, RLE, ZWNJ, ZWJ, and PDF must not render at all.
182
            buffer[leftToRightMark - start] = zeroWidthSpace;
191
            buffer[leftToRightMark - start] = zeroWidthSpace;
183
            buffer[rightToLeftMark - start] = zeroWidthSpace;
192
            buffer[rightToLeftMark - start] = zeroWidthSpace;
193
        } else if (start == (leftToRightEmbed & ~(GlyphPage::size - 1))) {
184
            buffer[leftToRightEmbed - start] = zeroWidthSpace;
194
            buffer[leftToRightEmbed - start] = zeroWidthSpace;
185
            buffer[rightToLeftEmbed - start] = zeroWidthSpace;
195
            buffer[rightToLeftEmbed - start] = zeroWidthSpace;
186
            buffer[leftToRightOverride - start] = zeroWidthSpace;
196
            buffer[leftToRightOverride - start] = zeroWidthSpace;
187
            buffer[rightToLeftOverride - start] = zeroWidthSpace;
197
            buffer[rightToLeftOverride - start] = zeroWidthSpace;
198
            buffer[popDirectionalFormatting - start] = zeroWidthSpace;
199
        } else if (start == (leftToRightIsolate & ~(GlyphPage::size - 1))) {
188
            buffer[leftToRightIsolate - start] = zeroWidthSpace;
200
            buffer[leftToRightIsolate - start] = zeroWidthSpace;
189
            buffer[rightToLeftIsolate - start] = zeroWidthSpace;
201
            buffer[rightToLeftIsolate - start] = zeroWidthSpace;
190
            buffer[zeroWidthNonJoiner - start] = zeroWidthSpace;
191
            buffer[zeroWidthJoiner - start] = zeroWidthSpace;
192
            buffer[popDirectionalFormatting - start] = zeroWidthSpace;
193
            buffer[popDirectionalIsolate - start] = zeroWidthSpace;
202
            buffer[popDirectionalIsolate - start] = zeroWidthSpace;
194
            buffer[firstStrongIsolate - start] = zeroWidthSpace;
203
            buffer[firstStrongIsolate - start] = zeroWidthSpace;
204
        } else if (start == (zeroWidthNonJoiner & ~(GlyphPage::size - 1))) {
205
            buffer[zeroWidthNonJoiner - start] = zeroWidthSpace;
206
            buffer[zeroWidthJoiner - start] = zeroWidthSpace;
195
        } else if (start == (objectReplacementCharacter & ~(GlyphPage::size - 1))) {
207
        } else if (start == (objectReplacementCharacter & ~(GlyphPage::size - 1))) {
196
            // Object replacement character must not render at all.
208
            // Object replacement character must not render at all.
197
            buffer[objectReplacementCharacter - start] = zeroWidthSpace;
209
            buffer[objectReplacementCharacter - start] = zeroWidthSpace;
- 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 -5 / +29 lines
Lines 31-40 a/Source/WebCore/platform/graphics/GlyphPage.h_sec1
31
#define GlyphPage_h
31
#define GlyphPage_h
32
32
33
#include "Glyph.h"
33
#include "Glyph.h"
34
#include <array>
34
#include <string.h>
35
#include <string.h>
35
#include <unicode/utypes.h>
36
#include <unicode/utypes.h>
37
#include <wtf/Optional.h>
36
#include <wtf/RefCounted.h>
38
#include <wtf/RefCounted.h>
37
#include <wtf/Ref.h>
39
#include <wtf/Ref.h>
40
#include <wtf/Vector.h>
38
41
39
namespace WebCore {
42
namespace WebCore {
40
43
Lines 43-51 class Font; a/Source/WebCore/platform/graphics/GlyphPage.h_sec2
43
// Holds the glyph index and the corresponding Font information for a given
46
// Holds the glyph index and the corresponding Font information for a given
44
// character.
47
// character.
45
struct GlyphData {
48
struct GlyphData {
46
    GlyphData(Glyph g = 0, const Font* f = 0)
49
    GlyphData(Glyph g = 0, const Font* f = nullptr, Optional<float> advance = Nullopt)
47
        : glyph(g)
50
        : glyph(g)
48
        , font(f)
51
        , font(f)
52
        , advance(advance)
49
    {
53
    {
50
    }
54
    }
51
55
Lines 53-58 struct GlyphData { a/Source/WebCore/platform/graphics/GlyphPage.h_sec3
53
57
54
    Glyph glyph;
58
    Glyph glyph;
55
    const Font* font;
59
    const Font* font;
60
    Optional<float> advance;
56
};
61
};
57
62
58
// A GlyphPage contains a fixed-size set of GlyphData mappings for a contiguous
63
// A GlyphPage contains a fixed-size set of GlyphData mappings for a contiguous
Lines 72-78 public: a/Source/WebCore/platform/graphics/GlyphPage.h_sec4
72
77
73
    static unsigned count() { return s_count; }
78
    static unsigned count() { return s_count; }
74
79
75
    static const size_t size = 256; // Covers Latin-1 in a single page.
80
    static constexpr size_t size = 16;
76
    static unsigned indexForCharacter(UChar32 c) { return c % GlyphPage::size; }
81
    static unsigned indexForCharacter(UChar32 c) { return c % GlyphPage::size; }
77
82
78
    GlyphData glyphDataForCharacter(UChar32 c) const
83
    GlyphData glyphDataForCharacter(UChar32 c) const
Lines 85-94 public: a/Source/WebCore/platform/graphics/GlyphPage.h_sec5
85
        return glyphForIndex(indexForCharacter(c));
90
        return glyphForIndex(indexForCharacter(c));
86
    }
91
    }
87
92
93
    Optional<float> advanceForCharacter(UChar32 c) const
94
    {
95
        return advanceForIndex(indexForCharacter(c));
96
    }
97
88
    GlyphData glyphDataForIndex(unsigned index) const
98
    GlyphData glyphDataForIndex(unsigned index) const
89
    {
99
    {
90
        Glyph glyph = glyphForIndex(index);
100
        Glyph glyph = glyphForIndex(index);
91
        return GlyphData(glyph, glyph ? &m_font : nullptr);
101
        return GlyphData(glyph, glyph ? &m_font : nullptr, advanceForIndex(index));
92
    }
102
    }
93
103
94
    Glyph glyphForIndex(unsigned index) const
104
    Glyph glyphForIndex(unsigned index) const
Lines 97-107 public: a/Source/WebCore/platform/graphics/GlyphPage.h_sec6
97
        return m_glyphs[index];
107
        return m_glyphs[index];
98
    }
108
    }
99
109
110
    Optional<float> advanceForIndex(unsigned index) const
111
    {
112
        ASSERT_WITH_SECURITY_IMPLICATION(index < size);
113
        if (m_advances.isEmpty())
114
            return Nullopt;
115
        return m_advances[index];
116
    }
117
100
    // FIXME: Pages are immutable after initialization. This should be private.
118
    // FIXME: Pages are immutable after initialization. This should be private.
101
    void setGlyphForIndex(unsigned index, Glyph glyph)
119
    void setGlyphForIndex(unsigned index, Glyph glyph, Optional<float> advance = Nullopt)
102
    {
120
    {
103
        ASSERT_WITH_SECURITY_IMPLICATION(index < size);
121
        ASSERT_WITH_SECURITY_IMPLICATION(index < size);
104
        m_glyphs[index] = glyph;
122
        m_glyphs[index] = glyph;
123
        if (advance) {
124
            if (m_advances.isEmpty())
125
                m_advances.fill(0, size);
126
            m_advances[index] = advance.value();
127
        }
105
    }
128
    }
106
129
107
    const Font& font() const
130
    const Font& font() const
Lines 120-126 private: a/Source/WebCore/platform/graphics/GlyphPage.h_sec7
120
    }
143
    }
121
144
122
    const Font& m_font;
145
    const Font& m_font;
123
    Glyph m_glyphs[size] { };
146
    std::array<Glyph, size> m_glyphs;
147
    Vector<float> m_advances;
124
148
125
    WEBCORE_EXPORT static unsigned s_count;
149
    WEBCORE_EXPORT static unsigned s_count;
126
};
150
};
- a/Source/WebCore/platform/graphics/WidthIterator.cpp -1 / +3 lines
Lines 207-213 inline unsigned WidthIterator::advanceInternal(TextIterator& textIterator, Glyph a/Source/WebCore/platform/graphics/WidthIterator.cpp_sec1
207
        if (character == '\t' && m_run.allowTabs())
207
        if (character == '\t' && m_run.allowTabs())
208
            width = m_font->tabWidth(*font, m_run.tabSize(), m_run.xPos() + m_runWidthSoFar + widthSinceLastRounding);
208
            width = m_font->tabWidth(*font, m_run.tabSize(), m_run.xPos() + m_runWidthSoFar + widthSinceLastRounding);
209
        else {
209
        else {
210
            width = font->widthForGlyph(glyph);
210
            width = glyphData.advance.valueOrCompute([&] {
211
                return font->widthForGlyph(glyph);
212
            });
211
213
212
            // SVG uses horizontalGlyphStretch(), when textLength is used to stretch/squeeze text.
214
            // SVG uses horizontalGlyphStretch(), when textLength is used to stretch/squeeze text.
213
            width *= m_run.horizontalGlyphStretch();
215
            width *= m_run.horizontalGlyphStretch();
- a/Source/WebCore/platform/graphics/cocoa/FontCocoa.mm -34 / +1 lines
Lines 596-639 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
static inline Optional<CGSize> advanceForColorBitmapFont(const FontPlatformData& platformData, Glyph glyph)
600
{
601
    CTFontRef font = platformData.font();
602
    if (!font || !platformData.isColorBitmapFont())
603
        return Nullopt;
604
    CGSize advance;
605
    CTFontGetAdvancesForGlyphs(font, kCTFontOrientationDefault, &glyph, &advance, 1);
606
    return advance;
607
}
608
609
static inline bool canUseFastGlyphAdvanceGetter(const FontPlatformData& platformData, Glyph glyph, CGSize& advance, bool& populatedAdvance)
610
{
611
    if (platformData.isEmoji() || platformData.hasCustomTracking() || platformData.textRenderingMode() == OptimizeLegibility)
612
        return false;
613
    if (auto size = advanceForColorBitmapFont(platformData, glyph)) {
614
        populatedAdvance = true;
615
        advance = size.value();
616
        return false;
617
    }
618
    return true;
619
}
620
621
float Font::platformWidthForGlyph(Glyph glyph) const
599
float Font::platformWidthForGlyph(Glyph glyph) const
622
{
600
{
623
    CGSize advance = CGSizeZero;
601
    CGSize advance = CGSizeZero;
624
    bool horizontal = platformData().orientation() == Horizontal;
602
    bool horizontal = platformData().orientation() == Horizontal;
625
    bool populatedAdvance = false;
603
    CTFontGetAdvancesForGlyphs(m_platformData.ctFont(), horizontal ? kCTFontOrientationHorizontal : kCTFontOrientationVertical, &glyph, &advance, 1);
626
    if ((horizontal || m_isBrokenIdeographFallback) && canUseFastGlyphAdvanceGetter(this->platformData(), glyph, advance, populatedAdvance)) {
627
        float pointSize = platformData().size();
628
        CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize);
629
        CGFontRenderingStyle style = kCGFontRenderingStyleAntialiasing | kCGFontRenderingStyleSubpixelPositioning | kCGFontRenderingStyleSubpixelQuantization | kCGFontAntialiasingStyleUnfiltered;
630
        if (!CGFontGetGlyphAdvancesForStyle(platformData().cgFont(), &m, style, &glyph, 1, &advance)) {
631
            RetainPtr<CFStringRef> fullName = adoptCF(CGFontCopyFullName(platformData().cgFont()));
632
            LOG_ERROR("Unable to cache glyph widths for %@ %f", fullName.get(), pointSize);
633
            advance.width = 0;
634
        }
635
    } else if (!populatedAdvance && platformData().size())
636
        CTFontGetAdvancesForGlyphs(m_platformData.ctFont(), horizontal ? kCTFontOrientationHorizontal : kCTFontOrientationVertical, &glyph, &advance, 1);
637
604
638
    return advance.width + m_syntheticBoldOffset;
605
    return advance.width + m_syntheticBoldOffset;
639
}
606
}
- a/Source/WebCore/platform/graphics/mac/GlyphPageMac.cpp -12 / +16 lines
Lines 63-78 bool GlyphPage::fill(UChar* buffer, unsigned bufferLength) a/Source/WebCore/platform/graphics/mac/GlyphPageMac.cpp_sec1
63
    ASSERT(bufferLength == GlyphPage::size || bufferLength == 2 * GlyphPage::size);
63
    ASSERT(bufferLength == GlyphPage::size || bufferLength == 2 * GlyphPage::size);
64
64
65
    const Font& font = this->font();
65
    const Font& font = this->font();
66
    Vector<CGGlyph, 512> glyphs(bufferLength);
66
    Vector<CGGlyph> glyphs(bufferLength);
67
    unsigned glyphStep;
67
    memset(glyphs.data(), 0, sizeof(CGGlyph) * bufferLength);
68
    if (!shouldUseCoreText(buffer, bufferLength, font)) {
68
    if (!shouldUseCoreText(buffer, bufferLength, font))
69
        // We pass in either 256 or 512 UTF-16 characters: 256 for U+FFFF and less, 512 (double character surrogates)
70
        // for U+10000 and above. It is indeed possible to get back 512 glyphs back from the API, so the glyph buffer
71
        // we pass in must be 512. If we get back more than 256 glyphs though we'll ignore all the ones after 256,
72
        // this should not happen as the only time we pass in 512 characters is when they are surrogates.
73
        CGFontGetGlyphsForUnichars(font.platformData().cgFont(), buffer, glyphs.data(), bufferLength);
69
        CGFontGetGlyphsForUnichars(font.platformData().cgFont(), buffer, glyphs.data(), bufferLength);
74
        glyphStep = 1;
70
    else {
75
    } else {
76
        // Because we know the implementation of shouldUseCoreText(), if the font isn't for text combine and it isn't a system font,
71
        // Because we know the implementation of shouldUseCoreText(), if the font isn't for text combine and it isn't a system font,
77
        // we know it must have vertical glyphs.
72
        // we know it must have vertical glyphs.
78
        if (font.platformData().isForTextCombine() || font.platformData().isSystemFont())
73
        if (font.platformData().isForTextCombine() || font.platformData().isSystemFont())
Lines 82-94 bool GlyphPage::fill(UChar* buffer, unsigned bufferLength) a/Source/WebCore/platform/graphics/mac/GlyphPageMac.cpp_sec2
82
77
83
        // When buffer consists of surrogate pairs, CTFontGetVerticalGlyphsForCharacters and CTFontGetGlyphsForCharacters
78
        // When buffer consists of surrogate pairs, CTFontGetVerticalGlyphsForCharacters and CTFontGetGlyphsForCharacters
84
        // place the glyphs at indices corresponding to the first character of each pair.
79
        // place the glyphs at indices corresponding to the first character of each pair.
85
        glyphStep = bufferLength / GlyphPage::size;
80
        unsigned glyphStep = bufferLength / GlyphPage::size;
81
        if (glyphStep != 1) {
82
            for (unsigned i = 0; i < GlyphPage::size; ++i)
83
                glyphs[i] = glyphs[i * glyphStep];
84
        }
86
    }
85
    }
87
86
87
    Vector<CGSize> advances(GlyphPage::size);
88
    CTFontOrientation orientation = font.platformData().orientation() == Horizontal ? kCTFontOrientationHorizontal : kCTFontOrientationVertical;
89
    CGFontRenderingStyle style = kCGFontRenderingStyleAntialiasing | kCGFontRenderingStyleSubpixelPositioning | kCGFontRenderingStyleSubpixelQuantization | kCGFontAntialiasingStyleUnfiltered;
90
    CTFontGetUnsummedAdvancesForGlyphsAndStyle(font.platformData().ctFont(), orientation, style, glyphs.data(), advances.data(), GlyphPage::size);
91
88
    bool haveGlyphs = false;
92
    bool haveGlyphs = false;
89
    for (unsigned i = 0; i < GlyphPage::size; ++i) {
93
    for (unsigned i = 0; i < GlyphPage::size; ++i) {
90
        if (glyphs[i * glyphStep]) {
94
        if (glyphs[i]) {
91
            setGlyphForIndex(i, glyphs[i * glyphStep]);
95
            setGlyphForIndex(i, glyphs[i], advances[i].width);
92
            haveGlyphs = true;
96
            haveGlyphs = true;
93
        }
97
        }
94
    }
98
    }
- a/Source/WebCore/platform/spi/cocoa/CoreTextSPI.h -23 / +13 lines
Lines 42-47 enum { a/Source/WebCore/platform/spi/cocoa/CoreTextSPI.h_sec1
42
    kCTFontUIFontSystemUltraLight = 104,
42
    kCTFontUIFontSystemUltraLight = 104,
43
};
43
};
44
44
45
typedef CF_OPTIONS(uint32_t, CTFontTransformOptions)
46
{
47
    kCTFontTransformApplyShaping = (1 << 0),
48
    kCTFontTransformApplyPositioning = (1 << 1)
49
};
50
51
typedef CF_OPTIONS(uint32_t, CTFontDescriptorOptions)
52
{
53
    kCTFontDescriptorOptionSystemUIFont = 1 << 1,
54
    kCTFontDescriptorOptionPreferAppleSystemFont = kCTFontOptionsPreferSystemFont
55
};
56
45
#endif
57
#endif
46
58
47
extern "C" {
59
extern "C" {
Lines 52-98 typedef void (*CTUniCharDisposeCallback)(const UniChar* chars, void* refCon); a/Source/WebCore/platform/spi/cocoa/CoreTextSPI.h_sec2
52
extern const CFStringRef kCTFontReferenceURLAttribute;
64
extern const CFStringRef kCTFontReferenceURLAttribute;
53
extern const CFStringRef kCTFontOpticalSizeAttribute;
65
extern const CFStringRef kCTFontOpticalSizeAttribute;
54
66
55
#if PLATFORM(COCOA)
56
#if !USE(APPLE_INTERNAL_SDK)
57
typedef CF_OPTIONS(uint32_t, CTFontTransformOptions)
58
{
59
    kCTFontTransformApplyShaping = (1 << 0),
60
    kCTFontTransformApplyPositioning = (1 << 1)
61
};
62
#endif
63
bool CTFontTransformGlyphs(CTFontRef, CGGlyph glyphs[], CGSize advances[], CFIndex count, CTFontTransformOptions);
67
bool CTFontTransformGlyphs(CTFontRef, CGGlyph glyphs[], CGSize advances[], CFIndex count, CTFontTransformOptions);
64
#endif
65
68
66
CGSize CTRunGetInitialAdvance(CTRunRef run);
69
CGSize CTRunGetInitialAdvance(CTRunRef run);
67
CTLineRef CTLineCreateWithUniCharProvider(CTUniCharProviderCallback provide, CTUniCharDisposeCallback dispose, void* refCon);
70
CTLineRef CTLineCreateWithUniCharProvider(CTUniCharProviderCallback provide, CTUniCharDisposeCallback dispose, void* refCon);
68
CTTypesetterRef CTTypesetterCreateWithUniCharProviderAndOptions(CTUniCharProviderCallback provide, CTUniCharDisposeCallback dispose, void* refCon, CFDictionaryRef options);
71
CTTypesetterRef CTTypesetterCreateWithUniCharProviderAndOptions(CTUniCharProviderCallback provide, CTUniCharDisposeCallback dispose, void* refCon, CFDictionaryRef options);
69
bool CTFontGetVerticalGlyphsForCharacters(CTFontRef, const UniChar characters[], CGGlyph glyphs[], CFIndex count);
72
bool CTFontGetVerticalGlyphsForCharacters(CTFontRef, const UniChar characters[], CGGlyph glyphs[], CFIndex count);
73
void CTFontGetUnsummedAdvancesForGlyphsAndStyle(CTFontRef, CTFontOrientation, CGFontRenderingStyle, const CGGlyph[], CGSize advances[], CFIndex count);
70
74
71
CTFontDescriptorRef CTFontDescriptorCreateForUIType(CTFontUIFontType, CGFloat size, CFStringRef language);
75
CTFontDescriptorRef CTFontDescriptorCreateForUIType(CTFontUIFontType, CGFloat size, CFStringRef language);
72
CTFontDescriptorRef CTFontDescriptorCreateWithTextStyle(CFStringRef style, CFStringRef size, CFStringRef language);
76
CTFontDescriptorRef CTFontDescriptorCreateWithTextStyle(CFStringRef style, CFStringRef size, CFStringRef language);
73
CTFontDescriptorRef CTFontDescriptorCreateCopyWithSymbolicTraits(CTFontDescriptorRef original, CTFontSymbolicTraits symTraitValue, CTFontSymbolicTraits symTraitMask);
77
CTFontDescriptorRef CTFontDescriptorCreateCopyWithSymbolicTraits(CTFontDescriptorRef original, CTFontSymbolicTraits symTraitValue, CTFontSymbolicTraits symTraitMask);
74
CFBitVectorRef CTFontCopyGlyphCoverageForFeature(CTFontRef, CFDictionaryRef feature);
78
CFBitVectorRef CTFontCopyGlyphCoverageForFeature(CTFontRef, CFDictionaryRef feature);
75
79
76
#if PLATFORM(COCOA)
77
#if !USE(APPLE_INTERNAL_SDK)
78
typedef CF_OPTIONS(uint32_t, CTFontDescriptorOptions)
79
{
80
    kCTFontDescriptorOptionSystemUIFont = 1 << 1,
81
    kCTFontDescriptorOptionPreferAppleSystemFont = kCTFontOptionsPreferSystemFont
82
};
83
84
CTFontDescriptorRef CTFontDescriptorCreateWithAttributesAndOptions(CFDictionaryRef attributes, CTFontDescriptorOptions);
80
CTFontDescriptorRef CTFontDescriptorCreateWithAttributesAndOptions(CFDictionaryRef attributes, CTFontDescriptorOptions);
85
81
86
extern const CFStringRef kCTFontDescriptorTextStyleAttribute;
82
extern const CFStringRef kCTFontDescriptorTextStyleAttribute;
87
extern const CFStringRef kCTFontUIFontDesignTrait;
83
extern const CFStringRef kCTFontUIFontDesignTrait;
88
#endif
89
#endif
90
84
91
bool CTFontDescriptorIsSystemUIFont(CTFontDescriptorRef);
85
bool CTFontDescriptorIsSystemUIFont(CTFontDescriptorRef);
92
CTFontRef CTFontCreateForCSS(CFStringRef name, uint16_t weight, CTFontSymbolicTraits, CGFloat size);
86
CTFontRef CTFontCreateForCSS(CFStringRef name, uint16_t weight, CTFontSymbolicTraits, CGFloat size);
93
CTFontRef CTFontCreateForCharactersWithLanguage(CTFontRef currentFont, const UTF16Char *characters, CFIndex length, CFStringRef language, CFIndex *coveredLength);
87
CTFontRef CTFontCreateForCharactersWithLanguage(CTFontRef currentFont, const UTF16Char *characters, CFIndex length, CFStringRef language, CFIndex *coveredLength);
94
88
95
#if PLATFORM(COCOA)
96
extern const CFStringRef kCTUIFontTextStyleShortHeadline;
89
extern const CFStringRef kCTUIFontTextStyleShortHeadline;
97
extern const CFStringRef kCTUIFontTextStyleShortBody;
90
extern const CFStringRef kCTUIFontTextStyleShortBody;
98
extern const CFStringRef kCTUIFontTextStyleShortSubhead;
91
extern const CFStringRef kCTUIFontTextStyleShortSubhead;
Lines 118-131 extern const CGFloat kCTFontWeightSemibold; a/Source/WebCore/platform/spi/cocoa/CoreTextSPI.h_sec3
118
extern const CGFloat kCTFontWeightBold;
111
extern const CGFloat kCTFontWeightBold;
119
extern const CGFloat kCTFontWeightHeavy;
112
extern const CGFloat kCTFontWeightHeavy;
120
extern const CGFloat kCTFontWeightBlack;
113
extern const CGFloat kCTFontWeightBlack;
121
#endif
122
114
123
#if PLATFORM(IOS)
124
extern const CFStringRef kCTUIFontTextStyleTitle1;
115
extern const CFStringRef kCTUIFontTextStyleTitle1;
125
extern const CFStringRef kCTUIFontTextStyleTitle2;
116
extern const CFStringRef kCTUIFontTextStyleTitle2;
126
extern const CFStringRef kCTUIFontTextStyleTitle3;
117
extern const CFStringRef kCTUIFontTextStyleTitle3;
127
CTFontDescriptorRef CTFontCreatePhysicalFontDescriptorForCharactersWithLanguage(CTFontRef currentFont, const UTF16Char* characters, CFIndex length, CFStringRef language, CFIndex* coveredLength);
118
CTFontDescriptorRef CTFontCreatePhysicalFontDescriptorForCharactersWithLanguage(CTFontRef currentFont, const UTF16Char* characters, CFIndex length, CFStringRef language, CFIndex* coveredLength);
128
#endif
129
119
130
CTFontRef CTFontCreatePhysicalFontForCharactersWithLanguage(CTFontRef, const UTF16Char* characters, CFIndex length, CFStringRef language, CFIndex* coveredLength);
120
CTFontRef CTFontCreatePhysicalFontForCharactersWithLanguage(CTFontRef, const UTF16Char* characters, CFIndex length, CFStringRef language, CFIndex* coveredLength);
131
bool CTFontIsAppleColorEmoji(CTFontRef);
121
bool CTFontIsAppleColorEmoji(CTFontRef);
- a/Source/WebCore/rendering/mathml/MathOperator.cpp -45 / +100 lines
Lines 94-100 void MathOperator::setOperator(const RenderStyle& style, UChar baseCharacter, Ty a/Source/WebCore/rendering/mathml/MathOperator.cpp_sec1
94
94
95
void MathOperator::reset(const RenderStyle& style)
95
void MathOperator::reset(const RenderStyle& style)
96
{
96
{
97
    m_stretchType = StretchType::Unstretched;
97
    m_variantOrAssembly = Nullopt;
98
    m_maxPreferredWidth = 0;
98
    m_maxPreferredWidth = 0;
99
    m_width = 0;
99
    m_width = 0;
100
    m_ascent = 0;
100
    m_ascent = 0;
Lines 131-138 void MathOperator::setSizeVariant(const GlyphData& sizeVariant) a/Source/WebCore/rendering/mathml/MathOperator.cpp_sec2
131
{
131
{
132
    ASSERT(sizeVariant.font);
132
    ASSERT(sizeVariant.font);
133
    ASSERT(sizeVariant.font->mathData());
133
    ASSERT(sizeVariant.font->mathData());
134
    m_stretchType = StretchType::SizeVariant;
134
    m_variantOrAssembly = GlyphDataOrGlyphAssemblyData(sizeVariant);
135
    m_variant = sizeVariant;
136
    m_width = advanceWidthForGlyph(sizeVariant);
135
    m_width = advanceWidthForGlyph(sizeVariant);
137
    getAscentAndDescentForGlyph(sizeVariant, m_ascent, m_descent);
136
    getAscentAndDescentForGlyph(sizeVariant, m_ascent, m_descent);
138
}
137
}
Lines 140-167 void MathOperator::setSizeVariant(const GlyphData& sizeVariant) a/Source/WebCore/rendering/mathml/MathOperator.cpp_sec3
140
void MathOperator::setGlyphAssembly(const GlyphAssemblyData& assemblyData)
139
void MathOperator::setGlyphAssembly(const GlyphAssemblyData& assemblyData)
141
{
140
{
142
    ASSERT(m_operatorType == Type::VerticalOperator || m_operatorType == Type::HorizontalOperator);
141
    ASSERT(m_operatorType == Type::VerticalOperator || m_operatorType == Type::HorizontalOperator);
143
    m_stretchType = StretchType::GlyphAssembly;
142
    m_variantOrAssembly = GlyphDataOrGlyphAssemblyData(assemblyData);
144
    m_assembly = assemblyData;
145
    if (m_operatorType == Type::VerticalOperator) {
143
    if (m_operatorType == Type::VerticalOperator) {
146
        m_width = 0;
144
        m_width = 0;
147
        m_width = std::max<LayoutUnit>(m_width, advanceWidthForGlyph(m_assembly.topOrRight));
145
        m_width = std::max<LayoutUnit>(m_width, advanceWidthForGlyph(assemblyData.topOrRight));
148
        m_width = std::max<LayoutUnit>(m_width, advanceWidthForGlyph(m_assembly.extension));
146
        m_width = std::max<LayoutUnit>(m_width, advanceWidthForGlyph(assemblyData.extension));
149
        m_width = std::max<LayoutUnit>(m_width, advanceWidthForGlyph(m_assembly.bottomOrLeft));
147
        m_width = std::max<LayoutUnit>(m_width, advanceWidthForGlyph(assemblyData.bottomOrLeft));
150
        m_width = std::max<LayoutUnit>(m_width, advanceWidthForGlyph(m_assembly.middle));
148
        m_width = std::max<LayoutUnit>(m_width, advanceWidthForGlyph(assemblyData.middle));
151
    } else {
149
    } else {
152
        m_ascent = 0;
150
        m_ascent = 0;
153
        m_descent = 0;
151
        m_descent = 0;
154
        LayoutUnit ascent, descent;
152
        LayoutUnit ascent, descent;
155
        getAscentAndDescentForGlyph(m_assembly.bottomOrLeft, ascent, descent);
153
        getAscentAndDescentForGlyph(assemblyData.bottomOrLeft, ascent, descent);
156
        m_ascent = std::max(m_ascent, ascent);
154
        m_ascent = std::max(m_ascent, ascent);
157
        m_descent = std::max(m_descent, descent);
155
        m_descent = std::max(m_descent, descent);
158
        getAscentAndDescentForGlyph(m_assembly.extension, ascent, descent);
156
        getAscentAndDescentForGlyph(assemblyData.extension, ascent, descent);
159
        m_ascent = std::max(m_ascent, ascent);
157
        m_ascent = std::max(m_ascent, ascent);
160
        m_descent = std::max(m_descent, descent);
158
        m_descent = std::max(m_descent, descent);
161
        getAscentAndDescentForGlyph(m_assembly.topOrRight, ascent, descent);
159
        getAscentAndDescentForGlyph(assemblyData.topOrRight, ascent, descent);
162
        m_ascent = std::max(m_ascent, ascent);
160
        m_ascent = std::max(m_ascent, ascent);
163
        m_descent = std::max(m_descent, descent);
161
        m_descent = std::max(m_descent, descent);
164
        getAscentAndDescentForGlyph(m_assembly.middle, ascent, descent);
162
        getAscentAndDescentForGlyph(assemblyData.middle, ascent, descent);
165
        m_ascent = std::max(m_ascent, ascent);
163
        m_ascent = std::max(m_ascent, ascent);
166
        m_descent = std::max(m_descent, descent);
164
        m_descent = std::max(m_descent, descent);
167
    }
165
    }
Lines 439-445 void MathOperator::stretchTo(const RenderStyle& style, LayoutUnit targetSize) a/Source/WebCore/rendering/mathml/MathOperator.cpp_sec4
439
{
437
{
440
    ASSERT(m_operatorType == Type::VerticalOperator || m_operatorType == Type::HorizontalOperator);
438
    ASSERT(m_operatorType == Type::VerticalOperator || m_operatorType == Type::HorizontalOperator);
441
    calculateStretchyData(style, false, targetSize);
439
    calculateStretchyData(style, false, targetSize);
442
    if (m_stretchType == StretchType::GlyphAssembly) {
440
    if (isAssembly()) {
443
        if (m_operatorType == Type::VerticalOperator) {
441
        if (m_operatorType == Type::VerticalOperator) {
444
            m_ascent = targetSize;
442
            m_ascent = targetSize;
445
            m_descent = 0;
443
            m_descent = 0;
Lines 503-510 LayoutRect MathOperator::paintGlyph(const RenderStyle& style, PaintInfo& info, c a/Source/WebCore/rendering/mathml/MathOperator.cpp_sec5
503
void MathOperator::fillWithVerticalExtensionGlyph(const RenderStyle& style, PaintInfo& info, const LayoutPoint& from, const LayoutPoint& to)
501
void MathOperator::fillWithVerticalExtensionGlyph(const RenderStyle& style, PaintInfo& info, const LayoutPoint& from, const LayoutPoint& to)
504
{
502
{
505
    ASSERT(m_operatorType == Type::VerticalOperator);
503
    ASSERT(m_operatorType == Type::VerticalOperator);
506
    ASSERT(m_stretchType == StretchType::GlyphAssembly);
504
    ASSERT(isAssembly());
507
    ASSERT(m_assembly.extension.font);
505
    auto& assembly = this->assembly();
506
    ASSERT(assembly.extension.font);
508
    ASSERT(from.y() <= to.y());
507
    ASSERT(from.y() <= to.y());
509
508
510
    // If there is no space for the extension glyph, we don't need to do anything.
509
    // If there is no space for the extension glyph, we don't need to do anything.
Lines 513-519 void MathOperator::fillWithVerticalExtensionGlyph(const RenderStyle& style, Pain a/Source/WebCore/rendering/mathml/MathOperator.cpp_sec6
513
512
514
    GraphicsContextStateSaver stateSaver(info.context());
513
    GraphicsContextStateSaver stateSaver(info.context());
515
514
516
    FloatRect glyphBounds = boundsForGlyph(m_assembly.extension);
515
    FloatRect glyphBounds = boundsForGlyph(assembly.extension);
517
516
518
    // Clipping the extender region here allows us to draw the bottom extender glyph into the
517
    // Clipping the extender region here allows us to draw the bottom extender glyph into the
519
    // regions of the bottom glyph without worrying about overdraw (hairy pixels) and simplifies later clipping.
518
    // regions of the bottom glyph without worrying about overdraw (hairy pixels) and simplifies later clipping.
Lines 529-535 void MathOperator::fillWithVerticalExtensionGlyph(const RenderStyle& style, Pain a/Source/WebCore/rendering/mathml/MathOperator.cpp_sec7
529
528
530
    // In practice, only small stretch sizes are requested but we limit the number of glyphs to avoid hangs.
529
    // In practice, only small stretch sizes are requested but we limit the number of glyphs to avoid hangs.
531
    for (unsigned extensionCount = 0; lastPaintedGlyphRect.maxY() < to.y() && extensionCount < kMaximumExtensionCount; extensionCount++) {
530
    for (unsigned extensionCount = 0; lastPaintedGlyphRect.maxY() < to.y() && extensionCount < kMaximumExtensionCount; extensionCount++) {
532
        lastPaintedGlyphRect = paintGlyph(style, info, m_assembly.extension, glyphOrigin, TrimTopAndBottom);
531
        lastPaintedGlyphRect = paintGlyph(style, info, assembly.extension, glyphOrigin, TrimTopAndBottom);
533
        glyphOrigin.setY(glyphOrigin.y() + lastPaintedGlyphRect.height());
532
        glyphOrigin.setY(glyphOrigin.y() + lastPaintedGlyphRect.height());
534
533
535
        // There's a chance that if the font size is small enough the glue glyph has been reduced to an empty rectangle
534
        // There's a chance that if the font size is small enough the glue glyph has been reduced to an empty rectangle
Lines 542-549 void MathOperator::fillWithVerticalExtensionGlyph(const RenderStyle& style, Pain a/Source/WebCore/rendering/mathml/MathOperator.cpp_sec8
542
void MathOperator::fillWithHorizontalExtensionGlyph(const RenderStyle& style, PaintInfo& info, const LayoutPoint& from, const LayoutPoint& to)
541
void MathOperator::fillWithHorizontalExtensionGlyph(const RenderStyle& style, PaintInfo& info, const LayoutPoint& from, const LayoutPoint& to)
543
{
542
{
544
    ASSERT(m_operatorType == Type::HorizontalOperator);
543
    ASSERT(m_operatorType == Type::HorizontalOperator);
545
    ASSERT(m_stretchType == StretchType::GlyphAssembly);
544
    ASSERT(isAssembly());
546
    ASSERT(m_assembly.extension.font);
545
    auto& assembly = this->assembly();
546
    ASSERT(assembly.extension.font);
547
    ASSERT(from.x() <= to.x());
547
    ASSERT(from.x() <= to.x());
548
    ASSERT(from.y() == to.y());
548
    ASSERT(from.y() == to.y());
549
549
Lines 567-573 void MathOperator::fillWithHorizontalExtensionGlyph(const RenderStyle& style, Pa a/Source/WebCore/rendering/mathml/MathOperator.cpp_sec9
567
567
568
    // In practice, only small stretch sizes are requested but we limit the number of glyphs to avoid hangs.
568
    // In practice, only small stretch sizes are requested but we limit the number of glyphs to avoid hangs.
569
    for (unsigned extensionCount = 0; lastPaintedGlyphRect.maxX() < to.x() && extensionCount < kMaximumExtensionCount; extensionCount++) {
569
    for (unsigned extensionCount = 0; lastPaintedGlyphRect.maxX() < to.x() && extensionCount < kMaximumExtensionCount; extensionCount++) {
570
        lastPaintedGlyphRect = paintGlyph(style, info, m_assembly.extension, glyphOrigin, TrimLeftAndRight);
570
        lastPaintedGlyphRect = paintGlyph(style, info, assembly.extension, glyphOrigin, TrimLeftAndRight);
571
        glyphOrigin.setX(glyphOrigin.x() + lastPaintedGlyphRect.width());
571
        glyphOrigin.setX(glyphOrigin.x() + lastPaintedGlyphRect.width());
572
572
573
        // There's a chance that if the font size is small enough the glue glyph has been reduced to an empty rectangle
573
        // There's a chance that if the font size is small enough the glue glyph has been reduced to an empty rectangle
Lines 580-607 void MathOperator::fillWithHorizontalExtensionGlyph(const RenderStyle& style, Pa a/Source/WebCore/rendering/mathml/MathOperator.cpp_sec10
580
void MathOperator::paintVerticalGlyphAssembly(const RenderStyle& style, PaintInfo& info, const LayoutPoint& paintOffset)
580
void MathOperator::paintVerticalGlyphAssembly(const RenderStyle& style, PaintInfo& info, const LayoutPoint& paintOffset)
581
{
581
{
582
    ASSERT(m_operatorType == Type::VerticalOperator);
582
    ASSERT(m_operatorType == Type::VerticalOperator);
583
    ASSERT(m_stretchType == StretchType::GlyphAssembly);
583
    ASSERT(isAssembly());
584
    ASSERT(m_assembly.topOrRight.font);
584
    auto& assembly = this->assembly();
585
    ASSERT(m_assembly.bottomOrLeft.font);
585
    ASSERT(assembly.topOrRight.font);
586
    ASSERT(assembly.bottomOrLeft.font);
586
587
587
    // We are positioning the glyphs so that the edge of the tight glyph bounds line up exactly with the edges of our paint box.
588
    // We are positioning the glyphs so that the edge of the tight glyph bounds line up exactly with the edges of our paint box.
588
    LayoutPoint operatorTopLeft = paintOffset;
589
    LayoutPoint operatorTopLeft = paintOffset;
589
    FloatRect topGlyphBounds = boundsForGlyph(m_assembly.topOrRight);
590
    FloatRect topGlyphBounds = boundsForGlyph(assembly.topOrRight);
590
    LayoutPoint topGlyphOrigin(operatorTopLeft.x(), operatorTopLeft.y() - topGlyphBounds.y());
591
    LayoutPoint topGlyphOrigin(operatorTopLeft.x(), operatorTopLeft.y() - topGlyphBounds.y());
591
    LayoutRect topGlyphPaintRect = paintGlyph(style, info, m_assembly.topOrRight, topGlyphOrigin, TrimBottom);
592
    LayoutRect topGlyphPaintRect = paintGlyph(style, info, assembly.topOrRight, topGlyphOrigin, TrimBottom);
592
593
593
    FloatRect bottomGlyphBounds = boundsForGlyph(m_assembly.bottomOrLeft);
594
    FloatRect bottomGlyphBounds = boundsForGlyph(assembly.bottomOrLeft);
594
    LayoutPoint bottomGlyphOrigin(operatorTopLeft.x(), operatorTopLeft.y() + stretchSize() - (bottomGlyphBounds.height() + bottomGlyphBounds.y()));
595
    LayoutPoint bottomGlyphOrigin(operatorTopLeft.x(), operatorTopLeft.y() + stretchSize() - (bottomGlyphBounds.height() + bottomGlyphBounds.y()));
595
    LayoutRect bottomGlyphPaintRect = paintGlyph(style, info, m_assembly.bottomOrLeft, bottomGlyphOrigin, TrimTop);
596
    LayoutRect bottomGlyphPaintRect = paintGlyph(style, info, assembly.bottomOrLeft, bottomGlyphOrigin, TrimTop);
596
597
597
    if (m_assembly.middle.font) {
598
    if (assembly.middle.font) {
598
        // Center the glyph origin between the start and end glyph paint extents. Then shift it half the paint height toward the bottom glyph.
599
        // Center the glyph origin between the start and end glyph paint extents. Then shift it half the paint height toward the bottom glyph.
599
        FloatRect middleGlyphBounds = boundsForGlyph(m_assembly.middle);
600
        FloatRect middleGlyphBounds = boundsForGlyph(assembly.middle);
600
        LayoutPoint middleGlyphOrigin(operatorTopLeft.x(), topGlyphOrigin.y());
601
        LayoutPoint middleGlyphOrigin(operatorTopLeft.x(), topGlyphOrigin.y());
601
        middleGlyphOrigin.moveBy(LayoutPoint(0, (bottomGlyphPaintRect.y() - topGlyphPaintRect.maxY()) / 2.0));
602
        middleGlyphOrigin.moveBy(LayoutPoint(0, (bottomGlyphPaintRect.y() - topGlyphPaintRect.maxY()) / 2.0));
602
        middleGlyphOrigin.moveBy(LayoutPoint(0, middleGlyphBounds.height() / 2.0));
603
        middleGlyphOrigin.moveBy(LayoutPoint(0, middleGlyphBounds.height() / 2.0));
603
604
604
        LayoutRect middleGlyphPaintRect = paintGlyph(style, info, m_assembly.middle, middleGlyphOrigin, TrimTopAndBottom);
605
        LayoutRect middleGlyphPaintRect = paintGlyph(style, info, assembly.middle, middleGlyphOrigin, TrimTopAndBottom);
605
        fillWithVerticalExtensionGlyph(style, info, topGlyphPaintRect.minXMaxYCorner(), middleGlyphPaintRect.minXMinYCorner());
606
        fillWithVerticalExtensionGlyph(style, info, topGlyphPaintRect.minXMaxYCorner(), middleGlyphPaintRect.minXMinYCorner());
606
        fillWithVerticalExtensionGlyph(style, info, middleGlyphPaintRect.minXMaxYCorner(), bottomGlyphPaintRect.minXMinYCorner());
607
        fillWithVerticalExtensionGlyph(style, info, middleGlyphPaintRect.minXMaxYCorner(), bottomGlyphPaintRect.minXMinYCorner());
607
    } else
608
    } else
Lines 611-635 void MathOperator::paintVerticalGlyphAssembly(const RenderStyle& style, PaintInf a/Source/WebCore/rendering/mathml/MathOperator.cpp_sec11
611
void MathOperator::paintHorizontalGlyphAssembly(const RenderStyle& style, PaintInfo& info, const LayoutPoint& paintOffset)
612
void MathOperator::paintHorizontalGlyphAssembly(const RenderStyle& style, PaintInfo& info, const LayoutPoint& paintOffset)
612
{
613
{
613
    ASSERT(m_operatorType == Type::HorizontalOperator);
614
    ASSERT(m_operatorType == Type::HorizontalOperator);
614
    ASSERT(m_stretchType == StretchType::GlyphAssembly);
615
    ASSERT(isAssembly());
615
    ASSERT(m_assembly.bottomOrLeft.font);
616
    auto& assembly = this->assembly();
616
    ASSERT(m_assembly.topOrRight.font);
617
    ASSERT(assembly.bottomOrLeft.font);
618
    ASSERT(assembly.topOrRight.font);
617
619
618
    // We are positioning the glyphs so that the edge of the tight glyph bounds line up exactly with the edges of our paint box.
620
    // We are positioning the glyphs so that the edge of the tight glyph bounds line up exactly with the edges of our paint box.
619
    LayoutPoint operatorTopLeft = paintOffset;
621
    LayoutPoint operatorTopLeft = paintOffset;
620
    LayoutUnit baselineY = operatorTopLeft.y() + m_ascent;
622
    LayoutUnit baselineY = operatorTopLeft.y() + m_ascent;
621
    LayoutPoint leftGlyphOrigin(operatorTopLeft.x(), baselineY);
623
    LayoutPoint leftGlyphOrigin(operatorTopLeft.x(), baselineY);
622
    LayoutRect leftGlyphPaintRect = paintGlyph(style, info, m_assembly.bottomOrLeft, leftGlyphOrigin, TrimRight);
624
    LayoutRect leftGlyphPaintRect = paintGlyph(style, info, assembly.bottomOrLeft, leftGlyphOrigin, TrimRight);
623
625
624
    FloatRect rightGlyphBounds = boundsForGlyph(m_assembly.topOrRight);
626
    FloatRect rightGlyphBounds = boundsForGlyph(assembly.topOrRight);
625
    LayoutPoint rightGlyphOrigin(operatorTopLeft.x() + stretchSize() - rightGlyphBounds.width(), baselineY);
627
    LayoutPoint rightGlyphOrigin(operatorTopLeft.x() + stretchSize() - rightGlyphBounds.width(), baselineY);
626
    LayoutRect rightGlyphPaintRect = paintGlyph(style, info, m_assembly.topOrRight, rightGlyphOrigin, TrimLeft);
628
    LayoutRect rightGlyphPaintRect = paintGlyph(style, info, assembly.topOrRight, rightGlyphOrigin, TrimLeft);
627
629
628
    if (m_assembly.middle.font) {
630
    if (assembly.middle.font) {
629
        // Center the glyph origin between the start and end glyph paint extents.
631
        // Center the glyph origin between the start and end glyph paint extents.
630
        LayoutPoint middleGlyphOrigin(operatorTopLeft.x(), baselineY);
632
        LayoutPoint middleGlyphOrigin(operatorTopLeft.x(), baselineY);
631
        middleGlyphOrigin.moveBy(LayoutPoint((rightGlyphPaintRect.x() - leftGlyphPaintRect.maxX()) / 2.0, 0));
633
        middleGlyphOrigin.moveBy(LayoutPoint((rightGlyphPaintRect.x() - leftGlyphPaintRect.maxX()) / 2.0, 0));
632
        LayoutRect middleGlyphPaintRect = paintGlyph(style, info, m_assembly.middle, middleGlyphOrigin, TrimLeftAndRight);
634
        LayoutRect middleGlyphPaintRect = paintGlyph(style, info, assembly.middle, middleGlyphOrigin, TrimLeftAndRight);
633
        fillWithHorizontalExtensionGlyph(style, info, LayoutPoint(leftGlyphPaintRect.maxX(), baselineY), LayoutPoint(middleGlyphPaintRect.x(), baselineY));
635
        fillWithHorizontalExtensionGlyph(style, info, LayoutPoint(leftGlyphPaintRect.maxX(), baselineY), LayoutPoint(middleGlyphPaintRect.x(), baselineY));
634
        fillWithHorizontalExtensionGlyph(style, info, LayoutPoint(middleGlyphPaintRect.maxX(), baselineY), LayoutPoint(rightGlyphPaintRect.x(), baselineY));
636
        fillWithHorizontalExtensionGlyph(style, info, LayoutPoint(middleGlyphPaintRect.maxX(), baselineY), LayoutPoint(rightGlyphPaintRect.x(), baselineY));
635
    } else
637
    } else
Lines 656-662 void MathOperator::paint(const RenderStyle& style, PaintInfo& info, const Layout a/Source/WebCore/rendering/mathml/MathOperator.cpp_sec12
656
        }
658
        }
657
    }
659
    }
658
660
659
    if (m_stretchType == StretchType::GlyphAssembly) {
661
    if (isAssembly()) {
660
        if (m_operatorType == Type::VerticalOperator)
662
        if (m_operatorType == Type::VerticalOperator)
661
            paintVerticalGlyphAssembly(style, info, paintOffset);
663
            paintVerticalGlyphAssembly(style, info, paintOffset);
662
        else
664
        else
Lines 665-677 void MathOperator::paint(const RenderStyle& style, PaintInfo& info, const Layout a/Source/WebCore/rendering/mathml/MathOperator.cpp_sec13
665
    }
667
    }
666
668
667
    GlyphData glyphData;
669
    GlyphData glyphData;
668
    ASSERT(m_stretchType == StretchType::Unstretched || m_stretchType == StretchType::SizeVariant);
670
    ASSERT(!m_variantOrAssembly || isVariant());
669
    if (m_stretchType == StretchType::Unstretched) {
671
    if (!m_variantOrAssembly) {
670
        if (!getBaseGlyph(style, glyphData))
672
        if (!getBaseGlyph(style, glyphData))
671
            return;
673
            return;
672
    } else if (m_stretchType == StretchType::SizeVariant) {
674
    } else if (isVariant()) {
673
        ASSERT(m_variant.font);
675
        auto& variant = this->variant();
674
        glyphData = m_variant;
676
        ASSERT(variant.font);
677
        glyphData = variant;
675
    }
678
    }
676
    GlyphBuffer buffer;
679
    GlyphBuffer buffer;
677
    buffer.add(glyphData.glyph, glyphData.font, advanceWidthForGlyph(glyphData));
680
    buffer.add(glyphData.glyph, glyphData.font, advanceWidthForGlyph(glyphData));
Lines 681-686 void MathOperator::paint(const RenderStyle& style, PaintInfo& info, const Layout a/Source/WebCore/rendering/mathml/MathOperator.cpp_sec14
681
    paintInfo.context().drawGlyphs(style.fontCascade(), *glyphData.font, buffer, 0, 1, operatorOrigin);
684
    paintInfo.context().drawGlyphs(style.fontCascade(), *glyphData.font, buffer, 0, 1, operatorOrigin);
682
}
685
}
683
686
687
bool MathOperator::isVariant() const
688
{
689
    if (!m_variantOrAssembly)
690
        return false;
691
692
    bool result = false;
693
    auto visitor = WTF::makeVisitor(
694
        [&](const GlyphData&) { result = true; },
695
        [&](const GlyphAssemblyData&) { result = false; }
696
    );
697
    std::experimental::visit(visitor, m_variantOrAssembly.value());
698
    return result;
699
}
700
701
bool MathOperator::isAssembly() const
702
{
703
    if (!m_variantOrAssembly)
704
        return false;
705
706
    bool result = false;
707
    auto visitor = WTF::makeVisitor(
708
        [&](const GlyphData&) { result = false; },
709
        [&](const GlyphAssemblyData&) { result = true; }
710
    );
711
    std::experimental::visit(visitor, m_variantOrAssembly.value());
712
    return result;
713
}
714
715
GlyphData& MathOperator::variant()
716
{
717
    ASSERT(m_variantOrAssembly);
718
    GlyphData* result = nullptr;
719
    auto visitor = WTF::makeVisitor(
720
        [&](GlyphData& m_variant) { result = &m_variant; },
721
        [&](GlyphAssemblyData&) { CRASH_WITH_SECURITY_IMPLICATION(); }
722
    );
723
    std::experimental::visit(visitor, m_variantOrAssembly.value());
724
    return *result;
725
}
726
727
auto MathOperator::assembly() -> GlyphAssemblyData&
728
{
729
    ASSERT(m_variantOrAssembly);
730
    GlyphAssemblyData* result = nullptr;
731
    auto visitor = WTF::makeVisitor(
732
        [&](GlyphData&) { CRASH_WITH_SECURITY_IMPLICATION(); },
733
        [&](GlyphAssemblyData& m_assembly) { result = &m_assembly; }
734
    );
735
    std::experimental::visit(visitor, m_variantOrAssembly.value());
736
    return *result;
737
}
738
684
}
739
}
685
740
686
#endif
741
#endif
- a/Source/WebCore/rendering/mathml/MathOperator.h -6 / +9 lines
Lines 32-37 a/Source/WebCore/rendering/mathml/MathOperator.h_sec1
32
#include "OpenTypeMathData.h"
32
#include "OpenTypeMathData.h"
33
#include "PaintInfo.h"
33
#include "PaintInfo.h"
34
#include <unicode/utypes.h>
34
#include <unicode/utypes.h>
35
#include <wtf/Optional.h>
36
#include <wtf/Variant.h>
35
37
36
namespace WebCore {
38
namespace WebCore {
37
39
Lines 62-68 private: a/Source/WebCore/rendering/mathml/MathOperator.h_sec2
62
        GlyphData bottomOrLeft;
64
        GlyphData bottomOrLeft;
63
        GlyphData middle;
65
        GlyphData middle;
64
    };
66
    };
65
    enum class StretchType { Unstretched, SizeVariant, GlyphAssembly };
66
    enum GlyphPaintTrimming {
67
    enum GlyphPaintTrimming {
67
        TrimTop,
68
        TrimTop,
68
        TrimBottom,
69
        TrimBottom,
Lines 88-100 private: a/Source/WebCore/rendering/mathml/MathOperator.h_sec3
88
    void paintVerticalGlyphAssembly(const RenderStyle&, PaintInfo&, const LayoutPoint&);
89
    void paintVerticalGlyphAssembly(const RenderStyle&, PaintInfo&, const LayoutPoint&);
89
    void paintHorizontalGlyphAssembly(const RenderStyle&, PaintInfo&, const LayoutPoint&);
90
    void paintHorizontalGlyphAssembly(const RenderStyle&, PaintInfo&, const LayoutPoint&);
90
91
92
    bool isVariant() const;
93
    bool isAssembly() const;
94
    GlyphData& variant();
95
    GlyphAssemblyData& assembly();
96
91
    UChar m_baseCharacter { 0 };
97
    UChar m_baseCharacter { 0 };
92
    Type m_operatorType { Type::NormalOperator };
98
    Type m_operatorType { Type::NormalOperator };
93
    StretchType m_stretchType { StretchType::Unstretched };
99
    typedef std::experimental::variant<GlyphData, GlyphAssemblyData> GlyphDataOrGlyphAssemblyData;
94
    union {
100
    Optional<GlyphDataOrGlyphAssemblyData> m_variantOrAssembly;
95
        GlyphData m_variant;
96
        GlyphAssemblyData m_assembly;
97
    };
98
    LayoutUnit m_maxPreferredWidth { 0 };
101
    LayoutUnit m_maxPreferredWidth { 0 };
99
    LayoutUnit m_width { 0 };
102
    LayoutUnit m_width { 0 };
100
    LayoutUnit m_ascent { 0 };
103
    LayoutUnit m_ascent { 0 };

Return to Bug 161119