1 // Copyright 2019 Google LLC. 2 #ifndef ParagraphImpl_DEFINED 3 #define ParagraphImpl_DEFINED 4 5 #include "include/core/SkFont.h" 6 #include "include/core/SkPaint.h" 7 #include "include/core/SkPicture.h" 8 #include "include/core/SkPoint.h" 9 #include "include/core/SkRect.h" 10 #include "include/core/SkRefCnt.h" 11 #include "include/core/SkScalar.h" 12 #include "include/core/SkSpan.h" 13 #include "include/core/SkString.h" 14 #include "include/core/SkTypes.h" 15 #include "include/private/SkBitmaskEnum.h" 16 #include "include/private/SkTArray.h" 17 #include "include/private/SkTHash.h" 18 #include "include/private/SkTemplates.h" 19 #include "modules/skparagraph/include/DartTypes.h" 20 #include "modules/skparagraph/include/FontCollection.h" 21 #include "modules/skparagraph/include/Paragraph.h" 22 #include "modules/skparagraph/include/ParagraphCache.h" 23 #include "modules/skparagraph/include/ParagraphStyle.h" 24 #include "modules/skparagraph/include/TextShadow.h" 25 #include "modules/skparagraph/include/TextStyle.h" 26 #include "modules/skparagraph/src/Run.h" 27 #include "modules/skparagraph/src/TextLine.h" 28 #include "modules/skunicode/include/SkUnicode.h" 29 30 #include <memory> 31 #include <string> 32 #include <vector> 33 34 class SkCanvas; 35 36 namespace skia { 37 namespace textlayout { 38 39 enum CodeUnitFlags { 40 kNoCodeUnitFlag = 0x00, 41 kPartOfWhiteSpaceBreak = 0x01, 42 kGraphemeStart = 0x02, 43 kSoftLineBreakBefore = 0x04, 44 kHardLineBreakBefore = 0x08, 45 kPartOfIntraWordBreak = 0x10, 46 }; 47 } // namespace textlayout 48 } // namespace skia 49 50 namespace sknonstd { 51 template <> struct is_bitmask_enum<skia::textlayout::CodeUnitFlags> : std::true_type {}; 52 } // namespace sknonstd 53 54 namespace skia { 55 namespace textlayout { 56 57 class LineMetrics; 58 class TextLine; 59 60 template <typename T> bool operator==(const SkSpan<T>& a, const SkSpan<T>& b) { 61 return a.size() == b.size() && a.begin() == b.begin(); 62 } 63 64 template <typename T> bool operator<=(const SkSpan<T>& a, const SkSpan<T>& b) { 65 return a.begin() >= b.begin() && a.end() <= b.end(); 66 } 67 68 template <typename TStyle> 69 struct StyleBlock { 70 StyleBlock() : fRange(EMPTY_RANGE), fStyle() { } 71 StyleBlock(size_t start, size_t end, const TStyle& style) : fRange(start, end), fStyle(style) {} 72 StyleBlock(TextRange textRange, const TStyle& style) : fRange(textRange), fStyle(style) {} 73 void add(TextRange tail) { 74 SkASSERT(fRange.end == tail.start); 75 fRange = TextRange(fRange.start, fRange.start + fRange.width() + tail.width()); 76 } 77 TextRange fRange; 78 TStyle fStyle; 79 }; 80 81 struct ResolvedFontDescriptor { 82 83 ResolvedFontDescriptor(TextIndex index, SkFont font) 84 : fFont(font), fTextStart(index) { } 85 SkFont fFont; 86 TextIndex fTextStart; 87 }; 88 /* 89 struct BidiRegion { 90 BidiRegion(size_t start, size_t end, uint8_t dir) 91 : text(start, end), direction(dir) { } 92 TextRange text; 93 uint8_t direction; 94 }; 95 */ 96 class ParagraphImpl final : public Paragraph { 97 98 public: 99 100 ParagraphImpl(const SkString& text, 101 ParagraphStyle style, 102 SkTArray<Block, true> blocks, 103 SkTArray<Placeholder, true> placeholders, 104 sk_sp<FontCollection> fonts, 105 std::unique_ptr<SkUnicode> unicode); 106 107 ParagraphImpl(const std::u16string& utf16text, 108 ParagraphStyle style, 109 SkTArray<Block, true> blocks, 110 SkTArray<Placeholder, true> placeholders, 111 sk_sp<FontCollection> fonts, 112 std::unique_ptr<SkUnicode> unicode); 113 ~ParagraphImpl() override; 114 115 void layout(SkScalar width) override; 116 void paint(SkCanvas* canvas, SkScalar x, SkScalar y) override; 117 std::vector<TextBox> getRectsForRange(unsigned start, 118 unsigned end, 119 RectHeightStyle rectHeightStyle, 120 RectWidthStyle rectWidthStyle) override; 121 std::vector<TextBox> getRectsForPlaceholders() override; 122 void getLineMetrics(std::vector<LineMetrics>&) override; 123 PositionWithAffinity getGlyphPositionAtCoordinate(SkScalar dx, SkScalar dy) override; 124 SkRange<size_t> getWordBoundary(unsigned offset) override; 125 126 size_t lineNumber() override { return fLines.size(); } 127 128 TextLine& addLine(SkVector offset, SkVector advance, 129 TextRange textExcludingSpaces, TextRange text, TextRange textIncludingNewlines, 130 ClusterRange clusters, ClusterRange clustersWithGhosts, SkScalar widthWithSpaces, 131 InternalLineMetrics sizes); 132 133 SkSpan<const char> text() const { return SkSpan<const char>(fText.c_str(), fText.size()); } 134 InternalState state() const { return fState; } 135 SkSpan<Run> runs() { return SkSpan<Run>(fRuns.data(), fRuns.size()); } 136 SkSpan<Block> styles() { 137 return SkSpan<Block>(fTextStyles.data(), fTextStyles.size()); 138 } 139 SkSpan<Placeholder> placeholders() { 140 return SkSpan<Placeholder>(fPlaceholders.data(), fPlaceholders.size()); 141 } 142 SkSpan<TextLine> lines() { return SkSpan<TextLine>(fLines.data(), fLines.size()); } 143 const ParagraphStyle& paragraphStyle() const { return fParagraphStyle; } 144 SkSpan<Cluster> clusters() { return SkSpan<Cluster>(fClusters.begin(), fClusters.size()); } 145 sk_sp<FontCollection> fontCollection() const { return fFontCollection; } 146 void formatLines(SkScalar maxWidth); 147 void ensureUTF16Mapping(); 148 TextIndex findNextGraphemeBoundary(TextIndex utf8); 149 TextIndex findPreviousGraphemeBoundary(TextIndex utf8); 150 size_t getUTF16Index(TextIndex index) { 151 return fUTF16IndexForUTF8Index[index]; 152 } 153 154 bool strutEnabled() const { return paragraphStyle().getStrutStyle().getStrutEnabled(); } 155 bool strutForceHeight() const { 156 return paragraphStyle().getStrutStyle().getForceStrutHeight(); 157 } 158 bool strutHeightOverride() const { 159 return paragraphStyle().getStrutStyle().getHeightOverride(); 160 } 161 InternalLineMetrics strutMetrics() const { return fStrutMetrics; } 162 163 SkString getEllipsis() const; 164 165 SkSpan<const char> text(TextRange textRange); 166 SkSpan<Cluster> clusters(ClusterRange clusterRange); 167 Cluster& cluster(ClusterIndex clusterIndex); 168 ClusterIndex clusterIndex(TextIndex textIndex) { 169 auto clusterIndex = this->fClustersIndexFromCodeUnit[textIndex]; 170 SkASSERT(clusterIndex != EMPTY_INDEX); 171 return clusterIndex; 172 } 173 Run& run(RunIndex runIndex) { 174 SkASSERT(runIndex < fRuns.size()); 175 return fRuns[runIndex]; 176 } 177 178 Run& runByCluster(ClusterIndex clusterIndex); 179 SkSpan<Block> blocks(BlockRange blockRange); 180 Block& block(BlockIndex blockIndex); 181 SkTArray<ResolvedFontDescriptor> resolvedFonts() const { return fFontSwitches; } 182 183 void markDirty() override { fState = kUnknown; } 184 185 int32_t unresolvedGlyphs() override; 186 187 void setState(InternalState state); 188 sk_sp<SkPicture> getPicture() { return fPicture; } 189 190 SkScalar widthWithTrailingSpaces() { return fMaxWidthWithTrailingSpaces; } 191 192 void resetContext(); 193 void resolveStrut(); 194 195 bool computeCodeUnitProperties(); 196 197 void buildClusterTable(); 198 void spaceGlyphs(); 199 bool shapeTextIntoEndlessLine(); 200 void breakShapedTextIntoLines(SkScalar maxWidth); 201 void paintLinesIntoPicture(SkScalar x, SkScalar y); 202 void paintLines(SkCanvas* canvas, SkScalar x, SkScalar y); 203 204 void updateTextAlign(TextAlign textAlign) override; 205 void updateText(size_t from, SkString text) override; 206 void updateFontSize(size_t from, size_t to, SkScalar fontSize) override; 207 void updateForegroundPaint(size_t from, size_t to, SkPaint paint) override; 208 void updateBackgroundPaint(size_t from, size_t to, SkPaint paint) override; 209 210 void visit(const Visitor&) override; 211 212 InternalLineMetrics getEmptyMetrics() const { return fEmptyMetrics; } 213 InternalLineMetrics getStrutMetrics() const { return fStrutMetrics; } 214 215 BlockRange findAllBlocks(TextRange textRange); 216 217 void resetShifts() { 218 for (auto& run : fRuns) { 219 run.resetJustificationShifts(); 220 run.resetShifts(); 221 } 222 } 223 224 bool codeUnitHasProperty(size_t index, CodeUnitFlags property) const { return (fCodeUnitProperties[index] & property) == property; } 225 226 SkUnicode* getUnicode() { return fUnicode.get(); } 227 228 private: 229 friend class ParagraphBuilder; 230 friend class ParagraphCacheKey; 231 friend class ParagraphCacheValue; 232 friend class ParagraphCache; 233 234 friend class TextWrapper; 235 friend class OneLineShaper; 236 237 void computeEmptyMetrics(); 238 239 // Input 240 SkTArray<StyleBlock<SkScalar>> fLetterSpaceStyles; 241 SkTArray<StyleBlock<SkScalar>> fWordSpaceStyles; 242 SkTArray<StyleBlock<SkPaint>> fBackgroundStyles; 243 SkTArray<StyleBlock<SkPaint>> fForegroundStyles; 244 SkTArray<StyleBlock<std::vector<TextShadow>>> fShadowStyles; 245 SkTArray<StyleBlock<Decoration>> fDecorationStyles; 246 SkTArray<Block, true> fTextStyles; // TODO: take out only the font stuff 247 SkTArray<Placeholder, true> fPlaceholders; 248 SkString fText; 249 250 // Internal structures 251 InternalState fState; 252 SkTArray<Run, false> fRuns; // kShaped 253 SkTArray<Cluster, true> fClusters; // kClusterized (cached: text, word spacing, letter spacing, resolved fonts) 254 SkTArray<CodeUnitFlags> fCodeUnitProperties; 255 SkTArray<size_t> fClustersIndexFromCodeUnit; 256 std::vector<size_t> fWords; 257 std::vector<SkUnicode::BidiRegion> fBidiRegions; 258 // These two arrays are used in measuring methods (getRectsForRange, getGlyphPositionAtCoordinate) 259 // They are filled lazily whenever they need and cached 260 SkTArray<TextIndex, true> fUTF8IndexForUTF16Index; 261 SkTArray<size_t, true> fUTF16IndexForUTF8Index; 262 size_t fUnresolvedGlyphs; 263 264 SkTArray<TextLine, false> fLines; // kFormatted (cached: width, max lines, ellipsis, text align) 265 sk_sp<SkPicture> fPicture; // kRecorded (cached: text styles) 266 267 SkTArray<ResolvedFontDescriptor> fFontSwitches; 268 269 InternalLineMetrics fEmptyMetrics; 270 InternalLineMetrics fStrutMetrics; 271 272 SkScalar fOldWidth; 273 SkScalar fOldHeight; 274 SkScalar fMaxWidthWithTrailingSpaces; 275 276 std::unique_ptr<SkUnicode> fUnicode; 277 }; 278 } // namespace textlayout 279 } // namespace skia 280 281 282 #endif // ParagraphImpl_DEFINED 283