Draw all underline segments in a particular run in the same call
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Jan 2014 21:56:26 +0000 (21:56 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Jan 2014 21:56:26 +0000 (21:56 +0000)
https://bugs.webkit.org/show_bug.cgi?id=127082

Reviewed by Simon Fraser.

Instead of running CGContextFillRect() in a loop, we can instead call CGContextFillRects()

In my tests, this seems to have about 0.5% speedup.

This patch creates some redundant code, but I think that refactoring would make the code
much less readable. I also am hesitant to make drawLineForText call drawLinesForText because
of the overhead of the vector that would be needed.

As there is no behavior change, no new tests are necessary

* platform/graphics/GraphicsContext.h:
* platform/graphics/cairo/GraphicsContextCairo.cpp:
(WebCore::GraphicsContext::drawLinesForText):
* platform/graphics/cg/GraphicsContextCG.cpp:
(WebCore::GraphicsContext::platformInit):
* platform/graphics/wince/GraphicsContextWinCE.cpp:
(WebCore::GraphicsContext::drawLinesForText):
* rendering/InlineTextBox.cpp:
(WebCore::drawSkipInkUnderline):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@162150 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/GraphicsContext.h
Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp
Source/WebCore/rendering/InlineTextBox.cpp

index adb1b8009bd604eb9d023cb41e040628bd0a9262..a853ce494d5d1365e02e501246e8591028e89bd9 100644 (file)
@@ -1,3 +1,30 @@
+2014-01-15  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        Draw all underline segments in a particular run in the same call
+        https://bugs.webkit.org/show_bug.cgi?id=127082
+
+        Reviewed by Simon Fraser.
+
+        Instead of running CGContextFillRect() in a loop, we can instead call CGContextFillRects()
+
+        In my tests, this seems to have about 0.5% speedup.
+
+        This patch creates some redundant code, but I think that refactoring would make the code
+        much less readable. I also am hesitant to make drawLineForText call drawLinesForText because
+        of the overhead of the vector that would be needed.
+
+        As there is no behavior change, no new tests are necessary
+
+        * platform/graphics/GraphicsContext.h:
+        * platform/graphics/cairo/GraphicsContextCairo.cpp:
+        (WebCore::GraphicsContext::drawLinesForText):
+        * platform/graphics/cg/GraphicsContextCG.cpp:
+        (WebCore::GraphicsContext::platformInit):
+        * platform/graphics/wince/GraphicsContextWinCE.cpp:
+        (WebCore::GraphicsContext::drawLinesForText):
+        * rendering/InlineTextBox.cpp:
+        (WebCore::drawSkipInkUnderline):
+
 2014-01-16  Brady Eidson  <beidson@apple.com>
 
         Use KeyedCoding as a persistent storage mechanism for blobs
index 27072f28a86210beded0d5cb5d08b8055f13953d..b147ab31c077077e5b10e3965077885d6efd6aaf 100644 (file)
@@ -371,6 +371,7 @@ namespace WebCore {
 
         FloatRect computeLineBoundsForText(const FloatPoint&, float width, bool printing);
         void drawLineForText(const FloatPoint&, float width, bool printing);
+        void drawLinesForText(const FloatPoint&, const DashArray& widths, bool printing);
         enum DocumentMarkerLineStyle {
 #if PLATFORM(IOS)
             TextCheckingDictationPhraseWithAlternativesLineStyle,
index 23d973d92e2cdc5ff0ea405153a7e83c8d535b78..069982123e4f6e246ad3f43f83e8482f30c9217c 100644 (file)
@@ -641,6 +641,12 @@ void GraphicsContext::drawLineForText(const FloatPoint& origin, float width, boo
     cairo_restore(cairoContext);
 }
 
+void GraphicsContext::drawLinesForText(const FloatPoint& point, const DashArray& widths, bool printing)
+{
+    for (size_t i = 0; i < widths.size(); i += 2)
+        drawLineForText(FloatPoint(point.x() + widths[i], point.y()), widths[i+1] - widths[i], printing);
+}
+
 void GraphicsContext::updateDocumentMarkerResources()
 {
     // Unnecessary, since our document markers don't use resources.
index dc30af0033201c84ff6e4f8a5a9b7e01d87a900c..f267c14508bde2c4e8042ee391311050fcb7beb0 100644 (file)
@@ -1455,10 +1455,11 @@ void GraphicsContext::drawLineForText(const FloatPoint& point, float width, bool
     if (restoreAntialiasMode)
         CGContextSetShouldAntialias(platformContext(), shouldAntialiasLine);
 
-    if (fillColor() != strokeColor())
+    bool fillColorIsNotEqualToStrokeColor = fillColor() != strokeColor();
+    if (fillColorIsNotEqualToStrokeColor)
         setCGFillColor(platformContext(), strokeColor(), strokeColorSpace());
     CGContextFillRect(platformContext(), bounds);
-    if (fillColor() != strokeColor())
+    if (fillColorIsNotEqualToStrokeColor)
         setCGFillColor(platformContext(), fillColor(), fillColorSpace());
     CGContextSetShouldAntialias(platformContext(), savedShouldAntialias);
 
@@ -1481,6 +1482,63 @@ void GraphicsContext::drawLineForText(const FloatPoint& point, float width, bool
 #endif
 }
 
+void GraphicsContext::drawLinesForText(const FloatPoint& point, const DashArray& widths, bool printing)
+{
+    if (paintingDisabled())
+        return;
+
+    if (widths.size() <= 0)
+        return;
+
+#if !PLATFORM(IOS)
+    bool shouldAntialiasLine;
+    FloatRect bounds = computeLineBoundsAndAntialiasingModeForText(*this, point, widths.last(), printing, shouldAntialiasLine);
+    
+    Vector<CGRect, 4> dashBounds;
+    ASSERT(!(widths.size() % 2));
+    dashBounds.reserveInitialCapacity(dashBounds.size() / 2);
+    for (size_t i = 0; i < widths.size(); i += 2)
+        dashBounds.append(CGRectMake(bounds.x() + widths[i], bounds.y(), widths[i+1] - widths[i], bounds.height()));
+
+    bool savedShouldAntialias = shouldAntialias();
+    bool restoreAntialiasMode = savedShouldAntialias != shouldAntialiasLine;
+
+    if (restoreAntialiasMode)
+        CGContextSetShouldAntialias(platformContext(), shouldAntialiasLine);
+
+    bool fillColorIsNotEqualToStrokeColor = fillColor() != strokeColor();
+    if (fillColorIsNotEqualToStrokeColor)
+        setCGFillColor(platformContext(), strokeColor(), strokeColorSpace());
+    CGContextFillRects(platformContext(), dashBounds.data(), dashBounds.size());
+    if (fillColorIsNotEqualToStrokeColor)
+        setCGFillColor(platformContext(), fillColor(), fillColorSpace());
+    CGContextSetShouldAntialias(platformContext(), savedShouldAntialias);
+
+    if (restoreAntialiasMode)
+        CGContextSetShouldAntialias(platformContext(), true);
+#else
+    CGContextRef context = platformContext();
+    CGContextSaveGState(context);
+
+    Color color(strokeColor());
+    
+    bool shouldAntialiasLine;
+    FloatRect rect = computeLineBoundsAndAntialiasingModeForText(*this, point, width, printing, shouldAntialiasLine, color);
+    
+    Vector<CGRect, 4> dashBounds;
+    ASSERT(!(widths.size() % 2));
+    dashBounds.reserveInitialCapacity(dashBounds.size() / 2);
+    for (size_t i = 0; i < widths.size(); i += 2)
+        dashBounds.append(CGRectMake(rect.x() + widths[i], rect.y(), widths[i+1] - widths[i], rect.height()));
+
+    if (m_state.shouldUseContextColors)
+        setCGFillColor(context, color, strokeColorSpace());
+    CGContextFillRects(context, dashBounds.data(), dashBounds.size());
+
+    CGContextRestoreGState(context);
+#endif
+}
+
 void GraphicsContext::setURLForRect(const URL& link, const IntRect& destRect)
 {
 #if !PLATFORM(IOS)
index 339021c058f5dd3a57e9cb6ec86105d320aa652f..9029d3015b9508185d658da8fa2a9b762d1001d4 100644 (file)
@@ -966,6 +966,12 @@ void GraphicsContext::drawLineForText(const FloatPoint& origin, float width, boo
     setStrokeStyle(oldStyle);
 }
 
+void GraphicsContext::drawLinesForText(const FloatPoint& point, const DashArray& widths, bool printing)
+{
+    for (size_t i = 0; i < widths.size(); i += 2)
+        drawLineForText(FloatPoint(point.x() + widths[i], point.y()), widths[i+1] - widths[i], printing);
+}
+
 void GraphicsContext::updateDocumentMarkerResources()
 {
     notImplemented();
index de90703f33bcdc75b92fe195d765f2ef56649a1d..ecdf04f4aac53a5a4f5a20d27526b4567b3b2099 100644 (file)
@@ -127,8 +127,7 @@ static void drawSkipInkUnderline(TextPainter& textPainter, GraphicsContext& cont
     DashArray a = translateIntersectionPointsToSkipInkBoundaries(intersections, underlineBoundingBox.height(), width);
 
     ASSERT(!(a.size() % 2));
-    for (auto i = a.begin(); i != a.end(); i++, i++)
-        context.drawLineForText(FloatPoint(localOrigin.x() + *i, localOrigin.y() + underlineOffset), *(i+1) - *i, isPrinting);
+    context.drawLinesForText(adjustedLocalOrigin, a, isPrinting);
 }
 #endif