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