Title: [230544] trunk/Source/WebCore
Revision
230544
Author
[email protected]
Date
2018-04-11 13:29:49 -0700 (Wed, 11 Apr 2018)

Log Message

Cache glyphs (using display lists) when painting at high frequency
https://bugs.webkit.org/show_bug.cgi?id=178750
<rdar://problem/35201729>

Patch by Said Abou-Hallawa <[email protected]> on 2018-04-11
Reviewed by Antti Koivisto.

This patch adds support for caching of glyph drawing commands when painting
at high frequency. Caching the glyph drawing will be done using DisplayLists.

GlyphDisplayListCache is basically a hash map which maps InlineTextBox
or SimpleLineLayout::Run to DisplayList. Before adding a new entry to it
we have to check whether the conditions for caching the glyph DisplayList
are met or not. If no entry is found for a given run, a new DisplayList
is created and a new entry is add to the cache.

* WebCore.xcodeproj/project.pbxproj:
* page/MemoryRelease.cpp:
(WebCore::releaseNoncriticalMemory): Make GlyphDisplayListCache respond
to memory pressure.

* platform/graphics/FontCascade.cpp:
(WebCore::FontCascade::displayListForTextRun const):
* platform/graphics/FontCascade.h:
(WebCore::FontCascade::displayListForTextRun):
Record the drawing of a glyph run into a DisplayList.

* rendering/GlyphDisplayListCache.h: Added.
(WebCore::GlyphDisplayListCache::singleton):
(WebCore::GlyphDisplayListCache::get):
(WebCore::GlyphDisplayListCache::remove):
(WebCore::GlyphDisplayListCache::clear):
(WebCore::GlyphDisplayListCache::size const):
(WebCore::GlyphDisplayListCache::sizeInBytes const):
A simple cache for the TextRun DisplayList. Adding a new entry in the
cache happens under restricted conditions. So this cache is not expected
to grow much.

* rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::~InlineTextBox):
(WebCore::InlineTextBox::paint):
(WebCore::InlineTextBox::paintMarkedTexts):
(WebCore::InlineTextBox::paintMarkedTextBackground):
(WebCore::InlineTextBox::paintMarkedTextForeground):
(WebCore::InlineTextBox::paintMarkedTextDecoration):
(WebCore::InlineTextBox::paintCompositionBackground):
(WebCore::InlineTextBox::paintCompositionUnderlines const):
(WebCore::InlineTextBox::paintCompositionUnderline const):
* rendering/InlineTextBox.h:
(WebCore::InlineTextBox::paintMarkedTexts):
InlineTextBox::paintMarkedTextForeground() now requires PaintInfo to know
whether the entry in the GlyphDisplayListCache should be removed or not.
Change all the GraphicsContext arguments to be PaintInfo.

* rendering/SimpleLineLayout.cpp:
(WebCore::SimpleLineLayout::Layout::~Layout):
* rendering/SimpleLineLayout.h:
* rendering/SimpleLineLayoutFunctions.cpp:
(WebCore::SimpleLineLayout::paintFlow):
(WebCore::SimpleLineLayout::simpleLineLayoutWillBeDeleted):
* rendering/SimpleLineLayoutFunctions.h:
* rendering/SimpleLineLayoutResolver.h:
(WebCore::SimpleLineLayout::RunResolver::Run::simpleRun const):
Implement the glyph caching for SimpleLineLayout::Run.

* rendering/TextPainter.cpp:
(WebCore::TextPainter::paintTextOrEmphasisMarks): If the DisplayList is
available, replay it back into the GraphicsContext. Make sure to reset to
the DisplayList pointer to nullptr after painting.

(WebCore::TextPainter::clearGlyphDisplayLists):
(WebCore::TextPainter::shouldUseGlyphDisplayList): Check whether we should
use DisplayList to the draw glyph run.

* rendering/TextPainter.h:
(WebCore::TextPainter::setGlyphDisplayListIfNeeded): Check whether we should
should use DisplayList to the draw glyph run and if we should, ensure first
the DisplayList is cached and set it in the TextPainter so it uses it when
the run is painted.

(WebCore::TextPainter::removeGlyphDisplayList): Remove the cached DisplayList
entry for a glyph layout run.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (230543 => 230544)


