blob: e25c0851164c9da1508bc7fc3fb0f587218ba5bd [file] [log] [blame]
// Copyright 2019 Google LLC.
#ifndef LineBreaker_DEFINED
#define LineBreaker_DEFINED
#include <functional> // std::function
#include <queue>
#include "modules/skparagraph/include/TextStyle.h"
#include "modules/skparagraph/src/ParagraphImpl.h"
#include "modules/skparagraph/src/Run.h"
#include "src/core/SkSpan.h"
namespace skia {
namespace textlayout {
typedef size_t GlyphIndex;
typedef SkRange<GlyphIndex> GlyphRange;
class ParagraphImpl;
class OneLineShaper : public SkShaper::RunHandler {
public:
explicit OneLineShaper(ParagraphImpl* paragraph)
: fParagraph(paragraph)
, fHeight(0.0f)
, fAdvance(SkPoint::Make(0.0f, 0.0f))
, fUnresolvedGlyphs(0) { }
bool shape();
size_t unresolvedGlyphs() { return fUnresolvedGlyphs; }
private:
struct RunBlock {
RunBlock() : fRun(nullptr) { }
// First unresolved block
explicit RunBlock(TextRange text) : fRun(nullptr), fText(text) { }
RunBlock(std::shared_ptr<Run> run, TextRange text, GlyphRange glyphs, size_t score)
: fRun(std::move(run))
, fText(text)
, fGlyphs(glyphs) { }
// Entire run comes as one block fully resolved
explicit RunBlock(std::shared_ptr<Run> run)
: fRun(std::move(run))
, fText(run->fTextRange)
, fGlyphs(GlyphRange(0, run->size())) { }
std::shared_ptr<Run> fRun;
TextRange fText;
GlyphRange fGlyphs;
bool isFullyResolved() { return fRun != nullptr && fGlyphs.width() == fRun->size(); }
};
using ShapeVisitor =
std::function<SkScalar(SkSpan<const char>, SkSpan<Block>, SkScalar&, TextIndex)>;
bool iterateThroughShapingRegions(const ShapeVisitor& shape);
using ShapeSingleFontVisitor = std::function<void(Block)>;
void iterateThroughFontStyles(SkSpan<Block> styleSpan, const ShapeSingleFontVisitor& visitor);
using TypefaceVisitor = std::function<bool(sk_sp<SkTypeface> typeface)>;
void matchResolvedFonts(const TextStyle& textStyle, const TypefaceVisitor& visitor);
#ifdef SK_DEBUG
void printState();
#endif
void dropUnresolved();
void finish(TextRange text, SkScalar height, SkScalar& advanceX);
void beginLine() override {}
void runInfo(const RunInfo&) override {}
void commitRunInfo() override {}
void commitLine() override {}
Buffer runBuffer(const RunInfo& info) override {
fCurrentRun = std::make_shared<Run>(fParagraph,
info,
fCurrentText.start,
fHeight,
fParagraph->fRuns.count(),
fAdvance.fX);
return fCurrentRun->newRunBuffer();
}
void commitRunBuffer(const RunInfo&) override;
TextRange clusteredText(GlyphRange glyphs);
ClusterIndex clusterIndex(GlyphIndex glyph) {
return fCurrentText.start + fCurrentRun->fClusterIndexes[glyph];
}
void addFullyResolved();
void addUnresolvedWithRun(GlyphRange glyphRange);
void sortOutGlyphs(std::function<void(GlyphRange)>&& sortOutUnresolvedBLock);
ClusterRange normalizeTextRange(GlyphRange glyphRange);
void increment(TextIndex& index);
void fillGaps(size_t);
ParagraphImpl* fParagraph;
TextRange fCurrentText;
SkScalar fHeight;
SkVector fAdvance;
size_t fUnresolvedGlyphs;
// TODO: Something that is not thead-safe since we don't need it
std::shared_ptr<Run> fCurrentRun;
std::queue<RunBlock> fUnresolvedBlocks;
std::vector<RunBlock> fResolvedBlocks;
};
}
}
#endif