blob: a746f95850a411883dae50f95d98bc6523206749 [file] [log] [blame]
// Copyright 2019 Google LLC.
#ifndef LineBreaker_DEFINED
#define LineBreaker_DEFINED
#include <functional> // std::function
#include <queue>
#include "include/core/SkSpan.h"
#include "modules/skparagraph/include/TextStyle.h"
#include "modules/skparagraph/src/ParagraphImpl.h"
#include "modules/skparagraph/src/Run.h"
namespace skia {
namespace textlayout {
class ParagraphImpl;
class OneLineShaper : public SkShaper::RunHandler {
public:
explicit OneLineShaper(ParagraphImpl* paragraph)
: fParagraph(paragraph)
, fHeight(0.0f)
, fUseHalfLeading(false)
, fBaselineShift(0.0f)
, fAdvance(SkPoint::Make(0.0f, 0.0f))
, fUnresolvedGlyphs(0)
, fUniqueRunId(paragraph->fRuns.size()){ }
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(fRun->fTextRange)
, fGlyphs(GlyphRange(0, fRun->size())) { }
std::shared_ptr<Run> fRun;
TextRange fText;
GlyphRange fGlyphs;
bool isFullyResolved() { return fRun != nullptr && fGlyphs.width() == fRun->size(); }
};
using ShapeVisitor =
std::function<SkScalar(TextRange textRange, SkSpan<Block>, SkScalar&, TextIndex, uint8_t)>;
bool iterateThroughShapingRegions(const ShapeVisitor& shape);
using ShapeSingleFontVisitor = std::function<void(Block, SkTArray<SkShaper::Feature>)>;
void iterateThroughFontStyles(TextRange textRange, SkSpan<Block> styleSpan, const ShapeSingleFontVisitor& visitor);
enum Resolved {
Nothing,
Something,
Everything
};
using TypefaceVisitor = std::function<Resolved(sk_sp<SkTypeface> typeface)>;
void matchResolvedFonts(const TextStyle& textStyle, const TypefaceVisitor& visitor);
#ifdef SK_DEBUG
void printState();
#endif
void finish(const Block& block, 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,
fUseHalfLeading,
fBaselineShift,
++fUniqueRunId,
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 fillGaps(size_t);
ParagraphImpl* fParagraph;
TextRange fCurrentText;
SkScalar fHeight;
bool fUseHalfLeading;
SkScalar fBaselineShift;
SkVector fAdvance;
size_t fUnresolvedGlyphs;
size_t fUniqueRunId;
// TODO: Something that is not thead-safe since we don't need it
std::shared_ptr<Run> fCurrentRun;
std::deque<RunBlock> fUnresolvedBlocks;
std::vector<RunBlock> fResolvedBlocks;
// Keeping all resolved typefaces
struct FontKey {
FontKey() {}
FontKey(SkUnichar unicode, SkFontStyle fontStyle, SkString locale)
: fUnicode(unicode), fFontStyle(fontStyle), fLocale(locale) { }
SkUnichar fUnicode;
SkFontStyle fFontStyle;
SkString fLocale;
bool operator==(const FontKey& other) const;
struct Hasher {
size_t operator()(const FontKey& key) const;
};
};
SkTHashMap<FontKey, sk_sp<SkTypeface>, FontKey::Hasher> fFallbackFonts;
};
} // namespace textlayout
} // namespace skia
#endif