/* * 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 SkGlyphRunInfo_DEFINED #define SkGlyphRunInfo_DEFINED #include #include #include #include "SkArenaAlloc.h" #include "SkDescriptor.h" #include "SkMask.h" #include "SkPath.h" #include "SkPoint.h" #include "SkSurfaceProps.h" #include "SkTemplates.h" #include "SkTextBlobPriv.h" #include "SkTypes.h" #if SK_SUPPORT_GPU class GrColorSpaceInfo; class GrRenderTargetContext; #endif class SkBaseDevice; class SkGlyphRunList; class SkRasterClip; template class SkSpan { public: SkSpan() : fPtr{nullptr}, fSize{0} {} SkSpan(T* ptr, size_t size) : fPtr{ptr}, fSize{size} { } template explicit SkSpan(std::vector& v) : fPtr{v.data()}, fSize{v.size()} {} SkSpan(const SkSpan& o) = default; SkSpan& operator=( const SkSpan& other ) = default; T& operator [] (size_t i) const { return fPtr[i]; } T* begin() const { return fPtr; } T* end() const { return fPtr + fSize; } const T* cbegin() const { return fPtr; } const T* cend() const { return fPtr + fSize; } T* data() const { return fPtr; } size_t size() const { return fSize; } bool empty() const { return fSize == 0; } size_t size_bytes() const { return fSize * sizeof(T); } SkSpan toConst() const { return SkSpan{fPtr, fSize}; } private: T* fPtr; size_t fSize; }; class SkGlyphRun { public: SkGlyphRun() = default; SkGlyphRun(SkPaint&& runPaint, SkSpan denseIndices, SkSpan positions, SkSpan glyphIDs, SkSpan uniqueGlyphIDs, SkSpan text, SkSpan clusters); // A function that turns an SkGlyphRun into an SkGlyphRun for each glyph. using PerGlyph = std::function; void eachGlyphToGlyphRun(PerGlyph perGlyph); // The following made a ~5% speed improvement over not using a template. //using PerGlyphPos = std::function; template void forEachGlyphAndPosition(PerGlyphPos perGlyph) const; // The temporaryShunt calls are to allow inter-operating with existing code while glyph runs // are developed. void temporaryShuntToDrawPosText(SkBaseDevice* device, SkPoint origin); using TemporaryShuntCallback = std::function; void temporaryShuntToCallback(TemporaryShuntCallback callback); void filloutGlyphsAndPositions(SkGlyphID* glyphIDs, SkPoint* positions); size_t runSize() const { return fGlyphIDs.size(); } SkSpan positions() const { return fPositions.toConst(); } SkSpan shuntGlyphsIDs() const { return fGlyphIDs; } const SkPaint& paint() const { return fRunPaint; } SkPaint* mutablePaint() { return &fRunPaint; } SkSpan clusters() const { return fClusters; } SkSpan text() const { return fText; } private: // const SkSpan fUniqueGlyphIDIndices; // const SkSpan fPositions; // This is temporary while converting from the old per glyph code to the bulk code. const SkSpan fGlyphIDs; // The unique glyphs from fGlyphIDs. const SkSpan fUniqueGlyphIDs; // Original text from SkTextBlob if present. Will be empty of not present. const SkSpan fText; // Original clusters from SkTextBlob if present. Will be empty if not present. const SkSpan fClusters; // Paint for this run modified to have glyph encoding and left alignment. SkPaint fRunPaint; }; class SkGlyphRunListDrawer { public: // Constructor for SkBitmpapDevice. SkGlyphRunListDrawer( const SkSurfaceProps& props, SkColorType colorType, SkScalerContextFlags flags); #if SK_SUPPORT_GPU SkGlyphRunListDrawer(const SkSurfaceProps&, const GrColorSpaceInfo&); explicit SkGlyphRunListDrawer(const GrRenderTargetContext& renderTargetContext); #endif using PerMask = std::function; using PerMaskCreator = std::function; using PerPath = std::function; using PerPathCreator = std::function; void drawForBitmapDevice( const SkGlyphRunList& glyphRunList, const SkMatrix& deviceMatrix, PerMaskCreator perMaskCreator, PerPathCreator perPathCreator); void drawUsingMasks( SkGlyphCache* cache, const SkGlyphRun& glyphRun, SkPoint origin, const SkMatrix& deviceMatrix, PerMask perMask); private: static bool ShouldDrawAsPath(const SkPaint& paint, const SkMatrix& matrix); bool ensureBitmapBuffers(size_t runSize); void drawUsingPaths( const SkGlyphRun& glyphRun, SkPoint origin, const SkSurfaceProps& props, PerPath perPath) const; void drawGlyphRunAsSubpixelMask( SkGlyphCache* cache, const SkGlyphRun& glyphRun, SkPoint origin, const SkMatrix& deviceMatrix, PerMask perMask); void drawGlyphRunAsFullpixelMask( SkGlyphCache* cache, const SkGlyphRun& glyphRun, SkPoint origin, const SkMatrix& deviceMatrix, PerMask perMask); // The props as on the actual device. const SkSurfaceProps fDeviceProps; // The props for when the bitmap device can't draw LCD text. const SkSurfaceProps fBitmapFallbackProps; const SkColorType fColorType; const SkScalerContextFlags fScalerContextFlags; size_t fMaxRunSize{0}; SkAutoTMalloc fPositions; }; 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 fGlyphRuns; public: SkGlyphRunList(); // Blob maybe null. SkGlyphRunList( const SkPaint& paint, const SkTextBlob* blob, SkPoint origin, SkSpan glyphRunList); SkGlyphRunList(SkGlyphRun* glyphRun); 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 auto& run : fGlyphRuns) { glyphCount += run.runSize(); } return glyphCount; } 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]; } void temporaryShuntToDrawPosText(SkBaseDevice* device, SkPoint origin) const { for (auto& run : fGlyphRuns) { run.temporaryShuntToDrawPosText(device, origin); } } }; class SkGlyphRunListIterator { public: explicit SkGlyphRunListIterator(const SkGlyphRunList& list) : fList{list} {} bool done() const { return fIndex == fList.size(); } void next() { fIndex += 1;} uint32_t glyphCount() const { return fList[fIndex].runSize(); } const uint16_t* glyphs() const { return fList[fIndex].shuntGlyphsIDs().data(); } const SkScalar* pos() const { return (const SkScalar*)fList[fIndex].positions().data(); } const SkPoint& offset() const { return fZero; } void applyFontToPaint(SkPaint* paint) const { *paint = fList[fIndex].paint(); } SkTextBlobRunIterator::GlyphPositioning positioning() const { return SkTextBlobRunIterator::kFull_Positioning; } const uint32_t* clusters() const { return fList[fIndex].clusters().data(); } uint32_t textSize() const { return fList[fIndex].text().size(); } const char* text() const { return fList[fIndex].text().data(); } const SkGlyphRun& glyphRun() const { return fList[fIndex]; } bool isLCD() const { return fList[fIndex].paint().isLCDRenderText(); } private: static constexpr SkPoint fZero{0, 0}; size_t fIndex{0}; const SkGlyphRunList& fList; }; class SkGlyphIDSet { public: SkSpan uniquifyGlyphIDs( uint32_t universeSize, SkSpan glyphIDs, SkGlyphID* uniqueGlyphIDs, uint16_t* denseindices); private: size_t fUniverseToUniqueSize{0}; SkAutoTMalloc fUniverseToUnique; }; class SkGlyphRunBuilder { public: void drawTextAtOrigin(const SkPaint& paint, const void* bytes, size_t byteLength); void drawText( const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin); void drawPosTextH( const SkPaint& paint, const void* bytes, size_t byteLength, const SkScalar* xpos, SkScalar constY); void drawPosText( const SkPaint& paint, const void* bytes, size_t byteLength, const SkPoint* pos); void drawTextBlob(const SkPaint& paint, const SkTextBlob& blob, SkPoint origin); void drawGlyphPos( const SkPaint& paint, SkSpan glyphIDs, const SkPoint* pos); const SkGlyphRunList& useGlyphRunList(); private: void initialize(size_t totalRunSize); SkSpan textToGlyphIDs( const SkPaint& paint, const void* bytes, size_t byteLength); // Returns the span of unique glyph IDs. SkSpan addDenseAndUnique( const SkPaint& paint, SkSpan glyphIDs, uint16_t* uniqueGlyphIDIndices, SkGlyphID* uniqueGlyphIDs); void makeGlyphRun( const SkPaint& runPaint, SkSpan glyphIDs, SkSpan positions, SkSpan uniqueGlyphIDIndices, SkSpan uniqueGlyphIDs, SkSpan text, SkSpan clusters); void makeGlyphRunList(const SkPaint& paint, const SkTextBlob* blob, SkPoint origin); size_t simplifyDrawText( const SkPaint& paint, SkSpan glyphIDs, SkPoint origin, uint16_t* uniqueGlyphIDIndices, SkGlyphID* uniqueGlyphIDs, SkPoint* positions, SkSpan text = SkSpan{}, SkSpan clusters = SkSpan{}); size_t simplifyDrawPosTextH( const SkPaint& paint, SkSpan glyphIDs, const SkScalar* xpos, SkScalar constY, uint16_t* uniqueGlyphIDIndices, SkGlyphID* uniqueGlyphIDs, SkPoint* positions, SkSpan text = SkSpan{}, SkSpan clusters = SkSpan{}); size_t simplifyDrawPosText( const SkPaint& paint, SkSpan glyphIDs, const SkPoint* pos, uint16_t* uniqueGlyphIDIndices, SkGlyphID* uniqueGlyphIDs, SkSpan text = SkSpan{}, SkSpan clusters = SkSpan{}); size_t fMaxTotalRunSize{0}; SkAutoTMalloc fUniqueGlyphIDIndices; SkAutoTMalloc fPositions; SkAutoTMalloc fUniqueGlyphIDs; std::vector 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 fScratchGlyphIDs; // Used as temporary storage for calculating positions for drawText. std::vector fScratchAdvances; // Used for collecting the set of unique glyphs. SkGlyphIDSet fGlyphIDSet; }; template inline void SkGlyphRun::forEachGlyphAndPosition(PerGlyphPos perGlyph) const { const SkPoint* ptCursor = fPositions.data(); for (auto glyphID : fGlyphIDs) { perGlyph(glyphID, *ptCursor++); } } #endif // SkGlyphRunInfo_DEFINED