Move InlineTextBox's text painting to it's own class
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 29 Oct 2013 22:29:30 +0000 (22:29 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 29 Oct 2013 22:29:30 +0000 (22:29 +0000)
https://bugs.webkit.org/show_bug.cgi?id=123355

Patch by Myles C. Maxfield <mmaxfield@apple.com> on 2013-10-29
Reviewed by Dean Jackson.

Implementing text-decoration-skip: ink requires drawing text
twice (once regularly, and once with a thick outline into a mask).
This patch pulls out the relevant text drawing code from
InlineTextBox into a new class, called TextPainter, which can be re-used
to draw text multiple times.

Because there should be no observable difference, no tests need to be updated.

* CMakeLists.txt: Adding new TextPainter class
* GNUmakefile.list.am: Adding new TextPainter class
* WebCore.vcxproj/WebCore.vcxproj: Adding new TextPainter class
* WebCore.vcxproj/WebCore.vcxproj.filters: Adding new TextPainter
class
* WebCore.xcodeproj/project.pbxproj: Adding new TextPainter class
* rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::paint): Moving text drawing code from
this function
* rendering/RenderingAllInOne.cpp: Adding new TextPainter class
* rendering/TextPainter.cpp: Added.
(WebCore::TextPainter::TextPainter):
(WebCore::drawTextOrEmphasisMarks):
(WebCore::paintTextWithShadows):
(WebCore::rotation):
(WebCore::TextPainter::paintText): New location for text drawing
code
(WebCore::TextPainter::paintTextInContext):
* rendering/TextPainter.h: Added.
(WebCore::SavedDrawingStateForMask::SavedDrawingStateForMask):
(WebCore::TextPainter::boxRect):

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

Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/rendering/InlineTextBox.cpp
Source/WebCore/rendering/RenderingAllInOne.cpp
Source/WebCore/rendering/TextPainter.cpp [new file with mode: 0644]
Source/WebCore/rendering/TextPainter.h [new file with mode: 0644]

