Title: [281300] trunk/Source/WebCore
Revision
281300
Author
[email protected]
Date
2021-08-20 01:05:02 -0700 (Fri, 20 Aug 2021)

Log Message

GlyphBuffer can become inconsistent with its backing string
https://bugs.webkit.org/show_bug.cgi?id=229064

Reviewed by Alan Bujtas.

This is split out from https://bugs.webkit.org/show_bug.cgi?id=215643.

Before shaping, the glyphs in the GlyphBuffer need to match one-to-one with code units in the string.
We iterate over the string, adding glyphs into the GlyphBuffer, but there was one early "continue"
in the loop that skips the add() call.

Because this patch adds ASSERT()s, this is actually covered by existing tests.

* platform/graphics/WidthIterator.cpp:
(WebCore::WidthIterator::commitCurrentFontRange):
(WebCore::addToGlyphBuffer):
(WebCore::WidthIterator::advanceInternal):
* platform/graphics/WidthIterator.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (281299 => 281300)


--- trunk/Source/WebCore/ChangeLog	2021-08-20 08:03:55 UTC (rev 281299)
+++ trunk/Source/WebCore/ChangeLog	2021-08-20 08:05:02 UTC (rev 281300)
@@ -1,3 +1,24 @@
+2021-08-20  Myles C. Maxfield  <[email protected]>
+
+        GlyphBuffer can become inconsistent with its backing string
+        https://bugs.webkit.org/show_bug.cgi?id=229064
+
+        Reviewed by Alan Bujtas.
+
+        This is split out from https://bugs.webkit.org/show_bug.cgi?id=215643.
+
+        Before shaping, the glyphs in the GlyphBuffer need to match one-to-one with code units in the string.
+        We iterate over the string, adding glyphs into the GlyphBuffer, but there was one early "continue"
+        in the loop that skips the add() call.
+
+        Because this patch adds ASSERT()s, this is actually covered by existing tests.
+
+        * platform/graphics/WidthIterator.cpp:
+        (WebCore::WidthIterator::commitCurrentFontRange):
+        (WebCore::addToGlyphBuffer):
+        (WebCore::WidthIterator::advanceInternal):
+        * platform/graphics/WidthIterator.h:
+
 2021-08-20  Tim Nguyen  <[email protected]>
 
         Ensure ancestors with opacity don't affect top layer elements

Modified: trunk/Source/WebCore/platform/graphics/WidthIterator.cpp (281299 => 281300)


--- trunk/Source/WebCore/platform/graphics/WidthIterator.cpp	2021-08-20 08:03:55 UTC (rev 281299)
+++ trunk/Source/WebCore/platform/graphics/WidthIterator.cpp	2021-08-20 08:05:02 UTC (rev 281300)
@@ -222,12 +222,18 @@
     }
 }
 
