blob: c5f8797e3e4f2841527fe7ec1c850ec9ffbe7f79 [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 ---------------------------------------------------------------------------
46GrTextBlob::SubRun::SubRun(SubRunType type, GrTextBlob* textBlob, const SkStrikeSpec& strikeSpec,
Herb Derbyc514e7d2019-12-11 17:00:31 -050047 GrMaskFormat format,
48 const SkSpan<GrGlyph*>& glyphs, const SkSpan<char>& vertexData,
Herb Derbya9047642019-12-06 12:12:11 -050049 sk_sp<GrTextStrike>&& grStrike)
50 : fType{type}
51 , fBlob{textBlob}
52 , fMaskFormat{format}
Herb Derbyc514e7d2019-12-11 17:00:31 -050053 , fGlyphs{glyphs}
54 , fVertexData{vertexData}
Herb Derbya9047642019-12-06 12:12:11 -050055 , fStrikeSpec{strikeSpec}
56 , fStrike{grStrike}
Herb Derbydf2c1ee2019-12-26 17:54:41 -050057 , fCurrentColor{textBlob->fColor}
Herb Derby5bf5b042019-12-12 16:37:03 -050058 , fCurrentOrigin{textBlob->fInitialOrigin}
Herb Derby1c5be7b2019-12-13 12:03:06 -050059 , fCurrentMatrix{textBlob->fInitialMatrix} {
Herb Derbya9047642019-12-06 12:12:11 -050060 SkASSERT(type != kTransformedPath);
Herb Derbycb718892019-12-07 00:07:42 -050061 textBlob->insertSubRun(this);
Herb Derbya9047642019-12-06 12:12:11 -050062}
63
64GrTextBlob::SubRun::SubRun(GrTextBlob* textBlob, const SkStrikeSpec& strikeSpec)
65 : fType{kTransformedPath}
66 , fBlob{textBlob}
67 , fMaskFormat{kA8_GrMaskFormat}
Herb Derbyc514e7d2019-12-11 17:00:31 -050068 , fGlyphs{SkSpan<GrGlyph*>{}}
69 , fVertexData{SkSpan<char>{}}
Herb Derbya9047642019-12-06 12:12:11 -050070 , fStrikeSpec{strikeSpec}
71 , fStrike{nullptr}
Herb Derbydf2c1ee2019-12-26 17:54:41 -050072 , fCurrentColor{textBlob->fColor}
Herb Derbycb718892019-12-07 00:07:42 -050073 , fPaths{} {
74 textBlob->insertSubRun(this);
75}
Herb Derbya9047642019-12-06 12:12:11 -050076
77void GrTextBlob::SubRun::appendGlyphs(const SkZip<SkGlyphVariant, SkPoint>& drawables) {
78 GrTextStrike* grStrike = fStrike.get();
79 SkScalar strikeToSource = fStrikeSpec.strikeToSourceRatio();
Herb Derbyc514e7d2019-12-11 17:00:31 -050080 GrGlyph** glyphCursor = fGlyphs.data();
81 char* vertexCursor = fVertexData.data();
Herb Derbya2d72252019-12-23 15:02:33 -050082 size_t vertexStride = this->vertexStride();
Herb Derbya9047642019-12-06 12:12:11 -050083 // We always write the third position component used by SDFs. If it is unused it gets
84 // overwritten. Similarly, we always write the color and the blob will later overwrite it
85 // with texture coords if it is unused.
Herb Derby3d3150c2019-12-23 15:26:44 -050086 size_t colorOffset = this->colorOffset();
Herb Derbya9047642019-12-06 12:12:11 -050087 for (auto [variant, pos] : drawables) {
88 SkGlyph* skGlyph = variant;
89 GrGlyph* grGlyph = grStrike->getGlyph(*skGlyph);
90 // Only floor the device coordinates.
91 SkRect dstRect;
92 if (!this->needsTransform()) {
93 pos = {SkScalarFloorToScalar(pos.x()), SkScalarFloorToScalar(pos.y())};
94 dstRect = grGlyph->destRect(pos);
95 } else {
96 dstRect = grGlyph->destRect(pos, strikeToSource);
97 }
98
99 this->joinGlyphBounds(dstRect);
100
Herb Derbya9047642019-12-06 12:12:11 -0500101 // V0
Herb Derbyc514e7d2019-12-11 17:00:31 -0500102 *reinterpret_cast<SkPoint3*>(vertexCursor) = {dstRect.fLeft, dstRect.fTop, 1.f};
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500103 *reinterpret_cast<GrColor*>(vertexCursor + colorOffset) = fCurrentColor;
Herb Derbyc514e7d2019-12-11 17:00:31 -0500104 vertexCursor += vertexStride;
Herb Derbya9047642019-12-06 12:12:11 -0500105
106 // V1
Herb Derbyc514e7d2019-12-11 17:00:31 -0500107 *reinterpret_cast<SkPoint3*>(vertexCursor) = {dstRect.fLeft, dstRect.fBottom, 1.f};
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500108 *reinterpret_cast<GrColor*>(vertexCursor + colorOffset) = fCurrentColor;
Herb Derbyc514e7d2019-12-11 17:00:31 -0500109 vertexCursor += vertexStride;
Herb Derbya9047642019-12-06 12:12:11 -0500110
111 // V2
Herb Derbyc514e7d2019-12-11 17:00:31 -0500112 *reinterpret_cast<SkPoint3*>(vertexCursor) = {dstRect.fRight, dstRect.fTop, 1.f};
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500113 *reinterpret_cast<GrColor*>(vertexCursor + colorOffset) = fCurrentColor;
Herb Derbyc514e7d2019-12-11 17:00:31 -0500114 vertexCursor += vertexStride;
Herb Derbya9047642019-12-06 12:12:11 -0500115
116 // V3
Herb Derbyc514e7d2019-12-11 17:00:31 -0500117 *reinterpret_cast<SkPoint3*>(vertexCursor) = {dstRect.fRight, dstRect.fBottom, 1.f};
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500118 *reinterpret_cast<GrColor*>(vertexCursor + colorOffset) = fCurrentColor;
Herb Derbyc514e7d2019-12-11 17:00:31 -0500119 vertexCursor += vertexStride;
Herb Derbya9047642019-12-06 12:12:11 -0500120
Herb Derbyc514e7d2019-12-11 17:00:31 -0500121 *glyphCursor++ = grGlyph;
Herb Derbya9047642019-12-06 12:12:11 -0500122 }
Herb Derbya9047642019-12-06 12:12:11 -0500123}
124
125void GrTextBlob::SubRun::resetBulkUseToken() { fBulkUseToken.reset(); }
126
127GrDrawOpAtlas::BulkUseTokenUpdater* GrTextBlob::SubRun::bulkUseToken() { return &fBulkUseToken; }
128void GrTextBlob::SubRun::setStrike(sk_sp<GrTextStrike> strike) { fStrike = std::move(strike); }
129GrTextStrike* GrTextBlob::SubRun::strike() const { return fStrike.get(); }
Herb Derbya9047642019-12-06 12:12:11 -0500130GrMaskFormat GrTextBlob::SubRun::maskFormat() const { return fMaskFormat; }
Herb Derbya2d72252019-12-23 15:02:33 -0500131size_t GrTextBlob::SubRun::vertexStride() const {
132 return GetVertexStride(this->maskFormat(), this->hasW());
133}
Herb Derby3d3150c2019-12-23 15:26:44 -0500134size_t GrTextBlob::SubRun::colorOffset() const {
135 return this->hasW() ? offsetof(SDFT3DVertex, color) : offsetof(Mask2DVertex, color);
136}
Herb Derbya56a1d72019-12-27 12:12:47 -0500137
138size_t GrTextBlob::SubRun::texCoordOffset() const {
139 switch (fMaskFormat) {
140 case kA8_GrMaskFormat:
141 return this->hasW() ? offsetof(SDFT3DVertex, atlasPos)
142 : offsetof(Mask2DVertex, atlasPos);
143 case kARGB_GrMaskFormat:
144 return this->hasW() ? offsetof(ARGB3DVertex, atlasPos)
145 : offsetof(ARGB2DVertex, atlasPos);
146 default:
147 SkASSERT(!this->hasW());
148 return offsetof(Mask2DVertex, atlasPos);
149 }
150}
151
Herb Derby91fd46a2019-12-26 11:36:30 -0500152char* GrTextBlob::SubRun::quadStart(size_t index) const {
Herb Derby23f29762020-01-10 16:26:14 -0500153 return SkTAddOffset<char>(fVertexData.data(), this->quadOffset(index));
154}
155
156size_t GrTextBlob::SubRun::quadOffset(size_t index) const {
157 return index * kVerticesPerGlyph * this->vertexStride();
Herb Derby91fd46a2019-12-26 11:36:30 -0500158}
Herb Derbya2d72252019-12-23 15:02:33 -0500159
Herb Derbya9047642019-12-06 12:12:11 -0500160const SkRect& GrTextBlob::SubRun::vertexBounds() const { return fVertexBounds; }
161void GrTextBlob::SubRun::joinGlyphBounds(const SkRect& glyphBounds) {
162 fVertexBounds.joinNonEmptyArg(glyphBounds);
163}
164
Herb Derbya9047642019-12-06 12:12:11 -0500165bool GrTextBlob::SubRun::drawAsDistanceFields() const { return fType == kTransformedSDFT; }
166
167bool GrTextBlob::SubRun::drawAsPaths() const { return fType == kTransformedPath; }
168
169bool GrTextBlob::SubRun::needsTransform() const {
170 return fType == kTransformedPath
171 || fType == kTransformedMask
172 || fType == kTransformedSDFT;
173}
174
175bool GrTextBlob::SubRun::hasW() const {
176 return fBlob->hasW(fType);
177}
178
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500179void GrTextBlob::SubRun::translateVerticesIfNeeded(
180 const SkMatrix& drawMatrix, SkPoint drawOrigin) {
181 SkVector translation;
182 if (this->needsTransform()) {
183 // If transform is needed, then the vertices are in source space, calculate the source
184 // space translation.
185 translation = drawOrigin - fCurrentOrigin;
186 } else {
187 // Calculate the translation in source space to a translation in device space. Calculate
188 // the translation by mapping (0, 0) through both the current matrix, and the draw
189 // matrix, and taking the difference.
190 SkMatrix currentMatrix{fCurrentMatrix};
191 currentMatrix.preTranslate(fCurrentOrigin.x(), fCurrentOrigin.y());
192 SkPoint currentDeviceOrigin{0, 0};
193 currentMatrix.mapPoints(&currentDeviceOrigin, 1);
194 SkMatrix completeDrawMatrix{drawMatrix};
195 completeDrawMatrix.preTranslate(drawOrigin.x(), drawOrigin.y());
196 SkPoint drawDeviceOrigin{0, 0};
197 completeDrawMatrix.mapPoints(&drawDeviceOrigin, 1);
198 translation = drawDeviceOrigin - currentDeviceOrigin;
199 }
200
201 if (translation != SkPoint{0, 0}) {
202 size_t vertexStride = this->vertexStride();
203 for (size_t quad = 0; quad < fGlyphs.size(); quad++) {
204 SkPoint* vertexCursor = reinterpret_cast<SkPoint*>(quadStart(quad));
205 for (int i = 0; i < 4; ++i) {
206 *vertexCursor += translation;
207 vertexCursor = SkTAddOffset<SkPoint>(vertexCursor, vertexStride);
208 }
Herb Derby91fd46a2019-12-26 11:36:30 -0500209 }
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500210 fCurrentMatrix = drawMatrix;
211 fCurrentOrigin = drawOrigin;
Herb Derby91fd46a2019-12-26 11:36:30 -0500212 }
213}
214
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500215void GrTextBlob::SubRun::updateVerticesColorIfNeeded(GrColor newColor) {
216 if (this->maskFormat() != kARGB_GrMaskFormat && fCurrentColor != newColor) {
217 size_t vertexStride = this->vertexStride();
218 size_t colorOffset = this->colorOffset();
219 for (size_t quad = 0; quad < fGlyphs.size(); quad++) {
220 GrColor* colorCursor = SkTAddOffset<GrColor>(quadStart(quad), colorOffset);
221 for (int i = 0; i < 4; ++i) {
222 *colorCursor = newColor;
223 colorCursor = SkTAddOffset<GrColor>(colorCursor, vertexStride);
224 }
Herb Derby6ca4f312019-12-26 15:23:49 -0500225 }
Herb Derbydf2c1ee2019-12-26 17:54:41 -0500226 this->fCurrentColor = newColor;
Herb Derby6ca4f312019-12-26 15:23:49 -0500227 }
Herb Derby6ca4f312019-12-26 15:23:49 -0500228}
229
Herb Derbybc131b82020-01-07 16:07:42 -0500230void GrTextBlob::SubRun::updateTexCoords(int begin, int end) {
231 const size_t vertexStride = this->vertexStride();
232 const size_t texCoordOffset = this->texCoordOffset();
233 char* vertex = this->quadStart(begin);
Jim Van Verth2f2c77a2020-01-24 15:48:23 +0000234 uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
Herb Derbybc131b82020-01-07 16:07:42 -0500235 for (int i = begin; i < end; i++) {
236 GrGlyph* glyph = this->fGlyphs[i];
237 SkASSERT(glyph != nullptr);
238
239 int width = glyph->fBounds.width();
240 int height = glyph->fBounds.height();
Jim Van Verth2f2c77a2020-01-24 15:48:23 +0000241 uint16_t u0, v0, u1, v1;
Herb Derbybc131b82020-01-07 16:07:42 -0500242 if (this->drawAsDistanceFields()) {
243 u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset;
244 v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset;
245 u1 = u0 + width - 2 * SK_DistanceFieldInset;
246 v1 = v0 + height - 2 * SK_DistanceFieldInset;
247 } else {
248 u0 = glyph->fAtlasLocation.fX;
249 v0 = glyph->fAtlasLocation.fY;
250 u1 = u0 + width;
251 v1 = v0 + height;
252 }
253
Jim Van Verth2f2c77a2020-01-24 15:48:23 +0000254 // We pack the 2bit page index in the low bit of the u and v texture coords
Herb Derbybc131b82020-01-07 16:07:42 -0500255 uint32_t pageIndex = glyph->pageIndex();
Jim Van Verth2f2c77a2020-01-24 15:48:23 +0000256 SkASSERT(pageIndex < 4);
257 uint16_t uBit = (pageIndex >> 1u) & 0x1u;
258 uint16_t vBit = pageIndex & 0x1u;
259 u0 <<= 1u;
260 u0 |= uBit;
261 v0 <<= 1u;
262 v0 |= vBit;
263 u1 <<= 1u;
264 u1 |= uBit;
265 v1 <<= 1u;
266 v1 |= vBit;
Herb Derbybc131b82020-01-07 16:07:42 -0500267
268 textureCoords[0] = u0;
269 textureCoords[1] = v0;
Jim Van Verth2f2c77a2020-01-24 15:48:23 +0000270 textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
Herb Derbybc131b82020-01-07 16:07:42 -0500271 textureCoords[0] = u0;
272 textureCoords[1] = v1;
Jim Van Verth2f2c77a2020-01-24 15:48:23 +0000273 textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
Herb Derbybc131b82020-01-07 16:07:42 -0500274 textureCoords[0] = u1;
275 textureCoords[1] = v0;
Jim Van Verth2f2c77a2020-01-24 15:48:23 +0000276 textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
Herb Derbybc131b82020-01-07 16:07:42 -0500277 textureCoords[0] = u1;
278 textureCoords[1] = v1;
Jim Van Verth2f2c77a2020-01-24 15:48:23 +0000279 textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
Herb Derbybc131b82020-01-07 16:07:42 -0500280 }
Herb Derbya56a1d72019-12-27 12:12:47 -0500281}
282
Herb Derbya8fa4902020-01-16 15:41:54 -0500283// GrStrikeCache may evict the strike a blob needs to generate texture coordinates.
284// If our strike has been abandoned in this way, we'll translate all our old glyphs
285// over to a new strike and carry on with that.
286void GrTextBlob::SubRun::updateStrikeIfNeeded(SkBulkGlyphMetricsAndImages* metricsAndImages,
287 GrStrikeCache* cache) {
288 if (this->strike()->isAbandoned()) {
289 sk_sp<GrTextStrike> newStrike = this->strikeSpec().findOrCreateGrStrike(cache);
290
291 // Take the glyphs from the old strike, and translate them a new strike.
292 for (size_t i = 0; i < fGlyphs.size(); i++) {
293 fGlyphs[i] = newStrike->getGlyph(fGlyphs[i]->fPackedID, metricsAndImages);
294 }
295
296 this->setStrike(newStrike);
297 }
298}
299
Herb Derbya9047642019-12-06 12:12:11 -0500300void GrTextBlob::SubRun::setUseLCDText(bool useLCDText) { fFlags.useLCDText = useLCDText; }
301bool GrTextBlob::SubRun::hasUseLCDText() const { return fFlags.useLCDText; }
302void GrTextBlob::SubRun::setAntiAliased(bool antiAliased) { fFlags.antiAliased = antiAliased; }
303bool GrTextBlob::SubRun::isAntiAliased() const { return fFlags.antiAliased; }
304const SkStrikeSpec& GrTextBlob::SubRun::strikeSpec() const { return fStrikeSpec; }
305
306// -- GrTextBlob -----------------------------------------------------------------------------------
307void GrTextBlob::operator delete(void* p) { ::operator delete(p); }
308void* GrTextBlob::operator new(size_t) { SK_ABORT("All blobs are created by placement new."); }
309void* GrTextBlob::operator new(size_t, void* p) { return p; }
310
311GrTextBlob::~GrTextBlob() = default;
312
Herb Derby659e4092019-12-06 15:38:10 -0500313sk_sp<GrTextBlob> GrTextBlob::Make(const SkGlyphRunList& glyphRunList,
Herb Derbyeba195f2019-12-03 16:44:47 -0500314 GrStrikeCache* strikeCache,
Herb Derby1c5be7b2019-12-13 12:03:06 -0500315 const SkMatrix& drawMatrix,
Herb Derbya00da612019-03-04 17:10:01 -0500316 GrColor color,
Herb Derbyeba195f2019-12-03 16:44:47 -0500317 bool forceWForDistanceFields) {
Herb Derbycd498e12019-12-06 14:17:31 -0500318
Herb Derby3d1a3bb2019-12-06 18:15:49 -0500319 static_assert(sizeof(ARGB2DVertex) <= sizeof(Mask2DVertex));
Herb Derbycb718892019-12-07 00:07:42 -0500320 static_assert(alignof(ARGB2DVertex) <= alignof(Mask2DVertex));
321 size_t quadSize = sizeof(Mask2DVertex) * kVerticesPerGlyph;
Herb Derby1c5be7b2019-12-13 12:03:06 -0500322 if (drawMatrix.hasPerspective() || forceWForDistanceFields) {
Herb Derby3d1a3bb2019-12-06 18:15:49 -0500323 static_assert(sizeof(ARGB3DVertex) <= sizeof(SDFT3DVertex));
Herb Derbycb718892019-12-07 00:07:42 -0500324 static_assert(alignof(ARGB3DVertex) <= alignof(SDFT3DVertex));
325 quadSize = sizeof(SDFT3DVertex) * kVerticesPerGlyph;
Herb Derbye74c7762019-12-04 14:15:41 -0500326 }
327
Herb Derbycb718892019-12-07 00:07:42 -0500328 // We can use the alignment of SDFT3DVertex as a proxy for all Vertex alignments.
329 static_assert(alignof(SDFT3DVertex) >= alignof(Mask2DVertex));
Herb Derbyc514e7d2019-12-11 17:00:31 -0500330 // Assume there is no padding needed between glyph pointers and vertices.
Herb Derbycb718892019-12-07 00:07:42 -0500331 static_assert(alignof(GrGlyph*) >= alignof(SDFT3DVertex));
Herb Derbyc514e7d2019-12-11 17:00:31 -0500332
333 // In the arena, the layout is GrGlyph*... | SDFT3DVertex... | SubRun, so there is no padding
334 // between GrGlyph* and SDFT3DVertex, but padding is needed between the Mask2DVertex array
335 // and the SubRun.
336 size_t vertexToSubRunPadding = alignof(SDFT3DVertex) - alignof(SubRun);
337 size_t arenaSize =
338 sizeof(GrGlyph*) * glyphRunList.totalGlyphCount()
339 + quadSize * glyphRunList.totalGlyphCount()
340 + glyphRunList.runCount() * (sizeof(SubRun) + vertexToSubRunPadding);
341
342 size_t allocationSize = sizeof(GrTextBlob) + arenaSize;
Ben Wagner75d6db72018-09-20 14:39:39 -0400343
Herb Derbycb718892019-12-07 00:07:42 -0500344 void* allocation = ::operator new (allocationSize);
Herb Derbyb12175f2018-05-23 16:38:09 -0400345
Herb Derbyaebc5f82019-12-10 14:07:10 -0500346 SkColor initialLuminance = SkPaintPriv::ComputeLuminanceColor(glyphRunList.paint());
Herb Derby00ae9592019-12-03 15:55:56 -0500347 sk_sp<GrTextBlob> blob{new (allocation) GrTextBlob{
Herb Derby1c5be7b2019-12-13 12:03:06 -0500348 arenaSize, strikeCache, drawMatrix, glyphRunList.origin(),
Herb Derbyaebc5f82019-12-10 14:07:10 -0500349 color, initialLuminance, forceWForDistanceFields}};
joshualitt92303772016-02-10 11:55:52 -0800350
Herb Derbyf7d5d742018-11-16 13:24:32 -0500351 return blob;
joshualitt92303772016-02-10 11:55:52 -0800352}
353
Herb Derbya9047642019-12-06 12:12:11 -0500354void GrTextBlob::setupKey(const GrTextBlob::Key& key, const SkMaskFilterBase::BlurRec& blurRec,
355 const SkPaint& paint) {
356 fKey = key;
357 if (key.fHasBlur) {
358 fBlurRec = blurRec;
359 }
360 if (key.fStyle != SkPaint::kFill_Style) {
361 fStrokeInfo.fFrameWidth = paint.getStrokeWidth();
362 fStrokeInfo.fMiterLimit = paint.getStrokeMiter();
363 fStrokeInfo.fJoin = paint.getStrokeJoin();
364 }
365}
366const GrTextBlob::Key& GrTextBlob::GetKey(const GrTextBlob& blob) { return blob.fKey; }
367uint32_t GrTextBlob::Hash(const GrTextBlob::Key& key) { return SkOpts::hash(&key, sizeof(Key)); }
368
Herb Derbycb718892019-12-07 00:07:42 -0500369bool GrTextBlob::hasDistanceField() const {
370 return SkToBool(fTextType & kHasDistanceField_TextType);
371}
Herb Derbya9047642019-12-06 12:12:11 -0500372bool GrTextBlob::hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); }
Herb Derby1c5be7b2019-12-13 12:03:06 -0500373bool GrTextBlob::hasPerspective() const { return fInitialMatrix.hasPerspective(); }
Herb Derbya9047642019-12-06 12:12:11 -0500374
375void GrTextBlob::setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
376void GrTextBlob::setHasBitmap() { fTextType |= kHasBitmap_TextType; }
377void GrTextBlob::setMinAndMaxScale(SkScalar scaledMin, SkScalar scaledMax) {
378 // we init fMaxMinScale and fMinMaxScale in the constructor
379 fMaxMinScale = SkMaxScalar(scaledMin, fMaxMinScale);
380 fMinMaxScale = SkMinScalar(scaledMax, fMinMaxScale);
381}
382
383size_t GrTextBlob::GetVertexStride(GrMaskFormat maskFormat, bool hasWCoord) {
384 switch (maskFormat) {
385 case kA8_GrMaskFormat:
Herb Derbycd498e12019-12-06 14:17:31 -0500386 return hasWCoord ? sizeof(SDFT3DVertex) : sizeof(Mask2DVertex);
Herb Derbya9047642019-12-06 12:12:11 -0500387 case kARGB_GrMaskFormat:
Herb Derbycd498e12019-12-06 14:17:31 -0500388 return hasWCoord ? sizeof(ARGB3DVertex) : sizeof(ARGB2DVertex);
Herb Derbya9047642019-12-06 12:12:11 -0500389 default:
390 SkASSERT(!hasWCoord);
Herb Derbycd498e12019-12-06 14:17:31 -0500391 return sizeof(Mask2DVertex);
Herb Derbya9047642019-12-06 12:12:11 -0500392 }
393}
394
Herb Derby0edb2142018-10-16 17:04:11 -0400395bool GrTextBlob::mustRegenerate(const SkPaint& paint, bool anyRunHasSubpixelPosition,
396 const SkMaskFilterBase::BlurRec& blurRec,
Herb Derby5bf5b042019-12-12 16:37:03 -0500397 const SkMatrix& drawMatrix, SkPoint drawOrigin) {
joshualittfd5f6c12015-12-10 07:44:50 -0800398 // If we have LCD text then our canonical color will be set to transparent, in this case we have
399 // to regenerate the blob on any color change
400 // We use the grPaint to get any color filter effects
401 if (fKey.fCanonicalColor == SK_ColorTRANSPARENT &&
Herb Derbyaebc5f82019-12-10 14:07:10 -0500402 fInitialLuminance != SkPaintPriv::ComputeLuminanceColor(paint)) {
joshualittfd5f6c12015-12-10 07:44:50 -0800403 return true;
404 }
405
Herb Derby1c5be7b2019-12-13 12:03:06 -0500406 if (fInitialMatrix.hasPerspective() != drawMatrix.hasPerspective()) {
joshualittfd5f6c12015-12-10 07:44:50 -0800407 return true;
408 }
409
Brian Salomon5c6ac642017-12-19 11:09:32 -0500410 /** This could be relaxed for blobs with only distance field glyphs. */
Mike Reed2c383152019-12-18 16:47:47 -0500411 if (fInitialMatrix.hasPerspective() && !SkMatrixPriv::CheapEqual(fInitialMatrix, drawMatrix)) {
joshualittfd5f6c12015-12-10 07:44:50 -0800412 return true;
413 }
414
415 // We only cache one masked version
416 if (fKey.fHasBlur &&
Mike Reed1be1f8d2018-03-14 13:01:17 -0400417 (fBlurRec.fSigma != blurRec.fSigma || fBlurRec.fStyle != blurRec.fStyle)) {
joshualittfd5f6c12015-12-10 07:44:50 -0800418 return true;
419 }
420
421 // Similarly, we only cache one version for each style
422 if (fKey.fStyle != SkPaint::kFill_Style &&
Herb Derbybc6f9c92018-08-08 13:58:45 -0400423 (fStrokeInfo.fFrameWidth != paint.getStrokeWidth() ||
424 fStrokeInfo.fMiterLimit != paint.getStrokeMiter() ||
425 fStrokeInfo.fJoin != paint.getStrokeJoin())) {
joshualittfd5f6c12015-12-10 07:44:50 -0800426 return true;
427 }
428
429 // Mixed blobs must be regenerated. We could probably figure out a way to do integer scrolls
430 // for mixed blobs if this becomes an issue.
431 if (this->hasBitmap() && this->hasDistanceField()) {
Herb Derbyeba195f2019-12-03 16:44:47 -0500432 // Identical view matrices and we can reuse in all cases
Mike Reed2c383152019-12-18 16:47:47 -0500433 return !(SkMatrixPriv::CheapEqual(fInitialMatrix, drawMatrix) &&
434 drawOrigin == fInitialOrigin);
joshualittfd5f6c12015-12-10 07:44:50 -0800435 }
436
437 if (this->hasBitmap()) {
Herb Derby1c5be7b2019-12-13 12:03:06 -0500438 if (fInitialMatrix.getScaleX() != drawMatrix.getScaleX() ||
439 fInitialMatrix.getScaleY() != drawMatrix.getScaleY() ||
440 fInitialMatrix.getSkewX() != drawMatrix.getSkewX() ||
441 fInitialMatrix.getSkewY() != drawMatrix.getSkewY()) {
joshualittfd5f6c12015-12-10 07:44:50 -0800442 return true;
443 }
444
Herb Derby9830fc42019-09-12 10:58:26 -0400445 // TODO(herb): this is not needed for full pixel glyph choice, but is needed to adjust
446 // the quads properly. Devise a system that regenerates the quads from original data
447 // using the transform to allow this to be used in general.
448
449 // We can update the positions in the text blob without regenerating the whole
450 // blob, but only for integer translations.
Herb Derby435adfe2020-01-14 15:12:04 -0500451 // Calculate the translation in source space to a translation in device space by mapping
452 // (0, 0) through both the initial matrix and the draw matrix; take the difference.
453 SkMatrix initialMatrix{fInitialMatrix};
454 initialMatrix.preTranslate(fInitialOrigin.x(), fInitialOrigin.y());
455 SkPoint initialDeviceOrigin{0, 0};
456 initialMatrix.mapPoints(&initialDeviceOrigin, 1);
457 SkMatrix completeDrawMatrix{drawMatrix};
458 completeDrawMatrix.preTranslate(drawOrigin.x(), drawOrigin.y());
459 SkPoint drawDeviceOrigin{0, 0};
460 completeDrawMatrix.mapPoints(&drawDeviceOrigin, 1);
461 SkPoint translation = drawDeviceOrigin - initialDeviceOrigin;
462
463 if (!SkScalarIsInt(translation.x()) || !SkScalarIsInt(translation.y())) {
Herb Derby9830fc42019-09-12 10:58:26 -0400464 return true;
joshualittfd5f6c12015-12-10 07:44:50 -0800465 }
joshualittfd5f6c12015-12-10 07:44:50 -0800466 } else if (this->hasDistanceField()) {
467 // A scale outside of [blob.fMaxMinScale, blob.fMinMaxScale] would result in a different
468 // distance field being generated, so we have to regenerate in those cases
Herb Derby1c5be7b2019-12-13 12:03:06 -0500469 SkScalar newMaxScale = drawMatrix.getMaxScale();
470 SkScalar oldMaxScale = fInitialMatrix.getMaxScale();
joshualittfd5f6c12015-12-10 07:44:50 -0800471 SkScalar scaleAdjust = newMaxScale / oldMaxScale;
472 if (scaleAdjust < fMaxMinScale || scaleAdjust > fMinMaxScale) {
473 return true;
474 }
joshualittfd5f6c12015-12-10 07:44:50 -0800475 }
476
joshualittfd5f6c12015-12-10 07:44:50 -0800477 // It is possible that a blob has neither distanceField nor bitmaptext. This is in the case
478 // when all of the runs inside the blob are drawn as paths. In this case, we always regenerate
479 // the blob anyways at flush time, so no need to regenerate explicitly
480 return false;
481}
482
Herb Derbyc1b482c2018-08-09 15:02:27 -0400483void GrTextBlob::flush(GrTextTarget* target, const SkSurfaceProps& props,
484 const GrDistanceFieldAdjustTable* distanceAdjustTable,
Brian Osmancf860852018-10-31 14:04:39 -0400485 const SkPaint& paint, const SkPMColor4f& filteredColor, const GrClip& clip,
Herb Derby5bf5b042019-12-12 16:37:03 -0500486 const SkMatrix& drawMatrix, SkPoint drawOrigin) {
Jim Van Verth54d9c882018-02-08 16:14:48 -0500487
Herb Derbycb718892019-12-07 00:07:42 -0500488 for (SubRun* subRun = fFirstSubRun; subRun != nullptr; subRun = subRun->fNextSubRun) {
489 if (subRun->drawAsPaths()) {
Herb Derbydac1ed52018-09-12 17:04:21 -0400490 SkPaint runPaint{paint};
Herb Derbycb718892019-12-07 00:07:42 -0500491 runPaint.setAntiAlias(subRun->isAntiAliased());
Herb Derby1b8dcd12019-11-15 15:21:15 -0500492 // If there are shaders, blurs or styles, the path must be scaled into source
493 // space independently of the CTM. This allows the CTM to be correct for the
494 // different effects.
495 GrStyle style(runPaint);
Herb Derby9f491482018-08-08 11:53:00 -0400496
Herb Derby1b8dcd12019-11-15 15:21:15 -0500497 bool scalePath = runPaint.getShader()
498 || style.applies()
499 || runPaint.getMaskFilter();
Robert Phillips137ca522018-08-15 10:14:33 -0400500
Herb Derby1b8dcd12019-11-15 15:21:15 -0500501
Herb Derbycb718892019-12-07 00:07:42 -0500502 for (const auto& pathGlyph : subRun->fPaths) {
Herb Derby1c5be7b2019-12-13 12:03:06 -0500503 SkMatrix ctm{drawMatrix};
Herb Derby7b186102020-01-15 18:11:10 -0500504 ctm.preTranslate(drawOrigin.x(), drawOrigin.y());
Herb Derbycb718892019-12-07 00:07:42 -0500505 SkMatrix pathMatrix = SkMatrix::MakeScale(
506 subRun->fStrikeSpec.strikeToSourceRatio());
Herb Derby7b186102020-01-15 18:11:10 -0500507 pathMatrix.postTranslate(pathGlyph.fOrigin.x(), pathGlyph.fOrigin.y());
Herb Derbydac1ed52018-09-12 17:04:21 -0400508
509 // TmpPath must be in the same scope as GrShape shape below.
Robert Phillips137ca522018-08-15 10:14:33 -0400510 SkTLazy<SkPath> tmpPath;
Herb Derby1b8dcd12019-11-15 15:21:15 -0500511 const SkPath* path = &pathGlyph.fPath;
Herb Derby2984d262019-11-20 14:40:39 -0500512 if (!scalePath) {
513 // Scale can be applied to CTM -- no effects.
Herb Derby2984d262019-11-20 14:40:39 -0500514 ctm.preConcat(pathMatrix);
Robert Phillipsd20d2612018-08-28 10:09:01 -0400515 } else {
Herb Derby2984d262019-11-20 14:40:39 -0500516 // Scale the outline into source space.
Herb Derbydac1ed52018-09-12 17:04:21 -0400517
Herb Derby2984d262019-11-20 14:40:39 -0500518 // Transform the path form the normalized outline to source space. This
519 // way the CTM will remain the same so it can be used by the effects.
520 SkPath* sourceOutline = tmpPath.init();
521 path->transform(pathMatrix, sourceOutline);
522 sourceOutline->setIsVolatile(true);
523 path = sourceOutline;
Robert Phillips137ca522018-08-15 10:14:33 -0400524 }
525
Robert Phillips46a13382018-08-23 13:53:01 -0400526 // TODO: we are losing the mutability of the path here
527 GrShape shape(*path, paint);
Herb Derbydac1ed52018-09-12 17:04:21 -0400528 target->drawShape(clip, runPaint, ctm, shape);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500529 }
Herb Derby1b8dcd12019-11-15 15:21:15 -0500530 } else {
Herb Derbyc514e7d2019-12-11 17:00:31 -0500531 int glyphCount = subRun->fGlyphs.size();
Jim Van Verth54d9c882018-02-08 16:14:48 -0500532 if (0 == glyphCount) {
533 continue;
534 }
535
536 bool skipClip = false;
537 bool submitOp = true;
538 SkIRect clipRect = SkIRect::MakeEmpty();
539 SkRect rtBounds = SkRect::MakeWH(target->width(), target->height());
540 SkRRect clipRRect;
541 GrAA aa;
Jim Van Verthb515ae72018-05-23 16:44:55 -0400542 // We can clip geometrically if we're not using SDFs or transformed glyphs,
Jim Van Verth54d9c882018-02-08 16:14:48 -0500543 // and we have an axis-aligned rectangular non-AA clip
Herb Derbycb718892019-12-07 00:07:42 -0500544 if (!subRun->drawAsDistanceFields() && !subRun->needsTransform() &&
Jim Van Verthcf838c72018-03-05 14:40:36 -0500545 clip.isRRect(rtBounds, &clipRRect, &aa) &&
Jim Van Verth54d9c882018-02-08 16:14:48 -0500546 clipRRect.isRect() && GrAA::kNo == aa) {
547 skipClip = true;
548 // We only need to do clipping work if the subrun isn't contained by the clip
549 SkRect subRunBounds;
Herb Derby5bf5b042019-12-12 16:37:03 -0500550 this->computeSubRunBounds(
551 &subRunBounds, *subRun, drawMatrix, drawOrigin, false);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500552 if (!clipRRect.getBounds().contains(subRunBounds)) {
553 // If the subrun is completely outside, don't add an op for it
554 if (!clipRRect.getBounds().intersects(subRunBounds)) {
555 submitOp = false;
556 }
557 else {
558 clipRRect.getBounds().round(&clipRect);
559 }
560 }
561 }
562
563 if (submitOp) {
Herb Derby5bf5b042019-12-12 16:37:03 -0500564 auto op = this->makeOp(*subRun, glyphCount, drawMatrix, drawOrigin,
Herb Derbybc6f9c92018-08-08 13:58:45 -0400565 clipRect, paint, filteredColor, props, distanceAdjustTable,
Robert Phillips5a66efb2018-03-07 15:13:18 -0500566 target);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500567 if (op) {
568 if (skipClip) {
569 target->addDrawOp(GrNoClip(), std::move(op));
570 }
571 else {
572 target->addDrawOp(clip, std::move(op));
573 }
574 }
575 }
576 }
Jim Van Verth89737de2018-02-06 21:30:20 +0000577 }
Jim Van Verth89737de2018-02-06 21:30:20 +0000578}
579
Herb Derby1c5be7b2019-12-13 12:03:06 -0500580void GrTextBlob::computeSubRunBounds(SkRect* outBounds, const SubRun& subRun,
Herb Derby5bf5b042019-12-12 16:37:03 -0500581 const SkMatrix& drawMatrix, SkPoint drawOrigin,
Herb Derbya9047642019-12-06 12:12:11 -0500582 bool needsGlyphTransform) {
583 // We don't yet position distance field text on the cpu, so we have to map the vertex bounds
584 // into device space.
585 // We handle vertex bounds differently for distance field text and bitmap text because
586 // the vertex bounds of bitmap text are in device space. If we are flushing multiple runs
587 // from one blob then we are going to pay the price here of mapping the rect for each run.
588 *outBounds = subRun.vertexBounds();
589 if (needsGlyphTransform) {
590 // Distance field text is positioned with the (X,Y) as part of the glyph position,
591 // and currently the view matrix is applied on the GPU
Herb Derby5bf5b042019-12-12 16:37:03 -0500592 outBounds->offset(drawOrigin - fInitialOrigin);
Herb Derby1c5be7b2019-12-13 12:03:06 -0500593 drawMatrix.mapRect(outBounds);
Herb Derbya9047642019-12-06 12:12:11 -0500594 } else {
595 // Bitmap text is fully positioned on the CPU, and offset by an (X,Y) translate in
596 // device space.
Herb Derby1c5be7b2019-12-13 12:03:06 -0500597 SkMatrix boundsMatrix = fInitialMatrixInverse;
Herb Derbya9047642019-12-06 12:12:11 -0500598
599 boundsMatrix.postTranslate(-fInitialOrigin.x(), -fInitialOrigin.y());
600
Herb Derby5bf5b042019-12-12 16:37:03 -0500601 boundsMatrix.postTranslate(drawOrigin.x(), drawOrigin.y());
Herb Derbya9047642019-12-06 12:12:11 -0500602
Herb Derby1c5be7b2019-12-13 12:03:06 -0500603 boundsMatrix.postConcat(drawMatrix);
Herb Derbya9047642019-12-06 12:12:11 -0500604 boundsMatrix.mapRect(outBounds);
605
606 // Due to floating point numerical inaccuracies, we have to round out here
607 outBounds->roundOut(outBounds);
608 }
joshualitt323c2eb2016-01-20 06:48:47 -0800609}
joshualitt2e2202e2015-12-10 11:22:08 -0800610
Herb Derbya9047642019-12-06 12:12:11 -0500611const GrTextBlob::Key& GrTextBlob::key() const { return fKey; }
612size_t GrTextBlob::size() const { return fSize; }
613
614std::unique_ptr<GrDrawOp> GrTextBlob::test_makeOp(
Herb Derby1c5be7b2019-12-13 12:03:06 -0500615 int glyphCount, const SkMatrix& drawMatrix,
Herb Derby5bf5b042019-12-12 16:37:03 -0500616 SkPoint drawOrigin, const SkPaint& paint, const SkPMColor4f& filteredColor,
Herb Derbya9047642019-12-06 12:12:11 -0500617 const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable,
618 GrTextTarget* target) {
Herb Derbycb718892019-12-07 00:07:42 -0500619 SubRun* info = fFirstSubRun;
Herb Derbya9047642019-12-06 12:12:11 -0500620 SkIRect emptyRect = SkIRect::MakeEmpty();
Herb Derby5bf5b042019-12-12 16:37:03 -0500621 return this->makeOp(*info, glyphCount, drawMatrix, drawOrigin, emptyRect,
Herb Derbya9047642019-12-06 12:12:11 -0500622 paint, filteredColor, props, distanceAdjustTable, target);
623}
624
625bool GrTextBlob::hasW(GrTextBlob::SubRunType type) const {
626 if (type == kTransformedSDFT) {
627 return this->hasPerspective() || fForceWForDistanceFields;
628 } else if (type == kTransformedMask || type == kTransformedPath) {
629 return this->hasPerspective();
Herb Derbye9f691d2019-12-04 12:11:13 -0500630 }
Herb Derbya9047642019-12-06 12:12:11 -0500631
632 // The viewMatrix is implicitly SkMatrix::I when drawing kDirectMask, because it is not
633 // used.
634 return false;
635}
636
637GrTextBlob::SubRun* GrTextBlob::makeSubRun(SubRunType type,
638 const SkZip<SkGlyphVariant, SkPoint>& drawables,
639 const SkStrikeSpec& strikeSpec,
640 GrMaskFormat format) {
Herb Derbyc514e7d2019-12-11 17:00:31 -0500641 SkSpan<GrGlyph*> glyphs{fAlloc.makeArrayDefault<GrGlyph*>(drawables.size()), drawables.size()};
Herb Derbya9047642019-12-06 12:12:11 -0500642 bool hasW = this->hasW(type);
Herb Derby3d3150c2019-12-23 15:26:44 -0500643
644 SkASSERT(!fInitialMatrix.hasPerspective() || hasW);
645
Herb Derbyc514e7d2019-12-11 17:00:31 -0500646 size_t vertexDataSize = drawables.size() * GetVertexStride(format, hasW) * kVerticesPerGlyph;
647 SkSpan<char> vertexData{fAlloc.makeArrayDefault<char>(vertexDataSize), vertexDataSize};
Herb Derbya9047642019-12-06 12:12:11 -0500648
649 sk_sp<GrTextStrike> grStrike = strikeSpec.findOrCreateGrStrike(fStrikeCache);
650
Herb Derbycb718892019-12-07 00:07:42 -0500651 SubRun* subRun = fAlloc.make<SubRun>(
Herb Derbyc514e7d2019-12-11 17:00:31 -0500652 type, this, strikeSpec, format, glyphs, vertexData, std::move(grStrike));
Herb Derbya9047642019-12-06 12:12:11 -0500653
Herb Derbycb718892019-12-07 00:07:42 -0500654 subRun->appendGlyphs(drawables);
Herb Derbya9047642019-12-06 12:12:11 -0500655
Herb Derbycb718892019-12-07 00:07:42 -0500656 return subRun;
Herb Derbya9047642019-12-06 12:12:11 -0500657}
658
659void GrTextBlob::addSingleMaskFormat(
660 SubRunType type,
661 const SkZip<SkGlyphVariant, SkPoint>& drawables,
662 const SkStrikeSpec& strikeSpec,
663 GrMaskFormat format) {
664 this->makeSubRun(type, drawables, strikeSpec, format);
665}
666
667void GrTextBlob::addMultiMaskFormat(
668 SubRunType type,
669 const SkZip<SkGlyphVariant, SkPoint>& drawables,
670 const SkStrikeSpec& strikeSpec) {
671 this->setHasBitmap();
672 if (drawables.empty()) { return; }
673
674 auto glyphSpan = drawables.get<0>();
675 SkGlyph* glyph = glyphSpan[0];
676 GrMaskFormat format = GrGlyph::FormatFromSkGlyph(glyph->maskFormat());
677 size_t startIndex = 0;
678 for (size_t i = 1; i < drawables.size(); i++) {
679 glyph = glyphSpan[i];
680 GrMaskFormat nextFormat = GrGlyph::FormatFromSkGlyph(glyph->maskFormat());
681 if (format != nextFormat) {
682 auto sameFormat = drawables.subspan(startIndex, i - startIndex);
683 this->addSingleMaskFormat(type, sameFormat, strikeSpec, format);
684 format = nextFormat;
685 startIndex = i;
686 }
687 }
688 auto sameFormat = drawables.last(drawables.size() - startIndex);
689 this->addSingleMaskFormat(type, sameFormat, strikeSpec, format);
690}
691
692void GrTextBlob::addSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables,
693 const SkStrikeSpec& strikeSpec,
694 const SkFont& runFont,
695 SkScalar minScale,
696 SkScalar maxScale) {
697 this->setHasDistanceField();
698 this->setMinAndMaxScale(minScale, maxScale);
699
700 SubRun* subRun = this->makeSubRun(kTransformedSDFT, drawables, strikeSpec, kA8_GrMaskFormat);
701 subRun->setUseLCDText(runFont.getEdging() == SkFont::Edging::kSubpixelAntiAlias);
702 subRun->setAntiAliased(runFont.hasSomeAntiAliasing());
Herb Derbye9f691d2019-12-04 12:11:13 -0500703}
704
Herb Derbycb718892019-12-07 00:07:42 -0500705GrTextBlob::GrTextBlob(size_t allocSize,
Herb Derbyeba195f2019-12-03 16:44:47 -0500706 GrStrikeCache* strikeCache,
Herb Derby1c5be7b2019-12-13 12:03:06 -0500707 const SkMatrix& drawMatrix,
Herb Derbyeba195f2019-12-03 16:44:47 -0500708 SkPoint origin,
709 GrColor color,
Herb Derbyaebc5f82019-12-10 14:07:10 -0500710 SkColor initialLuminance,
Herb Derby00ae9592019-12-03 15:55:56 -0500711 bool forceWForDistanceFields)
Herb Derbycb718892019-12-07 00:07:42 -0500712 : fSize{allocSize}
Herb Derby00ae9592019-12-03 15:55:56 -0500713 , fStrikeCache{strikeCache}
Herb Derby1c5be7b2019-12-13 12:03:06 -0500714 , fInitialMatrix{drawMatrix}
715 , fInitialMatrixInverse{make_inverse(drawMatrix)}
Herb Derbyeba195f2019-12-03 16:44:47 -0500716 , fInitialOrigin{origin}
Herb Derby00ae9592019-12-03 15:55:56 -0500717 , fForceWForDistanceFields{forceWForDistanceFields}
Herb Derbycb718892019-12-07 00:07:42 -0500718 , fColor{color}
Herb Derbyaebc5f82019-12-10 14:07:10 -0500719 , fInitialLuminance{initialLuminance}
Herb Derbycb718892019-12-07 00:07:42 -0500720 , fAlloc{SkTAddOffset<char>(this, sizeof(GrTextBlob)), allocSize, allocSize/2} { }
Herb Derby00ae9592019-12-03 15:55:56 -0500721
Herb Derbycb718892019-12-07 00:07:42 -0500722void GrTextBlob::insertSubRun(SubRun* subRun) {
723 if (fFirstSubRun == nullptr) {
724 fFirstSubRun = subRun;
725 fLastSubRun = subRun;
726 } else {
727 fLastSubRun->fNextSubRun = subRun;
728 fLastSubRun = subRun;
729 }
730}
731
732std::unique_ptr<GrAtlasTextOp> GrTextBlob::makeOp(
Herb Derbya9047642019-12-06 12:12:11 -0500733 SubRun& info, int glyphCount,
Herb Derby5bf5b042019-12-12 16:37:03 -0500734 const SkMatrix& drawMatrix, SkPoint drawOrigin, const SkIRect& clipRect,
Herb Derbya9047642019-12-06 12:12:11 -0500735 const SkPaint& paint, const SkPMColor4f& filteredColor, const SkSurfaceProps& props,
736 const GrDistanceFieldAdjustTable* distanceAdjustTable, GrTextTarget* target) {
737 GrMaskFormat format = info.maskFormat();
738
739 GrPaint grPaint;
Herb Derby1c5be7b2019-12-13 12:03:06 -0500740 target->makeGrPaint(info.maskFormat(), paint, drawMatrix, &grPaint);
Herb Derbya9047642019-12-06 12:12:11 -0500741 std::unique_ptr<GrAtlasTextOp> op;
742 if (info.drawAsDistanceFields()) {
743 // TODO: Can we be even smarter based on the dest transfer function?
744 op = GrAtlasTextOp::MakeDistanceField(
745 target->getContext(), std::move(grPaint), glyphCount, distanceAdjustTable,
746 target->colorInfo().isLinearlyBlended(), SkPaintPriv::ComputeLuminanceColor(paint),
747 props, info.isAntiAliased(), info.hasUseLCDText());
Herb Derbyeba195f2019-12-03 16:44:47 -0500748 } else {
Herb Derbya9047642019-12-06 12:12:11 -0500749 op = GrAtlasTextOp::MakeBitmap(target->getContext(), std::move(grPaint), format, glyphCount,
750 info.needsTransform());
751 }
752 GrAtlasTextOp::Geometry& geometry = op->geometry();
Herb Derby1c5be7b2019-12-13 12:03:06 -0500753 geometry.fDrawMatrix = drawMatrix;
Herb Derbya9047642019-12-06 12:12:11 -0500754 geometry.fClipRect = clipRect;
755 geometry.fBlob = SkRef(this);
756 geometry.fSubRunPtr = &info;
757 geometry.fColor = info.maskFormat() == kARGB_GrMaskFormat ? SK_PMColor4fWHITE : filteredColor;
Herb Derby5bf5b042019-12-12 16:37:03 -0500758 geometry.fDrawOrigin = drawOrigin;
Herb Derbya9047642019-12-06 12:12:11 -0500759 op->init();
760 return op;
761}
Herb Derbyeba195f2019-12-03 16:44:47 -0500762
Herb Derbya9047642019-12-06 12:12:11 -0500763void GrTextBlob::processDeviceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
764 const SkStrikeSpec& strikeSpec) {
765 this->addMultiMaskFormat(kDirectMask, drawables, strikeSpec);
766}
Herb Derbyeba195f2019-12-03 16:44:47 -0500767
Herb Derbya9047642019-12-06 12:12:11 -0500768void GrTextBlob::processSourcePaths(const SkZip<SkGlyphVariant, SkPoint>& drawables,
769 const SkFont& runFont,
770 const SkStrikeSpec& strikeSpec) {
771 this->setHasBitmap();
Herb Derbycb718892019-12-07 00:07:42 -0500772 SubRun* subRun = fAlloc.make<SubRun>(this, strikeSpec);
773 subRun->setAntiAliased(runFont.hasSomeAntiAliasing());
Herb Derbya9047642019-12-06 12:12:11 -0500774 for (auto [variant, pos] : drawables) {
Herb Derbycb718892019-12-07 00:07:42 -0500775 subRun->fPaths.emplace_back(*variant.path(), pos);
Herb Derbyeba195f2019-12-03 16:44:47 -0500776 }
777}
778
Herb Derbya9047642019-12-06 12:12:11 -0500779void GrTextBlob::processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables,
780 const SkStrikeSpec& strikeSpec,
781 const SkFont& runFont,
782 SkScalar minScale,
783 SkScalar maxScale) {
784 this->addSDFT(drawables, strikeSpec, runFont, minScale, maxScale);
joshualitt8e0ef292016-02-19 14:13:03 -0800785}
Herb Derbya9047642019-12-06 12:12:11 -0500786
787void GrTextBlob::processSourceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
788 const SkStrikeSpec& strikeSpec) {
789 this->addMultiMaskFormat(kTransformedMask, drawables, strikeSpec);
790}
791
792// -- GrTextBlob::VertexRegenerator ----------------------------------------------------------------
Herb Derbya9047642019-12-06 12:12:11 -0500793GrTextBlob::VertexRegenerator::VertexRegenerator(GrResourceProvider* resourceProvider,
Herb Derbya9047642019-12-06 12:12:11 -0500794 GrTextBlob::SubRun* subRun,
Herb Derbya9047642019-12-06 12:12:11 -0500795 GrDeferredUploadTarget* uploadTarget,
Mike Klein99e002f2020-01-16 16:45:03 +0000796 GrStrikeCache* grStrikeCache,
Herb Derbya9047642019-12-06 12:12:11 -0500797 GrAtlasManager* fullAtlasManager)
798 : fResourceProvider(resourceProvider)
Herb Derbya9047642019-12-06 12:12:11 -0500799 , fUploadTarget(uploadTarget)
Mike Klein99e002f2020-01-16 16:45:03 +0000800 , fGrStrikeCache(grStrikeCache)
Herb Derbya9047642019-12-06 12:12:11 -0500801 , fFullAtlasManager(fullAtlasManager)
Herb Derbya8fa4902020-01-16 15:41:54 -0500802 , fSubRun(subRun) { }
Herb Derbya9047642019-12-06 12:12:11 -0500803
Herb Derbyb45558d2020-01-07 16:57:12 -0500804std::tuple<bool, int> GrTextBlob::VertexRegenerator::updateTextureCoordinatesMaybeStrike(
805 const int begin, const int end) {
Herb Derby586f8d02020-01-07 15:28:07 -0500806 fSubRun->resetBulkUseToken();
Herb Derbya9047642019-12-06 12:12:11 -0500807
Herb Derby586f8d02020-01-07 15:28:07 -0500808 const SkStrikeSpec& strikeSpec = fSubRun->strikeSpec();
Herb Derbya9047642019-12-06 12:12:11 -0500809
Herb Derby586f8d02020-01-07 15:28:07 -0500810 if (!fMetricsAndImages.isValid()
Herb Derbya9047642019-12-06 12:12:11 -0500811 || fMetricsAndImages->descriptor() != strikeSpec.descriptor()) {
Herb Derby586f8d02020-01-07 15:28:07 -0500812 fMetricsAndImages.init(strikeSpec);
813 }
814
Herb Derbya8fa4902020-01-16 15:41:54 -0500815 fSubRun->updateStrikeIfNeeded(fMetricsAndImages.get(), fGrStrikeCache);
Herb Derbya9047642019-12-06 12:12:11 -0500816
Herb Derbybc131b82020-01-07 16:07:42 -0500817 // Update the atlas information in the GrStrike.
Herb Derby83b907e2020-01-06 13:44:29 -0500818 auto code = GrDrawOpAtlas::ErrorCode::kSucceeded;
Herb Derby586f8d02020-01-07 15:28:07 -0500819 GrTextStrike* grStrike = fSubRun->strike();
Herb Derbybc131b82020-01-07 16:07:42 -0500820 auto tokenTracker = fUploadTarget->tokenTracker();
Herb Derbyb45558d2020-01-07 16:57:12 -0500821 int i = begin;
822 for (; i < end; i++) {
823 GrGlyph* glyph = fSubRun->fGlyphs[i];
Herb Derby586f8d02020-01-07 15:28:07 -0500824 SkASSERT(glyph && glyph->fMaskFormat == fSubRun->maskFormat());
Herb Derbya9047642019-12-06 12:12:11 -0500825
Herb Derby586f8d02020-01-07 15:28:07 -0500826 if (!fFullAtlasManager->hasGlyph(glyph)) {
827 code = grStrike->addGlyphToAtlas(
Mike Klein99e002f2020-01-16 16:45:03 +0000828 fResourceProvider, fUploadTarget, fGrStrikeCache, fFullAtlasManager, glyph,
829 fMetricsAndImages.get(), fSubRun->maskFormat(), fSubRun->needsTransform());
Herb Derby586f8d02020-01-07 15:28:07 -0500830 if (code != GrDrawOpAtlas::ErrorCode::kSucceeded) {
831 break;
Herb Derbya9047642019-12-06 12:12:11 -0500832 }
Herb Derbya9047642019-12-06 12:12:11 -0500833 }
Herb Derby586f8d02020-01-07 15:28:07 -0500834 fFullAtlasManager->addGlyphToBulkAndSetUseToken(
835 fSubRun->bulkUseToken(), glyph, tokenTracker->nextDrawToken());
Herb Derbya9047642019-12-06 12:12:11 -0500836 }
Herb Derby23f29762020-01-10 16:26:14 -0500837 int glyphsPlacedInAtlas = i - begin;
Herb Derbya9047642019-12-06 12:12:11 -0500838
Herb Derbybc131b82020-01-07 16:07:42 -0500839 // Update the quads with the new atlas coordinates.
Herb Derby23f29762020-01-10 16:26:14 -0500840 fSubRun->updateTexCoords(begin, begin + glyphsPlacedInAtlas);
Herb Derbybc131b82020-01-07 16:07:42 -0500841
Herb Derbyb45558d2020-01-07 16:57:12 -0500842 if (code == GrDrawOpAtlas::ErrorCode::kSucceeded) {
843 // If we reach here with begin > 0, some earlier call to regenerate() exhausted the atlas
844 // before it could place all its glyphs and returned kTryAgain. Invalidate texture
845 // coordinates, forcing them to be regenerated, minding the atlas flush between.
846 fSubRun->fAtlasGeneration =
847 begin > 0 ? GrDrawOpAtlas::kInvalidAtlasGeneration
848 : fFullAtlasManager->atlasGeneration(fSubRun->maskFormat());
Herb Derbya9047642019-12-06 12:12:11 -0500849 }
Herb Derby83b907e2020-01-06 13:44:29 -0500850
Herb Derby23f29762020-01-10 16:26:14 -0500851 return {code != GrDrawOpAtlas::ErrorCode::kError, glyphsPlacedInAtlas};
Herb Derbya9047642019-12-06 12:12:11 -0500852}
853
Herb Derby23f29762020-01-10 16:26:14 -0500854std::tuple<bool, int> GrTextBlob::VertexRegenerator::regenerate(int begin, int end) {
Herb Derbya9047642019-12-06 12:12:11 -0500855 uint64_t currentAtlasGen = fFullAtlasManager->atlasGeneration(fSubRun->maskFormat());
856 // If regenerate() is called multiple times then the atlas gen may have changed. So we check
857 // this each time.
Herb Derbya9047642019-12-06 12:12:11 -0500858
Herb Derbya8fa4902020-01-16 15:41:54 -0500859 // TODO: figure out why this needs to latch true instead of maintaining the invariant with
860 // the atlas generation.
861 fRegenerateTextureCoordinates =
862 fRegenerateTextureCoordinates || fSubRun->fAtlasGeneration != currentAtlasGen;
863 if (fSubRun->strike()->isAbandoned() || fRegenerateTextureCoordinates) {
Herb Derby23f29762020-01-10 16:26:14 -0500864 return this->updateTextureCoordinatesMaybeStrike(begin, end);
Herb Derby51a95ce2020-01-08 17:49:51 -0500865 } else {
Herb Derby51a95ce2020-01-08 17:49:51 -0500866 // All glyphs are inserted into the atlas if fCurrGlyph is at the end of fGlyphs.
Herb Derby23f29762020-01-10 16:26:14 -0500867 if (end == (int)fSubRun->fGlyphs.size()) {
Herb Derby51a95ce2020-01-08 17:49:51 -0500868 // Set use tokens for all of the glyphs in our SubRun. This is only valid if we
Brian Salomon43cbd722020-01-03 22:09:12 -0500869 // have a valid atlas generation
870 fFullAtlasManager->setUseTokenBulk(*fSubRun->bulkUseToken(),
871 fUploadTarget->tokenTracker()->nextDrawToken(),
872 fSubRun->maskFormat());
873 }
Herb Derby23f29762020-01-10 16:26:14 -0500874 return {true, end - begin};
Herb Derbya9047642019-12-06 12:12:11 -0500875 }
Herb Derbya9047642019-12-06 12:12:11 -0500876}