index 6f33274ce7d15bb168550d1b994126f7491e917c..af0b278cd66a0955cc567d66e120d37dd254e39b 100644 (file)
@@ -2182,6 +2182,7 @@ set(WebCore_SOURCES
     rendering/SimpleLineLayoutFunctions.cpp
     rendering/TextAutosizer.cpp
     rendering/TextPaintStyle.cpp
+    rendering/TextPainter.cpp
     rendering/break_lines.cpp
 
     rendering/mathml/RenderMathMLBlock.cpp
index b40606a34e41de1ee88da0dcbdf4743203744599..5c800f96f6058335a97c5425ea88f623ebfe9ef7 100644 (file)
@@ -1,3 +1,40 @@
+2013-10-29  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        Move InlineTextBox's text painting to it's own class
+        https://bugs.webkit.org/show_bug.cgi?id=123355
+
+        Reviewed by Dean Jackson.
+
+        Implementing text-decoration-skip: ink requires drawing text
+        twice (once regularly, and once with a thick outline into a mask).
+        This patch pulls out the relevant text drawing code from
+        InlineTextBox into a new class, called TextPainter, which can be re-used
+        to draw text multiple times.
+
+        Because there should be no observable difference, no tests need to be updated.
+
+        * CMakeLists.txt: Adding new TextPainter class
+        * GNUmakefile.list.am: Adding new TextPainter class
+        * WebCore.vcxproj/WebCore.vcxproj: Adding new TextPainter class
+        * WebCore.vcxproj/WebCore.vcxproj.filters: Adding new TextPainter
+        class
+        * WebCore.xcodeproj/project.pbxproj: Adding new TextPainter class
+        * rendering/InlineTextBox.cpp:
+        (WebCore::InlineTextBox::paint): Moving text drawing code from
+        this function
+        * rendering/RenderingAllInOne.cpp: Adding new TextPainter class
+        * rendering/TextPainter.cpp: Added.
+        (WebCore::TextPainter::TextPainter):
+        (WebCore::drawTextOrEmphasisMarks):
+        (WebCore::paintTextWithShadows):
+        (WebCore::rotation):
+        (WebCore::TextPainter::paintText): New location for text drawing
+        code
+        (WebCore::TextPainter::paintTextInContext):
+        * rendering/TextPainter.h: Added.
+        (WebCore::SavedDrawingStateForMask::SavedDrawingStateForMask):
+        (WebCore::TextPainter::boxRect):
+
 2013-10-29  Jer Noble  <jer.noble@apple.com>
 
         [MSE] [Mac] Enable MediaSource on the Mac
index bf80f30fba6fa7ac5d28b8e37b2bd1d4ab2261c0..7c981d5b45adbcad279934318659469d9a0944e1 100644 (file)
@@ -4494,6 +4494,8 @@ webcore_sources += \
        Source/WebCore/rendering/TextAutosizer.cpp \
        Source/WebCore/rendering/TextAutosizer.h \
        Source/WebCore/rendering/TextPaintStyle.cpp \
+       Source/WebCore/rendering/TextPainter.cpp \
+       Source/WebCore/rendering/TextPainter.h \
        Source/WebCore/rendering/TextPaintStyle.h \
        Source/WebCore/rendering/VerticalPositionCache.h \
        Source/WebCore/rendering/mathml/RenderMathMLBlock.cpp \
index bd21bebc128a58d40b049348f7ac18a3ddc0b72b..148ddbdf60f78b2bfa51d9f4ef0779a9e3ade2b4 100644 (file)
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="..\rendering\TextPainter.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|x64'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="..\workers\SharedWorkerRepository.cpp" />
     <ClCompile Include="..\xml\DOMParser.cpp" />
     <ClCompile Include="..\xml\NativeXPathNSResolver.cpp" />
     <ClInclude Include="..\rendering\svg\SVGResourcesCycleSolver.h" />
     <ClInclude Include="..\rendering\TableLayout.h" />
     <ClInclude Include="..\rendering\TextPaintStyle.h" />
+    <ClInclude Include="..\rendering\TextPainter.h" />
     <ClInclude Include="..\rendering\TrailingFloatsRootInlineBox.h" />
     <ClInclude Include="..\rendering\mathml\RenderMathMLBlock.h" />
     <ClInclude Include="..\rendering\mathml\RenderMathMLFenced.h" />
index 92da89eddc4edf96d8ccc498d9f8dabb91cb38dd..b3c1ee519e6445b54fc1cb2f95e0be0ba81427d3 100644 (file)
     <ClCompile Include="..\rendering\svg\SVGTextRunRenderingContext.cpp">
       <Filter>rendering\svg</Filter>
     </ClCompile>
+    <ClCompile Include="..\rendering\TextPainter.cpp">
+      <Filter>rendering</Filter>
+    </ClCompile>
     <ClCompile Include="..\xml\DOMParser.cpp">
       <Filter>xml</Filter>
     </ClCompile>
     <ClInclude Include="..\rendering\TableLayout.h">
       <Filter>rendering</Filter>
     </ClInclude>
+    <ClInclude Include="..\rendering\TextPainter.h">
+      <Filter>rendering</Filter>
+    </ClInclude>
     <ClInclude Include="..\rendering\TrailingFloatsRootInlineBox.h">
       <Filter>rendering</Filter>
     </ClInclude>
       <Filter>platform\win</Filter>
     </MASM>
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
index 711e76f4749e4ca760a15efd9cddfa9f54fdaaff..b8319a95f472549a8a9d72c0f36499715669b648 100644 (file)
                1C11CCC60AA6093700DADB20 /* DOMDocumentFragment.h in Copy Generated Headers */ = {isa = PBXBuildFile; fileRef = 85089CD30A98C42800A275AA /* DOMDocumentFragment.h */; };
                1C11CCC70AA6093700DADB20 /* DOMCDATASection.h in Copy Generated Headers */ = {isa = PBXBuildFile; fileRef = 85089CCF0A98C42700A275AA /* DOMCDATASection.h */; };
                1C11CCC80AA6093700DADB20 /* DOMHTMLElement.h in Copy Generated Headers */ = {isa = PBXBuildFile; fileRef = 85DF2EEB0AA387CB00AD64C5 /* DOMHTMLElement.h */; };
+               1C18DA58181AF6A500C4EF22 /* TextPainter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C18DA56181AF6A500C4EF22 /* TextPainter.cpp */; };
+               1C18DA59181AF6A500C4EF22 /* TextPainter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C18DA57181AF6A500C4EF22 /* TextPainter.h */; };
                1C26497A0D7E248A00BD10F2 /* DocumentLoaderMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C2649790D7E248A00BD10F2 /* DocumentLoaderMac.cpp */; };
                1C26497C0D7E24EC00BD10F2 /* PageMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C26497B0D7E24EC00BD10F2 /* PageMac.cpp */; };
                1C4C8F020AD85D87009475CE /* DeleteButtonController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C4C8F000AD85D87009475CE /* DeleteButtonController.h */; settings = {ATTRIBUTES = (Private, ); }; };
                1AF8E1C1125673E000230FF7 /* ProxyServerCFNet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProxyServerCFNet.cpp; sourceTree = "<group>"; };
                1AFE11970CBFFCC4003017FA /* JSSQLResultSetRowList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSQLResultSetRowList.cpp; sourceTree = "<group>"; };
                1AFE11980CBFFCC4003017FA /* JSSQLResultSetRowList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSQLResultSetRowList.h; sourceTree = "<group>"; };
+               1C18DA56181AF6A500C4EF22 /* TextPainter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextPainter.cpp; sourceTree = "<group>"; };
+               1C18DA57181AF6A500C4EF22 /* TextPainter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextPainter.h; sourceTree = "<group>"; };
                1C2649790D7E248A00BD10F2 /* DocumentLoaderMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentLoaderMac.cpp; sourceTree = "<group>"; };
                1C26497B0D7E24EC00BD10F2 /* PageMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PageMac.cpp; sourceTree = "<group>"; };
                1C435CD314E8544F004E10EA /* Inspector.json */ = {isa = PBXFileReference; lastKnownFileType = text; path = Inspector.json; sourceTree = "<group>"; };
                                E4C91A0D1802343100A17F6D /* TextPaintStyle.h */,
                                37FC96DA1104ED71003E1FAD /* TrailingFloatsRootInlineBox.h */,
                                BCA257141293C010007A263D /* VerticalPositionCache.h */,