--- trunk/Source/WebCore/ChangeLog	2018-04-11 20:02:29 UTC (rev 230543)
+++ trunk/Source/WebCore/ChangeLog	2018-04-11 20:29:49 UTC (rev 230544)
@@ -1,3 +1,87 @@
+2018-04-11  Said Abou-Hallawa  <[email protected]>
+
+        Cache glyphs (using display lists) when painting at high frequency
+        https://bugs.webkit.org/show_bug.cgi?id=178750
+        <rdar://problem/35201729>
+
+        Reviewed by Antti Koivisto.
+
+        This patch adds support for caching of glyph drawing commands when painting
+        at high frequency. Caching the glyph drawing will be done using DisplayLists.
+
+        GlyphDisplayListCache is basically a hash map which maps InlineTextBox
+        or SimpleLineLayout::Run to DisplayList. Before adding a new entry to it
+        we have to check whether the conditions for caching the glyph DisplayList
+        are met or not. If no entry is found for a given run, a new DisplayList
+        is created and a new entry is add to the cache.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * page/MemoryRelease.cpp:
+        (WebCore::releaseNoncriticalMemory): Make GlyphDisplayListCache respond
+        to memory pressure.
+
+        * platform/graphics/FontCascade.cpp:
+        (WebCore::FontCascade::displayListForTextRun const):
+        * platform/graphics/FontCascade.h:
+        (WebCore::FontCascade::displayListForTextRun):
+        Record the drawing of a glyph run into a DisplayList.
+
+        * rendering/GlyphDisplayListCache.h: Added.
+        (WebCore::GlyphDisplayListCache::singleton):
+        (WebCore::GlyphDisplayListCache::get):
+        (WebCore::GlyphDisplayListCache::remove):
+        (WebCore::GlyphDisplayListCache::clear):
+        (WebCore::GlyphDisplayListCache::size const):
+        (WebCore::GlyphDisplayListCache::sizeInBytes const):
+        A simple cache for the TextRun DisplayList. Adding a new entry in the
+        cache happens under restricted conditions. So this cache is not expected
+        to grow much.
+
+        * rendering/InlineTextBox.cpp:
+        (WebCore::InlineTextBox::~InlineTextBox):
+        (WebCore::InlineTextBox::paint):
+        (WebCore::InlineTextBox::paintMarkedTexts):
+        (WebCore::InlineTextBox::paintMarkedTextBackground):
+        (WebCore::InlineTextBox::paintMarkedTextForeground):
+        (WebCore::InlineTextBox::paintMarkedTextDecoration):
+        (WebCore::InlineTextBox::paintCompositionBackground):
+        (WebCore::InlineTextBox::paintCompositionUnderlines const):
+        (WebCore::InlineTextBox::paintCompositionUnderline const):
+        * rendering/InlineTextBox.h:
+        (WebCore::InlineTextBox::paintMarkedTexts):
+        InlineTextBox::paintMarkedTextForeground() now requires PaintInfo to know
+        whether the entry in the GlyphDisplayListCache should be removed or not.
+        Change all the GraphicsContext arguments to be PaintInfo.
+
+        * rendering/SimpleLineLayout.cpp:
+        (WebCore::SimpleLineLayout::Layout::~Layout):
+        * rendering/SimpleLineLayout.h:
+        * rendering/SimpleLineLayoutFunctions.cpp:
+        (WebCore::SimpleLineLayout::paintFlow):
+        (WebCore::SimpleLineLayout::simpleLineLayoutWillBeDeleted):
+        * rendering/SimpleLineLayoutFunctions.h:
+        * rendering/SimpleLineLayoutResolver.h:
+        (WebCore::SimpleLineLayout::RunResolver::Run::simpleRun const):
+        Implement the glyph caching for SimpleLineLayout::Run.
+
+        * rendering/TextPainter.cpp:
+        (WebCore::TextPainter::paintTextOrEmphasisMarks): If the DisplayList is
+        available, replay it back into the GraphicsContext. Make sure to reset to
+        the DisplayList pointer to nullptr after painting.
+
+        (WebCore::TextPainter::clearGlyphDisplayLists):
+        (WebCore::TextPainter::shouldUseGlyphDisplayList): Check whether we should
+        use DisplayList to the draw glyph run.
+
+        * rendering/TextPainter.h:
+        (WebCore::TextPainter::setGlyphDisplayListIfNeeded): Check whether we should
+        should use DisplayList to the draw glyph run and if we should, ensure first
+        the DisplayList is cached and set it in the TextPainter so it uses it when
+        the run is painted.
+
+        (WebCore::TextPainter::removeGlyphDisplayList): Remove the cached DisplayList
+        entry for a glyph layout run.
+
 2018-04-11  Brent Fulgham  <[email protected]>
 
         GraphicsLayerCA::createPlatformCALayer always disables extended color in its backing store

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (230543 => 230544)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-04-11 20:02:29 UTC (rev 230543)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-04-11 20:29:49 UTC (rev 230544)
@@ -8254,6 +8254,7 @@
 		555B87EB1CAAF0AB00349425 /* ImageDecoderCG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageDecoderCG.h; sourceTree = "<group>"; };
 		5576A5621D88A70800CCC04C /* ImageFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageFrame.cpp; sourceTree = "<group>"; };
 		5576A5631D88A70800CCC04C /* ImageFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageFrame.h; sourceTree = "<group>"; };
+		5597FCCB2076C06800D35BB0 /* GlyphDisplayListCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GlyphDisplayListCache.h; sourceTree = "<group>"; };
 		55A336F61D8209F40022C4C7 /* NativeImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeImage.h; sourceTree = "<group>"; };
 		55A336F81D821E3C0022C4C7 /* ImageBackingStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageBackingStore.h; sourceTree = "<group>"; };
 		55AF14E31EAAC59B0026EEAA /* UTIRegistry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UTIRegistry.cpp; sourceTree = "<group>"; };
@@ -25478,6 +25479,7 @@
 				9A528E8117D7F52F00AA9518 /* FloatingObjects.cpp */,
 				9A528E8217D7F52F00AA9518 /* FloatingObjects.h */,
 				935C477409AC4D8D00A6AAB4 /* GapRects.h */,
