rendering/SimpleLineLayoutFunctions.cpp
rendering/TextAutosizer.cpp
rendering/TextPaintStyle.cpp
+ rendering/TextPainter.cpp
rendering/break_lines.cpp
rendering/mathml/RenderMathMLBlock.cpp
+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
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 \
<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" />
<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>
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 */,
#include "SVGTextRunRenderingContext.h"
#include "Text.h"
#include "TextPaintStyle.h"
+#include "TextPainter.h"
#include "break_lines.h"
#include <wtf/text/CString.h>
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.
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
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();
#include "RenderWidget.cpp"
#include "RootInlineBox.cpp"
#include "ScrollBehavior.cpp"
+#include "TextPainter.cpp"
#include "break_lines.cpp"
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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