+                               1C18DA56181AF6A500C4EF22 /* TextPainter.cpp */,
+                               1C18DA57181AF6A500C4EF22 /* TextPainter.h */,
                        );
                        path = rendering;
                        sourceTree = "<group>";
                                29A812360FBB9C1D00510293 /* AccessibilityObject.h in Headers */,
                                A409C985116D0DDD007197BD /* AccessibilityProgressIndicator.h in Headers */,
                                29A812390FBB9C1D00510293 /* AccessibilityRenderObject.h in Headers */,
+                               1C18DA59181AF6A500C4EF22 /* TextPainter.h in Headers */,
                                93C4F6EB1108F9A50099D0DB /* AccessibilityScrollbar.h in Headers */,
                                29489FC712C00F0300D83F0F /* AccessibilityScrollView.h in Headers */,
                                0709FC4E1025DEE30059CDBA /* AccessibilitySlider.h in Headers */,
                                FEAD7D8716C339EE00D4670B /* SQLTransactionBackendSync.cpp in Sources */,
                                97BC6A541505F081001B74AC /* SQLTransactionClient.cpp in Sources */,
                                97BC6A561505F081001B74AC /* SQLTransactionCoordinator.cpp in Sources */,
+                               1C18DA58181AF6A500C4EF22 /* TextPainter.cpp in Sources */,
                                FE36FD1616C7826500F887C1 /* SQLTransactionStateMachine.cpp in Sources */,
                                078E08FF17D14CEE00420AA1 /* MediaStream.cpp in Sources */,
                                97BC6A5A1505F081001B74AC /* SQLTransactionSync.cpp in Sources */,
index 29ea203347d3fe9fcac2e9d3922c1cf51a0d3ad9..95a7caec502a496b8a7607856f660953bc4ff3ce 100644 (file)
@@ -48,6 +48,7 @@
 #include "SVGTextRunRenderingContext.h"
 #include "Text.h"
 #include "TextPaintStyle.h"
+#include "TextPainter.h"
 #include "break_lines.h"
 #include <wtf/text/CString.h>
 
@@ -397,54 +398,6 @@ FloatSize InlineTextBox::applyShadowToGraphicsContext(GraphicsContext* context,
     return extraOffset;
 }
 