+				5597FCCB2076C06800D35BB0 /* GlyphDisplayListCache.h */,
 				E112F4701E3A85F200D6CDFD /* Grid.cpp */,
 				E112F46F1E3A85D800D6CDFD /* Grid.h */,
 				E12DE7151E4B748700F9ACCF /* GridTrackSizingAlgorithm.cpp */,

Modified: trunk/Source/WebCore/page/MemoryRelease.cpp (230543 => 230544)


--- trunk/Source/WebCore/page/MemoryRelease.cpp	2018-04-11 20:02:29 UTC (rev 230543)
+++ trunk/Source/WebCore/page/MemoryRelease.cpp	2018-04-11 20:29:49 UTC (rev 230544)
@@ -46,6 +46,7 @@
 #include "ScrollingThread.h"
 #include "StyleScope.h"
 #include "StyledElement.h"
+#include "TextPainter.h"
 #include "WorkerThread.h"
 #include <wtf/FastMalloc.h>
 #include <wtf/SystemTracing.h>
@@ -64,6 +65,7 @@
     FontDescription::invalidateCaches();
 
     clearWidthCaches();
+    TextPainter::clearGlyphDisplayLists();
 
     for (auto* document : Document::allDocuments())
         document->clearSelectorQueryCache();

Modified: trunk/Source/WebCore/platform/graphics/FontCascade.cpp (230543 => 230544)


--- trunk/Source/WebCore/platform/graphics/FontCascade.cpp	2018-04-11 20:02:29 UTC (rev 230543)
+++ trunk/Source/WebCore/platform/graphics/FontCascade.cpp	2018-04-11 20:29:49 UTC (rev 230544)
@@ -26,6 +26,7 @@
 
 #include "CharacterProperties.h"
 #include "ComplexTextController.h"
+#include "DisplayListRecorder.h"
 #include "FloatRect.h"
 #include "FontCache.h"
 #include "GlyphBuffer.h"
@@ -305,6 +306,32 @@
         drawEmphasisMarksForComplexText(context, run, mark, point, from, destination);
 }
 