-void WidthIterator::commitCurrentFontRange(GlyphBuffer& glyphBuffer, unsigned lastGlyphCount, unsigned currentCharacterIndex, const Font& font, const Font& primaryFont, UChar32 character, float widthOfCurrentFontRange, CharactersTreatedAsSpace& charactersTreatedAsSpace)
+void WidthIterator::commitCurrentFontRange(GlyphBuffer& glyphBuffer, unsigned& lastGlyphCount, unsigned currentCharacterIndex, const Font*& font, const Font& newFont, const Font& primaryFont, UChar32 character, float& widthOfCurrentFontRange, float nextCharacterWidth, CharactersTreatedAsSpace& charactersTreatedAsSpace)
 {
+#if ASSERT_ENABLED
+    ASSERT(font);
+    for (unsigned i = lastGlyphCount; i < glyphBuffer.size(); ++i)
+        ASSERT(&glyphBuffer.fontAt(i) == font);
+#endif
+
     std::optional<GlyphBufferAdvance> initialAdvance;
     auto transformsType = shouldApplyFontTransforms(glyphBuffer, lastGlyphCount, currentCharacterIndex);
     if (transformsType != TransformsType::None) {
-        auto applyFontTransformsResult = applyFontTransforms(glyphBuffer, lastGlyphCount, currentCharacterIndex, font, transformsType == TransformsType::Forced, charactersTreatedAsSpace);
+        auto applyFontTransformsResult = applyFontTransforms(glyphBuffer, lastGlyphCount, currentCharacterIndex, *font, transformsType == TransformsType::Forced, charactersTreatedAsSpace);
         m_runWidthSoFar += applyFontTransformsResult.additionalAdvance;
         initialAdvance = applyFontTransformsResult.initialAdvance;
     }
@@ -234,11 +240,11 @@
     applyInitialAdvance(glyphBuffer, initialAdvance, lastGlyphCount);
     m_currentCharacterIndex = currentCharacterIndex;
 
-    if (widthOfCurrentFontRange && m_fallbackFonts && &font != &primaryFont) {
+    if (widthOfCurrentFontRange && m_fallbackFonts && font != &primaryFont) {
         // FIXME: This does a little extra work that could be avoided if
         // glyphDataForCharacter() returned whether it chose to use a small caps font.
         if (!m_font.isSmallCaps() || character == u_toupper(character))
-            m_fallbackFonts->add(&font);
+            m_fallbackFonts->add(font);
         else {
             auto glyphFont = m_font.glyphDataForCharacter(u_toupper(character), m_run.rtl()).font;
             if (glyphFont != &primaryFont)
@@ -245,6 +251,10 @@
                 m_fallbackFonts->add(glyphFont);
         }
     }
+
+    lastGlyphCount = glyphBuffer.size();
+    font = &newFont;
+    widthOfCurrentFontRange = nextCharacterWidth;
 }
 
 bool WidthIterator::hasExtraSpacing() const
@@ -252,6 +262,21 @@
     return (m_font.letterSpacing() || m_font.wordSpacing() || m_expansion) && !m_run.spacingDisabled();
 }
 
+static void addToGlyphBuffer(GlyphBuffer& glyphBuffer, Glyph glyph, const Font& font, float width, GlyphBufferStringOffset currentCharacterIndex, UChar32 character)
+{
+    glyphBuffer.add(glyph, font, width, currentCharacterIndex);
+#if USE(CTFONTSHAPEGLYPHS)
+    // These 0 glyphs are needed by shapers if the source text has surrogate pairs.
+    // However, CTFontTransformGlyphs() can't delete these 0 glyphs from the shaped text,
+    // so we shouldn't add them in the first place if we're using that shaping routine.
+    // Any other shaping routine should delete these glyphs from the shaped text.
+    if (!U_IS_BMP(character))
+        glyphBuffer.add(0, font, 0, currentCharacterIndex + 1);
+#else
+    UNUSED_PARAM(character);
+#endif
+}
+
 template <typename TextIterator>
 inline void WidthIterator::advanceInternal(TextIterator& textIterator, GlyphBuffer& glyphBuffer)
 {
@@ -291,6 +316,11 @@
         const GlyphData& glyphData = m_font.glyphDataForCharacter(character, rtl);
         Glyph glyph = glyphData.glyph;
         if (!glyph && !characterMustDrawSomething) {
+            commitCurrentFontRange(glyphBuffer, lastGlyphCount, currentCharacterIndex, lastFontData, primaryFont, primaryFont, character, widthOfCurrentFontRange, width, charactersTreatedAsSpace);
+
+            Glyph deletedGlyph = 0xFFFF;
+            addToGlyphBuffer(glyphBuffer, deletedGlyph, primaryFont, 0, currentCharacterIndex, character);
+
             textIterator.advance(advanceLength);
             currentCharacterIndex = textIterator.currentIndex();
             continue;
@@ -300,12 +330,9 @@
         previousWidth = width;
         width = font.widthForGlyph(glyph);
 
-        if (&font != lastFontData) {
-            commitCurrentFontRange(glyphBuffer, lastGlyphCount, currentCharacterIndex, *lastFontData, primaryFont, character, widthOfCurrentFontRange, charactersTreatedAsSpace);
-            lastGlyphCount = glyphBuffer.size();
-            lastFontData = &font;
-            widthOfCurrentFontRange = width;
-        } else
+        if (&font != lastFontData)
+            commitCurrentFontRange(glyphBuffer, lastGlyphCount, currentCharacterIndex, lastFontData, font, primaryFont, character, widthOfCurrentFontRange, width, charactersTreatedAsSpace);
+        else
             widthOfCurrentFontRange += width;
 
         auto transformsType = shouldApplyFontTransforms(glyphBuffer, lastGlyphCount, currentCharacterIndex);
@@ -326,15 +353,7 @@
         if (m_forTextEmphasis && !FontCascade::canReceiveTextEmphasis(character))
             glyph = 0;
 
-        glyphBuffer.add(glyph, font, width, currentCharacterIndex);
-#if USE(CTFONTSHAPEGLYPHS)
-        // These 0 glyphs are needed by shapers if the source text has surrogate pairs.
-        // However, CTFontTransformGlyphs() can't delete these 0 glyphs from the shaped text,
-        // so we shouldn't add them in the first place if we're using that shaping routine.
-        // Any other shaping routine should delete these glyphs from the shaped text.
-        if (!U_IS_BMP(character))
-            glyphBuffer.add(0, font, 0, currentCharacterIndex + 1);
-#endif
+        addToGlyphBuffer(glyphBuffer, glyph, font, width, currentCharacterIndex, character);
 
         // Advance past the character we just dealt with.
         textIterator.advance(advanceLength);
@@ -349,7 +368,7 @@
         }
     }
 
