| 1 | /* |
| 2 | * Copyright 2016 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
| 8 | #ifndef SkShaper_DEFINED |
| 9 | #define SkShaper_DEFINED |
| 10 | |
| 11 | #include "include/core/SkFontMgr.h" |
| 12 | #include "include/core/SkPoint.h" |
| 13 | #include "include/core/SkRefCnt.h" |
| 14 | #include "include/core/SkScalar.h" |
| 15 | #include "include/core/SkTextBlob.h" |
| 16 | #include "include/core/SkTypes.h" |
| 17 | |
| 18 | #include <memory> |
| 19 | |
| 20 | #if !defined(SKSHAPER_IMPLEMENTATION) |
| 21 | #define SKSHAPER_IMPLEMENTATION 0 |
| 22 | #endif |
| 23 | |
| 24 | #if !defined(SKSHAPER_API) |
| 25 | #if defined(SKSHAPER_DLL) |
| 26 | #if defined(_MSC_VER) |
| 27 | #if SKSHAPER_IMPLEMENTATION |
| 28 | #define SKSHAPER_API __declspec(dllexport) |
| 29 | #else |
| 30 | #define SKSHAPER_API __declspec(dllimport) |
| 31 | #endif |
| 32 | #else |
| 33 | #define SKSHAPER_API __attribute__((visibility("default"))) |
| 34 | #endif |
| 35 | #else |
| 36 | #define SKSHAPER_API |
| 37 | #endif |
| 38 | #endif |
| 39 | |
| 40 | class SkFont; |
| 41 | class SkFontMgr; |
| 42 | |
| 43 | /** |
| 44 | Shapes text using HarfBuzz and places the shaped text into a |
| 45 | client-managed buffer. |
| 46 | |
| 47 | If compiled without HarfBuzz, fall back on SkPaint::textToGlyphs. |
| 48 | */ |
| 49 | class SKSHAPER_API SkShaper { |
| 50 | public: |
| 51 | static std::unique_ptr<SkShaper> MakePrimitive(); |
| 52 | #ifdef SK_SHAPER_HARFBUZZ_AVAILABLE |
| 53 | static std::unique_ptr<SkShaper> MakeShaperDrivenWrapper(sk_sp<SkFontMgr> = nullptr); |
| 54 | static std::unique_ptr<SkShaper> MakeShapeThenWrap(sk_sp<SkFontMgr> = nullptr); |
| 55 | static std::unique_ptr<SkShaper> MakeShapeDontWrapOrReorder(sk_sp<SkFontMgr> = nullptr); |
| 56 | #endif |
| 57 | #ifdef SK_SHAPER_CORETEXT_AVAILABLE |
| 58 | static std::unique_ptr<SkShaper> MakeCoreText(); |
| 59 | #endif |
| 60 | |
| 61 | static std::unique_ptr<SkShaper> Make(sk_sp<SkFontMgr> = nullptr); |
| 62 | |
| 63 | SkShaper(); |
| 64 | virtual ~SkShaper(); |
| 65 | |
| 66 | class RunIterator { |
| 67 | public: |
| 68 | virtual ~RunIterator() = default; |
| 69 | /** Set state to that of current run and move iterator to end of that run. */ |
| 70 | virtual void consume() = 0; |
| 71 | /** Offset to one past the last (utf8) element in the current run. */ |
| 72 | virtual size_t endOfCurrentRun() const = 0; |
| 73 | /** Return true if consume should no longer be called. */ |
| 74 | virtual bool atEnd() const = 0; |
| 75 | }; |
| 76 | class FontRunIterator : public RunIterator { |
| 77 | public: |
| 78 | virtual const SkFont& currentFont() const = 0; |
| 79 | }; |
| 80 | class BiDiRunIterator : public RunIterator { |
| 81 | public: |
| 82 | /** The unicode bidi embedding level (even ltr, odd rtl) */ |
| 83 | virtual uint8_t currentLevel() const = 0; |
| 84 | }; |
| 85 | class ScriptRunIterator : public RunIterator { |
| 86 | public: |
| 87 | /** Should be iso15924 codes. */ |
| 88 | virtual SkFourByteTag currentScript() const = 0; |
| 89 | }; |
| 90 | class LanguageRunIterator : public RunIterator { |
| 91 | public: |
| 92 | /** Should be BCP-47, c locale names may also work. */ |
| 93 | virtual const char* currentLanguage() const = 0; |
| 94 | }; |
| 95 | struct Feature { |
| 96 | SkFourByteTag tag; |
| 97 | uint32_t value; |
| 98 | size_t start; // Offset to the start (utf8) element of the run. |
| 99 | size_t end; // Offset to one past the last (utf8) element of the run. |
| 100 | }; |
| 101 | |
| 102 | private: |
| 103 | template <typename RunIteratorSubclass> |
| 104 | class TrivialRunIterator : public RunIteratorSubclass { |
| 105 | public: |
| 106 | static_assert(std::is_base_of<RunIterator, RunIteratorSubclass>::value, "" ); |
| 107 | TrivialRunIterator(size_t utf8Bytes) : fEnd(utf8Bytes), fAtEnd(fEnd == 0) {} |
| 108 | void consume() override { SkASSERT(!fAtEnd); fAtEnd = true; } |
| 109 | size_t endOfCurrentRun() const override { return fAtEnd ? fEnd : 0; } |
| 110 | bool atEnd() const override { return fAtEnd; } |
| 111 | private: |
| 112 | size_t fEnd; |
| 113 | bool fAtEnd; |
| 114 | }; |
| 115 | |
| 116 | public: |
| 117 | static std::unique_ptr<FontRunIterator> |
| 118 | MakeFontMgrRunIterator(const char* utf8, size_t utf8Bytes, |
| 119 | const SkFont& font, sk_sp<SkFontMgr> fallback); |
| 120 | static std::unique_ptr<SkShaper::FontRunIterator> |
| 121 | MakeFontMgrRunIterator(const char* utf8, size_t utf8Bytes, |
| 122 | const SkFont& font, sk_sp<SkFontMgr> fallback, |
| 123 | const char* requestName, SkFontStyle requestStyle, |
| 124 | const SkShaper::LanguageRunIterator*); |
| 125 | class TrivialFontRunIterator : public TrivialRunIterator<FontRunIterator> { |
| 126 | public: |
| 127 | TrivialFontRunIterator(const SkFont& font, size_t utf8Bytes) |
| 128 | : TrivialRunIterator(utf8Bytes), fFont(font) {} |
| 129 | const SkFont& currentFont() const override { return fFont; } |
| 130 | private: |
| 131 | SkFont fFont; |
| 132 | }; |
| 133 | |
| 134 | static std::unique_ptr<BiDiRunIterator> |
| 135 | MakeBiDiRunIterator(const char* utf8, size_t utf8Bytes, uint8_t bidiLevel); |
| 136 | #ifdef SK_SHAPER_HARFBUZZ_AVAILABLE |
| 137 | static std::unique_ptr<BiDiRunIterator> |
| 138 | MakeIcuBiDiRunIterator(const char* utf8, size_t utf8Bytes, uint8_t bidiLevel); |
| 139 | #endif |
| 140 | class TrivialBiDiRunIterator : public TrivialRunIterator<BiDiRunIterator> { |
| 141 | public: |
| 142 | TrivialBiDiRunIterator(uint8_t bidiLevel, size_t utf8Bytes) |
| 143 | : TrivialRunIterator(utf8Bytes), fBidiLevel(bidiLevel) {} |
| 144 | uint8_t currentLevel() const override { return fBidiLevel; } |
| 145 | private: |
| 146 | uint8_t fBidiLevel; |
| 147 | }; |
| 148 | |
| 149 | static std::unique_ptr<ScriptRunIterator> |
| 150 | MakeScriptRunIterator(const char* utf8, size_t utf8Bytes, SkFourByteTag script); |
| 151 | #ifdef SK_SHAPER_HARFBUZZ_AVAILABLE |
| 152 | static std::unique_ptr<ScriptRunIterator> |
| 153 | MakeHbIcuScriptRunIterator(const char* utf8, size_t utf8Bytes); |
| 154 | #endif |
| 155 | class TrivialScriptRunIterator : public TrivialRunIterator<ScriptRunIterator> { |
| 156 | public: |
| 157 | TrivialScriptRunIterator(SkFourByteTag script, size_t utf8Bytes) |
| 158 | : TrivialRunIterator(utf8Bytes), fScript(script) {} |
| 159 | SkFourByteTag currentScript() const override { return fScript; } |
| 160 | private: |
| 161 | SkFourByteTag fScript; |
| 162 | }; |
| 163 | |
| 164 | static std::unique_ptr<LanguageRunIterator> |
| 165 | MakeStdLanguageRunIterator(const char* utf8, size_t utf8Bytes); |
| 166 | class TrivialLanguageRunIterator : public TrivialRunIterator<LanguageRunIterator> { |
| 167 | public: |
| 168 | TrivialLanguageRunIterator(const char* language, size_t utf8Bytes) |
| 169 | : TrivialRunIterator(utf8Bytes), fLanguage(language) {} |
| 170 | const char* currentLanguage() const override { return fLanguage.c_str(); } |
| 171 | private: |
| 172 | SkString fLanguage; |
| 173 | }; |
| 174 | |
| 175 | class RunHandler { |
| 176 | public: |
| 177 | virtual ~RunHandler() = default; |
| 178 | |
| 179 | struct Range { |
| 180 | constexpr Range() : fBegin(0), fSize(0) {} |
| 181 | constexpr Range(size_t begin, size_t size) : fBegin(begin), fSize(size) {} |
| 182 | size_t fBegin; |
| 183 | size_t fSize; |
| 184 | constexpr size_t begin() const { return fBegin; } |
| 185 | constexpr size_t end() const { return begin() + size(); } |
| 186 | constexpr size_t size() const { return fSize; } |
| 187 | }; |
| 188 | |
| 189 | struct RunInfo { |
| 190 | const SkFont& fFont; |
| 191 | uint8_t fBidiLevel; |
| 192 | SkVector fAdvance; |
| 193 | size_t glyphCount; |
| 194 | Range utf8Range; |
| 195 | }; |
| 196 | |
| 197 | struct Buffer { |
| 198 | SkGlyphID* glyphs; // required |
| 199 | SkPoint* positions; // required, if (!offsets) put glyphs[i] at positions[i] |
| 200 | // if ( offsets) positions[i+1]-positions[i] are advances |
| 201 | SkPoint* offsets; // optional, if ( offsets) put glyphs[i] at positions[i]+offsets[i] |
| 202 | uint32_t* clusters; // optional, utf8+clusters[i] starts run which produced glyphs[i] |
| 203 | SkPoint point; // offset to add to all positions |
| 204 | }; |
| 205 | |
| 206 | /** Called when beginning a line. */ |
| 207 | virtual void beginLine() = 0; |
| 208 | |
| 209 | /** Called once for each run in a line. Can compute baselines and offsets. */ |
| 210 | virtual void runInfo(const RunInfo&) = 0; |
| 211 | |
| 212 | /** Called after all runInfo calls for a line. */ |
| 213 | virtual void commitRunInfo() = 0; |
| 214 | |
| 215 | /** Called for each run in a line after commitRunInfo. The buffer will be filled out. */ |
| 216 | virtual Buffer runBuffer(const RunInfo&) = 0; |
| 217 | |
| 218 | /** Called after each runBuffer is filled out. */ |
| 219 | virtual void commitRunBuffer(const RunInfo&) = 0; |
| 220 | |
| 221 | /** Called when ending a line. */ |
| 222 | virtual void commitLine() = 0; |
| 223 | }; |
| 224 | |
| 225 | virtual void shape(const char* utf8, size_t utf8Bytes, |
| 226 | const SkFont& srcFont, |
| 227 | bool leftToRight, |
| 228 | SkScalar width, |
| 229 | RunHandler*) const = 0; |
| 230 | |
| 231 | virtual void shape(const char* utf8, size_t utf8Bytes, |
| 232 | FontRunIterator&, |
| 233 | BiDiRunIterator&, |
| 234 | ScriptRunIterator&, |
| 235 | LanguageRunIterator&, |
| 236 | SkScalar width, |
| 237 | RunHandler*) const = 0; |
| 238 | |
| 239 | virtual void shape(const char* utf8, size_t utf8Bytes, |
| 240 | FontRunIterator&, |
| 241 | BiDiRunIterator&, |
| 242 | ScriptRunIterator&, |
| 243 | LanguageRunIterator&, |
| 244 | const Feature* features, size_t featuresSize, |
| 245 | SkScalar width, |
| 246 | RunHandler*) const = 0; |
| 247 | |
| 248 | private: |
| 249 | SkShaper(const SkShaper&) = delete; |
| 250 | SkShaper& operator=(const SkShaper&) = delete; |
| 251 | }; |
| 252 | |
| 253 | /** |
| 254 | * Helper for shaping text directly into a SkTextBlob. |
| 255 | */ |
| 256 | class SKSHAPER_API SkTextBlobBuilderRunHandler final : public SkShaper::RunHandler { |
| 257 | public: |
| 258 | SkTextBlobBuilderRunHandler(const char* utf8Text, SkPoint offset) |
| 259 | : fUtf8Text(utf8Text) |
| 260 | , fOffset(offset) {} |
| 261 | sk_sp<SkTextBlob> makeBlob(); |
| 262 | SkPoint endPoint() { return fOffset; } |
| 263 | |
| 264 | void beginLine() override; |
| 265 | void runInfo(const RunInfo&) override; |
| 266 | void commitRunInfo() override; |
| 267 | Buffer runBuffer(const RunInfo&) override; |
| 268 | void commitRunBuffer(const RunInfo&) override; |
| 269 | void commitLine() override; |
| 270 | |
| 271 | private: |
| 272 | SkTextBlobBuilder fBuilder; |
| 273 | char const * const fUtf8Text; |
| 274 | uint32_t* fClusters; |
| 275 | int fClusterOffset; |
| 276 | int fGlyphCount; |
| 277 | SkScalar fMaxRunAscent; |
| 278 | SkScalar fMaxRunDescent; |
| 279 | SkScalar fMaxRunLeading; |
| 280 | SkPoint fCurrentPosition; |
| 281 | SkPoint fOffset; |
| 282 | }; |
| 283 | |
| 284 | #endif // SkShaper_DEFINED |
| 285 | |