+std::unique_ptr<DisplayList::DisplayList> FontCascade::displayListForTextRun(GraphicsContext& context, const TextRun& run, unsigned from, std::optional<unsigned> to, CustomFontNotReadyAction customFontNotReadyAction) const
+{
+    ASSERT(!context.paintingDisabled());
+    unsigned destination = to.value_or(run.length());
+    
+    // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
+    CodePath codePathToUse = codePath(run);
+    if (codePathToUse != Complex && (enableKerning() || requiresShaping()) && (from || destination != run.length()))
+        codePathToUse = Complex;
+    
+    GlyphBuffer glyphBuffer;
+    float startX = glyphBufferForTextRun(codePathToUse, run, from, destination, glyphBuffer);
+    // We couldn't generate any glyphs for the run. Give up.
+    if (glyphBuffer.isEmpty())
+        return nullptr;
+    
+    std::unique_ptr<DisplayList::DisplayList> displayList = std::make_unique<DisplayList::DisplayList>();
+    GraphicsContext recordingContext([&](GraphicsContext& displayListContext) {
+        return std::make_unique<DisplayList::Recorder>(displayListContext, *displayList, context.state(), FloatRect(), AffineTransform());
+    });
+    
+    FloatPoint startPoint(startX, 0);
+    drawGlyphBuffer(recordingContext, glyphBuffer, startPoint, customFontNotReadyAction);
+    return displayList;
+}
+    
 float FontCascade::widthOfTextRange(const TextRun& run, unsigned from, unsigned to, HashSet<const Font*>* fallbackFonts, float* outWidthBeforeRange, float* outWidthAfterRange) const
 {
     ASSERT(from <= to);

Modified: trunk/Source/WebCore/platform/graphics/FontCascade.h (230543 => 230544)


--- trunk/Source/WebCore/platform/graphics/FontCascade.h	2018-04-11 20:02:29 UTC (rev 230543)
+++ trunk/Source/WebCore/platform/graphics/FontCascade.h	2018-04-11 20:29:49 UTC (rev 230544)
@@ -48,6 +48,10 @@
 class TextLayout;
 class TextRun;
 
+namespace DisplayList {
+class DisplayList;
+}
+    
 struct GlyphData;
 
 struct GlyphOverflow {
@@ -197,6 +201,8 @@
 
     WeakPtr<FontCascade> createWeakPtr() const { return m_weakPtrFactory.createWeakPtr(*const_cast<FontCascade*>(this)); }
 
+    std::unique_ptr<DisplayList::DisplayList> displayListForTextRun(GraphicsContext&, const TextRun&, unsigned from = 0, std::optional<unsigned> to = { }, CustomFontNotReadyAction = CustomFontNotReadyAction::DoNotPaintIfFontNotReady) const;
+    
 private:
     enum ForTextEmphasisOrNot { NotForTextEmphasis, ForTextEmphasis };
 

Added: trunk/Source/WebCore/rendering/GlyphDisplayListCache.h (0 => 230544)


--- trunk/Source/WebCore/rendering/GlyphDisplayListCache.h	                        (rev 0)
+++ trunk/Source/WebCore/rendering/GlyphDisplayListCache.h	2018-04-11 20:29:49 UTC (rev 230544)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "DisplayList.h"
+#include "FontCascade.h"
+#include "Logging.h"
+#include "TextRun.h"
+#include <wtf/HashMap.h>
+#include <wtf/MemoryPressureHandler.h>
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+template<typename LayoutRun>
+class GlyphDisplayListCache {
+public:
+    GlyphDisplayListCache() = default;
+
+    static GlyphDisplayListCache& singleton()
+    {
+        static NeverDestroyed<GlyphDisplayListCache> cache;
+        return cache;
+    }
+
+    DisplayList::DisplayList* get(const LayoutRun& run, const FontCascade& font, GraphicsContext& context, const TextRun& textRun)
+    {
+        if (MemoryPressureHandler::singleton().isUnderMemoryPressure()) {
+            if (!m_glyphRunMap.isEmpty()) {
+                LOG(MemoryPressure, "GlyphDisplayListCache::%s - Under memory pressure - size: %d - sizeInBytes: %ld", __FUNCTION__, size(), sizeInBytes());
+                clear();
+            }
+            return nullptr;
+        }
+
+        if (auto displayList = m_glyphRunMap.get(&run))
+            return displayList;
+
+        if (auto displayList = font.displayListForTextRun(context, textRun))
+            return m_glyphRunMap.add(&run, WTFMove(displayList)).iterator->value.get();
+
+        return nullptr;
+    }
+
+    void remove(const LayoutRun& run)
+    {
+        m_glyphRunMap.remove(&run);
+    }
+
+    void clear()
+    {
+        m_glyphRunMap.clear();
+    }
+
+    unsigned size() const
+    {
+        return m_glyphRunMap.size();
+    }
+    
+    size_t sizeInBytes() const
+    {
+        size_t sizeInBytes = 0;
+        for (const auto& entry : m_glyphRunMap)
+            sizeInBytes += entry.value->sizeInBytes();
+        return sizeInBytes;
+    }
+    
+private:
+    using GlyphRunMap = HashMap<const LayoutRun*, std::unique_ptr<DisplayList::DisplayList>>;
+    GlyphRunMap m_glyphRunMap;
+};
+    
+}

Modified: trunk/Source/WebCore/rendering/InlineTextBox.cpp (230543 => 230544)


--- trunk/Source/WebCore/rendering/InlineTextBox.cpp	2018-04-11 20:02:29 UTC (rev 230543)
+++ trunk/Source/WebCore/rendering/InlineTextBox.cpp	2018-04-11 20:29:49 UTC (rev 230544)
@@ -73,6 +73,7 @@
 {
     if (!knownToHaveNoOverflow() && gTextBoxesWithOverflow)
         gTextBoxesWithOverflow->remove(this);
+    TextPainter::removeGlyphDisplayList(*this);
 }
 
 void InlineTextBox::markDirty(bool dirty)
@@ -503,7 +504,7 @@
     // and composition underlines.
     if (paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseTextClip && !isPrinting) {
         if (containsComposition && !useCustomUnderlines)
-            paintCompositionBackground(context, boxOrigin);
+            paintCompositionBackground(paintInfo, boxOrigin);
 
         Vector<MarkedText> markedTexts = collectMarkedTextsForDocumentMarkers(TextPaintPhase::Background);
 #if ENABLE(TEXT_SELECTION)
@@ -518,7 +519,7 @@
         // Coalesce styles of adjacent marked texts to minimize the number of drawing commands.
         auto coalescedStyledMarkedTexts = coalesceAdjacentMarkedTexts(styledMarkedTexts, &MarkedTextStyle::areBackgroundMarkedTextStylesEqual);
 
-        paintMarkedTexts(context, TextPaintPhase::Background, boxRect, coalescedStyledMarkedTexts);
+        paintMarkedTexts(paintInfo, TextPaintPhase::Background, boxRect, coalescedStyledMarkedTexts);
     }
 
     // FIXME: Right now, InlineTextBoxes never call addRelevantUnpaintedObject() even though they might
@@ -564,7 +565,7 @@
     // Coalesce styles of adjacent marked texts to minimize the number of drawing commands.
     auto coalescedStyledMarkedTexts = coalesceAdjacentMarkedTexts(styledMarkedTexts, &MarkedTextStyle::areForegroundMarkedTextStylesEqual);
 
-    paintMarkedTexts(context, TextPaintPhase::Foreground, boxRect, coalescedStyledMarkedTexts);
+    paintMarkedTexts(paintInfo, TextPaintPhase::Foreground, boxRect, coalescedStyledMarkedTexts);
 
     // Paint decorations
     TextDecoration textDecorations = lineStyle.textDecorationsInEffect();
@@ -601,7 +602,7 @@
         // Coalesce styles of adjacent marked texts to minimize the number of drawing commands.
         auto coalescedStyledMarkedTexts = coalesceAdjacentMarkedTexts(styledMarkedTexts, &MarkedTextStyle::areDecorationMarkedTextStylesEqual);
 
-        paintMarkedTexts(context, TextPaintPhase::Decoration, boxRect, coalescedStyledMarkedTexts, textDecorationSelectionClipOutRect);
+        paintMarkedTexts(paintInfo, TextPaintPhase::Decoration, boxRect, coalescedStyledMarkedTexts, textDecorationSelectionClipOutRect);
     }
 
     // 3. Paint fancy decorations, including composition underlines and platform-specific underlines for spelling errors, grammar errors, et cetera.
