| // Copyright 2021 Google LLC. |
| #ifndef Processor_DEFINED |
| #define Processor_DEFINED |
| |
| #include <string> |
| #include "experimental/sktext/include/Types.h" |
| #include "experimental/sktext/src/Line.h" |
| #include "experimental/sktext/src/TextRun.h" |
| #include "include/core/SkCanvas.h" |
| #include "include/core/SkFontMgr.h" |
| #include "include/core/SkFontStyle.h" |
| #include "include/core/SkPaint.h" |
| #include "include/core/SkSize.h" |
| #include "include/core/SkString.h" |
| #include "include/core/SkTextBlob.h" |
| #include "modules/skshaper/src/SkUnicode.h" |
| |
| namespace skia { |
| namespace text { |
| |
| class Block { |
| public: |
| enum BlockType { |
| kFont, |
| kDecor, |
| kFormat, |
| }; |
| Block(BlockType type, TextRange range) |
| : fType(type) |
| , fRange(range) { } |
| BlockType fType; |
| TextRange fRange; |
| }; |
| |
| class FontBlock : public Block { |
| public: |
| FontBlock(const SkString& family, SkScalar size, SkFontStyle style, TextRange range) |
| : Block(Block::kFont, range) |
| , fFontFamily(family) |
| , fFontSize(size) |
| , fFontStyle(style) { } |
| SkString fFontFamily; |
| SkScalar fFontSize; |
| SkFontStyle fFontStyle; |
| |
| // TODO: Features |
| }; |
| |
| class DecorBlock : public Block { |
| public: |
| DecorBlock(const SkPaint* foreground, const SkPaint* background, TextRange range) |
| : Block(Block::kDecor, range) |
| , fForegroundColor(foreground) |
| , fBackgroundColor(background) { } |
| |
| DecorBlock(TextRange range) |
| : DecorBlock(nullptr, nullptr, range) { } |
| |
| const SkPaint* fForegroundColor; |
| const SkPaint* fBackgroundColor; |
| // Everything else |
| }; |
| |
| class TextFormatStyle { |
| public: |
| TextFormatStyle(TextAlign textAlign, TextDirection defaultTextDirection) |
| : fTextAlign(textAlign), fDefaultTextDirection(defaultTextDirection) { } |
| TextAlign fTextAlign; |
| TextDirection fDefaultTextDirection; |
| }; |
| |
| class TextFontStyle { |
| public: |
| TextFontStyle(TextDirection textDirection, sk_sp<SkFontMgr> fontManager) |
| : fTextDirection(textDirection), fFontManager(fontManager) { } |
| TextDirection fTextDirection; |
| sk_sp<SkFontMgr> fFontManager; |
| }; |
| |
| class TextOutput { |
| public: |
| TextOutput(sk_sp<SkTextBlob> textBlob, const SkPaint& paint, SkSize offset) : fTextBlob(std::move(textBlob)), fPaint(paint), fOffset(offset) { } |
| sk_sp<SkTextBlob> fTextBlob; |
| SkPaint fPaint; |
| SkSize fOffset; |
| }; |
| |
| class Processor { |
| |
| public: |
| |
| Processor(const SkString& text) |
| : fText(text) |
| , fUnicode(nullptr) {} |
| |
| ~Processor() = default; |
| |
| // All the Unicode information |
| SkUnicode* getUnicode() { return fUnicode == nullptr ? nullptr : fUnicode.get(); } |
| |
| // Once the text is measured you can get approximate sizing for it |
| bool shape(TextFontStyle fontStyle, SkTArray<FontBlock, true> fontBlocks); |
| |
| // Once the text is fit into the required box you can get the real sizes for it |
| bool wrap(SkScalar width, SkScalar height); |
| |
| // Once the text is formatted you can get it's glyphs info line by line |
| bool format(TextFormatStyle textFormatStyle); |
| |
| // Once the text is decorated you can iterate it by segments (intersect of run, decor block and line) |
| bool decorate(SkTArray<DecorBlock, true> decorBlocks); |
| |
| bool hasProperty(size_t index, CodeUnitFlags flag) { |
| return (fCodeUnitProperties[index] & flag) == flag; |
| } |
| |
| bool isHardLineBreak(size_t index) { |
| return this->hasProperty(index, CodeUnitFlags::kHardLineBreakBefore); |
| } |
| |
| bool isSoftLineBreak(size_t index) { |
| return index != 0 && this->hasProperty(index, CodeUnitFlags::kSoftLineBreakBefore); |
| } |
| |
| bool isWhitespaces(TextRange range) { |
| if (range.leftToRight()) { |
| for (auto i = range.fStart; i < range.fEnd; ++i) { |
| if (!this->hasProperty(i, CodeUnitFlags::kPartOfWhiteSpace)) { |
| return false; |
| } |
| } |
| } else { |
| for (auto i = range.fStart; i > range.fEnd; --i) { |
| if (!this->hasProperty(i, CodeUnitFlags::kPartOfWhiteSpace)) { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| bool isClusterEdge(size_t index) { |
| return this->hasProperty(index, CodeUnitFlags::kGraphemeStart) || |
| this->hasProperty(index, CodeUnitFlags::kGlyphStart); |
| } |
| |
| void adjustLeft(size_t* index) { |
| SkASSERT(index != nullptr); |
| while (*index != 0) { |
| if (isClusterEdge(*index)) { |
| return; |
| } |
| --index; |
| } |
| } |
| |
| TextRun& run(const size_t index) { return fRuns[index]; } |
| |
| // Simplification (using default font manager, default font family and default everything possible) |
| static bool drawText(const char* text, SkCanvas* canvas, SkScalar x, SkScalar y); |
| static bool drawText(const char* text, SkCanvas* canvas, SkScalar width); |
| static bool drawText(const char* text, SkCanvas* canvas, TextFormatStyle textFormat, SkColor foreground, SkColor background, const SkString& fontFamily, SkScalar fontSize, SkFontStyle fontStyle, SkScalar x, SkScalar y); |
| static bool drawText(const char* text, SkCanvas* canvas, |
| TextFormatStyle textFormat, SkColor foreground, SkColor background, const SkString& fontFamily, SkScalar fontSize, SkFontStyle fontStyle, |
| SkSize reqSize, SkScalar x, SkScalar y); |
| |
| void sortDecorBlocks(SkTArray<DecorBlock, true>& decorBlocks); |
| |
| bool computeCodeUnitProperties(); |
| |
| void markGlyphs(); |
| |
| // Iterating through the output glyphs and breaking the runs by units flag (no breaking if units == CodeUnitFlags::kNonExistingFlag) |
| template<typename Visitor> |
| void iterateByVisualOrder(CodeUnitFlags units, Visitor visitor); |
| template<typename Visitor> |
| void iterateByVisualOrder(SkTArray<DecorBlock, true>& decorBlocks, Visitor visitor); |
| |
| private: |
| friend class TextIterator; |
| friend class Shaper; |
| friend class Wrapper; |
| |
| SkString fText; |
| SkTArray<FontBlock, true> fFontBlocks; |
| //TextFormatStyle fTextFormatStyle; |
| //TextFontStyle fTextFontStyle; |
| SkTArray<TextRun, false> fRuns; |
| SkTArray<Line, false> fLines; |
| SkTArray<TextOutput, false> fTextOutputs; |
| |
| std::unique_ptr<SkUnicode> fUnicode; |
| SkTArray<CodeUnitFlags, true> fCodeUnitProperties; |
| }; |
| |
| } // namespace text |
| } // namespace skia |
| |
| #endif // Processor_DEFINED |