blob: 4e90c8c368960f79c00b32547bbc86b2b581cf7e [file] [log] [blame]
/*
* 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 <optional>
#include <vector>
#include "include/core/SkFont.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRSXform.h"
#include "include/core/SkSpan.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkTemplates.h"
#include "src/core/SkGlyphBuffer.h"
#include "src/core/SkZip.h"
class SkBaseDevice;
class SkCanvas;
class SkGlyph;
class SkTextBlob;
class SkTextBlobRunIterator;
namespace sktext {
class GlyphRunBuilder;
class GlyphRunList;
class SkSubRunBuffers {
public:
class ScopedBuffers {
public:
ScopedBuffers(SkSubRunBuffers* painter, size_t size);
~ScopedBuffers();
std::tuple<SkDrawableGlyphBuffer*, SkSourceGlyphBuffer*> buffers() {
return {&fBuffers->fAccepted, &fBuffers->fRejected};
}
private:
SkSubRunBuffers* const fBuffers;
};
static ScopedBuffers SK_WARN_UNUSED_RESULT EnsureBuffers(const GlyphRunList& glyphRunList);
private:
SkDrawableGlyphBuffer fAccepted;
SkSourceGlyphBuffer fRejected;
};
class GlyphRun {
public:
GlyphRun(const SkFont& font,
SkSpan<const SkPoint> positions,
SkSpan<const SkGlyphID> glyphIDs,
SkSpan<const char> text,
SkSpan<const uint32_t> clusters,
SkSpan<const SkVector> scaledRotations);
GlyphRun(const GlyphRun& glyphRun, const SkFont& font);
size_t runSize() const { return fSource.size(); }
SkSpan<const SkPoint> positions() const { return fSource.get<1>(); }
SkSpan<const SkGlyphID> glyphsIDs() const { return fSource.get<0>(); }
SkZip<const SkGlyphID, const SkPoint> source() const { return fSource; }
const SkFont& font() const { return fFont; }
SkSpan<const uint32_t> clusters() const { return fClusters; }
SkSpan<const char> text() const { return fText; }
SkSpan<const SkVector> scaledRotations() const { return fScaledRotations; }
private:
// GlyphIDs and positions.
const SkZip<const SkGlyphID, const SkPoint> fSource;
// 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;
// Possible RSXForm information
const SkSpan<const SkVector> fScaledRotations;
// Font for this run modified to have glyph encoding and left alignment.
SkFont fFont;
};
class GlyphRunList {
SkSpan<const GlyphRun> fGlyphRuns;
public:
// Blob maybe null.
GlyphRunList(const SkTextBlob* blob,
SkRect bounds,
SkPoint origin,
SkSpan<const GlyphRun> glyphRunList,
GlyphRunBuilder* builder);
GlyphRunList(const GlyphRun& glyphRun,
const SkRect& bounds,
SkPoint origin,
GlyphRunBuilder* builder);
uint64_t uniqueID() const;
bool anyRunsLCD() 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 GlyphRun& run : *this) {
glyphCount += run.runSize();
}
return glyphCount;
}
bool hasRSXForm() const {
for (const GlyphRun& run : *this) {
if (!run.scaledRotations().empty()) { return true; }
}
return false;
}
sk_sp<SkTextBlob> makeBlob() const;
SkPoint origin() const { return fOrigin; }
SkRect sourceBounds() const { return fSourceBounds; }
SkRect sourceBoundsWithOrigin() const { return fSourceBounds.makeOffset(fOrigin); }
const SkTextBlob* blob() const { return fOriginalTextBlob; }
GlyphRunBuilder* builder() const { return fBuilder; }
SkSubRunBuffers* buffers() const;
auto begin() -> decltype(fGlyphRuns.begin()) { return fGlyphRuns.begin(); }
auto end() -> decltype(fGlyphRuns.end()) { return fGlyphRuns.end(); }
auto begin() const -> decltype(std::cbegin(fGlyphRuns)) { return std::cbegin(fGlyphRuns); }
auto end() const -> decltype(std::cend(fGlyphRuns)) { return std::cend(fGlyphRuns); }
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]; }
private:
// The text blob is needed to hook up the call back that the SkTextBlob destructor calls. It
// should be used for nothing else.
const SkTextBlob* fOriginalTextBlob{nullptr};
const SkRect fSourceBounds{SkRect::MakeEmpty()};
const SkPoint fOrigin = {0, 0};
GlyphRunBuilder* const fBuilder;
};
class GlyphRunBuilder {
public:
GlyphRunList makeGlyphRunList(const GlyphRun& run, const SkPaint& paint, SkPoint origin);
const GlyphRunList& textToGlyphRunList(const SkFont& font,
const SkPaint& paint,
const void* bytes,
size_t byteLength,
SkPoint origin,
SkTextEncoding encoding = SkTextEncoding::kUTF8);
const GlyphRunList& blobToGlyphRunList(const SkTextBlob& blob, SkPoint origin);
std::tuple<SkSpan<const SkPoint>, SkSpan<const SkVector>>
convertRSXForm(SkSpan<const SkRSXform> xforms);
bool empty() const { return fGlyphRunListStorage.empty(); }
SkSubRunBuffers* buffers() { return &fSubRunBuffers; }
private:
void initialize(const SkTextBlob& blob);
void prepareBuffers(int positionCount, int RSXFormCount);
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,
SkSpan<const SkVector> scaledRotations);
const GlyphRunList& setGlyphRunList(
const SkTextBlob* blob, const SkRect& bounds, SkPoint origin);
int fMaxTotalRunSize{0};
skia_private::AutoTMalloc<SkPoint> fPositions;
int fMaxScaledRotations{0};
skia_private::AutoTMalloc<SkVector> fScaledRotations;
std::vector<GlyphRun> fGlyphRunListStorage;
std::optional<GlyphRunList> fGlyphRunList; // Defaults to no value;
// 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;
SkSubRunBuffers fSubRunBuffers;
};
inline SkSubRunBuffers* GlyphRunList::buffers() const { return fBuilder->buffers(); }
} // namespace sktext
#endif // SkGlyphRun_DEFINED