@@ -609,7 +610,7 @@
         paintPlatformDocumentMarkers(context, boxOrigin);
 
         if (useCustomUnderlines)
-            paintCompositionUnderlines(context, boxOrigin);
+            paintCompositionUnderlines(paintInfo, boxOrigin);
     }
     
     if (shouldRotate)
@@ -943,29 +944,30 @@
     return textOrigin;
 }
 
-void InlineTextBox::paintMarkedTexts(GraphicsContext& context, TextPaintPhase phase, const FloatRect& boxRect, const Vector<StyledMarkedText>& markedTexts, const FloatRect& decorationClipOutRect)
+void InlineTextBox::paintMarkedTexts(PaintInfo& paintInfo, TextPaintPhase phase, const FloatRect& boxRect, const Vector<StyledMarkedText>& markedTexts, const FloatRect& decorationClipOutRect)
 {
     switch (phase) {
     case TextPaintPhase::Background:
         for (auto& markedText : markedTexts)
-            paintMarkedTextBackground(context, boxRect.location(), markedText.style.backgroundColor, markedText.startOffset, markedText.endOffset);
+            paintMarkedTextBackground(paintInfo, boxRect.location(), markedText.style.backgroundColor, markedText.startOffset, markedText.endOffset);
         return;
     case TextPaintPhase::Foreground:
         for (auto& markedText : markedTexts)
-            paintMarkedTextForeground(context, boxRect, markedText);
+            paintMarkedTextForeground(paintInfo, boxRect, markedText);
         return;
     case TextPaintPhase::Decoration:
         for (auto& markedText : markedTexts)
-            paintMarkedTextDecoration(context, boxRect, decorationClipOutRect, markedText);
+            paintMarkedTextDecoration(paintInfo, boxRect, decorationClipOutRect, markedText);
         return;
     }
 }
 
-void InlineTextBox::paintMarkedTextBackground(GraphicsContext& context, const FloatPoint& boxOrigin, const Color& color, unsigned clampedStartOffset, unsigned clampedEndOffset)
+void InlineTextBox::paintMarkedTextBackground(PaintInfo& paintInfo, const FloatPoint& boxOrigin, const Color& color, unsigned clampedStartOffset, unsigned clampedEndOffset)
 {
     if (clampedStartOffset >= clampedEndOffset)
         return;
 
+    GraphicsContext& context = paintInfo.context();
     GraphicsContextStateSaver stateSaver { context };
     updateGraphicsContext(context, TextPaintStyle { color }); // Don't draw text at all!
 
@@ -989,11 +991,12 @@
     context.fillRect(snapRectToDevicePixelsWithWritingDirection(selectionRect, renderer().document().deviceScaleFactor(), textRun.ltr()), color);
 }
 
-void InlineTextBox::paintMarkedTextForeground(GraphicsContext& context, const FloatRect& boxRect, const StyledMarkedText& markedText)
+void InlineTextBox::paintMarkedTextForeground(PaintInfo& paintInfo, const FloatRect& boxRect, const StyledMarkedText& markedText)
 {
     if (markedText.startOffset >= markedText.endOffset)
         return;
 
+    GraphicsContext& context = paintInfo.context();
     const FontCascade& font = lineFont();
     const RenderStyle& lineStyle = this->lineStyle();
 
@@ -1012,6 +1015,9 @@
         textPainter.setShadow(&markedText.style.textShadow.value());
     textPainter.setEmphasisMark(emphasisMark, emphasisMarkOffset, combinedText());
 
+    TextRun textRun = createTextRun();
+    textPainter.setGlyphDisplayListIfNeeded(*this, paintInfo, font, context, textRun);
+
     GraphicsContextStateSaver stateSaver { context, false };
     if (markedText.type == MarkedText::DraggedContent) {
         stateSaver.save();
@@ -1018,14 +1024,15 @@
         context.setAlpha(markedText.style.alpha);
     }
     // TextPainter wants the box rectangle and text origin of the entire line box.
-    textPainter.paintRange(createTextRun(), boxRect, textOriginFromBoxRect(boxRect), markedText.startOffset, markedText.endOffset);
+    textPainter.paintRange(textRun, boxRect, textOriginFromBoxRect(boxRect), markedText.startOffset, markedText.endOffset);
 }
 
