blob: ca296a10925a74b9605c9c5ddf85443d443fc22b [file] [log] [blame]
// Copyright 2019 Google LLC.
#ifndef TextLine_DEFINED
#define TextLine_DEFINED
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkScalar.h"
#include "include/private/SkBitmaskEnum.h" // IWYU pragma: keep
#include "include/private/base/SkTArray.h"
#include "modules/skparagraph/include/DartTypes.h"
#include "modules/skparagraph/include/Metrics.h"
#include "modules/skparagraph/include/ParagraphPainter.h"
#include "modules/skparagraph/include/TextStyle.h"
#include "modules/skparagraph/src/Run.h"
#include <stddef.h>
#include <functional>
#include <memory>
#include <vector>
class SkString;
namespace skia {
namespace textlayout {
class ParagraphImpl;
class TextLine {
struct ClipContext {
const Run* run;
size_t pos;
size_t size;
SkScalar fTextShift; // Shifts the text inside the run so it's placed at the right position
SkRect clip;
SkScalar fExcludedTrailingSpaces;
bool clippingNeeded;
enum TextAdjustment {
GlyphCluster = 0x01, // All text producing glyphs pointing to the same ClusterIndex
GlyphemeCluster = 0x02, // base glyph + all attached diacritics
Grapheme = 0x04, // Text adjusted to graphemes
GraphemeGluster = 0x05, // GlyphCluster & Grapheme
TextLine() = default;
TextLine(const TextLine&) = delete;
TextLine& operator=(const TextLine&) = delete;
TextLine(TextLine&&) = default;
TextLine& operator=(TextLine&&) = default;
~TextLine() = default;
TextLine(ParagraphImpl* owner,
SkVector offset,
SkVector advance,
BlockRange blocks,
TextRange textExcludingSpaces,
TextRange text,
TextRange textIncludingNewlines,
ClusterRange clusters,
ClusterRange clustersWithGhosts,
SkScalar widthWithSpaces,
InternalLineMetrics sizes);
TextRange trimmedText() const { return fTextExcludingSpaces; }
TextRange textWithNewlines() const { return fTextIncludingNewlines; }
TextRange text() const { return fText; }
ClusterRange clusters() const { return fClusterRange; }
ClusterRange clustersWithSpaces() const { return fGhostClusterRange; }
Run* ellipsis() const { return fEllipsis.get(); }
InternalLineMetrics sizes() const { return fSizes; }
bool empty() const { return fTextExcludingSpaces.empty(); }
SkScalar spacesWidth() const { return fWidthWithSpaces - width(); }
SkScalar height() const { return fAdvance.fY; }
SkScalar width() const {
return fAdvance.fX + (fEllipsis != nullptr ? fEllipsis->fAdvance.fX : 0);
SkScalar widthWithoutEllipsis() const { return fAdvance.fX; }
SkVector offset() const;
SkScalar alphabeticBaseline() const { return fSizes.alphabeticBaseline(); }
SkScalar ideographicBaseline() const { return fSizes.ideographicBaseline(); }
SkScalar baseline() const { return fSizes.baseline(); }
using RunVisitor = std::function<bool(
const Run* run, SkScalar runOffset, TextRange textRange, SkScalar* width)>;
void iterateThroughVisualRuns(bool includingGhostSpaces, const RunVisitor& runVisitor) const;
using RunStyleVisitor = std::function<void(
TextRange textRange, const TextStyle& style, const ClipContext& context)>;
SkScalar iterateThroughSingleRunByStyles(TextAdjustment textAdjustment,
const Run* run,
SkScalar runOffset,
TextRange textRange,
StyleType styleType,
const RunStyleVisitor& visitor) const;
using ClustersVisitor = std::function<bool(const Cluster* cluster, bool ghost)>;
void iterateThroughClustersInGlyphsOrder(bool reverse,
bool includeGhosts,
const ClustersVisitor& visitor) const;
void format(TextAlign align, SkScalar maxWidth);
void paint(ParagraphPainter* painter, SkScalar x, SkScalar y);
void visit(SkScalar x, SkScalar y);
void ensureTextBlobCachePopulated();
void createEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr);
// For testing internal structures
void scanStyles(StyleType style, const RunStyleVisitor& visitor);
void setMaxRunMetrics(const InternalLineMetrics& metrics) { fMaxRunMetrics = metrics; }
InternalLineMetrics getMaxRunMetrics() const { return fMaxRunMetrics; }
bool isFirstLine() const;
bool isLastLine() const;
void getRectsForRange(TextRange textRange,
RectHeightStyle rectHeightStyle,
RectWidthStyle rectWidthStyle,
std::vector<TextBox>& boxes) const;
void getRectsForPlaceholders(std::vector<TextBox>& boxes);
PositionWithAffinity getGlyphPositionAtCoordinate(SkScalar dx);
ClipContext measureTextInsideOneRun(TextRange textRange,
const Run* run,
SkScalar runOffsetInLine,
SkScalar textOffsetInRunInLine,
bool includeGhostSpaces,
TextAdjustment textAdjustment) const;
LineMetrics getMetrics() const;
SkRect extendHeight(const ClipContext& context) const;
void shiftVertically(SkScalar shift) { fOffset.fY += shift; }
void setAscentStyle(LineMetricStyle style) { fAscentStyle = style; }
void setDescentStyle(LineMetricStyle style) { fDescentStyle = style; }
bool endsWithHardLineBreak() const;
std::unique_ptr<Run> shapeEllipsis(const SkString& ellipsis, const Cluster* cluster);
void justify(SkScalar maxWidth);
void buildTextBlob(TextRange textRange, const TextStyle& style, const ClipContext& context);
void paintBackground(ParagraphPainter* painter,
SkScalar x,
SkScalar y,
TextRange textRange,
const TextStyle& style,
const ClipContext& context) const;
void paintShadow(ParagraphPainter* painter,
SkScalar x,
SkScalar y,
TextRange textRange,
const TextStyle& style,
const ClipContext& context) const;
void paintDecorations(ParagraphPainter* painter,
SkScalar x,
SkScalar y,
TextRange textRange,
const TextStyle& style,
const ClipContext& context) const;
void shiftCluster(const Cluster* cluster, SkScalar shift, SkScalar prevShift);
ParagraphImpl* fOwner;
BlockRange fBlockRange;
TextRange fTextExcludingSpaces;
TextRange fText;
TextRange fTextIncludingNewlines;
ClusterRange fClusterRange;
ClusterRange fGhostClusterRange;
// Avoid the malloc/free in the common case of one run per line
SkSTArray<1, size_t, true> fRunsInVisualOrder;
SkVector fAdvance; // Text size
SkVector fOffset; // Text position
SkScalar fShift; // Let right
SkScalar fWidthWithSpaces;
std::unique_ptr<Run> fEllipsis; // In case the line ends with the ellipsis
InternalLineMetrics fSizes; // Line metrics as a max of all run metrics and struts
InternalLineMetrics fMaxRunMetrics; // No struts - need it for GetRectForRange(max height)
bool fHasBackground;
bool fHasShadows;
bool fHasDecorations;
LineMetricStyle fAscentStyle;
LineMetricStyle fDescentStyle;
struct TextBlobRecord {
void paint(ParagraphPainter* painter, SkScalar x, SkScalar y);
sk_sp<SkTextBlob> fBlob;
SkPoint fOffset = SkPoint::Make(0.0f, 0.0f);
ParagraphPainter::SkPaintOrID fPaint;
SkRect fBounds = SkRect::MakeEmpty();
bool fClippingNeeded = false;
SkRect fClipRect = SkRect::MakeEmpty();
// Extra fields only used for the (experimental) visitor
const Run* fVisitor_Run;
size_t fVisitor_Pos;
bool fTextBlobCachePopulated;
std::vector<TextBlobRecord> fTextBlobCache;
} // namespace textlayout
} // namespace skia
namespace sknonstd {
template <> struct is_bitmask_enum<skia::textlayout::TextLine::TextAdjustment> : std::true_type {};
} // namespace sknonstd
#endif // TextLine_DEFINED