-static void paintTextWithShadows(GraphicsContext* context, const Font& font, const TextRun& textRun, const AtomicString& emphasisMark, int emphasisMarkOffset, int startOffset, int endOffset, int truncationPoint, const FloatPoint& textOrigin,
-                                 const FloatRect& boxRect, const ShadowData* shadow, bool stroked, bool horizontal)
-{
-    Color fillColor = context->fillColor();
-    ColorSpace fillColorSpace = context->fillColorSpace();
-    bool opaque = fillColor.alpha() == 255;
-    if (!opaque)
-        context->setFillColor(Color::black, fillColorSpace);
-
-    do {
-        IntSize extraOffset;
-        if (shadow)
-            extraOffset = roundedIntSize(InlineTextBox::applyShadowToGraphicsContext(context, shadow, boxRect, stroked, opaque, horizontal));
-        else if (!opaque)
-            context->setFillColor(fillColor, fillColorSpace);
-
-        if (startOffset <= endOffset) {
-            if (emphasisMark.isEmpty())
-                context->drawText(font, textRun, textOrigin + extraOffset, startOffset, endOffset);
-            else
-                context->drawEmphasisMarks(font, textRun, emphasisMark, textOrigin + extraOffset + IntSize(0, emphasisMarkOffset), startOffset, endOffset);
-        } else {
-            if (endOffset > 0) {
-                if (emphasisMark.isEmpty())
-                    context->drawText(font, textRun, textOrigin + extraOffset,  0, endOffset);
-                else
-                    context->drawEmphasisMarks(font, textRun, emphasisMark, textOrigin + extraOffset + IntSize(0, emphasisMarkOffset),  0, endOffset);
-            }
-            if (startOffset < truncationPoint) {
-                if (emphasisMark.isEmpty())
-                    context->drawText(font, textRun, textOrigin + extraOffset, startOffset, truncationPoint);
-                else
-                    context->drawEmphasisMarks(font, textRun, emphasisMark, textOrigin + extraOffset + IntSize(0, emphasisMarkOffset),  startOffset, truncationPoint);
-            }
-        }
-
-        if (!shadow)
-            break;
-
-        if (shadow->next() || stroked || !opaque)
-            context->restore();
-        else
-            context->clearShadow();
-
-        shadow = shadow->next();
-    } while (shadow || stroked || !opaque);
-}
-
 bool InlineTextBox::getEmphasisMarkPosition(const RenderStyle& style, TextEmphasisPosition& emphasisPosition) const
 {
     // This function returns true if there are text emphasis marks and they are suppressed by ruby text.
@@ -468,14 +421,6 @@ bool InlineTextBox::getEmphasisMarkPosition(const RenderStyle& style, TextEmphas
     return !rubyText || !rubyText->hasLines();
 }
 
-enum RotationDirection { Counterclockwise, Clockwise };
-
-static inline AffineTransform rotation(const FloatRect& boxRect, RotationDirection clockwise)
-{
-    return clockwise ? AffineTransform(0, 1, -1, 0, boxRect.x() + boxRect.maxY(), boxRect.maxY() - boxRect.x())
-        : AffineTransform(0, -1, 1, 0, boxRect.x() - boxRect.maxY(), boxRect.x() + boxRect.maxY());
-}
-
 void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /*lineTop*/, LayoutUnit /*lineBottom*/)
 {
     if (isLineBreak() || !paintInfo.shouldPaintWithinRoot(renderer()) || renderer().style().visibility() != VISIBLE
@@ -628,59 +573,8 @@ void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset,
 
     const ShadowData* textShadow = paintInfo.forceBlackText() ? 0 : lineStyle.textShadow();
 
-    if (!paintSelectedTextOnly) {
-        // For stroked painting, we have to change the text drawing mode.  It's probably dangerous to leave that mutated as a side
-        // effect, so only when we know we're stroking, do a save/restore.
-        GraphicsContextStateSaver stateSaver(*context, textPaintStyle.strokeWidth > 0);
-
-        updateGraphicsContext(*context, textPaintStyle);
-        if (!paintSelectedTextSeparately || ePos <= sPos) {
-            // FIXME: Truncate right-to-left text correctly.
-            paintTextWithShadows(context, font, textRun, nullAtom, 0, 0, length, length, textOrigin, boxRect, textShadow, textPaintStyle.strokeWidth > 0, isHorizontal());
-        } else
-            paintTextWithShadows(context, font, textRun, nullAtom, 0, ePos, sPos, length, textOrigin, boxRect, textShadow, textPaintStyle.strokeWidth > 0, isHorizontal());
-
-        if (!emphasisMark.isEmpty()) {
-            updateGraphicsContext(*context, textPaintStyle, UseEmphasisMarkColor);
-
-            DEFINE_STATIC_LOCAL(TextRun, objectReplacementCharacterTextRun, (&objectReplacementCharacter, 1));
-            TextRun& emphasisMarkTextRun = combinedText ? objectReplacementCharacterTextRun : textRun;
-            FloatPoint emphasisMarkTextOrigin = combinedText ? FloatPoint(boxOrigin.x() + boxRect.width() / 2, boxOrigin.y() + font.fontMetrics().ascent()) : textOrigin;
-            if (combinedText)
-                context->concatCTM(rotation(boxRect, Clockwise));
-
-            if (!paintSelectedTextSeparately || ePos <= sPos) {
-                // FIXME: Truncate right-to-left text correctly.
-                paintTextWithShadows(context, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, 0, length, length, emphasisMarkTextOrigin, boxRect, textShadow, textPaintStyle.strokeWidth > 0, isHorizontal());
-            } else
-                paintTextWithShadows(context, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, ePos, sPos, length, emphasisMarkTextOrigin, boxRect, textShadow, textPaintStyle.strokeWidth > 0, isHorizontal());
-
-            if (combinedText)
-                context->concatCTM(rotation(boxRect, Counterclockwise));
-        }
-    }
-
-    if ((paintSelectedTextOnly || paintSelectedTextSeparately) && sPos < ePos) {
-        // paint only the text that is selected
-        GraphicsContextStateSaver stateSaver(*context, selectionPaintStyle.strokeWidth > 0);
-
-        updateGraphicsContext(*context, selectionPaintStyle);
-        paintTextWithShadows(context, font, textRun, nullAtom, 0, sPos, ePos, length, textOrigin, boxRect, selectionShadow, selectionPaintStyle.strokeWidth > 0, isHorizontal());
-        if (!emphasisMark.isEmpty()) {
-            updateGraphicsContext(*context, selectionPaintStyle, UseEmphasisMarkColor);
-
-            DEFINE_STATIC_LOCAL(TextRun, objectReplacementCharacterTextRun, (&objectReplacementCharacter, 1));
-            TextRun& emphasisMarkTextRun = combinedText ? objectReplacementCharacterTextRun : textRun;
-            FloatPoint emphasisMarkTextOrigin = combinedText ? FloatPoint(boxOrigin.x() + boxRect.width() / 2, boxOrigin.y() + font.fontMetrics().ascent()) : textOrigin;
-            if (combinedText)
-                context->concatCTM(rotation(boxRect, Clockwise));
-
-            paintTextWithShadows(context, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, sPos, ePos, length, emphasisMarkTextOrigin, boxRect, selectionShadow, selectionPaintStyle.strokeWidth > 0, isHorizontal());
-
-            if (combinedText)
-                context->concatCTM(rotation(boxRect, Counterclockwise));
-        }
-    }
+    TextPainter textPainter(*context, paintSelectedTextOnly, paintSelectedTextSeparately, font, sPos, ePos, length, emphasisMark, combinedText, textRun, boxRect, textOrigin, emphasisMarkOffset, textShadow, selectionShadow, isHorizontal(), textPaintStyle, selectionPaintStyle);
+    textPainter.paintText();
 
     // Paint decorations
     TextDecoration textDecorations = lineStyle.textDecorationsInEffect();
index a71c14c7e83767ef4b9e9694982394811979f89e..3667d82ba5b5e88e26bf0306464f3b7c23381236 100644 (file)
 #include "RenderWidget.cpp"
 #include "RootInlineBox.cpp"
 #include "ScrollBehavior.cpp"
+#include "TextPainter.cpp"
 #include "break_lines.cpp"
 
diff --git a/Source/WebCore/rendering/TextPainter.cpp b/Source/WebCore/rendering/TextPainter.cpp
new file mode 100644 (file)
index 0000000..dcaa516
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2013 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#include "config.h"
+#include "TextPainter.h"
+
+#include "GraphicsContext.h"
+#include "InlineTextBox.h"
+#include "RenderCombineText.h"
+#include "TextPaintStyle.h"
+
+namespace WebCore {
+
+TextPainter::TextPainter(GraphicsContext& context, bool paintSelectedTextOnly, bool paintSelectedTextSeparately, const Font& font,
+    int startPositionInTextRun, int endPositionInTextBoxString, int length, const AtomicString& emphasisMark, RenderCombineText* combinedText, TextRun& textRun,
+    FloatRect& boxRect, FloatPoint& textOrigin, int emphasisMarkOffset, const ShadowData* textShadow, const ShadowData* selectionShadow,
+    bool textBoxIsHorizontal, TextPaintStyle& textPaintStyle, TextPaintStyle& selectionPaintStyle)
+    : m_paintSelectedTextOnly(paintSelectedTextOnly)
+    , m_paintSelectedTextSeparately(paintSelectedTextSeparately)
+    , m_font(font)
+    , m_startPositionInTextRun(startPositionInTextRun)
+    , m_endPositionInTextRun(endPositionInTextBoxString)
+    , m_length(length)
+    , m_emphasisMark(emphasisMark)
+    , m_combinedText(combinedText)
+    , m_textRun(textRun)
+    , m_boxRect(boxRect)
+    , m_textOrigin(textOrigin)
+    , m_emphasisMarkOffset(emphasisMarkOffset)
+    , m_textBoxIsHorizontal(textBoxIsHorizontal)
+    , m_savedDrawingStateForMask(&context, &textPaintStyle, &selectionPaintStyle, textShadow, selectionShadow)
+{
+}
+
+static void drawTextOrEmphasisMarks(GraphicsContext& context, const Font& font, const TextRun& textRun, const AtomicString& emphasisMark,
+    int emphasisMarkOffset, const FloatPoint& point, const int from, const int to)
+{
+    if (emphasisMark.isEmpty())
+        context.drawText(font, textRun, point, from, to);
+    else
+        context.drawEmphasisMarks(font, textRun, emphasisMark, point + IntSize(0, emphasisMarkOffset), from, to);
+}
+
+static void paintTextWithShadows(GraphicsContext* context, const Font& font, const TextRun& textRun, const AtomicString& emphasisMark,
+    int emphasisMarkOffset, int startOffset, int endOffset, int truncationPoint, const FloatPoint& textOrigin, const FloatRect& boxRect,
+    const ShadowData* shadow, bool stroked, bool horizontal)
+{
+    Color fillColor = context->fillColor();
+    ColorSpace fillColorSpace = context->fillColorSpace();
+    bool opaque = !fillColor.hasAlpha();
+    if (!opaque)
+        context->setFillColor(Color::black, fillColorSpace);
+
+    do {
+        IntSize extraOffset;
+        if (shadow)
+            extraOffset = roundedIntSize(InlineTextBox::applyShadowToGraphicsContext(context, shadow, boxRect, stroked, opaque, horizontal));
+        else if (!opaque)
+            context->setFillColor(fillColor, fillColorSpace);
+
+        if (startOffset <= endOffset)
+            drawTextOrEmphasisMarks(*context, font, textRun, emphasisMark, emphasisMarkOffset, textOrigin + extraOffset, startOffset, endOffset);
+        else {
+            if (endOffset > 0)
+                drawTextOrEmphasisMarks(*context, font, textRun, emphasisMark, emphasisMarkOffset, textOrigin + extraOffset, 0, endOffset);
+            if (startOffset < truncationPoint)
+                drawTextOrEmphasisMarks(*context, font, textRun, emphasisMark, emphasisMarkOffset, textOrigin + extraOffset, startOffset, truncationPoint);
+        }
+
+        if (!shadow)
+            break;
+
+        if (shadow->next() || stroked || !opaque)
+            context->restore();
+        else
+            context->clearShadow();
+
+        shadow = shadow->next();
+    } while (shadow || stroked || !opaque);
+}
+
+void TextPainter::paintText()
+{
+    ASSERT(m_savedDrawingStateForMask.m_textPaintStyle);
+    ASSERT(m_savedDrawingStateForMask.m_selectionPaintStyle);
+    
+    FloatPoint boxOrigin = boxRect().location();
+
+    if (!m_paintSelectedTextOnly) {
+        // For stroked painting, we have to change the text drawing mode. It's probably dangerous to leave that mutated as a side
+        // effect, so only when we know we're stroking, do a save/restore.
+        GraphicsContextStateSaver stateSaver(*m_savedDrawingStateForMask.m_context, m_savedDrawingStateForMask.m_textPaintStyle->strokeWidth > 0);
+
+        updateGraphicsContext(*m_savedDrawingStateForMask.m_context, *m_savedDrawingStateForMask.m_textPaintStyle);
+        if (!m_paintSelectedTextSeparately || m_endPositionInTextRun <= m_startPositionInTextRun) {
+            // FIXME: Truncate right-to-left text correctly.
+            paintTextWithShadows(m_savedDrawingStateForMask.m_context, m_font, m_textRun, nullAtom, 0, 0, m_length, m_length, m_textOrigin, m_boxRect, m_savedDrawingStateForMask.m_textShadow, m_savedDrawingStateForMask.m_textPaintStyle->strokeWidth > 0, m_textBoxIsHorizontal);
+        } else
+            paintTextWithShadows(m_savedDrawingStateForMask.m_context, m_font, m_textRun, nullAtom, 0, m_endPositionInTextRun, m_startPositionInTextRun, m_length, m_textOrigin, m_boxRect, m_savedDrawingStateForMask.m_textShadow, m_savedDrawingStateForMask.m_textPaintStyle->strokeWidth > 0, m_textBoxIsHorizontal);
+
+        if (!m_emphasisMark.isEmpty()) {
+            updateGraphicsContext(*m_savedDrawingStateForMask.m_context, *m_savedDrawingStateForMask.m_textPaintStyle, UseEmphasisMarkColor);
+
+            DEFINE_STATIC_LOCAL(TextRun, objectReplacementCharacterTextRun, (&objectReplacementCharacter, 1));
+            TextRun& emphasisMarkTextRun = m_combinedText ? objectReplacementCharacterTextRun : m_textRun;
+            FloatPoint emphasisMarkTextOrigin = m_combinedText ? FloatPoint(boxOrigin.x() + m_boxRect.width() / 2, boxOrigin.y() + m_font.fontMetrics().ascent()) : m_textOrigin;
+            if (m_combinedText)
+                m_savedDrawingStateForMask.m_context->concatCTM(rotation(m_boxRect, Clockwise));
+
+            if (!m_paintSelectedTextSeparately || m_endPositionInTextRun <= m_startPositionInTextRun) {
+                // FIXME: Truncate right-to-left text correctly.
+                paintTextWithShadows(m_savedDrawingStateForMask.m_context, m_combinedText ? m_combinedText->originalFont() : m_font, emphasisMarkTextRun, m_emphasisMark, m_emphasisMarkOffset, 0, m_length, m_length, emphasisMarkTextOrigin, m_boxRect, m_savedDrawingStateForMask.m_textShadow, m_savedDrawingStateForMask.m_textPaintStyle->strokeWidth > 0, m_textBoxIsHorizontal);
+            } else
+                paintTextWithShadows(m_savedDrawingStateForMask.m_context, m_combinedText ? m_combinedText->originalFont() : m_font, emphasisMarkTextRun, m_emphasisMark, m_emphasisMarkOffset, m_endPositionInTextRun, m_startPositionInTextRun, m_length, emphasisMarkTextOrigin, m_boxRect, m_savedDrawingStateForMask.m_textShadow, m_savedDrawingStateForMask.m_textPaintStyle->strokeWidth > 0, m_textBoxIsHorizontal);
+
+            if (m_combinedText)
+                m_savedDrawingStateForMask.m_context->concatCTM(rotation(m_boxRect, Counterclockwise));
+        }
+    }
+
+    if ((m_paintSelectedTextOnly || m_paintSelectedTextSeparately) && m_startPositionInTextRun < m_endPositionInTextRun) {
+        // paint only the text that is selected
+        GraphicsContextStateSaver stateSaver(*m_savedDrawingStateForMask.m_context, m_savedDrawingStateForMask.m_selectionPaintStyle->strokeWidth > 0);
+
+        updateGraphicsContext(*m_savedDrawingStateForMask.m_context, *m_savedDrawingStateForMask.m_selectionPaintStyle);
+        paintTextWithShadows(m_savedDrawingStateForMask.m_context, m_font, m_textRun, nullAtom, 0, m_startPositionInTextRun, m_endPositionInTextRun, m_length, m_textOrigin, m_boxRect, m_savedDrawingStateForMask.m_selectionShadow, m_savedDrawingStateForMask.m_selectionPaintStyle->strokeWidth > 0, m_textBoxIsHorizontal);
+        if (!m_emphasisMark.isEmpty()) {
+            updateGraphicsContext(*m_savedDrawingStateForMask.m_context, *m_savedDrawingStateForMask.m_selectionPaintStyle, UseEmphasisMarkColor);
+
+            DEFINE_STATIC_LOCAL(TextRun, objectReplacementCharacterTextRun, (&objectReplacementCharacter, 1));
+            TextRun& emphasisMarkTextRun = m_combinedText ? objectReplacementCharacterTextRun : m_textRun;
+            FloatPoint emphasisMarkTextOrigin = m_combinedText ? FloatPoint(boxOrigin.x() + m_boxRect.width() / 2, boxOrigin.y() + m_font.fontMetrics().ascent()) : m_textOrigin;
+            if (m_combinedText)
+                m_savedDrawingStateForMask.m_context->concatCTM(rotation(m_boxRect, Clockwise));
+
+            paintTextWithShadows(m_savedDrawingStateForMask.m_context, m_combinedText ? m_combinedText->originalFont() : m_font, emphasisMarkTextRun, m_emphasisMark, m_emphasisMarkOffset, m_startPositionInTextRun, m_endPositionInTextRun, m_length, emphasisMarkTextOrigin, m_boxRect, m_savedDrawingStateForMask.m_selectionShadow, m_savedDrawingStateForMask.m_selectionPaintStyle->strokeWidth > 0, m_textBoxIsHorizontal);
+
+            if (m_combinedText)
+                m_savedDrawingStateForMask.m_context->concatCTM(rotation(m_boxRect, Counterclockwise));
+        }
+    }
+}
+
+void TextPainter::paintTextInContext(GraphicsContext& context, float amountToIncreaseStrokeWidthBy)
+{
+    SavedDrawingStateForMask savedDrawingStateForMask = m_savedDrawingStateForMask;
+    
+    ASSERT(m_savedDrawingStateForMask.m_textPaintStyle);
+    ASSERT(m_savedDrawingStateForMask.m_selectionPaintStyle);
+    m_savedDrawingStateForMask.m_context = &context;
+    m_savedDrawingStateForMask.m_textPaintStyle->strokeWidth += amountToIncreaseStrokeWidthBy;
+    m_savedDrawingStateForMask.m_selectionPaintStyle->strokeWidth += amountToIncreaseStrokeWidthBy;
+    m_savedDrawingStateForMask.m_textShadow = nullptr;
+    m_savedDrawingStateForMask.m_selectionShadow = nullptr;
+    paintText();
+
+    m_savedDrawingStateForMask = savedDrawingStateForMask;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/rendering/TextPainter.h b/Source/WebCore/rendering/TextPainter.h
new file mode 100644 (file)
index 0000000..4615fc7
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2013 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#ifndef TextPainter_h
+#define TextPainter_h
+
+#include "AffineTransform.h"
+#include "RenderText.h"
+
+namespace WebCore {
+
+class RenderCombineText;
+
+struct TextPaintStyle;
+
+enum RotationDirection { Counterclockwise, Clockwise };
+
+static inline AffineTransform rotation(const FloatRect& boxRect, RotationDirection clockwise)
+{
+    return clockwise ? AffineTransform(0, 1, -1, 0, boxRect.x() + boxRect.maxY(), boxRect.maxY() - boxRect.x())
+        : AffineTransform(0, -1, 1, 0, boxRect.x() - boxRect.maxY(), boxRect.x() + boxRect.maxY());
+}
+
+struct SavedDrawingStateForMask {
+    SavedDrawingStateForMask(GraphicsContext* context, TextPaintStyle* textPaintStyle, TextPaintStyle* selectionPaintStyle,
+    const ShadowData* textShadow, const ShadowData* selectionShadow)
+        : m_context(context)
+        , m_textPaintStyle(textPaintStyle)
+        , m_selectionPaintStyle(selectionPaintStyle)
+        , m_textShadow(textShadow)
+        , m_selectionShadow(selectionShadow)
+    {
+    }
+    GraphicsContext* m_context;
+    TextPaintStyle* m_textPaintStyle;
+    TextPaintStyle* m_selectionPaintStyle;
+    const ShadowData* m_textShadow;
+    const ShadowData* m_selectionShadow;
+};
+
+class TextPainter {
+public:
+    TextPainter(GraphicsContext&, bool paintSelectedTextOnly, bool paintSelectedTextSeparately, const Font&,
+    int startPositionInTextRun, int endPositionInTextBoxString, int length, const AtomicString& emphasisMark, RenderCombineText*,
+    TextRun&, FloatRect& boxRect, FloatPoint& textOrigin, int emphasisMarkOffset, const ShadowData* textShadow, const ShadowData* selectionShadow,
+    bool textBoxIsHorizontal, TextPaintStyle& nonSelectionPaintStyle, TextPaintStyle& selectionPaintStyle);
+    
+    const FloatRect& boxRect() const { return m_boxRect; }
+    void paintText();
+    void paintTextInContext(GraphicsContext&, float amountToIncreaseStrokeWidthBy);
+
+private:
+    bool m_paintSelectedTextOnly;
+    bool m_paintSelectedTextSeparately;
+    const Font& m_font;
+    int m_startPositionInTextRun;
+    int m_endPositionInTextRun;
+    int m_length;
+    const AtomicString& m_emphasisMark;
+    RenderCombineText* m_combinedText;
+    TextRun& m_textRun;
+    FloatRect& m_boxRect;
+    FloatPoint& m_textOrigin;
+    int m_emphasisMarkOffset;
+    bool m_textBoxIsHorizontal;
+    SavedDrawingStateForMask m_savedDrawingStateForMask;
+};
+
+} // namespace WebCore
+
+#endif // TextPainter_h