-void InlineTextBox::paintMarkedTextDecoration(GraphicsContext& context, const FloatRect& boxRect, const FloatRect& clipOutRect, const StyledMarkedText& markedText)
+void InlineTextBox::paintMarkedTextDecoration(PaintInfo& paintInfo, const FloatRect& boxRect, const FloatRect& clipOutRect, const StyledMarkedText& markedText)
 {
     if (m_truncation == cFullTruncation)
         return;
 
+    GraphicsContext& context = paintInfo.context();
     updateGraphicsContext(context, markedText.style.textStyles);
 
     bool isCombinedText = combinedText();
@@ -1073,12 +1080,12 @@
         context.concatCTM(rotation(boxRect, Counterclockwise));
 }
 
-void InlineTextBox::paintCompositionBackground(GraphicsContext& context, const FloatPoint& boxOrigin)
+void InlineTextBox::paintCompositionBackground(PaintInfo& paintInfo, const FloatPoint& boxOrigin)
 {
-    paintMarkedTextBackground(context, boxOrigin, Color::compositionFill, clampedOffset(renderer().frame().editor().compositionStart()), clampedOffset(renderer().frame().editor().compositionEnd()));
+    paintMarkedTextBackground(paintInfo, boxOrigin, Color::compositionFill, clampedOffset(renderer().frame().editor().compositionStart()), clampedOffset(renderer().frame().editor().compositionEnd()));
 }
 
-void InlineTextBox::paintCompositionUnderlines(GraphicsContext& context, const FloatPoint& boxOrigin) const
+void InlineTextBox::paintCompositionUnderlines(PaintInfo& paintInfo, const FloatPoint& boxOrigin) const
 {
     if (m_truncation == cFullTruncation)
         return;
@@ -1095,7 +1102,7 @@
             break; // Underline is completely after this run, bail. A later run will paint it.
 
         // Underline intersects this run. Paint it.
-        paintCompositionUnderline(context, boxOrigin, underline);
+        paintCompositionUnderline(paintInfo, boxOrigin, underline);
 
         if (underline.endOffset > end() + 1)
             break; // Underline also runs into the next run. Bail now, no more marker advancement.
@@ -1109,7 +1116,7 @@
     start = logicalWidth - width - start;
 }
 
-void InlineTextBox::paintCompositionUnderline(GraphicsContext& context, const FloatPoint& boxOrigin, const CompositionUnderline& underline) const
+void InlineTextBox::paintCompositionUnderline(PaintInfo& paintInfo, const FloatPoint& boxOrigin, const CompositionUnderline& underline) const
 {
     if (m_truncation == cFullTruncation)
         return;
@@ -1150,6 +1157,7 @@
     start += 1;
     width -= 2;
 
+    GraphicsContext& context = paintInfo.context();
     context.setStrokeColor(underline.compositionUnderlineColor == CompositionUnderlineColor::TextColor ? renderer().style().visitedDependentColor(CSSPropertyWebkitTextFillColor) : underline.color);
     context.setStrokeThickness(lineThickness);
     context.drawLineForText(FloatPoint(boxOrigin.x() + start, boxOrigin.y() + logicalHeight() - lineThickness), width, renderer().document().printing());

Modified: trunk/Source/WebCore/rendering/InlineTextBox.h (230543 => 230544)


--- trunk/Source/WebCore/rendering/InlineTextBox.h	2018-04-11 20:02:29 UTC (rev 230543)
+++ trunk/Source/WebCore/rendering/InlineTextBox.h	2018-04-11 20:29:49 UTC (rev 230544)
@@ -168,18 +168,18 @@
 
     FloatPoint textOriginFromBoxRect(const FloatRect&) const;
 
-    void paintMarkedTexts(GraphicsContext&, TextPaintPhase, const FloatRect& boxRect, const Vector<StyledMarkedText>&, const FloatRect& decorationClipOutRect = { });
+    void paintMarkedTexts(PaintInfo&, TextPaintPhase, const FloatRect& boxRect, const Vector<StyledMarkedText>&, const FloatRect& decorationClipOutRect = { });
 
     void paintPlatformDocumentMarker(GraphicsContext&, const FloatPoint& boxOrigin, const MarkedText&);
     void paintPlatformDocumentMarkers(GraphicsContext&, const FloatPoint& boxOrigin);
 
-    void paintCompositionBackground(GraphicsContext&, const FloatPoint& boxOrigin);
-    void paintCompositionUnderlines(GraphicsContext&, const FloatPoint& boxOrigin) const;
-    void paintCompositionUnderline(GraphicsContext&, const FloatPoint& boxOrigin, const CompositionUnderline&) const;
+    void paintCompositionBackground(PaintInfo&, const FloatPoint& boxOrigin);
+    void paintCompositionUnderlines(PaintInfo&, const FloatPoint& boxOrigin) const;
+    void paintCompositionUnderline(PaintInfo&, const FloatPoint& boxOrigin, const CompositionUnderline&) const;
 
-    void paintMarkedTextBackground(GraphicsContext&, const FloatPoint& boxOrigin, const Color&, unsigned clampedStartOffset, unsigned clampedEndOffset);
-    void paintMarkedTextForeground(GraphicsContext&, const FloatRect& boxRect, const StyledMarkedText&);
-    void paintMarkedTextDecoration(GraphicsContext&, const FloatRect& boxRect, const FloatRect& clipOutRect, const StyledMarkedText&);
+    void paintMarkedTextBackground(PaintInfo&, const FloatPoint& boxOrigin, const Color&, unsigned clampedStartOffset, unsigned clampedEndOffset);
+    void paintMarkedTextForeground(PaintInfo&, const FloatRect& boxRect, const StyledMarkedText&);
+    void paintMarkedTextDecoration(PaintInfo&, const FloatRect& boxRect, const FloatRect& clipOutRect, const StyledMarkedText&);
 
     const RenderCombineText* combinedText() const;
     const FontCascade& lineFont() const;

Modified: trunk/Source/WebCore/rendering/SimpleLineLayout.cpp (230543 => 230544)


--- trunk/Source/WebCore/rendering/SimpleLineLayout.cpp	2018-04-11 20:02:29 UTC (rev 230543)
+++ trunk/Source/WebCore/rendering/SimpleLineLayout.cpp	2018-04-11 20:29:49 UTC (rev 230544)
@@ -978,5 +978,10 @@
     memcpy(m_runs, runVector.data(), m_runCount * sizeof(Run));
 }
 
