blob: 0082f450bfcdcac803997fe9a99eca3f9926e4f9 [file] [log] [blame]
// Copyright 2019 Google LLC.
#ifndef TextLine_DEFINED
#define TextLine_DEFINED
#include "include/core/SkCanvas.h"
#include "include/private/SkTArray.h"
#include "include/private/SkTHash.h"
#include "modules/skparagraph/include/DartTypes.h"
#include "modules/skparagraph/include/TextStyle.h"
#include "modules/skparagraph/src/Run.h"
#include "src/core/SkSpan.h"
namespace skia {
namespace textlayout {
class TextBlock {
public:
TextBlock() : fText(), fTextStyle() {}
TextBlock(SkSpan<const char> text, const TextStyle& style) : fText(text), fTextStyle(style) {}
SkSpan<const char> text() const { return fText; }
TextStyle style() const { return fTextStyle; }
void add(SkSpan<const char> tail) {
SkASSERT(fText.end() == tail.begin());
fText = SkSpan<const char>(fText.begin(), fText.size() + tail.size());
}
protected:
SkSpan<const char> fText;
TextStyle fTextStyle;
};
class TextLine {
public:
TextLine() = default;
TextLine(TextLine&&);
~TextLine() = default;
TextLine(SkVector offset, SkVector advance, SkSpan<const TextBlock> blocks,
SkSpan<const char> text, SkSpan<const char> textWithSpaces,
SkSpan<const Cluster> clusters, size_t start, size_t end, LineMetrics sizes);
SkSpan<const char> trimmedText() const { return fText; }
SkSpan<const char> textWithSpaces() const { return fTextWithSpaces; }
SkSpan<const Cluster> clusters() const { return fClusters; }
SkVector offset() const { return fOffset + SkVector::Make(fShift, 0); }
Run* ellipsis() const { return fEllipsis.get(); }
LineMetrics sizes() const { return fSizes; }
bool empty() const { return fText.empty(); }
SkScalar shift() const { return fShift; }
SkScalar height() const { return fAdvance.fY; }
SkScalar width() const {
return fAdvance.fX + (fEllipsis != nullptr ? fEllipsis->fAdvance.fX : 0);
}
void shiftTo(SkScalar shift) { fShift = shift; }
SkScalar alphabeticBaseline() const { return fSizes.alphabeticBaseline(); }
SkScalar ideographicBaseline() const { return fSizes.ideographicBaseline(); }
SkScalar baseline() const { return fSizes.baseline(); }
SkScalar roundingDelta() const { return fSizes.delta(); }
using StyleVisitor = std::function<SkScalar(SkSpan<const char> text, const TextStyle& style,
SkScalar offsetX)>;
void iterateThroughStylesInTextOrder(StyleType styleType, const StyleVisitor& visitor) const;
using RunVisitor = std::function<bool(Run* run, size_t pos, size_t size, SkRect clip,
SkScalar shift, bool clippingNeeded)>;
SkScalar iterateThroughRuns(SkSpan<const char> text,
SkScalar offsetX,
bool includeEmptyText,
const RunVisitor& visitor) const;
using ClustersVisitor = std::function<bool(const Cluster* cluster)>;
void iterateThroughClustersInGlyphsOrder(bool reverse, const ClustersVisitor& visitor) const;
void format(TextAlign effectiveAlign, SkScalar maxWidth, bool last);
void paint(SkCanvas* canvas);
void createEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr);
// For testing internal structures
void scanStyles(StyleType style, const StyleVisitor& visitor);
void scanRuns(const RunVisitor& visitor);
private:
Run* shapeEllipsis(const SkString& ellipsis, Run* run);
void justify(SkScalar maxWidth);
SkRect measureTextInsideOneRun(SkSpan<const char> text,
Run* run,
size_t& pos,
size_t& size,
bool& clippingNeeded) const;
SkScalar paintText(SkCanvas* canvas, SkSpan<const char> text, const TextStyle& style,
SkScalar offsetX) const;
SkScalar paintBackground(SkCanvas* canvas, SkSpan<const char> text, const TextStyle& style,
SkScalar offsetX) const;
SkScalar paintShadow(SkCanvas* canvas, SkSpan<const char> text, const TextStyle& style,
SkScalar offsetX) const;
SkScalar paintDecorations(SkCanvas* canvas, SkSpan<const char> text, const TextStyle& style,
SkScalar offsetX) const;
void computeDecorationPaint(SkPaint& paint, SkRect clip, const TextStyle& style,
SkPath& path) const;
bool contains(const Cluster* cluster) const {
return cluster->text().begin() >= fText.begin() && cluster->text().end() <= fText.end();
}
SkSpan<const TextBlock> fBlocks;
SkSpan<const char> fText;
SkSpan<const char> fTextWithSpaces;
SkSpan<const Cluster> fClusters;
// TODO: To clip by glyph:
//size_t fStartPos;
//size_t fEndPos;
SkTArray<Run*, true> fLogical;
SkScalar fShift; // Shift to left - right - center
SkVector fAdvance; // Text size
SkVector fOffset; // Text position
std::unique_ptr<Run> fEllipsis; // In case the line ends with the ellipsis
LineMetrics fSizes; // Line metrics as a max of all run metrics
static SkTHashMap<SkFont, Run> fEllipsisCache; // All found so far shapes of ellipsis
};
} // namespace textlayout
} // namespace skia
#endif // TextLine_DEFINED