• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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