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/skshaper/src/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, TextRange text, TextRange textWithSpaces, 129 ClusterRange clusters, ClusterRange clustersWithGhosts, SkScalar widthWithSpaces, 130 InternalLineMetrics sizes); 131 132 SkSpan<const char> text() const { return SkSpan<const char>(fText.c_str(), fText.size()); } 133 InternalState state() const { return fState; } 134 SkSpan<Run> runs() { return SkSpan<Run>(fRuns.data(), fRuns.size()); } 135 SkSpan<Block> styles() { 136 return SkSpan<Block>(fTextStyles.data(), fTextStyles.size()); 137 } 138 SkSpan<Placeholder> placeholders() { 139 return SkSpan<Placeholder>(fPlaceholders.data(), fPlaceholders.size()); 140 } 141 SkSpan<TextLine> lines() { return SkSpan<TextLine>(fLines.data(), fLines.size()); } 142 const ParagraphStyle& paragraphStyle() const { return fParagraphStyle; } 143 SkSpan<Cluster> clusters() { return SkSpan<Cluster>(fClusters.begin(), fClusters.size()); } 144 sk_sp<FontCollection> fontCollection() const { return fFontCollection; } 145 void formatLines(SkScalar maxWidth); 146 void ensureUTF16Mapping(); 147 TextIndex findNextGraphemeBoundary(TextIndex utf8); 148 TextIndex findPreviousGraphemeBoundary(TextIndex utf8); 149 size_t getUTF16Index(TextIndex index) { 150 return fUTF16IndexForUTF8Index[index]; 151 } 152 153 bool strutEnabled() const { return paragraphStyle().getStrutStyle().getStrutEnabled(); } 154 bool strutForceHeight() const { 155 return paragraphStyle().getStrutStyle().getForceStrutHeight(); 156 } 157 bool strutHeightOverride() const { 158 return paragraphStyle().getStrutStyle().getHeightOverride(); 159 } 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); 167 ClusterIndex clusterIndex(TextIndex textIndex) { 168 auto clusterIndex = this->fClustersIndexFromCodeUnit[textIndex]; 169 SkASSERT(clusterIndex != EMPTY_INDEX); 170 return clusterIndex; 171 } 172 Run& run(RunIndex runIndex) { 173 SkASSERT(runIndex < fRuns.size()); 174 return fRuns[runIndex]; 175 } 176 177 Run& runByCluster(ClusterIndex clusterIndex); 178 SkSpan<Block> blocks(BlockRange blockRange); 179 Block& block(BlockIndex blockIndex); 180 SkTArray<ResolvedFontDescriptor> resolvedFonts() const { return fFontSwitches; } 181 182 void markDirty() override { fState = kUnknown; } 183 184 int32_t unresolvedGlyphs() override; 185 186 void setState(InternalState state); 187 sk_sp<SkPicture> getPicture() { return fPicture; } 188 189 SkScalar widthWithTrailingSpaces() { return fMaxWidthWithTrailingSpaces; } 190 191 void resetContext(); 192 void resolveStrut(); 193 194 bool computeCodeUnitProperties(); 195 196 void buildClusterTable(); 197 void spaceGlyphs(); 198 bool shapeTextIntoEndlessLine(); 199 void breakShapedTextIntoLines(SkScalar maxWidth); 200 void paintLinesIntoPicture(SkScalar x, SkScalar y); 201 void paintLines(SkCanvas* canvas, SkScalar x, SkScalar y); 202 203 void updateTextAlign(TextAlign textAlign) override; 204 void updateText(size_t from, SkString text) override; 205 void updateFontSize(size_t from, size_t to, SkScalar fontSize) override; 206 void updateForegroundPaint(size_t from, size_t to, SkPaint paint) override; 207 void updateBackgroundPaint(size_t from, size_t to, SkPaint paint) override; 208 209 void visit(const Visitor&) override; 210 211 InternalLineMetrics getEmptyMetrics() const { return fEmptyMetrics; } 212 InternalLineMetrics getStrutMetrics() const { return fStrutMetrics; } 213 214 BlockRange findAllBlocks(TextRange textRange); 215 216 void resetShifts() { 217 for (auto& run : fRuns) { 218 run.resetJustificationShifts(); 219 run.resetShifts(); 220 } 221 } 222 223 bool codeUnitHasProperty(size_t index, CodeUnitFlags property) const { return (fCodeUnitProperties[index] & property) == property; } 224 225 SkUnicode* getUnicode() { return fUnicode.get(); } 226 227 private: 228 friend class ParagraphBuilder; 229 friend class ParagraphCacheKey; 230 friend class ParagraphCacheValue; 231 friend class ParagraphCache; 232 233 friend class TextWrapper; 234 friend class OneLineShaper; 235 236 void computeEmptyMetrics(); 237 238 // Input 239 SkTArray<StyleBlock<SkScalar>> fLetterSpaceStyles; 240 SkTArray<StyleBlock<SkScalar>> fWordSpaceStyles; 241 SkTArray<StyleBlock<SkPaint>> fBackgroundStyles; 242 SkTArray<StyleBlock<SkPaint>> fForegroundStyles; 243 SkTArray<StyleBlock<std::vector<TextShadow>>> fShadowStyles; 244 SkTArray<StyleBlock<Decoration>> fDecorationStyles; 245 SkTArray<Block, true> fTextStyles; // TODO: take out only the font stuff 246 SkTArray<Placeholder, true> fPlaceholders; 247 SkString fText; 248 249 // Internal structures 250 InternalState fState; 251 SkTArray<Run, false> fRuns; // kShaped 252 SkTArray<Cluster, true> fClusters; // kClusterized (cached: text, word spacing, letter spacing, resolved fonts) 253 SkTArray<CodeUnitFlags> fCodeUnitProperties; 254 SkTArray<size_t> fClustersIndexFromCodeUnit; 255 std::vector<size_t> fWords; 256 std::vector<SkUnicode::BidiRegion> fBidiRegions; 257 // These two arrays are used in measuring methods (getRectsForRange, getGlyphPositionAtCoordinate) 258 // They are filled lazily whenever they need and cached 259 SkTArray<TextIndex, true> fUTF8IndexForUTF16Index; 260 SkTArray<size_t, true> fUTF16IndexForUTF8Index; 261 size_t fUnresolvedGlyphs; 262 263 SkTArray<TextLine, false> fLines; // kFormatted (cached: width, max lines, ellipsis, text align) 264 sk_sp<SkPicture> fPicture; // kRecorded (cached: text styles) 265 266 SkTArray<ResolvedFontDescriptor> fFontSwitches; 267 268 InternalLineMetrics fEmptyMetrics; 269 InternalLineMetrics fStrutMetrics; 270 271 SkScalar fOldWidth; 272 SkScalar fOldHeight; 273 SkScalar fMaxWidthWithTrailingSpaces; 274 275 std::unique_ptr<SkUnicode> fUnicode; 276 }; 277 } // namespace textlayout 278 } // namespace skia 279 280 281 #endif // ParagraphImpl_DEFINED 282