+Layout::~Layout()
+{
+    simpleLineLayoutWillBeDeleted(*this);
 }
+
 }
+}

Modified: trunk/Source/WebCore/rendering/SimpleLineLayout.h (230543 => 230544)


--- trunk/Source/WebCore/rendering/SimpleLineLayout.h	2018-04-11 20:02:29 UTC (rev 230543)
+++ trunk/Source/WebCore/rendering/SimpleLineLayout.h	2018-04-11 20:29:49 UTC (rev 230544)
@@ -81,6 +81,8 @@
     using SimpleLineStruts = Vector<SimpleLineStrut, 4>;
     static std::unique_ptr<Layout> create(const RunVector&, unsigned lineCount);
 
+    ~Layout();
+
     unsigned lineCount() const { return m_lineCount; }
 
     unsigned runCount() const { return m_runCount; }

Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp (230543 => 230544)


--- trunk/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp	2018-04-11 20:02:29 UTC (rev 230543)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp	2018-04-11 20:29:49 UTC (rev 230544)
@@ -120,6 +120,8 @@
         TextRun textRun { run.hasHyphen() ? textWithHyphen : run.text(), 0, run.expansion(), run.expansionBehavior() };
         textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize());
         FloatPoint textOrigin { rect.x() + paintOffset.x(), roundToDevicePixel(run.baselinePosition() + paintOffset.y(), deviceScaleFactor) };
+
+        textPainter.setGlyphDisplayListIfNeeded(run.simpleRun(), paintInfo, style.fontCascade(), paintInfo.context(), textRun);
         textPainter.paint(textRun, rect, textOrigin);
         if (textDecorationPainter) {
             textDecorationPainter->setWidth(rect.width());
@@ -261,6 +263,12 @@
     return flowContents.segmentForPosition(position).renderer;
 }
 
