blob: 0b58bd98bdea51645ede7b13ef30645d8d04fbd9 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TextPainter_h
#define TextPainter_h
#include "core/CoreExport.h"
#include "core/style/ComputedStyleConstants.h"
#include "platform/fonts/TextBlob.h"
#include "platform/geometry/FloatPoint.h"
#include "platform/geometry/FloatRect.h"
#include "platform/geometry/LayoutRect.h"
#include "platform/graphics/Color.h"
#include "platform/transforms/AffineTransform.h"
#include "wtf/Allocator.h"
#include "wtf/text/AtomicString.h"
namespace blink {
class ComputedStyle;
class Font;
class GraphicsContext;
class GraphicsContextStateSaver;
class LayoutTextCombine;
class LayoutObject;
class LineLayoutItem;
struct PaintInfo;
class ShadowList;
class TextRun;
struct TextRunPaintInfo;
class CORE_EXPORT TextPainter {
STACK_ALLOCATED();
public:
struct Style;
TextPainter(GraphicsContext&,
const Font&,
const TextRun&,
const LayoutPoint& textOrigin,
const LayoutRect& textBounds,
bool horizontal);
~TextPainter();
void setEmphasisMark(const AtomicString&, TextEmphasisPosition);
void setCombinedText(LayoutTextCombine* combinedText) {
m_combinedText = combinedText;
}
static void updateGraphicsContext(GraphicsContext&,
const Style&,
bool horizontal,
GraphicsContextStateSaver&);
void paint(unsigned startOffset,
unsigned endOffset,
unsigned length,
const Style&,
TextBlobPtr* cachedTextBlob = 0);
struct Style {
STACK_ALLOCATED();
Color currentColor;
Color fillColor;
Color strokeColor;
Color emphasisMarkColor;
float strokeWidth;
const ShadowList* shadow;
bool operator==(const Style& other) {
return currentColor == other.currentColor &&
fillColor == other.fillColor && strokeColor == other.strokeColor &&
emphasisMarkColor == other.emphasisMarkColor &&
strokeWidth == other.strokeWidth && shadow == other.shadow;
}
bool operator!=(const Style& other) { return !(*this == other); }
};
static Style textPaintingStyle(LineLayoutItem,
const ComputedStyle&,
const PaintInfo&);
static Style selectionPaintingStyle(LineLayoutItem,
bool haveSelection,
const PaintInfo&,
const Style& textStyle);
static Color textColorForWhiteBackground(Color);
enum RotationDirection { Counterclockwise, Clockwise };
static AffineTransform rotation(const LayoutRect& boxRect, RotationDirection);
private:
void updateGraphicsContext(const Style& style,
GraphicsContextStateSaver& saver) {
updateGraphicsContext(m_graphicsContext, style, m_horizontal, saver);
}
enum PaintInternalStep { PaintText, PaintEmphasisMark };
template <PaintInternalStep step>
void paintInternalRun(TextRunPaintInfo&, unsigned from, unsigned to);
template <PaintInternalStep step>
void paintInternal(unsigned startOffset,
unsigned endOffset,
unsigned truncationPoint,
TextBlobPtr* cachedTextBlob = 0);
void paintEmphasisMarkForCombinedText();
GraphicsContext& m_graphicsContext;
const Font& m_font;
const TextRun& m_run;
LayoutPoint m_textOrigin;
LayoutRect m_textBounds;
bool m_horizontal;
AtomicString m_emphasisMark;
int m_emphasisMarkOffset;
LayoutTextCombine* m_combinedText;
};
inline AffineTransform TextPainter::rotation(
const LayoutRect& boxRect,
RotationDirection rotationDirection) {
// Why this matrix is correct: consider the case of a clockwise rotation.
// Let the corner points that define |boxRect| be ABCD, where A is top-left
// and B is bottom-left.
// 1. We want B to end up at the same pixel position after rotation as A is
// before rotation.
// 2. Before rotation, B is at (x(), maxY())
// 3. Rotating clockwise by 90 degrees places B at the coordinates
// (-maxY(), x()).
// 4. Point A before rotation is at (x(), y())
// 5. Therefore the translation from (3) to (4) is (x(), y()) - (-maxY(), x())
// = (x() + maxY(), y() - x())
// A similar argument derives the counter-clockwise case.
return rotationDirection == Clockwise
? AffineTransform(0, 1, -1, 0, boxRect.x() + boxRect.maxY(),
boxRect.y() - boxRect.x())
: AffineTransform(0, -1, 1, 0, boxRect.x() - boxRect.y(),
boxRect.x() + boxRect.maxY());
}
} // namespace blink
#endif // TextPainter_h