/*
* Copyright 2018 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkGlyphRun_DEFINED
#define SkGlyphRun_DEFINED
#include <functional>
#include <vector>
#include "SkFont.h"
#include "SkPaint.h"
#include "SkPoint.h"
#include "SkSpan.h"
#include "SkTemplates.h"
#include "SkTypes.h"
class SkBaseDevice;
class SkGlyph;
class SkTextBlob;
class SkGlyphRun {
public:
SkGlyphRun() = default;
SkGlyphRun(const SkFont& font,
SkSpan<const SkPoint> positions,
SkSpan<const SkGlyphID> glyphIDs,
SkSpan<const char> text,
SkSpan<const uint32_t> clusters);
SkGlyphRun(const SkGlyphRun& glyphRun, const SkFont& font);
void filloutGlyphsAndPositions(SkGlyphID* glyphIDs, SkPoint* positions);
size_t runSize() const { return fGlyphIDs.size(); }
SkSpan<const SkPoint> positions() const { return fPositions.toConst(); }
SkSpan<const SkGlyphID> glyphsIDs() const { return fGlyphIDs; }
const SkFont& font() const { return fFont; }
SkSpan<const uint32_t> clusters() const { return fClusters; }
SkSpan<const char> text() const { return fText; }
private:
// Positions of each glyph.
const SkSpan<const SkPoint> fPositions;
// This is temporary while converting from the old per glyph code to the bulk code.
const SkSpan<const SkGlyphID> fGlyphIDs;
// Original text from SkTextBlob if present. Will be empty of not present.
const SkSpan<const char> fText;
// Original clusters from SkTextBlob if present. Will be empty if not present.
const SkSpan<const uint32_t> fClusters;
// Paint for this run modified to have glyph encoding and left alignment.
SkFont fFont;
};
class SkGlyphRunList {
const SkPaint* fOriginalPaint{nullptr}; // This should be deleted soon.
// The text blob is needed to hookup the call back that the SkTextBlob destructor calls. It
// should be used for nothing else
const SkTextBlob* fOriginalTextBlob{nullptr};
SkPoint fOrigin = {0, 0};
SkSpan<const SkGlyphRun> fGlyphRuns;
public:
SkGlyphRunList();
// Blob maybe null.
SkGlyphRunList(
const SkPaint& paint,
const SkTextBlob* blob,
SkPoint origin,
SkSpan<const SkGlyphRun> glyphRunList);
SkGlyphRunList(const SkGlyphRun& glyphRun, const SkPaint& paint);
uint64_t uniqueID() const;
bool anyRunsLCD() const;
bool anyRunsSubpixelPositioned() const;
void temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID) const;
bool canCache() const { return fOriginalTextBlob != nullptr; }
size_t runCount() const { return fGlyphRuns.size(); }
size_t totalGlyphCount() const {
size_t glyphCount = 0;
for(const auto& run : fGlyphRuns) {
glyphCount += run.runSize();
}
return glyphCount;
}
bool allFontsFinite() const;
SkPoint origin() const { return fOrigin; }
const SkPaint& paint() const { return *fOriginalPaint; }
const SkTextBlob* blob() const { return fOriginalTextBlob; }
auto begin() -> decltype(fGlyphRuns.begin()) { return fGlyphRuns.begin(); }
auto end() -> decltype(fGlyphRuns.end()) { return fGlyphRuns.end(); }
auto begin() const -> decltype(fGlyphRuns.cbegin()) { return fGlyphRuns.cbegin(); }
auto end() const -> decltype(fGlyphRuns.cend()) { return fGlyphRuns.cend(); }
auto size() const -> decltype(fGlyphRuns.size()) { return fGlyphRuns.size(); }
auto empty() const -> decltype(fGlyphRuns.empty()) { return fGlyphRuns.empty(); }
auto operator [] (size_t i) const -> decltype(fGlyphRuns[i]) { return fGlyphRuns[i]; }
};
class SkGlyphIDSet {
public:
SkSpan<const SkGlyphID> uniquifyGlyphIDs(
uint32_t universeSize, SkSpan<const SkGlyphID> glyphIDs,
SkGlyphID* uniqueGlyphIDs, uint16_t* denseindices);
private:
size_t fUniverseToUniqueSize{0};
SkAutoTMalloc<uint16_t> fUniverseToUnique;
};
class SkGlyphRunBuilder {
public:
void drawTextUTF8(
const SkPaint& paint, const SkFont&, const void* bytes, size_t byteLength, SkPoint origin);
void drawGlyphsWithPositions(
const SkPaint&, const SkFont&, SkSpan<const SkGlyphID> glyphIDs, const SkPoint* pos);
void drawTextBlob(const SkPaint& paint, const SkTextBlob& blob, SkPoint origin, SkBaseDevice*);
const SkGlyphRunList& useGlyphRunList();
bool empty() const { return fGlyphRunListStorage.size() == 0; }
static void DispatchBlob(SkGlyphRunBuilder* builder, const SkPaint& paint,
const SkTextBlob& blob, SkPoint origin, SkBaseDevice* device);
private:
void initialize(size_t totalRunSize);
SkSpan<const SkGlyphID> textToGlyphIDs(
const SkFont& font, const void* bytes, size_t byteLength, SkTextEncoding);
void makeGlyphRun(
const SkFont& font,
SkSpan<const SkGlyphID> glyphIDs,
SkSpan<const SkPoint> positions,
SkSpan<const char> text,
SkSpan<const uint32_t> clusters);
void makeGlyphRunList(const SkPaint& paint, const SkTextBlob* blob, SkPoint origin);
void simplifyDrawText(
const SkFont& font, SkSpan<const SkGlyphID> glyphIDs,
SkPoint origin, SkPoint* positions,
SkSpan<const char> text = SkSpan<const char>{},
SkSpan<const uint32_t> clusters = SkSpan<const uint32_t>{});
void simplifyDrawPosTextH(
const SkFont& font, SkSpan<const SkGlyphID> glyphIDs,
const SkScalar* xpos, SkScalar constY, SkPoint* positions,
SkSpan<const char> text = SkSpan<const char>{},
SkSpan<const uint32_t> clusters = SkSpan<const uint32_t>{});
void simplifyDrawPosText(
const SkFont& font, SkSpan<const SkGlyphID> glyphIDs,
const SkPoint* pos,
SkSpan<const char> text = SkSpan<const char>{},
SkSpan<const uint32_t> clusters = SkSpan<const uint32_t>{});
size_t fMaxTotalRunSize{0};
SkAutoTMalloc<SkPoint> fPositions;
std::vector<SkGlyphRun> fGlyphRunListStorage;
SkGlyphRunList fGlyphRunList;
// Used as a temporary for preparing using utfN text. This implies that only one run of
// glyph ids will ever be needed because blobs are already glyph based.
std::vector<SkGlyphID> fScratchGlyphIDs;
// Used as temporary storage for calculating positions for drawText.
std::vector<SkPoint> fScratchAdvances;
// Used for collecting the set of unique glyphs.
SkGlyphIDSet fGlyphIDSet;
SkAutoTMalloc<SkGlyphID> fUniqueGlyphIDs;
SkAutoTMalloc<uint16_t> fUniqueGlyphIDIndices;
};
#endif // SkGlyphRun_DEFINED