+void simpleLineLayoutWillBeDeleted(const Layout& layout)
+{
+    for (unsigned i = 0; i < layout.runCount(); ++i)
+        TextPainter::removeGlyphDisplayList(layout.runAt(i));
+}
+
 #if ENABLE(TREE_DEBUGGING)
 static void printPrefix(TextStream& stream, int& printedCharacters, int depth)
 {

Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutFunctions.h (230543 => 230544)


--- trunk/Source/WebCore/rendering/SimpleLineLayoutFunctions.h	2018-04-11 20:02:29 UTC (rev 230543)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutFunctions.h	2018-04-11 20:29:49 UTC (rev 230544)
@@ -66,6 +66,8 @@
 
 const RenderObject& rendererForPosition(const FlowContents&, unsigned);
 
+void simpleLineLayoutWillBeDeleted(const Layout&);
+
 #if ENABLE(TREE_DEBUGGING)
 void outputLineLayoutForFlow(WTF::TextStream&, const RenderBlockFlow&, const Layout&, int depth);
 #endif

Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutResolver.h (230543 => 230544)


--- trunk/Source/WebCore/rendering/SimpleLineLayoutResolver.h	2018-04-11 20:02:29 UTC (rev 230543)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutResolver.h	2018-04-11 20:29:49 UTC (rev 230544)
@@ -56,6 +56,7 @@
         String textWithHyphen() const;
         bool isEndOfLine() const;
         bool hasHyphen() const { return m_iterator.simpleRun().hasHyphen; }
+        const SimpleLineLayout::Run& simpleRun() const { return m_iterator.simpleRun(); }
 
         unsigned lineIndex() const;
 

Modified: trunk/Source/WebCore/rendering/TextPainter.cpp (230543 => 230544)


--- trunk/Source/WebCore/rendering/TextPainter.cpp	2018-04-11 20:02:29 UTC (rev 230543)
+++ trunk/Source/WebCore/rendering/TextPainter.cpp	2018-04-11 20:29:49 UTC (rev 230544)
@@ -23,9 +23,11 @@
 #include "config.h"
 #include "TextPainter.h"
 
+#include "DisplayListReplayer.h"
 #include "GraphicsContext.h"
 #include "InlineTextBox.h"
 #include "RenderCombineText.h"
+#include "RenderLayer.h"
 #include "ShadowData.h"
 #include <wtf/NeverDestroyed.h>
 
@@ -98,10 +100,18 @@
     float emphasisMarkOffset, const FloatPoint& textOrigin, unsigned startOffset, unsigned endOffset)
 {
     ASSERT(startOffset < endOffset);
-    if (emphasisMark.isEmpty())
+    if (!emphasisMark.isEmpty())
+        m_context.drawEmphasisMarks(font, textRun, emphasisMark, textOrigin + FloatSize(0, emphasisMarkOffset), startOffset, endOffset);
+    else if (startOffset || endOffset < textRun.length() || !m_glyphDisplayList)
         m_context.drawText(font, textRun, textOrigin, startOffset, endOffset);
-    else
-        m_context.drawEmphasisMarks(font, textRun, emphasisMark, textOrigin + FloatSize(0, emphasisMarkOffset), startOffset, endOffset);
+    else {
+        // Replaying back a whole cached glyph run to the GraphicsContext.
+        m_context.translate(textOrigin);
+        DisplayList::Replayer replayer(m_context, *m_glyphDisplayList);
+        replayer.replay();
+        m_context.translate(-textOrigin);
+    }
+    m_glyphDisplayList = nullptr;
 }
 
 void TextPainter::paintTextWithShadows(const ShadowData* shadow, const FontCascade& font, const TextRun& textRun, const FloatRect& boxRect, const FloatPoint& textOrigin,
@@ -195,4 +205,15 @@
     paintTextAndEmphasisMarksIfNeeded(textRun, boxRect, textOrigin, start, end, m_style, m_shadow);
 }
 
+void TextPainter::clearGlyphDisplayLists()
+{
+    GlyphDisplayListCache<InlineTextBox>::singleton().clear();
+    GlyphDisplayListCache<SimpleLineLayout::Run>::singleton().clear();
+}
+
+bool TextPainter::shouldUseGlyphDisplayList(const PaintInfo& paintInfo)
+{
+    return !paintInfo.context().paintingDisabled() && paintInfo.enclosingSelfPaintingLayer() && paintInfo.enclosingSelfPaintingLayer()->paintingFrequently();
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/rendering/TextPainter.h (230543 => 230544)


--- trunk/Source/WebCore/rendering/TextPainter.h	2018-04-11 20:02:29 UTC (rev 230543)
+++ trunk/Source/WebCore/rendering/TextPainter.h	2018-04-11 20:29:49 UTC (rev 230544)
@@ -24,6 +24,7 @@
 
 #include "AffineTransform.h"
 #include "FloatRect.h"
+#include "GlyphDisplayListCache.h"
 #include "TextFlags.h"
 #include "TextPaintStyle.h"
 #include <wtf/text/AtomicString.h>
@@ -58,6 +59,21 @@
     void paint(const TextRun&, const FloatRect& boxRect, const FloatPoint& textOrigin);
     void paintRange(const TextRun&, const FloatRect& boxRect, const FloatPoint& textOrigin, unsigned start, unsigned end);
 
+    template<typename LayoutRun>
+    void setGlyphDisplayListIfNeeded(const LayoutRun& run, const PaintInfo& paintInfo, const FontCascade& font, GraphicsContext& context, const TextRun& textRun)
+    {
+        if (!TextPainter::shouldUseGlyphDisplayList(paintInfo))
+            TextPainter::removeGlyphDisplayList(run);
+        else
+            m_glyphDisplayList = GlyphDisplayListCache<LayoutRun>::singleton().get(run, font, context, textRun);
+    }
+
+    template<typename LayoutRun>
+    static void removeGlyphDisplayList(const LayoutRun& run) { GlyphDisplayListCache<LayoutRun>::singleton().remove(run); }
+
+    static void clearGlyphDisplayLists();
+    static bool shouldUseGlyphDisplayList(const PaintInfo&);
+
 private:
     void paintTextOrEmphasisMarks(const FontCascade&, const TextRun&, const AtomicString& emphasisMark, float emphasisMarkOffset,
         const FloatPoint& textOrigin, unsigned startOffset, unsigned endOffset);
@@ -74,6 +90,7 @@
     const RenderCombineText* m_combinedText { nullptr };
     float m_emphasisMarkOffset { 0 };
     bool m_textBoxIsHorizontal { true };
+    DisplayList::DisplayList* m_glyphDisplayList { nullptr };
 };
 
 inline void TextPainter::setEmphasisMark(const AtomicString& mark, float offset, const RenderCombineText* combinedText)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to