1 // Copyright 2021 Google LLC. 2 #ifndef Processor_DEFINED 3 #define Processor_DEFINED 4 5 #include <string> 6 #include "experimental/sktext/include/Types.h" 7 #include "experimental/sktext/src/Line.h" 8 #include "experimental/sktext/src/TextRun.h" 9 #include "include/core/SkCanvas.h" 10 #include "include/core/SkFontMgr.h" 11 #include "include/core/SkFontStyle.h" 12 #include "include/core/SkPaint.h" 13 #include "include/core/SkSize.h" 14 #include "include/core/SkString.h" 15 #include "include/core/SkTextBlob.h" 16 #include "modules/skshaper/src/SkUnicode.h" 17 18 namespace skia { 19 namespace text { 20 21 class Block { 22 public: 23 enum BlockType { 24 kFont, 25 kDecor, 26 kFormat, 27 }; Block(BlockType type,TextRange range)28 Block(BlockType type, TextRange range) 29 : fType(type) 30 , fRange(range) { } 31 BlockType fType; 32 TextRange fRange; 33 }; 34 35 class FontBlock : public Block { 36 public: FontBlock(const SkString & family,SkScalar size,SkFontStyle style,TextRange range)37 FontBlock(const SkString& family, SkScalar size, SkFontStyle style, TextRange range) 38 : Block(Block::kFont, range) 39 , fFontFamily(family) 40 , fFontSize(size) 41 , fFontStyle(style) { } 42 SkString fFontFamily; 43 SkScalar fFontSize; 44 SkFontStyle fFontStyle; 45 46 // TODO: Features 47 }; 48 49 class DecorBlock : public Block { 50 public: DecorBlock(const SkPaint * foreground,const SkPaint * background,TextRange range)51 DecorBlock(const SkPaint* foreground, const SkPaint* background, TextRange range) 52 : Block(Block::kDecor, range) 53 , fForegroundColor(foreground) 54 , fBackgroundColor(background) { } 55 DecorBlock(TextRange range)56 DecorBlock(TextRange range) 57 : DecorBlock(nullptr, nullptr, range) { } 58 59 const SkPaint* fForegroundColor; 60 const SkPaint* fBackgroundColor; 61 // Everything else 62 }; 63 64 class TextFormatStyle { 65 public: TextFormatStyle(TextAlign textAlign,TextDirection defaultTextDirection)66 TextFormatStyle(TextAlign textAlign, TextDirection defaultTextDirection) 67 : fTextAlign(textAlign), fDefaultTextDirection(defaultTextDirection) { } 68 TextAlign fTextAlign; 69 TextDirection fDefaultTextDirection; 70 }; 71 72 class TextFontStyle { 73 public: TextFontStyle(TextDirection textDirection,sk_sp<SkFontMgr> fontManager)74 TextFontStyle(TextDirection textDirection, sk_sp<SkFontMgr> fontManager) 75 : fTextDirection(textDirection), fFontManager(fontManager) { } 76 TextDirection fTextDirection; 77 sk_sp<SkFontMgr> fFontManager; 78 }; 79 80 class TextOutput { 81 public: TextOutput(sk_sp<SkTextBlob> textBlob,const SkPaint & paint,SkSize offset)82 TextOutput(sk_sp<SkTextBlob> textBlob, const SkPaint& paint, SkSize offset) : fTextBlob(std::move(textBlob)), fPaint(paint), fOffset(offset) { } 83 sk_sp<SkTextBlob> fTextBlob; 84 SkPaint fPaint; 85 SkSize fOffset; 86 }; 87 88 class Processor { 89 90 public: 91 Processor(const SkString & text)92 Processor(const SkString& text) 93 : fText(text) 94 , fUnicode(nullptr) {} 95 96 ~Processor() = default; 97 98 // All the Unicode information getUnicode()99 SkUnicode* getUnicode() { return fUnicode == nullptr ? nullptr : fUnicode.get(); } 100 101 // Once the text is measured you can get approximate sizing for it 102 bool shape(TextFontStyle fontStyle, SkTArray<FontBlock, true> fontBlocks); 103 104 // Once the text is fit into the required box you can get the real sizes for it 105 bool wrap(SkScalar width, SkScalar height); 106 107 // Once the text is formatted you can get it's glyphs info line by line 108 bool format(TextFormatStyle textFormatStyle); 109 110 // Once the text is decorated you can iterate it by segments (intersect of run, decor block and line) 111 bool decorate(SkTArray<DecorBlock, true> decorBlocks); 112 hasProperty(size_t index,CodeUnitFlags flag)113 bool hasProperty(size_t index, CodeUnitFlags flag) { 114 return (fCodeUnitProperties[index] & flag) == flag; 115 } 116 isHardLineBreak(size_t index)117 bool isHardLineBreak(size_t index) { 118 return this->hasProperty(index, CodeUnitFlags::kHardLineBreakBefore); 119 } 120 isSoftLineBreak(size_t index)121 bool isSoftLineBreak(size_t index) { 122 return index != 0 && this->hasProperty(index, CodeUnitFlags::kSoftLineBreakBefore); 123 } 124 isWhitespaces(TextRange range)125 bool isWhitespaces(TextRange range) { 126 if (range.leftToRight()) { 127 for (auto i = range.fStart; i < range.fEnd; ++i) { 128 if (!this->hasProperty(i, CodeUnitFlags::kPartOfWhiteSpace)) { 129 return false; 130 } 131 } 132 } else { 133 for (auto i = range.fStart; i > range.fEnd; --i) { 134 if (!this->hasProperty(i, CodeUnitFlags::kPartOfWhiteSpace)) { 135 return false; 136 } 137 } 138 } 139 return true; 140 } 141 isClusterEdge(size_t index)142 bool isClusterEdge(size_t index) { 143 return this->hasProperty(index, CodeUnitFlags::kGraphemeStart) || 144 this->hasProperty(index, CodeUnitFlags::kGlyphStart); 145 } 146 adjustLeft(size_t * index)147 void adjustLeft(size_t* index) { 148 SkASSERT(index != nullptr); 149 while (*index != 0) { 150 if (isClusterEdge(*index)) { 151 return; 152 } 153 --index; 154 } 155 } 156 run(const size_t index)157 TextRun& run(const size_t index) { return fRuns[index]; } 158 159 // Simplification (using default font manager, default font family and default everything possible) 160 static bool drawText(const char* text, SkCanvas* canvas, SkScalar x, SkScalar y); 161 static bool drawText(const char* text, SkCanvas* canvas, SkScalar width); 162 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); 163 static bool drawText(const char* text, SkCanvas* canvas, 164 TextFormatStyle textFormat, SkColor foreground, SkColor background, const SkString& fontFamily, SkScalar fontSize, SkFontStyle fontStyle, 165 SkSize reqSize, SkScalar x, SkScalar y); 166 167 void sortDecorBlocks(SkTArray<DecorBlock, true>& decorBlocks); 168 169 bool computeCodeUnitProperties(); 170 171 void markGlyphs(); 172 173 // Iterating through the output glyphs and breaking the runs by units flag (no breaking if units == CodeUnitFlags::kNonExistingFlag) 174 template<typename Visitor> 175 void iterateByVisualOrder(CodeUnitFlags units, Visitor visitor); 176 template<typename Visitor> 177 void iterateByVisualOrder(SkTArray<DecorBlock, true>& decorBlocks, Visitor visitor); 178 179 private: 180 friend class TextIterator; 181 friend class Shaper; 182 friend class Wrapper; 183 184 SkString fText; 185 SkTArray<FontBlock, true> fFontBlocks; 186 //TextFormatStyle fTextFormatStyle; 187 //TextFontStyle fTextFontStyle; 188 SkTArray<TextRun, false> fRuns; 189 SkTArray<Line, false> fLines; 190 SkTArray<TextOutput, false> fTextOutputs; 191 192 std::unique_ptr<SkUnicode> fUnicode; 193 SkTArray<CodeUnitFlags, true> fCodeUnitProperties; 194 }; 195 196 } // namespace text 197 } // namespace skia 198 199 #endif // Processor_DEFINED 200