summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/TextPainter.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/rendering/TextPainter.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/rendering/TextPainter.cpp')
-rw-r--r--Source/WebCore/rendering/TextPainter.cpp254
1 files changed, 122 insertions, 132 deletions
diff --git a/Source/WebCore/rendering/TextPainter.cpp b/Source/WebCore/rendering/TextPainter.cpp
index d5bbdb92d..eeb0027e2 100644
--- a/Source/WebCore/rendering/TextPainter.cpp
+++ b/Source/WebCore/rendering/TextPainter.cpp
@@ -26,161 +26,151 @@
#include "GraphicsContext.h"
#include "InlineTextBox.h"
#include "RenderCombineText.h"
-#include "TextPaintStyle.h"
+#include <wtf/NeverDestroyed.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)
+ShadowApplier::ShadowApplier(GraphicsContext& context, const ShadowData* shadow, const FloatRect& textRect, bool lastShadowIterationShouldDrawText, bool opaque, FontOrientation orientation)
+ : m_context(context)
+ , m_shadow(shadow)
+ , m_onlyDrawsShadow(!isLastShadowIteration() || !lastShadowIterationShouldDrawText)
+ , m_avoidDrawingShadow(shadowIsCompletelyCoveredByText(opaque))
+ , m_nothingToDraw(shadow && m_avoidDrawingShadow && m_onlyDrawsShadow)
+ , m_didSaveContext(false)
{
+ if (!shadow || m_nothingToDraw) {
+ m_shadow = nullptr;
+ return;
+ }
+
+ int shadowX = orientation == Horizontal ? shadow->x() : shadow->y();
+ int shadowY = orientation == Horizontal ? shadow->y() : -shadow->x();
+ FloatSize shadowOffset(shadowX, shadowY);
+ int shadowRadius = shadow->radius();
+ const Color& shadowColor = shadow->color();
+
+ // When drawing shadows, we usually clip the context to the area the shadow will reside, and then
+ // draw the text itself outside the clipped area (so only the shadow shows up). However, we can
+ // often draw the *last* shadow and the text itself in a single call.
+ if (m_onlyDrawsShadow) {
+ FloatRect shadowRect(textRect);
+ shadowRect.inflate(shadow->paintingExtent() + 3 * textRect.height());
+ shadowRect.move(shadowOffset);
+ context.save();
+ context.clip(shadowRect);
+
+ m_didSaveContext = true;
+ m_extraOffset = FloatSize(0, 2 * shadowRect.height() + std::max(0.0f, shadowOffset.height()) + shadowRadius);
+ shadowOffset -= m_extraOffset;
+ }
+
+ if (!m_avoidDrawingShadow)
+ context.setShadow(shadowOffset, shadowRadius, shadowColor);
}
-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)
+ShadowApplier::~ShadowApplier()
{
- if (emphasisMark.isEmpty())
- context.drawText(font, textRun, point, from, to);
- else
- context.drawEmphasisMarks(font, textRun, emphasisMark, point + IntSize(0, emphasisMarkOffset), from, to);
+ if (!m_shadow)
+ return;
+ if (m_onlyDrawsShadow)
+ m_context.restore();
+ else if (!m_avoidDrawingShadow)
+ m_context.clearShadow();
}
-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)
+TextPainter::TextPainter(GraphicsContext& context)
+ : m_context(context)
{
- 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()
+void TextPainter::drawTextOrEmphasisMarks(const FontCascade& font, const TextRun& textRun, const AtomicString& emphasisMark,
+ float emphasisMarkOffset, const FloatPoint& textOrigin, unsigned startOffset, unsigned endOffset)
{
- ASSERT(m_savedDrawingStateForMask.m_textPaintStyle);
- ASSERT(m_savedDrawingStateForMask.m_selectionPaintStyle);
-
- FloatPoint boxOrigin = m_boxRect.location();
+ ASSERT(startOffset < endOffset);
+ if (emphasisMark.isEmpty())
+ m_context.drawText(font, textRun, textOrigin, startOffset, endOffset);
+ else
+ m_context.drawEmphasisMarks(font, textRun, emphasisMark, textOrigin + FloatSize(0, emphasisMarkOffset), startOffset, endOffset);
+}
- 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));
- }
+void TextPainter::paintTextWithShadows(const ShadowData* shadow, const FontCascade& font, const TextRun& textRun, const FloatRect& boxRect, const FloatPoint& textOrigin,
+ unsigned startOffset, unsigned endOffset, const AtomicString& emphasisMark, float emphasisMarkOffset, bool stroked)
+{
+ if (!shadow) {
+ drawTextOrEmphasisMarks(font, textRun, emphasisMark, emphasisMarkOffset, textOrigin, startOffset, endOffset);
+ return;
}
- 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);
+ Color fillColor = m_context.fillColor();
+ bool opaque = fillColor.isOpaque();
+ bool lastShadowIterationShouldDrawText = !stroked && opaque;
+ if (!opaque)
+ m_context.setFillColor(Color::black);
+ while (shadow) {
+ ShadowApplier shadowApplier(m_context, shadow, boxRect, lastShadowIterationShouldDrawText, opaque, m_textBoxIsHorizontal ? Horizontal : Vertical);
+ if (!shadowApplier.nothingToDraw())
+ drawTextOrEmphasisMarks(font, textRun, emphasisMark, emphasisMarkOffset, textOrigin + shadowApplier.extraOffset(), startOffset, endOffset);
+ shadow = shadow->next();
+ }
- if (m_combinedText)
- m_savedDrawingStateForMask.m_context->concatCTM(rotation(m_boxRect, Counterclockwise));
- }
+ if (!lastShadowIterationShouldDrawText) {
+ if (!opaque)
+ m_context.setFillColor(fillColor);
+ drawTextOrEmphasisMarks(font, textRun, emphasisMark, emphasisMarkOffset, textOrigin, startOffset, endOffset);
}
}
-void TextPainter::paintTextInContext(GraphicsContext& context, float amountToIncreaseStrokeWidthBy)
+void TextPainter::paintTextAndEmphasisMarksIfNeeded(const TextRun& textRun, const FloatRect& boxRect, const FloatPoint& textOrigin, unsigned startOffset, unsigned endOffset,
+ const TextPaintStyle& paintStyle, const ShadowData* shadow)
{
- 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;
+ // FIXME: Truncate right-to-left text correctly.
+ paintTextWithShadows(shadow, *m_font, textRun, boxRect, textOrigin, startOffset, endOffset, nullAtom, 0, paintStyle.strokeWidth > 0);
+
+ if (m_emphasisMark.isEmpty())
+ return;
+
+ FloatPoint boxOrigin = boxRect.location();
+ updateGraphicsContext(m_context, paintStyle, UseEmphasisMarkColor);
+ static NeverDestroyed<TextRun> objectReplacementCharacterTextRun(StringView(&objectReplacementCharacter, 1));
+ const TextRun& emphasisMarkTextRun = m_combinedText ? objectReplacementCharacterTextRun.get() : textRun;
+ FloatPoint emphasisMarkTextOrigin = m_combinedText ? FloatPoint(boxOrigin.x() + boxRect.width() / 2, boxOrigin.y() + m_font->fontMetrics().ascent()) : textOrigin;
+ if (m_combinedText)
+ m_context.concatCTM(rotation(boxRect, Clockwise));
+
+ // FIXME: Truncate right-to-left text correctly.
+ paintTextWithShadows(shadow, m_combinedText ? m_combinedText->originalFont() : *m_font, emphasisMarkTextRun, boxRect, emphasisMarkTextOrigin, startOffset, endOffset,
+ m_emphasisMark, m_emphasisMarkOffset, paintStyle.strokeWidth > 0);
+
+ if (m_combinedText)
+ m_context.concatCTM(rotation(boxRect, Counterclockwise));
}
-
-#if ENABLE(CSS3_TEXT_DECORATION_SKIP_INK)
-DashArray TextPainter::dashesForIntersectionsWithRect(const FloatRect& lineExtents)
+
+void TextPainter::paintText(const TextRun& textRun, unsigned length, const FloatRect& boxRect, const FloatPoint& textOrigin, unsigned selectionStart, unsigned selectionEnd,
+ bool paintSelectedTextOnly, bool paintSelectedTextSeparately)
{
- return m_font.dashesForIntersectionsWithRect(m_textRun, m_textOrigin, lineExtents);
+ ASSERT(m_font);
+ 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(m_context, m_textPaintStyle.strokeWidth > 0);
+ updateGraphicsContext(m_context, m_textPaintStyle);
+ bool fullPaint = !paintSelectedTextSeparately || selectionEnd <= selectionStart;
+ if (fullPaint)
+ paintTextAndEmphasisMarksIfNeeded(textRun, boxRect, textOrigin, 0, length, m_textPaintStyle, m_textShadow);
+ else {
+ // Paint the before and after selection parts.
+ if (selectionStart > 0)
+ paintTextAndEmphasisMarksIfNeeded(textRun, boxRect, textOrigin, 0, selectionStart, m_textPaintStyle, m_textShadow);
+ if (selectionEnd < length)
+ paintTextAndEmphasisMarksIfNeeded(textRun, boxRect, textOrigin, selectionEnd, length, m_textPaintStyle, m_textShadow);
+ }
+ }
+ // Paint only the text that is selected.
+ if ((paintSelectedTextOnly || paintSelectedTextSeparately) && selectionStart < selectionEnd) {
+ GraphicsContextStateSaver stateSaver(m_context, m_selectionPaintStyle.strokeWidth > 0);
+ updateGraphicsContext(m_context, m_selectionPaintStyle);
+ paintTextAndEmphasisMarksIfNeeded(textRun, boxRect, textOrigin, selectionStart, selectionEnd, m_selectionPaintStyle, m_selectionShadow);
+ }
}
-#endif
} // namespace WebCore