Herb Derby | 41f4f31 | 2018-06-06 17:45:53 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2018 The Android Open Source Project |
| 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 | #include "SkGlyphRun.h" |
| 9 | |
| 10 | #include <algorithm> |
Mike Klein | 79aea6a | 2018-06-11 10:45:26 -0400 | [diff] [blame] | 11 | #include <new> |
Herb Derby | 41f4f31 | 2018-06-06 17:45:53 +0000 | [diff] [blame] | 12 | #include <tuple> |
| 13 | |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 14 | #include "SkDevice.h" |
Herb Derby | 41f4f31 | 2018-06-06 17:45:53 +0000 | [diff] [blame] | 15 | #include "SkDraw.h" |
| 16 | #include "SkGlyphCache.h" |
Hal Canary | fdcfb8b | 2018-06-13 09:42:32 -0400 | [diff] [blame] | 17 | #include "SkMSAN.h" |
Hal Canary | c640d0d | 2018-06-13 09:59:02 -0400 | [diff] [blame] | 18 | #include "SkMakeUnique.h" |
Herb Derby | 41f4f31 | 2018-06-06 17:45:53 +0000 | [diff] [blame] | 19 | #include "SkPaint.h" |
| 20 | #include "SkPaintPriv.h" |
| 21 | #include "SkStrikeCache.h" |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 22 | #include "SkTextBlob.h" |
| 23 | #include "SkTextBlobRunIterator.h" |
Hal Canary | c640d0d | 2018-06-13 09:59:02 -0400 | [diff] [blame] | 24 | #include "SkTo.h" |
Herb Derby | 41f4f31 | 2018-06-06 17:45:53 +0000 | [diff] [blame] | 25 | #include "SkUtils.h" |
| 26 | |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 27 | namespace { |
Herb Derby | 4ffa027 | 2018-06-04 15:49:15 -0400 | [diff] [blame] | 28 | static SkTypeface::Encoding convert_encoding(SkPaint::TextEncoding encoding) { |
Herb Derby | 41f4f31 | 2018-06-06 17:45:53 +0000 | [diff] [blame] | 29 | switch (encoding) { |
| 30 | case SkPaint::kUTF8_TextEncoding: return SkTypeface::kUTF8_Encoding; |
| 31 | case SkPaint::kUTF16_TextEncoding: return SkTypeface::kUTF16_Encoding; |
| 32 | case SkPaint::kUTF32_TextEncoding: return SkTypeface::kUTF32_Encoding; |
| 33 | default: return SkTypeface::kUTF32_Encoding; |
| 34 | } |
| 35 | } |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 36 | } // namespace |
| 37 | |
Herb Derby | 41f4f31 | 2018-06-06 17:45:53 +0000 | [diff] [blame] | 38 | |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 39 | // -- SkGlyphSet ---------------------------------------------------------------------------------- |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 40 | uint32_t SkGlyphSet::uniqueSize() { |
| 41 | // The size is how big the vector is grown since being passed into reuse. |
| 42 | return fUniqueGlyphIDs->size() - fStartOfUniqueIDs; |
| 43 | } |
| 44 | |
Herb Derby | 4ffa027 | 2018-06-04 15:49:15 -0400 | [diff] [blame] | 45 | uint16_t SkGlyphSet::add(SkGlyphID glyphID) { |
| 46 | static constexpr SkGlyphID kUndefGlyph{0}; |
| 47 | |
| 48 | if (glyphID >= fUniverseSize) { |
| 49 | glyphID = kUndefGlyph; |
| 50 | } |
| 51 | |
| 52 | if (glyphID >= fIndices.size()) { |
| 53 | fIndices.resize(glyphID + 1); |
| 54 | } |
| 55 | |
| 56 | auto index = fIndices[glyphID]; |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 57 | |
| 58 | // Remember we start at the end of what ever was passed in. |
| 59 | if (index < this->uniqueSize() && (*fUniqueGlyphIDs)[fStartOfUniqueIDs + index] == glyphID) { |
Herb Derby | 4ffa027 | 2018-06-04 15:49:15 -0400 | [diff] [blame] | 60 | return index; |
| 61 | } |
| 62 | |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 63 | uint16_t newIndex = SkTo<uint16_t>(this->uniqueSize()); |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 64 | fUniqueGlyphIDs->push_back(glyphID); |
Herb Derby | 4ffa027 | 2018-06-04 15:49:15 -0400 | [diff] [blame] | 65 | fIndices[glyphID] = newIndex; |
| 66 | return newIndex; |
| 67 | } |
| 68 | |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 69 | void SkGlyphSet::reuse(uint32_t glyphUniverseSize, std::vector<SkGlyphID>* uniqueGlyphIDs) { |
Herb Derby | 4ffa027 | 2018-06-04 15:49:15 -0400 | [diff] [blame] | 70 | SkASSERT(glyphUniverseSize <= (1 << 16)); |
| 71 | fUniverseSize = glyphUniverseSize; |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 72 | fUniqueGlyphIDs = uniqueGlyphIDs; |
Herb Derby | 149b541 | 2018-06-21 20:03:04 +0000 | [diff] [blame] | 73 | |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 74 | // Capture the vector end to act as the start of a new unique id vector. |
| 75 | fStartOfUniqueIDs = uniqueGlyphIDs->size(); |
| 76 | |
| 77 | // If we're hanging onto these arrays for a long time, we don't want their size to drift |
| 78 | // endlessly upwards. It's unusual to see a typeface with more than 4096 possible glyphs. |
Herb Derby | 4ffa027 | 2018-06-04 15:49:15 -0400 | [diff] [blame] | 79 | if (glyphUniverseSize < 4096 && fIndices.size() > 4096) { |
| 80 | fIndices.resize(4096); |
| 81 | fIndices.shrink_to_fit(); |
| 82 | } |
| 83 | |
| 84 | // No need to clear fIndices here... SkGlyphSet's set insertion algorithm is designed to work |
| 85 | // correctly even when the fIndexes buffer is uninitialized! |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 86 | } |
| 87 | |
Herb Derby | 9d85d63 | 2018-06-18 16:25:52 -0400 | [diff] [blame] | 88 | // -- SkGlyphRun ----------------------------------------------------------------------------------- |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 89 | SkGlyphRun::SkGlyphRun(SkSpan<uint16_t> denseIndex, |
| 90 | SkSpan<SkPoint> positions, |
| 91 | SkSpan<SkGlyphID> scratchGlyphs, |
| 92 | SkSpan<SkGlyphID> uniqueGlyphIDs, |
| 93 | SkSpan<const char> text, |
| 94 | SkSpan<uint32_t> clusters) |
| 95 | : fDenseIndex{denseIndex}, fPositions{positions} |
| 96 | , fTemporaryShuntGlyphIDs{scratchGlyphs} |
| 97 | , fUniqueGlyphIDs{uniqueGlyphIDs} |
| 98 | , fText{text} |
| 99 | , fClusters{clusters} { |
| 100 | SkASSERT(denseIndex.size() == positions.size()); |
| 101 | SkASSERT(denseIndex.size() == scratchGlyphs.size()); |
| 102 | } |
| 103 | |
Herb Derby | 9d85d63 | 2018-06-18 16:25:52 -0400 | [diff] [blame] | 104 | |
| 105 | void SkGlyphRun::temporaryShuntToDrawPosText(const SkPaint& paint, SkBaseDevice* device) { |
| 106 | |
| 107 | auto pos = (const SkScalar*) fPositions.data(); |
| 108 | |
| 109 | device->drawPosText( |
| 110 | fTemporaryShuntGlyphIDs.data(), fDenseIndex.size() * sizeof(SkGlyphID), |
| 111 | pos, 2, SkPoint::Make(0, 0), paint); |
| 112 | } |
| 113 | |
| 114 | void SkGlyphRun::temporaryShuntToCallback(TemporaryShuntCallback callback) { |
| 115 | auto bytes = (const char *)fTemporaryShuntGlyphIDs.data(); |
| 116 | auto pos = (const SkScalar*)fPositions.data(); |
| 117 | callback(this->runSize(), bytes, pos); |
| 118 | } |
| 119 | |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 120 | // -- SkGlyphRunList ------------------------------------------------------------------------------- |
| 121 | SkGlyphRunList::SkGlyphRunList(SkSpan<SkGlyphRun> glyphRuns, uint64_t uniqueID) |
| 122 | : fUniqueID{uniqueID} |
| 123 | , fGlyphRuns{glyphRuns} { } |
Herb Derby | 9d85d63 | 2018-06-18 16:25:52 -0400 | [diff] [blame] | 124 | |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 125 | // -- SkGlyphRunBuilder ---------------------------------------------------------------------------- |
| 126 | void SkGlyphRunBuilder::prepareDrawText( |
| 127 | const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin) { |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 128 | this->initialize(); |
| 129 | SkSpan<const char> originalText((const char*)bytes, byteLength); |
| 130 | if (paint.getTextEncoding() != SkPaint::kUTF8_TextEncoding) { |
| 131 | originalText = SkSpan<const char>(); |
| 132 | } |
| 133 | this->drawText(paint, bytes, byteLength, origin, originalText, SkSpan<uint32_t>()); |
| 134 | } |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 135 | |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 136 | void SkGlyphRunBuilder::prepareDrawPosTextH(const SkPaint& paint, const void* bytes, |
| 137 | size_t byteLength, const SkScalar* xpos, |
| 138 | SkScalar constY) { |
| 139 | this->initialize(); |
| 140 | this->drawPosTextH( |
| 141 | paint, bytes, byteLength, xpos, constY, SkSpan<const char>(), SkSpan<uint32_t>()); |
| 142 | } |
| 143 | |
| 144 | void SkGlyphRunBuilder::prepareDrawPosText(const SkPaint& paint, const void* bytes, |
| 145 | size_t byteLength, const SkPoint* pos) { |
| 146 | this->initialize(); |
| 147 | this->drawPosText(paint, bytes, byteLength, pos, SkSpan<const char>(), SkSpan<uint32_t>()); |
| 148 | } |
| 149 | |
| 150 | void SkGlyphRunBuilder::prepareTextBlob( |
| 151 | const SkPaint& paint, const SkTextBlob& blob, SkPoint origin) { |
| 152 | this->initialize(); |
| 153 | fUniqueID = blob.uniqueID(); |
| 154 | |
| 155 | SkPaint runPaint = paint; |
| 156 | |
| 157 | for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) { |
| 158 | // applyFontToPaint() always overwrites the exact same attributes, |
| 159 | // so it is safe to not re-seed the paint for this reason. |
| 160 | it.applyFontToPaint(&runPaint); |
| 161 | |
| 162 | // These better be glyphs |
| 163 | SkASSERT(runPaint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); |
| 164 | |
| 165 | auto text = SkSpan<const char>(it.text(), it.textSize()); |
| 166 | auto clusters = SkSpan<uint32_t>(it.clusters(), it.glyphCount()); |
| 167 | size_t glyphLen = it.glyphCount() * sizeof(SkGlyphID); |
| 168 | const SkPoint& offset = it.offset(); |
| 169 | |
| 170 | switch (it.positioning()) { |
| 171 | case SkTextBlob::kDefault_Positioning: { |
| 172 | auto dtOrigin = origin + offset; |
| 173 | this->drawText(runPaint, it.glyphs(), glyphLen, dtOrigin, text, clusters); |
| 174 | } |
| 175 | break; |
| 176 | case SkTextBlob::kHorizontal_Positioning: { |
| 177 | auto constY = origin.y() + offset.y(); |
| 178 | this->drawPosTextH( |
| 179 | runPaint, it.glyphs(), glyphLen, it.pos(), constY, text, clusters); |
| 180 | } |
| 181 | break; |
| 182 | case SkTextBlob::kFull_Positioning: |
| 183 | this->drawPosText( |
| 184 | runPaint, it.glyphs(), glyphLen, (const SkPoint*)it.pos(), text, clusters); |
| 185 | break; |
| 186 | default: |
| 187 | SK_ABORT("unhandled positioning mode"); |
| 188 | } |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | SkGlyphRun* SkGlyphRunBuilder::useGlyphRun() { |
| 193 | auto glyphRunList = this->useGlyphRunList(); |
| 194 | SkASSERT(glyphRunList->size() == 1); |
| 195 | return &(*glyphRunList)[0]; |
| 196 | } |
| 197 | |
| 198 | SkGlyphRunList* SkGlyphRunBuilder::useGlyphRunList() { |
| 199 | new ((void*)&fScratchGlyphRunList) SkGlyphRunList{SkSpan<SkGlyphRun>(fGlyphRuns), fUniqueID}; |
| 200 | return &fScratchGlyphRunList; |
| 201 | } |
| 202 | |
| 203 | size_t SkGlyphRunBuilder::runSize() const { return fDenseIndex.size() - fLastDenseIndex; } |
| 204 | |
| 205 | size_t SkGlyphRunBuilder::uniqueSize() const { return fUniqueGlyphs.size() - fLastUniqueIndex; } |
| 206 | |
| 207 | void SkGlyphRunBuilder::initialize() { |
| 208 | fUniqueID = 0; |
| 209 | fDenseIndex.clear(); |
| 210 | fPositions.clear(); |
| 211 | fUniqueGlyphs.clear(); |
| 212 | fGlyphRuns.clear(); |
| 213 | fLastDenseIndex = 0; |
| 214 | fLastUniqueIndex = 0; |
| 215 | } |
| 216 | |
| 217 | SkGlyphID* SkGlyphRunBuilder::addDenseAndUnique( |
| 218 | const SkPaint& paint, const void* bytes, size_t byteLength) { |
| 219 | |
| 220 | size_t runSize = 0; |
| 221 | SkGlyphID* glyphIDs = nullptr; |
| 222 | auto encoding = paint.getTextEncoding(); |
| 223 | auto typeface = SkPaintPriv::GetTypefaceOrDefault(paint); |
| 224 | if (encoding != SkPaint::kGlyphID_TextEncoding) { |
| 225 | auto tfEncoding = convert_encoding(encoding); |
| 226 | int utfSize = SkUTFN_CountUnichars(tfEncoding, bytes, byteLength); |
| 227 | if (utfSize > 0) { |
| 228 | runSize = SkTo<size_t>(utfSize); |
| 229 | fScratchGlyphIDs.resize(runSize); |
| 230 | typeface->charsToGlyphs(bytes, tfEncoding, fScratchGlyphIDs.data(), runSize); |
| 231 | glyphIDs = fScratchGlyphIDs.data(); |
| 232 | } |
| 233 | } else { |
| 234 | runSize = byteLength / 2; |
| 235 | glyphIDs = (SkGlyphID*)bytes; |
| 236 | } |
| 237 | |
| 238 | SkASSERT(glyphIDs != nullptr); |
| 239 | |
| 240 | if (runSize > 0) { |
| 241 | fGlyphSet.reuse(typeface->countGlyphs(), &fUniqueGlyphs); |
| 242 | for (size_t i = 0; i < runSize; i++) { |
| 243 | fDenseIndex.push_back(fGlyphSet.add(glyphIDs[i])); |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | return glyphIDs; |
| 248 | } |
| 249 | |
| 250 | void SkGlyphRunBuilder::addGlyphRunToList( |
| 251 | SkGlyphID* temporaryShuntGlyphIDs, SkSpan<const char> text, SkSpan<uint32_t> clusters) { |
| 252 | |
| 253 | // Ignore empty runs. |
| 254 | if (fDenseIndex.size() != fLastDenseIndex) { |
| 255 | auto runSize = this->runSize(); |
| 256 | auto uniqueSize = this->uniqueSize(); |
| 257 | |
| 258 | fGlyphRuns.emplace_back( |
| 259 | SkSpan<uint16_t>(&fDenseIndex[fLastDenseIndex], runSize), |
| 260 | SkSpan<SkPoint>(&fPositions[fLastDenseIndex], runSize), |
| 261 | SkSpan<SkGlyphID>(temporaryShuntGlyphIDs, runSize), |
| 262 | SkSpan<SkGlyphID>(&fUniqueGlyphs[fLastDenseIndex], uniqueSize), |
| 263 | text, |
| 264 | clusters); |
| 265 | |
| 266 | fLastDenseIndex = fDenseIndex.size(); |
| 267 | fLastUniqueIndex = fUniqueGlyphs.size(); |
| 268 | } |
| 269 | } |
| 270 | |
| 271 | void SkGlyphRunBuilder::drawText( |
| 272 | const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin, |
| 273 | SkSpan<const char> text, SkSpan<uint32_t> clusters) { |
| 274 | |
| 275 | SkGlyphID* temporaryShuntGlyphIDs = this->addDenseAndUnique(paint, bytes, byteLength); |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 276 | |
| 277 | fScratchAdvances.resize(this->uniqueSize()); |
| 278 | { |
| 279 | auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(paint); |
| 280 | cache->getAdvances(SkSpan<SkGlyphID>{fUniqueGlyphs}, fScratchAdvances.data()); |
| 281 | } |
| 282 | |
| 283 | SkPoint endOfLastGlyph = origin; |
| 284 | |
| 285 | for (size_t i = 0; i < this->runSize(); i++) { |
| 286 | fPositions.push_back(endOfLastGlyph); |
| 287 | endOfLastGlyph += fScratchAdvances[fDenseIndex[i]]; |
| 288 | } |
| 289 | |
| 290 | if (paint.getTextAlign() != SkPaint::kLeft_Align) { |
| 291 | SkVector len = endOfLastGlyph - origin; |
| 292 | if (paint.getTextAlign() == SkPaint::kCenter_Align) { |
| 293 | len.scale(SK_ScalarHalf); |
| 294 | } |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 295 | for (size_t i = fLastDenseIndex; i < this->runSize(); i++) { |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 296 | fPositions[i] -= len; |
| 297 | } |
| 298 | } |
| 299 | |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 300 | this->addGlyphRunToList(temporaryShuntGlyphIDs, text, clusters); |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 301 | } |
| 302 | |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 303 | void SkGlyphRunBuilder::drawPosTextH(const SkPaint& paint, const void* bytes, |
| 304 | size_t byteLength, const SkScalar* xpos, |
| 305 | SkScalar constY, |
| 306 | SkSpan<const char> text, SkSpan<uint32_t> clusters) { |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 307 | |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 308 | SkGlyphID* temporaryShuntGlyphIDs = this->addDenseAndUnique(paint, bytes, byteLength); |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 309 | |
| 310 | for (size_t i = 0; i < runSize(); i++) { |
| 311 | fPositions.push_back(SkPoint::Make(xpos[i], constY)); |
| 312 | } |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 313 | |
| 314 | this->addGlyphRunToList(temporaryShuntGlyphIDs, text, clusters); |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 315 | } |
| 316 | |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 317 | void SkGlyphRunBuilder::drawPosText(const SkPaint& paint, const void* bytes, |
| 318 | size_t byteLength, const SkPoint* pos, |
| 319 | SkSpan<const char> text, SkSpan<uint32_t> clusters) { |
| 320 | SkGlyphID* temporaryShuntGlyphIDs = this->addDenseAndUnique(paint, bytes, byteLength); |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 321 | |
| 322 | for (size_t i = 0; i < runSize(); i++) { |
| 323 | fPositions.push_back(pos[i]); |
| 324 | } |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 325 | |
Herb Derby | b9177cf | 2018-06-18 19:13:37 -0400 | [diff] [blame^] | 326 | this->addGlyphRunToList(temporaryShuntGlyphIDs, text, clusters); |
Herb Derby | 59d997a | 2018-06-07 12:44:09 -0400 | [diff] [blame] | 327 | } |
| 328 | |
| 329 | |