-    commitCurrentFontRange(glyphBuffer, lastGlyphCount, currentCharacterIndex, *lastFontData, primaryFont, character, widthOfCurrentFontRange, charactersTreatedAsSpace);
+    commitCurrentFontRange(glyphBuffer, lastGlyphCount, currentCharacterIndex, lastFontData, primaryFont, primaryFont, character, widthOfCurrentFontRange, width, charactersTreatedAsSpace);
 }
 
 auto WidthIterator::calculateAdditionalWidth(GlyphBuffer& glyphBuffer, GlyphBufferStringOffset currentCharacterIndex, unsigned leadingGlyphIndex, unsigned trailingGlyphIndex, float position) const -> AdditionalWidth

Modified: trunk/Source/WebCore/platform/graphics/WidthIterator.h (281299 => 281300)


--- trunk/Source/WebCore/platform/graphics/WidthIterator.h	2021-08-20 08:03:55 UTC (rev 281299)
+++ trunk/Source/WebCore/platform/graphics/WidthIterator.h	2021-08-20 08:05:02 UTC (rev 281300)
@@ -68,7 +68,7 @@
         GlyphBufferAdvance initialAdvance;
     };
     ApplyFontTransformsResult applyFontTransforms(GlyphBuffer&, unsigned lastGlyphCount, unsigned currentCharacterIndex, const Font&, bool force, CharactersTreatedAsSpace&);
-    void commitCurrentFontRange(GlyphBuffer&, unsigned lastGlyphCount, unsigned currentCharacterIndex, const Font&, const Font& primaryFont, UChar32 character, float widthOfCurrentFontRange, CharactersTreatedAsSpace&);
+    void commitCurrentFontRange(GlyphBuffer&, unsigned& lastGlyphCount, unsigned currentCharacterIndex, const Font*&, const Font& newFont, const Font& primaryFont, UChar32 character, float& widthOfCurrentFontRange, float nextCharacterWidth, CharactersTreatedAsSpace&);
     void applyInitialAdvance(GlyphBuffer&, std::optional<GlyphBufferAdvance> initialAdvance, unsigned lastGlyphCount);
 
     bool hasExtraSpacing() const;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to