blob: a20c44126a977d4f651171a10b60920bb13eac92 [file] [log] [blame]
joshualitt259fbf12015-07-21 11:39:34 -07001/*
2 * Copyright 2015 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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkColorFilter.h"
9#include "include/gpu/GrContext.h"
Herb Derby91fd46a2019-12-26 11:36:30 -050010#include "include/private/SkTemplates.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "src/core/SkMaskFilterBase.h"
12#include "src/core/SkPaintPriv.h"
13#include "src/gpu/GrBlurUtils.h"
14#include "src/gpu/GrClip.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/gpu/GrStyle.h"
Michael Ludwig663afe52019-06-03 16:46:19 -040016#include "src/gpu/geometry/GrShape.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/gpu/ops/GrAtlasTextOp.h"
Herb Derbya9047642019-12-06 12:12:11 -050018#include "src/gpu/text/GrAtlasManager.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/gpu/text/GrTextBlob.h"
20#include "src/gpu/text/GrTextTarget.h"
Ben Wagner75d6db72018-09-20 14:39:39 -040021
Herb Derby3d3150c2019-12-23 15:26:44 -050022#include <cstddef>
Mike Klein79aea6a2018-06-11 10:45:26 -040023#include <new>
joshualitt2e2202e2015-12-10 11:22:08 -080024
Herb Derbya9047642019-12-06 12:12:11 -050025static SkMatrix make_inverse(const SkMatrix& matrix) {
26 SkMatrix inverseMatrix;
27 if (!matrix.invert(&inverseMatrix)) {
28 inverseMatrix = SkMatrix::I();
29 }
30 return inverseMatrix;
31}
32
33// -- GrTextBlob::Key ------------------------------------------------------------------------------
34GrTextBlob::Key::Key() { sk_bzero(this, sizeof(Key)); }
35
36bool GrTextBlob::Key::operator==(const GrTextBlob::Key& other) const {
37 return 0 == memcmp(this, &other, sizeof(Key));
38}
39
40// -- GrTextBlob::PathGlyph ------------------------------------------------------------------------
41GrTextBlob::PathGlyph::PathGlyph(const SkPath& path, SkPoint origin)
42 : fPath(path)
43 , fOrigin(origin) {}
44
45// -- GrTextBlob::SubRun ---------------------------------------------------------------------------
Herb Derbye3c7ff42019-12-10 17:49:28 -050046// Hold data to draw the different types of sub run. SubRuns are produced knowing all the
47// glyphs that are included in them.
48class GrTextBlob::SubRun {
49public:
50 // SubRun for masks
51 SubRun(SubRunType type,
52 GrTextBlob* textBlob,
53 const SkStrikeSpec& strikeSpec,
54 GrMaskFormat format,
Herb Derbyc514e7d2019-12-11 17:00:31 -050055 const SkSpan<GrGlyph*>& glyphs, const SkSpan<char>& vertexData,
Herb Derbye3c7ff42019-12-10 17:49:28 -050056 sk_sp<GrTextStrike>&& grStrike);
57
58 // SubRun for paths
59 SubRun(GrTextBlob* textBlob, const SkStrikeSpec& strikeSpec);
60
61 void appendGlyphs(const SkZip<SkGlyphVariant, SkPoint>& drawables);
62
63 // TODO when this object is more internal, drop the privacy
64 void resetBulkUseToken();
65 GrDrawOpAtlas::BulkUseTokenUpdater* bulkUseToken();
66 void setStrike(sk_sp<GrTextStrike> strike);
67 GrTextStrike* strike() const;
Herb Derbye3c7ff42019-12-10 17:49:28 -050068
69 void setAtlasGeneration(uint64_t atlasGeneration);
70 uint64_t atlasGeneration() const;
71
Herb Derbye3c7ff42019-12-10 17:49:28 -050072 GrMaskFormat maskFormat() const;
73
Herb Derbya2d72252019-12-23 15:02:33 -050074 size_t vertexStride() const;
Herb Derby3d3150c2019-12-23 15:26:44 -050075 size_t colorOffset() const;
Herb Derbya56a1d72019-12-27 12:12:47 -050076 size_t texCoordOffset() const;
Herb Derby91fd46a2019-12-26 11:36:30 -050077 char* quadStart(size_t index) const;
Herb Derbya2d72252019-12-23 15:02:33 -050078
Herb Derbye3c7ff42019-12-10 17:49:28 -050079 const SkRect& vertexBounds() const;
80 void joinGlyphBounds(const SkRect& glyphBounds);
81
Herb Derbye3c7ff42019-12-10 17:49:28 -050082 bool drawAsDistanceFields() const;
83 bool drawAsPaths() const;
84 bool needsTransform() const;
Herb Derbye3c7ff42019-12-10 17:49:28 -050085
Herb Derbydf2c1ee2019-12-26 17:54:41 -050086 void translateVerticesIfNeeded(const SkMatrix& drawMatrix, SkPoint drawOrigin);
87 void updateVerticesColorIfNeeded(GrColor newColor);
Herb Derbya56a1d72019-12-27 12:12:47 -050088 void updateTexCoord(size_t index);
Herb Derby91fd46a2019-12-26 11:36:30 -050089
Herb Derbye3c7ff42019-12-10 17:49:28 -050090 // df properties
91 void setUseLCDText(bool useLCDText);
92 bool hasUseLCDText() const;
93 void setAntiAliased(bool antiAliased);
94 bool isAntiAliased() const;
95
96 const SkStrikeSpec& strikeSpec() const;
97
98 SubRun* fNextSubRun{nullptr};
99 const SubRunType fType;
100 GrTextBlob* const fBlob;
101 const GrMaskFormat fMaskFormat;
Herb Derbyc514e7d2019-12-11 17:00:31 -0500102 const SkSpan<GrGlyph*> fGlyphs;
103 const SkSpan<char> fVertexData;
Herb Derbye3c7ff42019-12-10 17:49:28 -0500104 const SkStrikeSpec fStrikeSpec;
105 sk_sp<GrTextStrike> fStrike;
106 struct {
107 bool useLCDText:1;
108 bool antiAliased:1;
109 } fFlags{false, false};
Herb Derbye3c7ff42019-12-10 17:49:28 -0500110 GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken;
111 SkRect fVertexBounds = SkRectPriv::MakeLargestInverted();
112 uint64_t fAtlasGeneration{GrDrawOpAtlas::kInvalidAtlasGeneration};
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500113 GrColor fCurrentColor;
Herb Derby5bf5b042019-12-12 16:37:03 -0500114 SkPoint fCurrentOrigin;
Herb Derby1c5be7b2019-12-13 12:03:06 -0500115 SkMatrix fCurrentMatrix;
Herb Derbye3c7ff42019-12-10 17:49:28 -0500116 std::vector<PathGlyph> fPaths;
Herb Derby05eb83b2019-12-23 15:42:47 -0500117
118private:
119 bool hasW() const;
120
Herb Derbye3c7ff42019-12-10 17:49:28 -0500121}; // SubRun
122
Herb Derbya9047642019-12-06 12:12:11 -0500123GrTextBlob::SubRun::SubRun(SubRunType type, GrTextBlob* textBlob, const SkStrikeSpec& strikeSpec,
Herb Derbyc514e7d2019-12-11 17:00:31 -0500124 GrMaskFormat format,
125 const SkSpan<GrGlyph*>& glyphs, const SkSpan<char>& vertexData,
Herb Derbya9047642019-12-06 12:12:11 -0500126 sk_sp<GrTextStrike>&& grStrike)
127 : fType{type}
128 , fBlob{textBlob}
129 , fMaskFormat{format}
Herb Derbyc514e7d2019-12-11 17:00:31 -0500130 , fGlyphs{glyphs}
131 , fVertexData{vertexData}
Herb Derbya9047642019-12-06 12:12:11 -0500132 , fStrikeSpec{strikeSpec}
133 , fStrike{grStrike}
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500134 , fCurrentColor{textBlob->fColor}
Herb Derby5bf5b042019-12-12 16:37:03 -0500135 , fCurrentOrigin{textBlob->fInitialOrigin}
Herb Derby1c5be7b2019-12-13 12:03:06 -0500136 , fCurrentMatrix{textBlob->fInitialMatrix} {
Herb Derbya9047642019-12-06 12:12:11 -0500137 SkASSERT(type != kTransformedPath);
Herb Derbycb718892019-12-07 00:07:42 -0500138 textBlob->insertSubRun(this);
Herb Derbya9047642019-12-06 12:12:11 -0500139}
140
141GrTextBlob::SubRun::SubRun(GrTextBlob* textBlob, const SkStrikeSpec& strikeSpec)
142 : fType{kTransformedPath}
143 , fBlob{textBlob}
144 , fMaskFormat{kA8_GrMaskFormat}
Herb Derbyc514e7d2019-12-11 17:00:31 -0500145 , fGlyphs{SkSpan<GrGlyph*>{}}
146 , fVertexData{SkSpan<char>{}}
Herb Derbya9047642019-12-06 12:12:11 -0500147 , fStrikeSpec{strikeSpec}
148 , fStrike{nullptr}
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500149 , fCurrentColor{textBlob->fColor}
Herb Derbycb718892019-12-07 00:07:42 -0500150 , fPaths{} {
151 textBlob->insertSubRun(this);
152}
Herb Derbya9047642019-12-06 12:12:11 -0500153
154void GrTextBlob::SubRun::appendGlyphs(const SkZip<SkGlyphVariant, SkPoint>& drawables) {
155 GrTextStrike* grStrike = fStrike.get();
156 SkScalar strikeToSource = fStrikeSpec.strikeToSourceRatio();
Herb Derbyc514e7d2019-12-11 17:00:31 -0500157 GrGlyph** glyphCursor = fGlyphs.data();
158 char* vertexCursor = fVertexData.data();
Herb Derbya2d72252019-12-23 15:02:33 -0500159 size_t vertexStride = this->vertexStride();
Herb Derbya9047642019-12-06 12:12:11 -0500160 // We always write the third position component used by SDFs. If it is unused it gets
161 // overwritten. Similarly, we always write the color and the blob will later overwrite it
162 // with texture coords if it is unused.
Herb Derby3d3150c2019-12-23 15:26:44 -0500163 size_t colorOffset = this->colorOffset();
Herb Derbya9047642019-12-06 12:12:11 -0500164 for (auto [variant, pos] : drawables) {
165 SkGlyph* skGlyph = variant;
166 GrGlyph* grGlyph = grStrike->getGlyph(*skGlyph);
167 // Only floor the device coordinates.
168 SkRect dstRect;
169 if (!this->needsTransform()) {
170 pos = {SkScalarFloorToScalar(pos.x()), SkScalarFloorToScalar(pos.y())};
171 dstRect = grGlyph->destRect(pos);
172 } else {
173 dstRect = grGlyph->destRect(pos, strikeToSource);
174 }
175
176 this->joinGlyphBounds(dstRect);
177
Herb Derbya9047642019-12-06 12:12:11 -0500178 // V0
Herb Derbyc514e7d2019-12-11 17:00:31 -0500179 *reinterpret_cast<SkPoint3*>(vertexCursor) = {dstRect.fLeft, dstRect.fTop, 1.f};
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500180 *reinterpret_cast<GrColor*>(vertexCursor + colorOffset) = fCurrentColor;
Herb Derbyc514e7d2019-12-11 17:00:31 -0500181 vertexCursor += vertexStride;
Herb Derbya9047642019-12-06 12:12:11 -0500182
183 // V1
Herb Derbyc514e7d2019-12-11 17:00:31 -0500184 *reinterpret_cast<SkPoint3*>(vertexCursor) = {dstRect.fLeft, dstRect.fBottom, 1.f};
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500185 *reinterpret_cast<GrColor*>(vertexCursor + colorOffset) = fCurrentColor;
Herb Derbyc514e7d2019-12-11 17:00:31 -0500186 vertexCursor += vertexStride;
Herb Derbya9047642019-12-06 12:12:11 -0500187
188 // V2
Herb Derbyc514e7d2019-12-11 17:00:31 -0500189 *reinterpret_cast<SkPoint3*>(vertexCursor) = {dstRect.fRight, dstRect.fTop, 1.f};
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500190 *reinterpret_cast<GrColor*>(vertexCursor + colorOffset) = fCurrentColor;
Herb Derbyc514e7d2019-12-11 17:00:31 -0500191 vertexCursor += vertexStride;
Herb Derbya9047642019-12-06 12:12:11 -0500192
193 // V3
Herb Derbyc514e7d2019-12-11 17:00:31 -0500194 *reinterpret_cast<SkPoint3*>(vertexCursor) = {dstRect.fRight, dstRect.fBottom, 1.f};
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500195 *reinterpret_cast<GrColor*>(vertexCursor + colorOffset) = fCurrentColor;
Herb Derbyc514e7d2019-12-11 17:00:31 -0500196 vertexCursor += vertexStride;
Herb Derbya9047642019-12-06 12:12:11 -0500197
Herb Derbyc514e7d2019-12-11 17:00:31 -0500198 *glyphCursor++ = grGlyph;
Herb Derbya9047642019-12-06 12:12:11 -0500199 }
Herb Derbya9047642019-12-06 12:12:11 -0500200}
201
202void GrTextBlob::SubRun::resetBulkUseToken() { fBulkUseToken.reset(); }
203
204GrDrawOpAtlas::BulkUseTokenUpdater* GrTextBlob::SubRun::bulkUseToken() { return &fBulkUseToken; }
205void GrTextBlob::SubRun::setStrike(sk_sp<GrTextStrike> strike) { fStrike = std::move(strike); }
206GrTextStrike* GrTextBlob::SubRun::strike() const { return fStrike.get(); }
Herb Derbya9047642019-12-06 12:12:11 -0500207void GrTextBlob::SubRun::setAtlasGeneration(uint64_t atlasGeneration) { fAtlasGeneration = atlasGeneration;}
208uint64_t GrTextBlob::SubRun::atlasGeneration() const { return fAtlasGeneration; }
Herb Derbya9047642019-12-06 12:12:11 -0500209GrMaskFormat GrTextBlob::SubRun::maskFormat() const { return fMaskFormat; }
Herb Derbya2d72252019-12-23 15:02:33 -0500210size_t GrTextBlob::SubRun::vertexStride() const {
211 return GetVertexStride(this->maskFormat(), this->hasW());
212}
Herb Derby3d3150c2019-12-23 15:26:44 -0500213size_t GrTextBlob::SubRun::colorOffset() const {
214 return this->hasW() ? offsetof(SDFT3DVertex, color) : offsetof(Mask2DVertex, color);
215}
Herb Derbya56a1d72019-12-27 12:12:47 -0500216
217size_t GrTextBlob::SubRun::texCoordOffset() const {
218 switch (fMaskFormat) {
219 case kA8_GrMaskFormat:
220 return this->hasW() ? offsetof(SDFT3DVertex, atlasPos)
221 : offsetof(Mask2DVertex, atlasPos);
222 case kARGB_GrMaskFormat:
223 return this->hasW() ? offsetof(ARGB3DVertex, atlasPos)
224 : offsetof(ARGB2DVertex, atlasPos);
225 default:
226 SkASSERT(!this->hasW());
227 return offsetof(Mask2DVertex, atlasPos);
228 }
229}
230
Herb Derby91fd46a2019-12-26 11:36:30 -0500231char* GrTextBlob::SubRun::quadStart(size_t index) const {
232 return SkTAddOffset<char>(
233 fVertexData.data(), index * kVerticesPerGlyph * this->vertexStride());
234}
Herb Derbya2d72252019-12-23 15:02:33 -0500235
Herb Derbya9047642019-12-06 12:12:11 -0500236const SkRect& GrTextBlob::SubRun::vertexBounds() const { return fVertexBounds; }
237void GrTextBlob::SubRun::joinGlyphBounds(const SkRect& glyphBounds) {
238 fVertexBounds.joinNonEmptyArg(glyphBounds);
239}
240
Herb Derbya9047642019-12-06 12:12:11 -0500241bool GrTextBlob::SubRun::drawAsDistanceFields() const { return fType == kTransformedSDFT; }
242
243bool GrTextBlob::SubRun::drawAsPaths() const { return fType == kTransformedPath; }
244
245bool GrTextBlob::SubRun::needsTransform() const {
246 return fType == kTransformedPath
247 || fType == kTransformedMask
248 || fType == kTransformedSDFT;
249}
250
251bool GrTextBlob::SubRun::hasW() const {
252 return fBlob->hasW(fType);
253}
254
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500255void GrTextBlob::SubRun::translateVerticesIfNeeded(
256 const SkMatrix& drawMatrix, SkPoint drawOrigin) {
257 SkVector translation;
258 if (this->needsTransform()) {
259 // If transform is needed, then the vertices are in source space, calculate the source
260 // space translation.
261 translation = drawOrigin - fCurrentOrigin;
262 } else {
263 // Calculate the translation in source space to a translation in device space. Calculate
264 // the translation by mapping (0, 0) through both the current matrix, and the draw
265 // matrix, and taking the difference.
266 SkMatrix currentMatrix{fCurrentMatrix};
267 currentMatrix.preTranslate(fCurrentOrigin.x(), fCurrentOrigin.y());
268 SkPoint currentDeviceOrigin{0, 0};
269 currentMatrix.mapPoints(&currentDeviceOrigin, 1);
270 SkMatrix completeDrawMatrix{drawMatrix};
271 completeDrawMatrix.preTranslate(drawOrigin.x(), drawOrigin.y());
272 SkPoint drawDeviceOrigin{0, 0};
273 completeDrawMatrix.mapPoints(&drawDeviceOrigin, 1);
274 translation = drawDeviceOrigin - currentDeviceOrigin;
275 }
276
277 if (translation != SkPoint{0, 0}) {
278 size_t vertexStride = this->vertexStride();
279 for (size_t quad = 0; quad < fGlyphs.size(); quad++) {
280 SkPoint* vertexCursor = reinterpret_cast<SkPoint*>(quadStart(quad));
281 for (int i = 0; i < 4; ++i) {
282 *vertexCursor += translation;
283 vertexCursor = SkTAddOffset<SkPoint>(vertexCursor, vertexStride);
284 }
Herb Derby91fd46a2019-12-26 11:36:30 -0500285 }
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500286 fCurrentMatrix = drawMatrix;
287 fCurrentOrigin = drawOrigin;
Herb Derby91fd46a2019-12-26 11:36:30 -0500288 }
289}
290
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500291void GrTextBlob::SubRun::updateVerticesColorIfNeeded(GrColor newColor) {
292 if (this->maskFormat() != kARGB_GrMaskFormat && fCurrentColor != newColor) {
293 size_t vertexStride = this->vertexStride();
294 size_t colorOffset = this->colorOffset();
295 for (size_t quad = 0; quad < fGlyphs.size(); quad++) {
296 GrColor* colorCursor = SkTAddOffset<GrColor>(quadStart(quad), colorOffset);
297 for (int i = 0; i < 4; ++i) {
298 *colorCursor = newColor;
299 colorCursor = SkTAddOffset<GrColor>(colorCursor, vertexStride);
300 }
Herb Derby6ca4f312019-12-26 15:23:49 -0500301 }
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500302 this->fCurrentColor = newColor;
Herb Derby6ca4f312019-12-26 15:23:49 -0500303 }
Herb Derby6ca4f312019-12-26 15:23:49 -0500304}
305
Herb Derbya56a1d72019-12-27 12:12:47 -0500306void GrTextBlob::SubRun::updateTexCoord(size_t index) {
307 GrGlyph* glyph = this->fGlyphs[index];
308 SkASSERT(glyph != nullptr);
309
310 int width = glyph->fBounds.width();
311 int height = glyph->fBounds.height();
312 uint16_t u0, v0, u1, v1;
313 if (this->drawAsDistanceFields()) {
314 u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset;
315 v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset;
316 u1 = u0 + width - 2 * SK_DistanceFieldInset;
317 v1 = v0 + height - 2 * SK_DistanceFieldInset;
318 } else {
319 u0 = glyph->fAtlasLocation.fX;
320 v0 = glyph->fAtlasLocation.fY;
321 u1 = u0 + width;
322 v1 = v0 + height;
323 }
324
325 // We pack the 2bit page index in the low bit of the u and v texture coords
326 uint32_t pageIndex = glyph->pageIndex();
327 SkASSERT(pageIndex < 4);
328 uint16_t uBit = (pageIndex >> 1u) & 0x1u;
329 uint16_t vBit = pageIndex & 0x1u;
330 u0 <<= 1u;
331 u0 |= uBit;
332 v0 <<= 1u;
333 v0 |= vBit;
334 u1 <<= 1u;
335 u1 |= uBit;
336 v1 <<= 1u;
337 v1 |= vBit;
338
339 char* vertex = this->quadStart(index);
340 size_t vertexStride = this->vertexStride();
341 size_t texCoordOffset = this->texCoordOffset();
342 uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
343 textureCoords[0] = u0;
344 textureCoords[1] = v0;
345 textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
346 textureCoords[0] = u0;
347 textureCoords[1] = v1;
348 textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
349 textureCoords[0] = u1;
350 textureCoords[1] = v0;
351 textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
352 textureCoords[0] = u1;
353 textureCoords[1] = v1;
354}
355
Herb Derbya9047642019-12-06 12:12:11 -0500356void GrTextBlob::SubRun::setUseLCDText(bool useLCDText) { fFlags.useLCDText = useLCDText; }
357bool GrTextBlob::SubRun::hasUseLCDText() const { return fFlags.useLCDText; }
358void GrTextBlob::SubRun::setAntiAliased(bool antiAliased) { fFlags.antiAliased = antiAliased; }
359bool GrTextBlob::SubRun::isAntiAliased() const { return fFlags.antiAliased; }
360const SkStrikeSpec& GrTextBlob::SubRun::strikeSpec() const { return fStrikeSpec; }
361
362// -- GrTextBlob -----------------------------------------------------------------------------------
363void GrTextBlob::operator delete(void* p) { ::operator delete(p); }
364void* GrTextBlob::operator new(size_t) { SK_ABORT("All blobs are created by placement new."); }
365void* GrTextBlob::operator new(size_t, void* p) { return p; }
366
367GrTextBlob::~GrTextBlob() = default;
368
Herb Derby659e4092019-12-06 15:38:10 -0500369sk_sp<GrTextBlob> GrTextBlob::Make(const SkGlyphRunList& glyphRunList,
Herb Derbyeba195f2019-12-03 16:44:47 -0500370 GrStrikeCache* strikeCache,
Herb Derby1c5be7b2019-12-13 12:03:06 -0500371 const SkMatrix& drawMatrix,
Herb Derbya00da612019-03-04 17:10:01 -0500372 GrColor color,
Herb Derbyeba195f2019-12-03 16:44:47 -0500373 bool forceWForDistanceFields) {
Herb Derbycd498e12019-12-06 14:17:31 -0500374
Herb Derby3d1a3bb2019-12-06 18:15:49 -0500375 static_assert(sizeof(ARGB2DVertex) <= sizeof(Mask2DVertex));
Herb Derbycb718892019-12-07 00:07:42 -0500376 static_assert(alignof(ARGB2DVertex) <= alignof(Mask2DVertex));
377 size_t quadSize = sizeof(Mask2DVertex) * kVerticesPerGlyph;
Herb Derby1c5be7b2019-12-13 12:03:06 -0500378 if (drawMatrix.hasPerspective() || forceWForDistanceFields) {
Herb Derby3d1a3bb2019-12-06 18:15:49 -0500379 static_assert(sizeof(ARGB3DVertex) <= sizeof(SDFT3DVertex));
Herb Derbycb718892019-12-07 00:07:42 -0500380 static_assert(alignof(ARGB3DVertex) <= alignof(SDFT3DVertex));
381 quadSize = sizeof(SDFT3DVertex) * kVerticesPerGlyph;
Herb Derbye74c7762019-12-04 14:15:41 -0500382 }
383
Herb Derbycb718892019-12-07 00:07:42 -0500384 // We can use the alignment of SDFT3DVertex as a proxy for all Vertex alignments.
385 static_assert(alignof(SDFT3DVertex) >= alignof(Mask2DVertex));
Herb Derbyc514e7d2019-12-11 17:00:31 -0500386 // Assume there is no padding needed between glyph pointers and vertices.
Herb Derbycb718892019-12-07 00:07:42 -0500387 static_assert(alignof(GrGlyph*) >= alignof(SDFT3DVertex));
Herb Derbyc514e7d2019-12-11 17:00:31 -0500388
389 // In the arena, the layout is GrGlyph*... | SDFT3DVertex... | SubRun, so there is no padding
390 // between GrGlyph* and SDFT3DVertex, but padding is needed between the Mask2DVertex array
391 // and the SubRun.
392 size_t vertexToSubRunPadding = alignof(SDFT3DVertex) - alignof(SubRun);
393 size_t arenaSize =
394 sizeof(GrGlyph*) * glyphRunList.totalGlyphCount()
395 + quadSize * glyphRunList.totalGlyphCount()
396 + glyphRunList.runCount() * (sizeof(SubRun) + vertexToSubRunPadding);
397
398 size_t allocationSize = sizeof(GrTextBlob) + arenaSize;
Ben Wagner75d6db72018-09-20 14:39:39 -0400399
Herb Derbycb718892019-12-07 00:07:42 -0500400 void* allocation = ::operator new (allocationSize);
Herb Derbyb12175f2018-05-23 16:38:09 -0400401
Herb Derbyaebc5f82019-12-10 14:07:10 -0500402 SkColor initialLuminance = SkPaintPriv::ComputeLuminanceColor(glyphRunList.paint());
Herb Derby00ae9592019-12-03 15:55:56 -0500403 sk_sp<GrTextBlob> blob{new (allocation) GrTextBlob{
Herb Derby1c5be7b2019-12-13 12:03:06 -0500404 arenaSize, strikeCache, drawMatrix, glyphRunList.origin(),
Herb Derbyaebc5f82019-12-10 14:07:10 -0500405 color, initialLuminance, forceWForDistanceFields}};
joshualitt92303772016-02-10 11:55:52 -0800406
Herb Derbyf7d5d742018-11-16 13:24:32 -0500407 return blob;
joshualitt92303772016-02-10 11:55:52 -0800408}
409
Herb Derbya9047642019-12-06 12:12:11 -0500410void GrTextBlob::setupKey(const GrTextBlob::Key& key, const SkMaskFilterBase::BlurRec& blurRec,
411 const SkPaint& paint) {
412 fKey = key;
413 if (key.fHasBlur) {
414 fBlurRec = blurRec;
415 }
416 if (key.fStyle != SkPaint::kFill_Style) {
417 fStrokeInfo.fFrameWidth = paint.getStrokeWidth();
418 fStrokeInfo.fMiterLimit = paint.getStrokeMiter();
419 fStrokeInfo.fJoin = paint.getStrokeJoin();
420 }
421}
422const GrTextBlob::Key& GrTextBlob::GetKey(const GrTextBlob& blob) { return blob.fKey; }
423uint32_t GrTextBlob::Hash(const GrTextBlob::Key& key) { return SkOpts::hash(&key, sizeof(Key)); }
424
Herb Derbycb718892019-12-07 00:07:42 -0500425bool GrTextBlob::hasDistanceField() const {
426 return SkToBool(fTextType & kHasDistanceField_TextType);
427}
Herb Derbya9047642019-12-06 12:12:11 -0500428bool GrTextBlob::hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); }
Herb Derby1c5be7b2019-12-13 12:03:06 -0500429bool GrTextBlob::hasPerspective() const { return fInitialMatrix.hasPerspective(); }
Herb Derbya9047642019-12-06 12:12:11 -0500430
431void GrTextBlob::setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
432void GrTextBlob::setHasBitmap() { fTextType |= kHasBitmap_TextType; }
433void GrTextBlob::setMinAndMaxScale(SkScalar scaledMin, SkScalar scaledMax) {
434 // we init fMaxMinScale and fMinMaxScale in the constructor
435 fMaxMinScale = SkMaxScalar(scaledMin, fMaxMinScale);
436 fMinMaxScale = SkMinScalar(scaledMax, fMinMaxScale);
437}
438
439size_t GrTextBlob::GetVertexStride(GrMaskFormat maskFormat, bool hasWCoord) {
440 switch (maskFormat) {
441 case kA8_GrMaskFormat:
Herb Derbycd498e12019-12-06 14:17:31 -0500442 return hasWCoord ? sizeof(SDFT3DVertex) : sizeof(Mask2DVertex);
Herb Derbya9047642019-12-06 12:12:11 -0500443 case kARGB_GrMaskFormat:
Herb Derbycd498e12019-12-06 14:17:31 -0500444 return hasWCoord ? sizeof(ARGB3DVertex) : sizeof(ARGB2DVertex);
Herb Derbya9047642019-12-06 12:12:11 -0500445 default:
446 SkASSERT(!hasWCoord);
Herb Derbycd498e12019-12-06 14:17:31 -0500447 return sizeof(Mask2DVertex);
Herb Derbya9047642019-12-06 12:12:11 -0500448 }
449}
450
Herb Derby0edb2142018-10-16 17:04:11 -0400451bool GrTextBlob::mustRegenerate(const SkPaint& paint, bool anyRunHasSubpixelPosition,
452 const SkMaskFilterBase::BlurRec& blurRec,
Herb Derby5bf5b042019-12-12 16:37:03 -0500453 const SkMatrix& drawMatrix, SkPoint drawOrigin) {
joshualittfd5f6c12015-12-10 07:44:50 -0800454 // If we have LCD text then our canonical color will be set to transparent, in this case we have
455 // to regenerate the blob on any color change
456 // We use the grPaint to get any color filter effects
457 if (fKey.fCanonicalColor == SK_ColorTRANSPARENT &&
Herb Derbyaebc5f82019-12-10 14:07:10 -0500458 fInitialLuminance != SkPaintPriv::ComputeLuminanceColor(paint)) {
joshualittfd5f6c12015-12-10 07:44:50 -0800459 return true;
460 }
461
Herb Derby1c5be7b2019-12-13 12:03:06 -0500462 if (fInitialMatrix.hasPerspective() != drawMatrix.hasPerspective()) {
joshualittfd5f6c12015-12-10 07:44:50 -0800463 return true;
464 }
465
Brian Salomon5c6ac642017-12-19 11:09:32 -0500466 /** This could be relaxed for blobs with only distance field glyphs. */
Mike Reed2c383152019-12-18 16:47:47 -0500467 if (fInitialMatrix.hasPerspective() && !SkMatrixPriv::CheapEqual(fInitialMatrix, drawMatrix)) {
joshualittfd5f6c12015-12-10 07:44:50 -0800468 return true;
469 }
470
471 // We only cache one masked version
472 if (fKey.fHasBlur &&
Mike Reed1be1f8d2018-03-14 13:01:17 -0400473 (fBlurRec.fSigma != blurRec.fSigma || fBlurRec.fStyle != blurRec.fStyle)) {
joshualittfd5f6c12015-12-10 07:44:50 -0800474 return true;
475 }
476
477 // Similarly, we only cache one version for each style
478 if (fKey.fStyle != SkPaint::kFill_Style &&
Herb Derbybc6f9c92018-08-08 13:58:45 -0400479 (fStrokeInfo.fFrameWidth != paint.getStrokeWidth() ||
480 fStrokeInfo.fMiterLimit != paint.getStrokeMiter() ||
481 fStrokeInfo.fJoin != paint.getStrokeJoin())) {
joshualittfd5f6c12015-12-10 07:44:50 -0800482 return true;
483 }
484
485 // Mixed blobs must be regenerated. We could probably figure out a way to do integer scrolls
486 // for mixed blobs if this becomes an issue.
487 if (this->hasBitmap() && this->hasDistanceField()) {
Herb Derbyeba195f2019-12-03 16:44:47 -0500488 // Identical view matrices and we can reuse in all cases
Mike Reed2c383152019-12-18 16:47:47 -0500489 return !(SkMatrixPriv::CheapEqual(fInitialMatrix, drawMatrix) &&
490 drawOrigin == fInitialOrigin);
joshualittfd5f6c12015-12-10 07:44:50 -0800491 }
492
493 if (this->hasBitmap()) {
Herb Derby1c5be7b2019-12-13 12:03:06 -0500494 if (fInitialMatrix.getScaleX() != drawMatrix.getScaleX() ||
495 fInitialMatrix.getScaleY() != drawMatrix.getScaleY() ||
496 fInitialMatrix.getSkewX() != drawMatrix.getSkewX() ||
497 fInitialMatrix.getSkewY() != drawMatrix.getSkewY()) {
joshualittfd5f6c12015-12-10 07:44:50 -0800498 return true;
499 }
500
Herb Derby9830fc42019-09-12 10:58:26 -0400501 // TODO(herb): this is not needed for full pixel glyph choice, but is needed to adjust
502 // the quads properly. Devise a system that regenerates the quads from original data
503 // using the transform to allow this to be used in general.
504
505 // We can update the positions in the text blob without regenerating the whole
506 // blob, but only for integer translations.
507 // This cool bit of math will determine the necessary translation to apply to the
508 // already generated vertex coordinates to move them to the correct position.
509 // Figure out the translation in view space given a translation in source space.
Herb Derby1c5be7b2019-12-13 12:03:06 -0500510 SkScalar transX = drawMatrix.getTranslateX() +
Herb Derby5bf5b042019-12-12 16:37:03 -0500511 drawMatrix.getScaleX() * (drawOrigin.x() - fInitialOrigin.x()) +
512 drawMatrix.getSkewX() * (drawOrigin.y() - fInitialOrigin.y()) -
Herb Derby1c5be7b2019-12-13 12:03:06 -0500513 fInitialMatrix.getTranslateX();
514 SkScalar transY = drawMatrix.getTranslateY() +
Herb Derby5bf5b042019-12-12 16:37:03 -0500515 drawMatrix.getSkewY() * (drawOrigin.x() - fInitialOrigin.x()) +
516 drawMatrix.getScaleY() * (drawOrigin.y() - fInitialOrigin.y()) -
Herb Derby1c5be7b2019-12-13 12:03:06 -0500517 fInitialMatrix.getTranslateY();
Herb Derby9830fc42019-09-12 10:58:26 -0400518 if (!SkScalarIsInt(transX) || !SkScalarIsInt(transY)) {
519 return true;
joshualittfd5f6c12015-12-10 07:44:50 -0800520 }
joshualittfd5f6c12015-12-10 07:44:50 -0800521 } else if (this->hasDistanceField()) {
522 // A scale outside of [blob.fMaxMinScale, blob.fMinMaxScale] would result in a different
523 // distance field being generated, so we have to regenerate in those cases
Herb Derby1c5be7b2019-12-13 12:03:06 -0500524 SkScalar newMaxScale = drawMatrix.getMaxScale();
525 SkScalar oldMaxScale = fInitialMatrix.getMaxScale();
joshualittfd5f6c12015-12-10 07:44:50 -0800526 SkScalar scaleAdjust = newMaxScale / oldMaxScale;
527 if (scaleAdjust < fMaxMinScale || scaleAdjust > fMinMaxScale) {
528 return true;
529 }
joshualittfd5f6c12015-12-10 07:44:50 -0800530 }
531
joshualittfd5f6c12015-12-10 07:44:50 -0800532 // It is possible that a blob has neither distanceField nor bitmaptext. This is in the case
533 // when all of the runs inside the blob are drawn as paths. In this case, we always regenerate
534 // the blob anyways at flush time, so no need to regenerate explicitly
535 return false;
536}
537
Herb Derbyc1b482c2018-08-09 15:02:27 -0400538void GrTextBlob::flush(GrTextTarget* target, const SkSurfaceProps& props,
539 const GrDistanceFieldAdjustTable* distanceAdjustTable,
Brian Osmancf860852018-10-31 14:04:39 -0400540 const SkPaint& paint, const SkPMColor4f& filteredColor, const GrClip& clip,
Herb Derby5bf5b042019-12-12 16:37:03 -0500541 const SkMatrix& drawMatrix, SkPoint drawOrigin) {
Jim Van Verth54d9c882018-02-08 16:14:48 -0500542
Herb Derbycb718892019-12-07 00:07:42 -0500543 for (SubRun* subRun = fFirstSubRun; subRun != nullptr; subRun = subRun->fNextSubRun) {
544 if (subRun->drawAsPaths()) {
Herb Derbydac1ed52018-09-12 17:04:21 -0400545 SkPaint runPaint{paint};
Herb Derbycb718892019-12-07 00:07:42 -0500546 runPaint.setAntiAlias(subRun->isAntiAliased());
Herb Derby1b8dcd12019-11-15 15:21:15 -0500547 // If there are shaders, blurs or styles, the path must be scaled into source
548 // space independently of the CTM. This allows the CTM to be correct for the
549 // different effects.
550 GrStyle style(runPaint);
Herb Derby9f491482018-08-08 11:53:00 -0400551
Herb Derby1b8dcd12019-11-15 15:21:15 -0500552 bool scalePath = runPaint.getShader()
553 || style.applies()
554 || runPaint.getMaskFilter();
Robert Phillips137ca522018-08-15 10:14:33 -0400555
Herb Derby1b8dcd12019-11-15 15:21:15 -0500556 // The origin for the blob may have changed, so figure out the delta.
Herb Derby5bf5b042019-12-12 16:37:03 -0500557 SkVector originShift = drawOrigin - fInitialOrigin;
Herb Derby1b8dcd12019-11-15 15:21:15 -0500558
Herb Derbycb718892019-12-07 00:07:42 -0500559 for (const auto& pathGlyph : subRun->fPaths) {
Herb Derby1c5be7b2019-12-13 12:03:06 -0500560 SkMatrix ctm{drawMatrix};
Herb Derbycb718892019-12-07 00:07:42 -0500561 SkMatrix pathMatrix = SkMatrix::MakeScale(
562 subRun->fStrikeSpec.strikeToSourceRatio());
Herb Derby1b8dcd12019-11-15 15:21:15 -0500563 // Shift the original glyph location in source space to the position of the new
564 // blob.
565 pathMatrix.postTranslate(originShift.x() + pathGlyph.fOrigin.x(),
566 originShift.y() + pathGlyph.fOrigin.y());
Herb Derbydac1ed52018-09-12 17:04:21 -0400567
568 // TmpPath must be in the same scope as GrShape shape below.
Robert Phillips137ca522018-08-15 10:14:33 -0400569 SkTLazy<SkPath> tmpPath;
Herb Derby1b8dcd12019-11-15 15:21:15 -0500570 const SkPath* path = &pathGlyph.fPath;
Herb Derby2984d262019-11-20 14:40:39 -0500571 if (!scalePath) {
572 // Scale can be applied to CTM -- no effects.
Herb Derby2984d262019-11-20 14:40:39 -0500573 ctm.preConcat(pathMatrix);
Robert Phillipsd20d2612018-08-28 10:09:01 -0400574 } else {
Herb Derby2984d262019-11-20 14:40:39 -0500575 // Scale the outline into source space.
Herb Derbydac1ed52018-09-12 17:04:21 -0400576
Herb Derby2984d262019-11-20 14:40:39 -0500577 // Transform the path form the normalized outline to source space. This
578 // way the CTM will remain the same so it can be used by the effects.
579 SkPath* sourceOutline = tmpPath.init();
580 path->transform(pathMatrix, sourceOutline);
581 sourceOutline->setIsVolatile(true);
582 path = sourceOutline;
Robert Phillips137ca522018-08-15 10:14:33 -0400583 }
584
Robert Phillips46a13382018-08-23 13:53:01 -0400585 // TODO: we are losing the mutability of the path here
586 GrShape shape(*path, paint);
Herb Derbydac1ed52018-09-12 17:04:21 -0400587 target->drawShape(clip, runPaint, ctm, shape);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500588 }
Herb Derby1b8dcd12019-11-15 15:21:15 -0500589 } else {
Herb Derbyc514e7d2019-12-11 17:00:31 -0500590 int glyphCount = subRun->fGlyphs.size();
Jim Van Verth54d9c882018-02-08 16:14:48 -0500591 if (0 == glyphCount) {
592 continue;
593 }
594
595 bool skipClip = false;
596 bool submitOp = true;
597 SkIRect clipRect = SkIRect::MakeEmpty();
598 SkRect rtBounds = SkRect::MakeWH(target->width(), target->height());
599 SkRRect clipRRect;
600 GrAA aa;
Jim Van Verthb515ae72018-05-23 16:44:55 -0400601 // We can clip geometrically if we're not using SDFs or transformed glyphs,
Jim Van Verth54d9c882018-02-08 16:14:48 -0500602 // and we have an axis-aligned rectangular non-AA clip
Herb Derbycb718892019-12-07 00:07:42 -0500603 if (!subRun->drawAsDistanceFields() && !subRun->needsTransform() &&
Jim Van Verthcf838c72018-03-05 14:40:36 -0500604 clip.isRRect(rtBounds, &clipRRect, &aa) &&
Jim Van Verth54d9c882018-02-08 16:14:48 -0500605 clipRRect.isRect() && GrAA::kNo == aa) {
606 skipClip = true;
607 // We only need to do clipping work if the subrun isn't contained by the clip
608 SkRect subRunBounds;
Herb Derby5bf5b042019-12-12 16:37:03 -0500609 this->computeSubRunBounds(
610 &subRunBounds, *subRun, drawMatrix, drawOrigin, false);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500611 if (!clipRRect.getBounds().contains(subRunBounds)) {
612 // If the subrun is completely outside, don't add an op for it
613 if (!clipRRect.getBounds().intersects(subRunBounds)) {
614 submitOp = false;
615 }
616 else {
617 clipRRect.getBounds().round(&clipRect);
618 }
619 }
620 }
621
622 if (submitOp) {
Herb Derby5bf5b042019-12-12 16:37:03 -0500623 auto op = this->makeOp(*subRun, glyphCount, drawMatrix, drawOrigin,
Herb Derbybc6f9c92018-08-08 13:58:45 -0400624 clipRect, paint, filteredColor, props, distanceAdjustTable,
Robert Phillips5a66efb2018-03-07 15:13:18 -0500625 target);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500626 if (op) {
627 if (skipClip) {
628 target->addDrawOp(GrNoClip(), std::move(op));
629 }
630 else {
631 target->addDrawOp(clip, std::move(op));
632 }
633 }
634 }
635 }
Jim Van Verth89737de2018-02-06 21:30:20 +0000636 }
Jim Van Verth89737de2018-02-06 21:30:20 +0000637}
638
Herb Derby1c5be7b2019-12-13 12:03:06 -0500639void GrTextBlob::computeSubRunBounds(SkRect* outBounds, const SubRun& subRun,
Herb Derby5bf5b042019-12-12 16:37:03 -0500640 const SkMatrix& drawMatrix, SkPoint drawOrigin,
Herb Derbya9047642019-12-06 12:12:11 -0500641 bool needsGlyphTransform) {
642 // We don't yet position distance field text on the cpu, so we have to map the vertex bounds
643 // into device space.
644 // We handle vertex bounds differently for distance field text and bitmap text because
645 // the vertex bounds of bitmap text are in device space. If we are flushing multiple runs
646 // from one blob then we are going to pay the price here of mapping the rect for each run.
647 *outBounds = subRun.vertexBounds();
648 if (needsGlyphTransform) {
649 // Distance field text is positioned with the (X,Y) as part of the glyph position,
650 // and currently the view matrix is applied on the GPU
Herb Derby5bf5b042019-12-12 16:37:03 -0500651 outBounds->offset(drawOrigin - fInitialOrigin);
Herb Derby1c5be7b2019-12-13 12:03:06 -0500652 drawMatrix.mapRect(outBounds);
Herb Derbya9047642019-12-06 12:12:11 -0500653 } else {
654 // Bitmap text is fully positioned on the CPU, and offset by an (X,Y) translate in
655 // device space.
Herb Derby1c5be7b2019-12-13 12:03:06 -0500656 SkMatrix boundsMatrix = fInitialMatrixInverse;
Herb Derbya9047642019-12-06 12:12:11 -0500657
658 boundsMatrix.postTranslate(-fInitialOrigin.x(), -fInitialOrigin.y());
659
Herb Derby5bf5b042019-12-12 16:37:03 -0500660 boundsMatrix.postTranslate(drawOrigin.x(), drawOrigin.y());
Herb Derbya9047642019-12-06 12:12:11 -0500661
Herb Derby1c5be7b2019-12-13 12:03:06 -0500662 boundsMatrix.postConcat(drawMatrix);
Herb Derbya9047642019-12-06 12:12:11 -0500663 boundsMatrix.mapRect(outBounds);
664
665 // Due to floating point numerical inaccuracies, we have to round out here
666 outBounds->roundOut(outBounds);
667 }
joshualitt323c2eb2016-01-20 06:48:47 -0800668}
joshualitt2e2202e2015-12-10 11:22:08 -0800669
Herb Derbya9047642019-12-06 12:12:11 -0500670const GrTextBlob::Key& GrTextBlob::key() const { return fKey; }
671size_t GrTextBlob::size() const { return fSize; }
672
673std::unique_ptr<GrDrawOp> GrTextBlob::test_makeOp(
Herb Derby1c5be7b2019-12-13 12:03:06 -0500674 int glyphCount, const SkMatrix& drawMatrix,
Herb Derby5bf5b042019-12-12 16:37:03 -0500675 SkPoint drawOrigin, const SkPaint& paint, const SkPMColor4f& filteredColor,
Herb Derbya9047642019-12-06 12:12:11 -0500676 const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable,
677 GrTextTarget* target) {
Herb Derbycb718892019-12-07 00:07:42 -0500678 SubRun* info = fFirstSubRun;
Herb Derbya9047642019-12-06 12:12:11 -0500679 SkIRect emptyRect = SkIRect::MakeEmpty();
Herb Derby5bf5b042019-12-12 16:37:03 -0500680 return this->makeOp(*info, glyphCount, drawMatrix, drawOrigin, emptyRect,
Herb Derbya9047642019-12-06 12:12:11 -0500681 paint, filteredColor, props, distanceAdjustTable, target);
682}
683
684bool GrTextBlob::hasW(GrTextBlob::SubRunType type) const {
685 if (type == kTransformedSDFT) {
686 return this->hasPerspective() || fForceWForDistanceFields;
687 } else if (type == kTransformedMask || type == kTransformedPath) {
688 return this->hasPerspective();
Herb Derbye9f691d2019-12-04 12:11:13 -0500689 }
Herb Derbya9047642019-12-06 12:12:11 -0500690
691 // The viewMatrix is implicitly SkMatrix::I when drawing kDirectMask, because it is not
692 // used.
693 return false;
694}
695
696GrTextBlob::SubRun* GrTextBlob::makeSubRun(SubRunType type,
697 const SkZip<SkGlyphVariant, SkPoint>& drawables,
698 const SkStrikeSpec& strikeSpec,
699 GrMaskFormat format) {
Herb Derbyc514e7d2019-12-11 17:00:31 -0500700 SkSpan<GrGlyph*> glyphs{fAlloc.makeArrayDefault<GrGlyph*>(drawables.size()), drawables.size()};
Herb Derbya9047642019-12-06 12:12:11 -0500701 bool hasW = this->hasW(type);
Herb Derby3d3150c2019-12-23 15:26:44 -0500702
703 SkASSERT(!fInitialMatrix.hasPerspective() || hasW);
704
Herb Derbyc514e7d2019-12-11 17:00:31 -0500705 size_t vertexDataSize = drawables.size() * GetVertexStride(format, hasW) * kVerticesPerGlyph;
706 SkSpan<char> vertexData{fAlloc.makeArrayDefault<char>(vertexDataSize), vertexDataSize};
Herb Derbya9047642019-12-06 12:12:11 -0500707
708 sk_sp<GrTextStrike> grStrike = strikeSpec.findOrCreateGrStrike(fStrikeCache);
709
Herb Derbycb718892019-12-07 00:07:42 -0500710 SubRun* subRun = fAlloc.make<SubRun>(
Herb Derbyc514e7d2019-12-11 17:00:31 -0500711 type, this, strikeSpec, format, glyphs, vertexData, std::move(grStrike));
Herb Derbya9047642019-12-06 12:12:11 -0500712
Herb Derbycb718892019-12-07 00:07:42 -0500713 subRun->appendGlyphs(drawables);
Herb Derbya9047642019-12-06 12:12:11 -0500714
Herb Derbycb718892019-12-07 00:07:42 -0500715 return subRun;
Herb Derbya9047642019-12-06 12:12:11 -0500716}
717
718void GrTextBlob::addSingleMaskFormat(
719 SubRunType type,
720 const SkZip<SkGlyphVariant, SkPoint>& drawables,
721 const SkStrikeSpec& strikeSpec,
722 GrMaskFormat format) {
723 this->makeSubRun(type, drawables, strikeSpec, format);
724}
725
726void GrTextBlob::addMultiMaskFormat(
727 SubRunType type,
728 const SkZip<SkGlyphVariant, SkPoint>& drawables,
729 const SkStrikeSpec& strikeSpec) {
730 this->setHasBitmap();
731 if (drawables.empty()) { return; }
732
733 auto glyphSpan = drawables.get<0>();
734 SkGlyph* glyph = glyphSpan[0];
735 GrMaskFormat format = GrGlyph::FormatFromSkGlyph(glyph->maskFormat());
736 size_t startIndex = 0;
737 for (size_t i = 1; i < drawables.size(); i++) {
738 glyph = glyphSpan[i];
739 GrMaskFormat nextFormat = GrGlyph::FormatFromSkGlyph(glyph->maskFormat());
740 if (format != nextFormat) {
741 auto sameFormat = drawables.subspan(startIndex, i - startIndex);
742 this->addSingleMaskFormat(type, sameFormat, strikeSpec, format);
743 format = nextFormat;
744 startIndex = i;
745 }
746 }
747 auto sameFormat = drawables.last(drawables.size() - startIndex);
748 this->addSingleMaskFormat(type, sameFormat, strikeSpec, format);
749}
750
751void GrTextBlob::addSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables,
752 const SkStrikeSpec& strikeSpec,
753 const SkFont& runFont,
754 SkScalar minScale,
755 SkScalar maxScale) {
756 this->setHasDistanceField();
757 this->setMinAndMaxScale(minScale, maxScale);
758
759 SubRun* subRun = this->makeSubRun(kTransformedSDFT, drawables, strikeSpec, kA8_GrMaskFormat);
760 subRun->setUseLCDText(runFont.getEdging() == SkFont::Edging::kSubpixelAntiAlias);
761 subRun->setAntiAliased(runFont.hasSomeAntiAliasing());
Herb Derbye9f691d2019-12-04 12:11:13 -0500762}
763
Herb Derbycb718892019-12-07 00:07:42 -0500764GrTextBlob::GrTextBlob(size_t allocSize,
Herb Derbyeba195f2019-12-03 16:44:47 -0500765 GrStrikeCache* strikeCache,
Herb Derby1c5be7b2019-12-13 12:03:06 -0500766 const SkMatrix& drawMatrix,
Herb Derbyeba195f2019-12-03 16:44:47 -0500767 SkPoint origin,
768 GrColor color,
Herb Derbyaebc5f82019-12-10 14:07:10 -0500769 SkColor initialLuminance,
Herb Derby00ae9592019-12-03 15:55:56 -0500770 bool forceWForDistanceFields)
Herb Derbycb718892019-12-07 00:07:42 -0500771 : fSize{allocSize}
Herb Derby00ae9592019-12-03 15:55:56 -0500772 , fStrikeCache{strikeCache}
Herb Derby1c5be7b2019-12-13 12:03:06 -0500773 , fInitialMatrix{drawMatrix}
774 , fInitialMatrixInverse{make_inverse(drawMatrix)}
Herb Derbyeba195f2019-12-03 16:44:47 -0500775 , fInitialOrigin{origin}
Herb Derby00ae9592019-12-03 15:55:56 -0500776 , fForceWForDistanceFields{forceWForDistanceFields}
Herb Derbycb718892019-12-07 00:07:42 -0500777 , fColor{color}
Herb Derbyaebc5f82019-12-10 14:07:10 -0500778 , fInitialLuminance{initialLuminance}
Herb Derbycb718892019-12-07 00:07:42 -0500779 , fAlloc{SkTAddOffset<char>(this, sizeof(GrTextBlob)), allocSize, allocSize/2} { }
Herb Derby00ae9592019-12-03 15:55:56 -0500780
Herb Derbycb718892019-12-07 00:07:42 -0500781void GrTextBlob::insertSubRun(SubRun* subRun) {
782 if (fFirstSubRun == nullptr) {
783 fFirstSubRun = subRun;
784 fLastSubRun = subRun;
785 } else {
786 fLastSubRun->fNextSubRun = subRun;
787 fLastSubRun = subRun;
788 }
789}
790
791std::unique_ptr<GrAtlasTextOp> GrTextBlob::makeOp(
Herb Derbya9047642019-12-06 12:12:11 -0500792 SubRun& info, int glyphCount,
Herb Derby5bf5b042019-12-12 16:37:03 -0500793 const SkMatrix& drawMatrix, SkPoint drawOrigin, const SkIRect& clipRect,
Herb Derbya9047642019-12-06 12:12:11 -0500794 const SkPaint& paint, const SkPMColor4f& filteredColor, const SkSurfaceProps& props,
795 const GrDistanceFieldAdjustTable* distanceAdjustTable, GrTextTarget* target) {
796 GrMaskFormat format = info.maskFormat();
797
798 GrPaint grPaint;
Herb Derby1c5be7b2019-12-13 12:03:06 -0500799 target->makeGrPaint(info.maskFormat(), paint, drawMatrix, &grPaint);
Herb Derbya9047642019-12-06 12:12:11 -0500800 std::unique_ptr<GrAtlasTextOp> op;
801 if (info.drawAsDistanceFields()) {
802 // TODO: Can we be even smarter based on the dest transfer function?
803 op = GrAtlasTextOp::MakeDistanceField(
804 target->getContext(), std::move(grPaint), glyphCount, distanceAdjustTable,
805 target->colorInfo().isLinearlyBlended(), SkPaintPriv::ComputeLuminanceColor(paint),
806 props, info.isAntiAliased(), info.hasUseLCDText());
Herb Derbyeba195f2019-12-03 16:44:47 -0500807 } else {
Herb Derbya9047642019-12-06 12:12:11 -0500808 op = GrAtlasTextOp::MakeBitmap(target->getContext(), std::move(grPaint), format, glyphCount,
809 info.needsTransform());
810 }
811 GrAtlasTextOp::Geometry& geometry = op->geometry();
Herb Derby1c5be7b2019-12-13 12:03:06 -0500812 geometry.fDrawMatrix = drawMatrix;
Herb Derbya9047642019-12-06 12:12:11 -0500813 geometry.fClipRect = clipRect;
814 geometry.fBlob = SkRef(this);
815 geometry.fSubRunPtr = &info;
816 geometry.fColor = info.maskFormat() == kARGB_GrMaskFormat ? SK_PMColor4fWHITE : filteredColor;
Herb Derby5bf5b042019-12-12 16:37:03 -0500817 geometry.fDrawOrigin = drawOrigin;
Herb Derbya9047642019-12-06 12:12:11 -0500818 op->init();
819 return op;
820}
Herb Derbyeba195f2019-12-03 16:44:47 -0500821
Herb Derbya9047642019-12-06 12:12:11 -0500822void GrTextBlob::processDeviceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
823 const SkStrikeSpec& strikeSpec) {
824 this->addMultiMaskFormat(kDirectMask, drawables, strikeSpec);
825}
Herb Derbyeba195f2019-12-03 16:44:47 -0500826
Herb Derbya9047642019-12-06 12:12:11 -0500827void GrTextBlob::processSourcePaths(const SkZip<SkGlyphVariant, SkPoint>& drawables,
828 const SkFont& runFont,
829 const SkStrikeSpec& strikeSpec) {
830 this->setHasBitmap();
Herb Derbycb718892019-12-07 00:07:42 -0500831 SubRun* subRun = fAlloc.make<SubRun>(this, strikeSpec);
832 subRun->setAntiAliased(runFont.hasSomeAntiAliasing());
Herb Derbya9047642019-12-06 12:12:11 -0500833 for (auto [variant, pos] : drawables) {
Herb Derbycb718892019-12-07 00:07:42 -0500834 subRun->fPaths.emplace_back(*variant.path(), pos);
Herb Derbyeba195f2019-12-03 16:44:47 -0500835 }
836}
837
Herb Derbya9047642019-12-06 12:12:11 -0500838void GrTextBlob::processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables,
839 const SkStrikeSpec& strikeSpec,
840 const SkFont& runFont,
841 SkScalar minScale,
842 SkScalar maxScale) {
843 this->addSDFT(drawables, strikeSpec, runFont, minScale, maxScale);
joshualitt8e0ef292016-02-19 14:13:03 -0800844}
Herb Derbya9047642019-12-06 12:12:11 -0500845
846void GrTextBlob::processSourceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
847 const SkStrikeSpec& strikeSpec) {
848 this->addMultiMaskFormat(kTransformedMask, drawables, strikeSpec);
849}
850
851// -- GrTextBlob::VertexRegenerator ----------------------------------------------------------------
Herb Derbya9047642019-12-06 12:12:11 -0500852GrTextBlob::VertexRegenerator::VertexRegenerator(GrResourceProvider* resourceProvider,
Herb Derbya9047642019-12-06 12:12:11 -0500853 GrTextBlob::SubRun* subRun,
Herb Derby5bf5b042019-12-12 16:37:03 -0500854 const SkMatrix& drawMatrix,
855 SkPoint drawOrigin,
Herb Derbya9047642019-12-06 12:12:11 -0500856 GrColor color,
857 GrDeferredUploadTarget* uploadTarget,
858 GrStrikeCache* grStrikeCache,
859 GrAtlasManager* fullAtlasManager)
860 : fResourceProvider(resourceProvider)
Herb Derbya9047642019-12-06 12:12:11 -0500861 , fUploadTarget(uploadTarget)
862 , fGrStrikeCache(grStrikeCache)
863 , fFullAtlasManager(fullAtlasManager)
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500864 , fSubRun(subRun){
Herb Derbya9047642019-12-06 12:12:11 -0500865 // Because the GrStrikeCache may evict the strike a blob depends on using for
866 // generating its texture coords, we have to track whether or not the strike has
867 // been abandoned. If it hasn't been abandoned, then we can use the GrGlyph*s as is
868 // otherwise we have to get the new strike, and use that to get the correct glyphs.
869 // Because we do not have the packed ids, and thus can't look up our glyphs in the
870 // new strike, we instead keep our ref to the old strike and use the packed ids from
871 // it. These ids will still be valid as long as we hold the ref. When we are done
872 // updating our cache of the GrGlyph*s, we drop our ref on the old strike
Herb Derby73630212019-12-13 16:29:14 -0500873 fActions.regenTextureCoordinates = fSubRun->strike()->isAbandoned();
874 fActions.regenStrike = fSubRun->strike()->isAbandoned();
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500875
876 fSubRun->updateVerticesColorIfNeeded(color);
877 fSubRun->translateVerticesIfNeeded(drawMatrix, drawOrigin);
Herb Derbya9047642019-12-06 12:12:11 -0500878}
879
Herb Derby73630212019-12-13 16:29:14 -0500880bool GrTextBlob::VertexRegenerator::doRegen(GrTextBlob::VertexRegenerator::Result* result) {
881 SkASSERT(!fActions.regenStrike || fActions.regenTextureCoordinates);
882 if (fActions.regenTextureCoordinates) {
Herb Derbya9047642019-12-06 12:12:11 -0500883 fSubRun->resetBulkUseToken();
884
885 const SkStrikeSpec& strikeSpec = fSubRun->strikeSpec();
886
887 if (!fMetricsAndImages.isValid()
888 || fMetricsAndImages->descriptor() != strikeSpec.descriptor()) {
889 fMetricsAndImages.init(strikeSpec);
890 }
891
Herb Derby73630212019-12-13 16:29:14 -0500892 if (fActions.regenStrike) {
Herb Derbya9047642019-12-06 12:12:11 -0500893 // Take the glyphs from the old strike, and translate them a new strike.
894 sk_sp<GrTextStrike> newStrike = strikeSpec.findOrCreateGrStrike(fGrStrikeCache);
895
896 // Start this batch at the start of the subRun plus any glyphs that were previously
897 // processed.
Herb Derbyc514e7d2019-12-11 17:00:31 -0500898 SkSpan<GrGlyph*> glyphs = fSubRun->fGlyphs.last(fSubRun->fGlyphs.size() - fCurrGlyph);
Herb Derbya9047642019-12-06 12:12:11 -0500899
900 // Convert old glyphs to newStrike.
901 for (auto& glyph : glyphs) {
902 SkPackedGlyphID id = glyph->fPackedID;
903 glyph = newStrike->getGlyph(id, fMetricsAndImages.get());
904 SkASSERT(id == glyph->fPackedID);
905 }
906
907 fSubRun->setStrike(newStrike);
908 }
909 }
910
Herb Derby7cf4a2e2019-12-23 14:51:55 -0500911 GrTextStrike* grStrike = fSubRun->strike();
Herb Derbya2d72252019-12-23 15:02:33 -0500912 auto vertexStride = fSubRun->vertexStride();
Herb Derbyc514e7d2019-12-11 17:00:31 -0500913 char* currVertex = fSubRun->fVertexData.data() + fCurrGlyph * kVerticesPerGlyph * vertexStride;
Herb Derbya9047642019-12-06 12:12:11 -0500914 result->fFirstVertex = currVertex;
915
Herb Derbyc514e7d2019-12-11 17:00:31 -0500916 for (int glyphIdx = fCurrGlyph; glyphIdx < (int)fSubRun->fGlyphs.size(); glyphIdx++) {
Herb Derbya9047642019-12-06 12:12:11 -0500917 GrGlyph* glyph = nullptr;
Herb Derby73630212019-12-13 16:29:14 -0500918 if (fActions.regenTextureCoordinates) {
Herb Derbyc514e7d2019-12-11 17:00:31 -0500919 glyph = fSubRun->fGlyphs[glyphIdx];
Herb Derbya9047642019-12-06 12:12:11 -0500920 SkASSERT(glyph && glyph->fMaskFormat == fSubRun->maskFormat());
921
922 if (!fFullAtlasManager->hasGlyph(glyph)) {
Herb Derby7cf4a2e2019-12-23 14:51:55 -0500923 GrDrawOpAtlas::ErrorCode code = grStrike->addGlyphToAtlas(
924 fResourceProvider, fUploadTarget, fGrStrikeCache, fFullAtlasManager, glyph,
925 fMetricsAndImages.get(), fSubRun->maskFormat(), fSubRun->needsTransform());
Herb Derbya9047642019-12-06 12:12:11 -0500926 if (GrDrawOpAtlas::ErrorCode::kError == code) {
927 // Something horrible has happened - drop the op
928 return false;
929 }
930 else if (GrDrawOpAtlas::ErrorCode::kTryAgain == code) {
931 fBrokenRun = glyphIdx > 0;
932 result->fFinished = false;
933 return true;
934 }
935 }
936 auto tokenTracker = fUploadTarget->tokenTracker();
937 fFullAtlasManager->addGlyphToBulkAndSetUseToken(fSubRun->bulkUseToken(), glyph,
938 tokenTracker->nextDrawToken());
939 }
940
Herb Derby73630212019-12-13 16:29:14 -0500941 if (fActions.regenTextureCoordinates) {
Herb Derbya56a1d72019-12-27 12:12:47 -0500942 fSubRun->updateTexCoord(glyphIdx);
Herb Derbya9047642019-12-06 12:12:11 -0500943 }
944
945 currVertex += vertexStride * GrAtlasTextOp::kVerticesPerGlyph;
946 ++result->fGlyphsRegenerated;
947 ++fCurrGlyph;
948 }
949
Herb Derby73630212019-12-13 16:29:14 -0500950 if (fActions.regenTextureCoordinates) {
Herb Derbya9047642019-12-06 12:12:11 -0500951 fSubRun->setAtlasGeneration(fBrokenRun
952 ? GrDrawOpAtlas::kInvalidAtlasGeneration
953 : fFullAtlasManager->atlasGeneration(fSubRun->maskFormat()));
954 } else {
955 // For the non-texCoords case we need to ensure that we update the associated use tokens
956 fFullAtlasManager->setUseTokenBulk(*fSubRun->bulkUseToken(),
957 fUploadTarget->tokenTracker()->nextDrawToken(),
958 fSubRun->maskFormat());
959 }
960 return true;
961}
962
963bool GrTextBlob::VertexRegenerator::regenerate(GrTextBlob::VertexRegenerator::Result* result) {
964 uint64_t currentAtlasGen = fFullAtlasManager->atlasGeneration(fSubRun->maskFormat());
965 // If regenerate() is called multiple times then the atlas gen may have changed. So we check
966 // this each time.
Herb Derby73630212019-12-13 16:29:14 -0500967 fActions.regenTextureCoordinates |= fSubRun->atlasGeneration() != currentAtlasGen;
Herb Derbya9047642019-12-06 12:12:11 -0500968
Herb Derby73630212019-12-13 16:29:14 -0500969 if (fActions.regenStrike
Herb Derby6ca4f312019-12-26 15:23:49 -0500970 |fActions.regenTextureCoordinates) {
Herb Derby73630212019-12-13 16:29:14 -0500971 return this->doRegen(result);
Herb Derbya9047642019-12-06 12:12:11 -0500972 } else {
Herb Derbya2d72252019-12-23 15:02:33 -0500973 auto vertexStride = fSubRun->vertexStride();
Herb Derbya9047642019-12-06 12:12:11 -0500974 result->fFinished = true;
Herb Derbyc514e7d2019-12-11 17:00:31 -0500975 result->fGlyphsRegenerated = fSubRun->fGlyphs.size() - fCurrGlyph;
976 result->fFirstVertex = fSubRun->fVertexData.data() +
977 fCurrGlyph * kVerticesPerGlyph * vertexStride;
978 fCurrGlyph = fSubRun->fGlyphs.size();
Herb Derbya9047642019-12-06 12:12:11 -0500979
980 // set use tokens for all of the glyphs in our subrun. This is only valid if we
981 // have a valid atlas generation
982 fFullAtlasManager->setUseTokenBulk(*fSubRun->bulkUseToken(),
983 fUploadTarget->tokenTracker()->nextDrawToken(),
984 fSubRun->maskFormat());
985 return true;
986 }
987 SK_ABORT("Should not get here");
988}
989
990
991
992