blob: 7219ea66cb891675076207c4e79c09f904c90deb [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 Derby5bf5b042019-12-12 16:37:03 -050025static SkVector calculate_translation(bool applyVM,
26 const SkMatrix& drawMatrix, SkPoint drawOrigin,
27 const SkMatrix& currentViewMatrix, SkPoint currentOrigin) {
28 SkVector translate;
Herb Derbya9047642019-12-06 12:12:11 -050029 if (applyVM) {
Herb Derby5bf5b042019-12-12 16:37:03 -050030 translate.fX = drawMatrix.getTranslateX() +
31 drawMatrix.getScaleX() * (drawOrigin.x() - currentOrigin.x()) +
32 drawMatrix.getSkewX() * (drawOrigin.y() - currentOrigin.y()) -
33 currentViewMatrix.getTranslateX();
Herb Derbya9047642019-12-06 12:12:11 -050034
Herb Derby5bf5b042019-12-12 16:37:03 -050035 translate.fY = drawMatrix.getTranslateY() +
36 drawMatrix.getSkewY() * (drawOrigin.x() - currentOrigin.x()) +
37 drawMatrix.getScaleY() * (drawOrigin.y() - currentOrigin.y()) -
38 currentViewMatrix.getTranslateY();
Herb Derbya9047642019-12-06 12:12:11 -050039 } else {
Herb Derby5bf5b042019-12-12 16:37:03 -050040 translate = drawOrigin - currentOrigin;
Herb Derbya9047642019-12-06 12:12:11 -050041 }
Herb Derby5bf5b042019-12-12 16:37:03 -050042
43 return translate;
Herb Derbya9047642019-12-06 12:12:11 -050044}
45
46static SkMatrix make_inverse(const SkMatrix& matrix) {
47 SkMatrix inverseMatrix;
48 if (!matrix.invert(&inverseMatrix)) {
49 inverseMatrix = SkMatrix::I();
50 }
51 return inverseMatrix;
52}
53
54// -- GrTextBlob::Key ------------------------------------------------------------------------------
55GrTextBlob::Key::Key() { sk_bzero(this, sizeof(Key)); }
56
57bool GrTextBlob::Key::operator==(const GrTextBlob::Key& other) const {
58 return 0 == memcmp(this, &other, sizeof(Key));
59}
60
61// -- GrTextBlob::PathGlyph ------------------------------------------------------------------------
62GrTextBlob::PathGlyph::PathGlyph(const SkPath& path, SkPoint origin)
63 : fPath(path)
64 , fOrigin(origin) {}
65
66// -- GrTextBlob::SubRun ---------------------------------------------------------------------------
Herb Derbye3c7ff42019-12-10 17:49:28 -050067// Hold data to draw the different types of sub run. SubRuns are produced knowing all the
68// glyphs that are included in them.
69class GrTextBlob::SubRun {
70public:
71 // SubRun for masks
72 SubRun(SubRunType type,
73 GrTextBlob* textBlob,
74 const SkStrikeSpec& strikeSpec,
75 GrMaskFormat format,
Herb Derbyc514e7d2019-12-11 17:00:31 -050076 const SkSpan<GrGlyph*>& glyphs, const SkSpan<char>& vertexData,
Herb Derbye3c7ff42019-12-10 17:49:28 -050077 sk_sp<GrTextStrike>&& grStrike);
78
79 // SubRun for paths
80 SubRun(GrTextBlob* textBlob, const SkStrikeSpec& strikeSpec);
81
82 void appendGlyphs(const SkZip<SkGlyphVariant, SkPoint>& drawables);
83
84 // TODO when this object is more internal, drop the privacy
85 void resetBulkUseToken();
86 GrDrawOpAtlas::BulkUseTokenUpdater* bulkUseToken();
87 void setStrike(sk_sp<GrTextStrike> strike);
88 GrTextStrike* strike() const;
Herb Derbye3c7ff42019-12-10 17:49:28 -050089
90 void setAtlasGeneration(uint64_t atlasGeneration);
91 uint64_t atlasGeneration() const;
92
Herb Derbye3c7ff42019-12-10 17:49:28 -050093 void setColor(GrColor color);
94 GrColor color() const;
95
96 GrMaskFormat maskFormat() const;
97
Herb Derbya2d72252019-12-23 15:02:33 -050098 size_t vertexStride() const;
Herb Derby3d3150c2019-12-23 15:26:44 -050099 size_t colorOffset() const;
Herb Derby91fd46a2019-12-26 11:36:30 -0500100 char* quadStart(size_t index) const;
Herb Derbya2d72252019-12-23 15:02:33 -0500101
Herb Derbye3c7ff42019-12-10 17:49:28 -0500102 const SkRect& vertexBounds() const;
103 void joinGlyphBounds(const SkRect& glyphBounds);
104
Herb Derbye3c7ff42019-12-10 17:49:28 -0500105 // This function assumes the translation will be applied before it is called again
Herb Derby5bf5b042019-12-12 16:37:03 -0500106 SkVector computeTranslation(const SkMatrix& drawMatrix, SkPoint drawOrigin);
Herb Derbye3c7ff42019-12-10 17:49:28 -0500107
108 bool drawAsDistanceFields() const;
109 bool drawAsPaths() const;
110 bool needsTransform() const;
Herb Derbye3c7ff42019-12-10 17:49:28 -0500111
Herb Derby91fd46a2019-12-26 11:36:30 -0500112 void updateTranslation(SkVector translation);
Herb Derby6ca4f312019-12-26 15:23:49 -0500113 void updateColor(GrColor newColor);
Herb Derby91fd46a2019-12-26 11:36:30 -0500114
Herb Derbye3c7ff42019-12-10 17:49:28 -0500115 // df properties
116 void setUseLCDText(bool useLCDText);
117 bool hasUseLCDText() const;
118 void setAntiAliased(bool antiAliased);
119 bool isAntiAliased() const;
120
121 const SkStrikeSpec& strikeSpec() const;
122
123 SubRun* fNextSubRun{nullptr};
124 const SubRunType fType;
125 GrTextBlob* const fBlob;
126 const GrMaskFormat fMaskFormat;
Herb Derbyc514e7d2019-12-11 17:00:31 -0500127 const SkSpan<GrGlyph*> fGlyphs;
128 const SkSpan<char> fVertexData;
Herb Derbye3c7ff42019-12-10 17:49:28 -0500129 const SkStrikeSpec fStrikeSpec;
130 sk_sp<GrTextStrike> fStrike;
131 struct {
132 bool useLCDText:1;
133 bool antiAliased:1;
134 } fFlags{false, false};
135 GrColor fColor;
136 GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken;
137 SkRect fVertexBounds = SkRectPriv::MakeLargestInverted();
138 uint64_t fAtlasGeneration{GrDrawOpAtlas::kInvalidAtlasGeneration};
Herb Derby5bf5b042019-12-12 16:37:03 -0500139 SkPoint fCurrentOrigin;
Herb Derby1c5be7b2019-12-13 12:03:06 -0500140 SkMatrix fCurrentMatrix;
Herb Derbye3c7ff42019-12-10 17:49:28 -0500141 std::vector<PathGlyph> fPaths;
Herb Derby05eb83b2019-12-23 15:42:47 -0500142
143private:
144 bool hasW() const;
145
Herb Derbye3c7ff42019-12-10 17:49:28 -0500146}; // SubRun
147
Herb Derbya9047642019-12-06 12:12:11 -0500148GrTextBlob::SubRun::SubRun(SubRunType type, GrTextBlob* textBlob, const SkStrikeSpec& strikeSpec,
Herb Derbyc514e7d2019-12-11 17:00:31 -0500149 GrMaskFormat format,
150 const SkSpan<GrGlyph*>& glyphs, const SkSpan<char>& vertexData,
Herb Derbya9047642019-12-06 12:12:11 -0500151 sk_sp<GrTextStrike>&& grStrike)
152 : fType{type}
153 , fBlob{textBlob}
154 , fMaskFormat{format}
Herb Derbyc514e7d2019-12-11 17:00:31 -0500155 , fGlyphs{glyphs}
156 , fVertexData{vertexData}
Herb Derbya9047642019-12-06 12:12:11 -0500157 , fStrikeSpec{strikeSpec}
158 , fStrike{grStrike}
159 , fColor{textBlob->fColor}
Herb Derby5bf5b042019-12-12 16:37:03 -0500160 , fCurrentOrigin{textBlob->fInitialOrigin}
Herb Derby1c5be7b2019-12-13 12:03:06 -0500161 , fCurrentMatrix{textBlob->fInitialMatrix} {
Herb Derbya9047642019-12-06 12:12:11 -0500162 SkASSERT(type != kTransformedPath);
Herb Derbycb718892019-12-07 00:07:42 -0500163 textBlob->insertSubRun(this);
Herb Derbya9047642019-12-06 12:12:11 -0500164}
165
166GrTextBlob::SubRun::SubRun(GrTextBlob* textBlob, const SkStrikeSpec& strikeSpec)
167 : fType{kTransformedPath}
168 , fBlob{textBlob}
169 , fMaskFormat{kA8_GrMaskFormat}
Herb Derbyc514e7d2019-12-11 17:00:31 -0500170 , fGlyphs{SkSpan<GrGlyph*>{}}
171 , fVertexData{SkSpan<char>{}}
Herb Derbya9047642019-12-06 12:12:11 -0500172 , fStrikeSpec{strikeSpec}
173 , fStrike{nullptr}
174 , fColor{textBlob->fColor}
Herb Derbycb718892019-12-07 00:07:42 -0500175 , fPaths{} {
176 textBlob->insertSubRun(this);
177}
Herb Derbya9047642019-12-06 12:12:11 -0500178
179void GrTextBlob::SubRun::appendGlyphs(const SkZip<SkGlyphVariant, SkPoint>& drawables) {
180 GrTextStrike* grStrike = fStrike.get();
181 SkScalar strikeToSource = fStrikeSpec.strikeToSourceRatio();
Herb Derbyc514e7d2019-12-11 17:00:31 -0500182 GrGlyph** glyphCursor = fGlyphs.data();
183 char* vertexCursor = fVertexData.data();
Herb Derbya9047642019-12-06 12:12:11 -0500184 GrColor color = this->color();
Herb Derbya2d72252019-12-23 15:02:33 -0500185 size_t vertexStride = this->vertexStride();
Herb Derbya9047642019-12-06 12:12:11 -0500186 // We always write the third position component used by SDFs. If it is unused it gets
187 // overwritten. Similarly, we always write the color and the blob will later overwrite it
188 // with texture coords if it is unused.
Herb Derby3d3150c2019-12-23 15:26:44 -0500189 size_t colorOffset = this->colorOffset();
Herb Derbya9047642019-12-06 12:12:11 -0500190 for (auto [variant, pos] : drawables) {
191 SkGlyph* skGlyph = variant;
192 GrGlyph* grGlyph = grStrike->getGlyph(*skGlyph);
193 // Only floor the device coordinates.
194 SkRect dstRect;
195 if (!this->needsTransform()) {
196 pos = {SkScalarFloorToScalar(pos.x()), SkScalarFloorToScalar(pos.y())};
197 dstRect = grGlyph->destRect(pos);
198 } else {
199 dstRect = grGlyph->destRect(pos, strikeToSource);
200 }
201
202 this->joinGlyphBounds(dstRect);
203
Herb Derbya9047642019-12-06 12:12:11 -0500204 // V0
Herb Derbyc514e7d2019-12-11 17:00:31 -0500205 *reinterpret_cast<SkPoint3*>(vertexCursor) = {dstRect.fLeft, dstRect.fTop, 1.f};
206 *reinterpret_cast<GrColor*>(vertexCursor + colorOffset) = color;
207 vertexCursor += vertexStride;
Herb Derbya9047642019-12-06 12:12:11 -0500208
209 // V1
Herb Derbyc514e7d2019-12-11 17:00:31 -0500210 *reinterpret_cast<SkPoint3*>(vertexCursor) = {dstRect.fLeft, dstRect.fBottom, 1.f};
211 *reinterpret_cast<GrColor*>(vertexCursor + colorOffset) = color;
212 vertexCursor += vertexStride;
Herb Derbya9047642019-12-06 12:12:11 -0500213
214 // V2
Herb Derbyc514e7d2019-12-11 17:00:31 -0500215 *reinterpret_cast<SkPoint3*>(vertexCursor) = {dstRect.fRight, dstRect.fTop, 1.f};
216 *reinterpret_cast<GrColor*>(vertexCursor + colorOffset) = color;
217 vertexCursor += vertexStride;
Herb Derbya9047642019-12-06 12:12:11 -0500218
219 // V3
Herb Derbyc514e7d2019-12-11 17:00:31 -0500220 *reinterpret_cast<SkPoint3*>(vertexCursor) = {dstRect.fRight, dstRect.fBottom, 1.f};
221 *reinterpret_cast<GrColor*>(vertexCursor + colorOffset) = color;
222 vertexCursor += vertexStride;
Herb Derbya9047642019-12-06 12:12:11 -0500223
Herb Derbyc514e7d2019-12-11 17:00:31 -0500224 *glyphCursor++ = grGlyph;
Herb Derbya9047642019-12-06 12:12:11 -0500225 }
Herb Derbya9047642019-12-06 12:12:11 -0500226}
227
228void GrTextBlob::SubRun::resetBulkUseToken() { fBulkUseToken.reset(); }
229
230GrDrawOpAtlas::BulkUseTokenUpdater* GrTextBlob::SubRun::bulkUseToken() { return &fBulkUseToken; }
231void GrTextBlob::SubRun::setStrike(sk_sp<GrTextStrike> strike) { fStrike = std::move(strike); }
232GrTextStrike* GrTextBlob::SubRun::strike() const { return fStrike.get(); }
Herb Derbya9047642019-12-06 12:12:11 -0500233void GrTextBlob::SubRun::setAtlasGeneration(uint64_t atlasGeneration) { fAtlasGeneration = atlasGeneration;}
234uint64_t GrTextBlob::SubRun::atlasGeneration() const { return fAtlasGeneration; }
Herb Derbya9047642019-12-06 12:12:11 -0500235void GrTextBlob::SubRun::setColor(GrColor color) { fColor = color; }
236GrColor GrTextBlob::SubRun::color() const { return fColor; }
237GrMaskFormat GrTextBlob::SubRun::maskFormat() const { return fMaskFormat; }
Herb Derbya2d72252019-12-23 15:02:33 -0500238size_t GrTextBlob::SubRun::vertexStride() const {
239 return GetVertexStride(this->maskFormat(), this->hasW());
240}
Herb Derby3d3150c2019-12-23 15:26:44 -0500241size_t GrTextBlob::SubRun::colorOffset() const {
242 return this->hasW() ? offsetof(SDFT3DVertex, color) : offsetof(Mask2DVertex, color);
243}
Herb Derby91fd46a2019-12-26 11:36:30 -0500244char* GrTextBlob::SubRun::quadStart(size_t index) const {
245 return SkTAddOffset<char>(
246 fVertexData.data(), index * kVerticesPerGlyph * this->vertexStride());
247}
Herb Derbya2d72252019-12-23 15:02:33 -0500248
Herb Derbya9047642019-12-06 12:12:11 -0500249const SkRect& GrTextBlob::SubRun::vertexBounds() const { return fVertexBounds; }
250void GrTextBlob::SubRun::joinGlyphBounds(const SkRect& glyphBounds) {
251 fVertexBounds.joinNonEmptyArg(glyphBounds);
252}
253
Herb Derby5bf5b042019-12-12 16:37:03 -0500254SkVector GrTextBlob::SubRun::computeTranslation(
255 const SkMatrix& drawMatrix, SkPoint drawOrigin){
Herb Derbya9047642019-12-06 12:12:11 -0500256 // Don't use the matrix to translate on distance field for fallback subruns.
Herb Derby5bf5b042019-12-12 16:37:03 -0500257
258 SkVector translate = calculate_translation(
259 !this->drawAsDistanceFields() && !this->needsTransform(),
260 drawMatrix, drawOrigin, fCurrentMatrix, fCurrentOrigin);
261
262 // Update SubRun indicating that the vertices now correspond to the origin and matrix used in
263 // the draw.
Herb Derby1c5be7b2019-12-13 12:03:06 -0500264 fCurrentMatrix = drawMatrix;
Herb Derby5bf5b042019-12-12 16:37:03 -0500265 fCurrentOrigin = drawOrigin;
266 return translate;
Herb Derbya9047642019-12-06 12:12:11 -0500267}
268
269bool GrTextBlob::SubRun::drawAsDistanceFields() const { return fType == kTransformedSDFT; }
270
271bool GrTextBlob::SubRun::drawAsPaths() const { return fType == kTransformedPath; }
272
273bool GrTextBlob::SubRun::needsTransform() const {
274 return fType == kTransformedPath
275 || fType == kTransformedMask
276 || fType == kTransformedSDFT;
277}
278
279bool GrTextBlob::SubRun::hasW() const {
280 return fBlob->hasW(fType);
281}
282
Herb Derby91fd46a2019-12-26 11:36:30 -0500283void GrTextBlob::SubRun::updateTranslation(SkVector translation) {
284 size_t vertexStride = this->vertexStride();
Herb Derby6ca4f312019-12-26 15:23:49 -0500285 for(size_t quad = 0; quad < fGlyphs.size(); quad++) {
286 SkPoint* vertexCursor = reinterpret_cast<SkPoint*>(quadStart(quad));
Herb Derby91fd46a2019-12-26 11:36:30 -0500287 for (int i = 0; i < 4; ++i) {
288 *vertexCursor += translation;
289 vertexCursor = SkTAddOffset<SkPoint>(vertexCursor, vertexStride);
290 }
291 }
292}
293
Herb Derby6ca4f312019-12-26 15:23:49 -0500294void GrTextBlob::SubRun::updateColor(GrColor newColor) {
295 size_t vertexStride = this->vertexStride();
296 size_t colorOffset = this->colorOffset();
297 for(size_t quad = 0; quad < fGlyphs.size(); quad++) {
298 GrColor* colorCursor = SkTAddOffset<GrColor>(quadStart(quad), colorOffset);
299 for (int i = 0; i < 4; ++i) {
300 *colorCursor = newColor;
301 colorCursor = SkTAddOffset<GrColor>(colorCursor, vertexStride);
302 }
303 }
304 this->fColor = newColor;
305}
306
Herb Derbya9047642019-12-06 12:12:11 -0500307void GrTextBlob::SubRun::setUseLCDText(bool useLCDText) { fFlags.useLCDText = useLCDText; }
308bool GrTextBlob::SubRun::hasUseLCDText() const { return fFlags.useLCDText; }
309void GrTextBlob::SubRun::setAntiAliased(bool antiAliased) { fFlags.antiAliased = antiAliased; }
310bool GrTextBlob::SubRun::isAntiAliased() const { return fFlags.antiAliased; }
311const SkStrikeSpec& GrTextBlob::SubRun::strikeSpec() const { return fStrikeSpec; }
312
313// -- GrTextBlob -----------------------------------------------------------------------------------
314void GrTextBlob::operator delete(void* p) { ::operator delete(p); }
315void* GrTextBlob::operator new(size_t) { SK_ABORT("All blobs are created by placement new."); }
316void* GrTextBlob::operator new(size_t, void* p) { return p; }
317
318GrTextBlob::~GrTextBlob() = default;
319
Herb Derby659e4092019-12-06 15:38:10 -0500320sk_sp<GrTextBlob> GrTextBlob::Make(const SkGlyphRunList& glyphRunList,
Herb Derbyeba195f2019-12-03 16:44:47 -0500321 GrStrikeCache* strikeCache,
Herb Derby1c5be7b2019-12-13 12:03:06 -0500322 const SkMatrix& drawMatrix,
Herb Derbya00da612019-03-04 17:10:01 -0500323 GrColor color,
Herb Derbyeba195f2019-12-03 16:44:47 -0500324 bool forceWForDistanceFields) {
Herb Derbycd498e12019-12-06 14:17:31 -0500325
Herb Derby3d1a3bb2019-12-06 18:15:49 -0500326 static_assert(sizeof(ARGB2DVertex) <= sizeof(Mask2DVertex));
Herb Derbycb718892019-12-07 00:07:42 -0500327 static_assert(alignof(ARGB2DVertex) <= alignof(Mask2DVertex));
328 size_t quadSize = sizeof(Mask2DVertex) * kVerticesPerGlyph;
Herb Derby1c5be7b2019-12-13 12:03:06 -0500329 if (drawMatrix.hasPerspective() || forceWForDistanceFields) {
Herb Derby3d1a3bb2019-12-06 18:15:49 -0500330 static_assert(sizeof(ARGB3DVertex) <= sizeof(SDFT3DVertex));
Herb Derbycb718892019-12-07 00:07:42 -0500331 static_assert(alignof(ARGB3DVertex) <= alignof(SDFT3DVertex));
332 quadSize = sizeof(SDFT3DVertex) * kVerticesPerGlyph;
Herb Derbye74c7762019-12-04 14:15:41 -0500333 }
334
Herb Derbycb718892019-12-07 00:07:42 -0500335 // We can use the alignment of SDFT3DVertex as a proxy for all Vertex alignments.
336 static_assert(alignof(SDFT3DVertex) >= alignof(Mask2DVertex));
Herb Derbyc514e7d2019-12-11 17:00:31 -0500337 // Assume there is no padding needed between glyph pointers and vertices.
Herb Derbycb718892019-12-07 00:07:42 -0500338 static_assert(alignof(GrGlyph*) >= alignof(SDFT3DVertex));
Herb Derbyc514e7d2019-12-11 17:00:31 -0500339
340 // In the arena, the layout is GrGlyph*... | SDFT3DVertex... | SubRun, so there is no padding
341 // between GrGlyph* and SDFT3DVertex, but padding is needed between the Mask2DVertex array
342 // and the SubRun.
343 size_t vertexToSubRunPadding = alignof(SDFT3DVertex) - alignof(SubRun);
344 size_t arenaSize =
345 sizeof(GrGlyph*) * glyphRunList.totalGlyphCount()
346 + quadSize * glyphRunList.totalGlyphCount()
347 + glyphRunList.runCount() * (sizeof(SubRun) + vertexToSubRunPadding);
348
349 size_t allocationSize = sizeof(GrTextBlob) + arenaSize;
Ben Wagner75d6db72018-09-20 14:39:39 -0400350
Herb Derbycb718892019-12-07 00:07:42 -0500351 void* allocation = ::operator new (allocationSize);
Herb Derbyb12175f2018-05-23 16:38:09 -0400352
Herb Derbyaebc5f82019-12-10 14:07:10 -0500353 SkColor initialLuminance = SkPaintPriv::ComputeLuminanceColor(glyphRunList.paint());
Herb Derby00ae9592019-12-03 15:55:56 -0500354 sk_sp<GrTextBlob> blob{new (allocation) GrTextBlob{
Herb Derby1c5be7b2019-12-13 12:03:06 -0500355 arenaSize, strikeCache, drawMatrix, glyphRunList.origin(),
Herb Derbyaebc5f82019-12-10 14:07:10 -0500356 color, initialLuminance, forceWForDistanceFields}};
joshualitt92303772016-02-10 11:55:52 -0800357
Herb Derbyf7d5d742018-11-16 13:24:32 -0500358 return blob;
joshualitt92303772016-02-10 11:55:52 -0800359}
360
Herb Derbya9047642019-12-06 12:12:11 -0500361void GrTextBlob::setupKey(const GrTextBlob::Key& key, const SkMaskFilterBase::BlurRec& blurRec,
362 const SkPaint& paint) {
363 fKey = key;
364 if (key.fHasBlur) {
365 fBlurRec = blurRec;
366 }
367 if (key.fStyle != SkPaint::kFill_Style) {
368 fStrokeInfo.fFrameWidth = paint.getStrokeWidth();
369 fStrokeInfo.fMiterLimit = paint.getStrokeMiter();
370 fStrokeInfo.fJoin = paint.getStrokeJoin();
371 }
372}
373const GrTextBlob::Key& GrTextBlob::GetKey(const GrTextBlob& blob) { return blob.fKey; }
374uint32_t GrTextBlob::Hash(const GrTextBlob::Key& key) { return SkOpts::hash(&key, sizeof(Key)); }
375
Herb Derbycb718892019-12-07 00:07:42 -0500376bool GrTextBlob::hasDistanceField() const {
377 return SkToBool(fTextType & kHasDistanceField_TextType);
378}
Herb Derbya9047642019-12-06 12:12:11 -0500379bool GrTextBlob::hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); }
Herb Derby1c5be7b2019-12-13 12:03:06 -0500380bool GrTextBlob::hasPerspective() const { return fInitialMatrix.hasPerspective(); }
Herb Derbya9047642019-12-06 12:12:11 -0500381
382void GrTextBlob::setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
383void GrTextBlob::setHasBitmap() { fTextType |= kHasBitmap_TextType; }
384void GrTextBlob::setMinAndMaxScale(SkScalar scaledMin, SkScalar scaledMax) {
385 // we init fMaxMinScale and fMinMaxScale in the constructor
386 fMaxMinScale = SkMaxScalar(scaledMin, fMaxMinScale);
387 fMinMaxScale = SkMinScalar(scaledMax, fMinMaxScale);
388}
389
390size_t GrTextBlob::GetVertexStride(GrMaskFormat maskFormat, bool hasWCoord) {
391 switch (maskFormat) {
392 case kA8_GrMaskFormat:
Herb Derbycd498e12019-12-06 14:17:31 -0500393 return hasWCoord ? sizeof(SDFT3DVertex) : sizeof(Mask2DVertex);
Herb Derbya9047642019-12-06 12:12:11 -0500394 case kARGB_GrMaskFormat:
Herb Derbycd498e12019-12-06 14:17:31 -0500395 return hasWCoord ? sizeof(ARGB3DVertex) : sizeof(ARGB2DVertex);
Herb Derbya9047642019-12-06 12:12:11 -0500396 default:
397 SkASSERT(!hasWCoord);
Herb Derbycd498e12019-12-06 14:17:31 -0500398 return sizeof(Mask2DVertex);
Herb Derbya9047642019-12-06 12:12:11 -0500399 }
400}
401
Herb Derby0edb2142018-10-16 17:04:11 -0400402bool GrTextBlob::mustRegenerate(const SkPaint& paint, bool anyRunHasSubpixelPosition,
403 const SkMaskFilterBase::BlurRec& blurRec,
Herb Derby5bf5b042019-12-12 16:37:03 -0500404 const SkMatrix& drawMatrix, SkPoint drawOrigin) {
joshualittfd5f6c12015-12-10 07:44:50 -0800405 // If we have LCD text then our canonical color will be set to transparent, in this case we have
406 // to regenerate the blob on any color change
407 // We use the grPaint to get any color filter effects
408 if (fKey.fCanonicalColor == SK_ColorTRANSPARENT &&
Herb Derbyaebc5f82019-12-10 14:07:10 -0500409 fInitialLuminance != SkPaintPriv::ComputeLuminanceColor(paint)) {
joshualittfd5f6c12015-12-10 07:44:50 -0800410 return true;
411 }
412
Herb Derby1c5be7b2019-12-13 12:03:06 -0500413 if (fInitialMatrix.hasPerspective() != drawMatrix.hasPerspective()) {
joshualittfd5f6c12015-12-10 07:44:50 -0800414 return true;
415 }
416
Brian Salomon5c6ac642017-12-19 11:09:32 -0500417 /** This could be relaxed for blobs with only distance field glyphs. */
Mike Reed2c383152019-12-18 16:47:47 -0500418 if (fInitialMatrix.hasPerspective() && !SkMatrixPriv::CheapEqual(fInitialMatrix, drawMatrix)) {
joshualittfd5f6c12015-12-10 07:44:50 -0800419 return true;
420 }
421
422 // We only cache one masked version
423 if (fKey.fHasBlur &&
Mike Reed1be1f8d2018-03-14 13:01:17 -0400424 (fBlurRec.fSigma != blurRec.fSigma || fBlurRec.fStyle != blurRec.fStyle)) {
joshualittfd5f6c12015-12-10 07:44:50 -0800425 return true;
426 }
427
428 // Similarly, we only cache one version for each style
429 if (fKey.fStyle != SkPaint::kFill_Style &&
Herb Derbybc6f9c92018-08-08 13:58:45 -0400430 (fStrokeInfo.fFrameWidth != paint.getStrokeWidth() ||
431 fStrokeInfo.fMiterLimit != paint.getStrokeMiter() ||
432 fStrokeInfo.fJoin != paint.getStrokeJoin())) {
joshualittfd5f6c12015-12-10 07:44:50 -0800433 return true;
434 }
435
436 // Mixed blobs must be regenerated. We could probably figure out a way to do integer scrolls
437 // for mixed blobs if this becomes an issue.
438 if (this->hasBitmap() && this->hasDistanceField()) {
Herb Derbyeba195f2019-12-03 16:44:47 -0500439 // Identical view matrices and we can reuse in all cases
Mike Reed2c383152019-12-18 16:47:47 -0500440 return !(SkMatrixPriv::CheapEqual(fInitialMatrix, drawMatrix) &&
441 drawOrigin == fInitialOrigin);
joshualittfd5f6c12015-12-10 07:44:50 -0800442 }
443
444 if (this->hasBitmap()) {
Herb Derby1c5be7b2019-12-13 12:03:06 -0500445 if (fInitialMatrix.getScaleX() != drawMatrix.getScaleX() ||
446 fInitialMatrix.getScaleY() != drawMatrix.getScaleY() ||
447 fInitialMatrix.getSkewX() != drawMatrix.getSkewX() ||
448 fInitialMatrix.getSkewY() != drawMatrix.getSkewY()) {
joshualittfd5f6c12015-12-10 07:44:50 -0800449 return true;
450 }
451
Herb Derby9830fc42019-09-12 10:58:26 -0400452 // TODO(herb): this is not needed for full pixel glyph choice, but is needed to adjust
453 // the quads properly. Devise a system that regenerates the quads from original data
454 // using the transform to allow this to be used in general.
455
456 // We can update the positions in the text blob without regenerating the whole
457 // blob, but only for integer translations.
458 // This cool bit of math will determine the necessary translation to apply to the
459 // already generated vertex coordinates to move them to the correct position.
460 // Figure out the translation in view space given a translation in source space.
Herb Derby1c5be7b2019-12-13 12:03:06 -0500461 SkScalar transX = drawMatrix.getTranslateX() +
Herb Derby5bf5b042019-12-12 16:37:03 -0500462 drawMatrix.getScaleX() * (drawOrigin.x() - fInitialOrigin.x()) +
463 drawMatrix.getSkewX() * (drawOrigin.y() - fInitialOrigin.y()) -
Herb Derby1c5be7b2019-12-13 12:03:06 -0500464 fInitialMatrix.getTranslateX();
465 SkScalar transY = drawMatrix.getTranslateY() +
Herb Derby5bf5b042019-12-12 16:37:03 -0500466 drawMatrix.getSkewY() * (drawOrigin.x() - fInitialOrigin.x()) +
467 drawMatrix.getScaleY() * (drawOrigin.y() - fInitialOrigin.y()) -
Herb Derby1c5be7b2019-12-13 12:03:06 -0500468 fInitialMatrix.getTranslateY();
Herb Derby9830fc42019-09-12 10:58:26 -0400469 if (!SkScalarIsInt(transX) || !SkScalarIsInt(transY)) {
470 return true;
joshualittfd5f6c12015-12-10 07:44:50 -0800471 }
joshualittfd5f6c12015-12-10 07:44:50 -0800472 } else if (this->hasDistanceField()) {
473 // A scale outside of [blob.fMaxMinScale, blob.fMinMaxScale] would result in a different
474 // distance field being generated, so we have to regenerate in those cases
Herb Derby1c5be7b2019-12-13 12:03:06 -0500475 SkScalar newMaxScale = drawMatrix.getMaxScale();
476 SkScalar oldMaxScale = fInitialMatrix.getMaxScale();
joshualittfd5f6c12015-12-10 07:44:50 -0800477 SkScalar scaleAdjust = newMaxScale / oldMaxScale;
478 if (scaleAdjust < fMaxMinScale || scaleAdjust > fMinMaxScale) {
479 return true;
480 }
joshualittfd5f6c12015-12-10 07:44:50 -0800481 }
482
joshualittfd5f6c12015-12-10 07:44:50 -0800483 // It is possible that a blob has neither distanceField nor bitmaptext. This is in the case
484 // when all of the runs inside the blob are drawn as paths. In this case, we always regenerate
485 // the blob anyways at flush time, so no need to regenerate explicitly
486 return false;
487}
488
Herb Derbyc1b482c2018-08-09 15:02:27 -0400489void GrTextBlob::flush(GrTextTarget* target, const SkSurfaceProps& props,
490 const GrDistanceFieldAdjustTable* distanceAdjustTable,
Brian Osmancf860852018-10-31 14:04:39 -0400491 const SkPaint& paint, const SkPMColor4f& filteredColor, const GrClip& clip,
Herb Derby5bf5b042019-12-12 16:37:03 -0500492 const SkMatrix& drawMatrix, SkPoint drawOrigin) {
Jim Van Verth54d9c882018-02-08 16:14:48 -0500493
Herb Derbycb718892019-12-07 00:07:42 -0500494 for (SubRun* subRun = fFirstSubRun; subRun != nullptr; subRun = subRun->fNextSubRun) {
495 if (subRun->drawAsPaths()) {
Herb Derbydac1ed52018-09-12 17:04:21 -0400496 SkPaint runPaint{paint};
Herb Derbycb718892019-12-07 00:07:42 -0500497 runPaint.setAntiAlias(subRun->isAntiAliased());
Herb Derby1b8dcd12019-11-15 15:21:15 -0500498 // If there are shaders, blurs or styles, the path must be scaled into source
499 // space independently of the CTM. This allows the CTM to be correct for the
500 // different effects.
501 GrStyle style(runPaint);
Herb Derby9f491482018-08-08 11:53:00 -0400502
Herb Derby1b8dcd12019-11-15 15:21:15 -0500503 bool scalePath = runPaint.getShader()
504 || style.applies()
505 || runPaint.getMaskFilter();
Robert Phillips137ca522018-08-15 10:14:33 -0400506
Herb Derby1b8dcd12019-11-15 15:21:15 -0500507 // The origin for the blob may have changed, so figure out the delta.
Herb Derby5bf5b042019-12-12 16:37:03 -0500508 SkVector originShift = drawOrigin - fInitialOrigin;
Herb Derby1b8dcd12019-11-15 15:21:15 -0500509
Herb Derbycb718892019-12-07 00:07:42 -0500510 for (const auto& pathGlyph : subRun->fPaths) {
Herb Derby1c5be7b2019-12-13 12:03:06 -0500511 SkMatrix ctm{drawMatrix};
Herb Derbycb718892019-12-07 00:07:42 -0500512 SkMatrix pathMatrix = SkMatrix::MakeScale(
513 subRun->fStrikeSpec.strikeToSourceRatio());
Herb Derby1b8dcd12019-11-15 15:21:15 -0500514 // Shift the original glyph location in source space to the position of the new
515 // blob.
516 pathMatrix.postTranslate(originShift.x() + pathGlyph.fOrigin.x(),
517 originShift.y() + pathGlyph.fOrigin.y());
Herb Derbydac1ed52018-09-12 17:04:21 -0400518
519 // TmpPath must be in the same scope as GrShape shape below.
Robert Phillips137ca522018-08-15 10:14:33 -0400520 SkTLazy<SkPath> tmpPath;
Herb Derby1b8dcd12019-11-15 15:21:15 -0500521 const SkPath* path = &pathGlyph.fPath;
Herb Derby2984d262019-11-20 14:40:39 -0500522 if (!scalePath) {
523 // Scale can be applied to CTM -- no effects.
Herb Derby2984d262019-11-20 14:40:39 -0500524 ctm.preConcat(pathMatrix);
Robert Phillipsd20d2612018-08-28 10:09:01 -0400525 } else {
Herb Derby2984d262019-11-20 14:40:39 -0500526 // Scale the outline into source space.
Herb Derbydac1ed52018-09-12 17:04:21 -0400527
Herb Derby2984d262019-11-20 14:40:39 -0500528 // Transform the path form the normalized outline to source space. This
529 // way the CTM will remain the same so it can be used by the effects.
530 SkPath* sourceOutline = tmpPath.init();
531 path->transform(pathMatrix, sourceOutline);
532 sourceOutline->setIsVolatile(true);
533 path = sourceOutline;
Robert Phillips137ca522018-08-15 10:14:33 -0400534 }
535
Robert Phillips46a13382018-08-23 13:53:01 -0400536 // TODO: we are losing the mutability of the path here
537 GrShape shape(*path, paint);
Herb Derbydac1ed52018-09-12 17:04:21 -0400538 target->drawShape(clip, runPaint, ctm, shape);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500539 }
Herb Derby1b8dcd12019-11-15 15:21:15 -0500540 } else {
Herb Derbyc514e7d2019-12-11 17:00:31 -0500541 int glyphCount = subRun->fGlyphs.size();
Jim Van Verth54d9c882018-02-08 16:14:48 -0500542 if (0 == glyphCount) {
543 continue;
544 }
545
546 bool skipClip = false;
547 bool submitOp = true;
548 SkIRect clipRect = SkIRect::MakeEmpty();
549 SkRect rtBounds = SkRect::MakeWH(target->width(), target->height());
550 SkRRect clipRRect;
551 GrAA aa;
Jim Van Verthb515ae72018-05-23 16:44:55 -0400552 // We can clip geometrically if we're not using SDFs or transformed glyphs,
Jim Van Verth54d9c882018-02-08 16:14:48 -0500553 // and we have an axis-aligned rectangular non-AA clip
Herb Derbycb718892019-12-07 00:07:42 -0500554 if (!subRun->drawAsDistanceFields() && !subRun->needsTransform() &&
Jim Van Verthcf838c72018-03-05 14:40:36 -0500555 clip.isRRect(rtBounds, &clipRRect, &aa) &&
Jim Van Verth54d9c882018-02-08 16:14:48 -0500556 clipRRect.isRect() && GrAA::kNo == aa) {
557 skipClip = true;
558 // We only need to do clipping work if the subrun isn't contained by the clip
559 SkRect subRunBounds;
Herb Derby5bf5b042019-12-12 16:37:03 -0500560 this->computeSubRunBounds(
561 &subRunBounds, *subRun, drawMatrix, drawOrigin, false);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500562 if (!clipRRect.getBounds().contains(subRunBounds)) {
563 // If the subrun is completely outside, don't add an op for it
564 if (!clipRRect.getBounds().intersects(subRunBounds)) {
565 submitOp = false;
566 }
567 else {
568 clipRRect.getBounds().round(&clipRect);
569 }
570 }
571 }
572
573 if (submitOp) {
Herb Derby5bf5b042019-12-12 16:37:03 -0500574 auto op = this->makeOp(*subRun, glyphCount, drawMatrix, drawOrigin,
Herb Derbybc6f9c92018-08-08 13:58:45 -0400575 clipRect, paint, filteredColor, props, distanceAdjustTable,
Robert Phillips5a66efb2018-03-07 15:13:18 -0500576 target);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500577 if (op) {
578 if (skipClip) {
579 target->addDrawOp(GrNoClip(), std::move(op));
580 }
581 else {
582 target->addDrawOp(clip, std::move(op));
583 }
584 }
585 }
586 }
Jim Van Verth89737de2018-02-06 21:30:20 +0000587 }
Jim Van Verth89737de2018-02-06 21:30:20 +0000588}
589
Herb Derby1c5be7b2019-12-13 12:03:06 -0500590void GrTextBlob::computeSubRunBounds(SkRect* outBounds, const SubRun& subRun,
Herb Derby5bf5b042019-12-12 16:37:03 -0500591 const SkMatrix& drawMatrix, SkPoint drawOrigin,
Herb Derbya9047642019-12-06 12:12:11 -0500592 bool needsGlyphTransform) {
593 // We don't yet position distance field text on the cpu, so we have to map the vertex bounds
594 // into device space.
595 // We handle vertex bounds differently for distance field text and bitmap text because
596 // the vertex bounds of bitmap text are in device space. If we are flushing multiple runs
597 // from one blob then we are going to pay the price here of mapping the rect for each run.
598 *outBounds = subRun.vertexBounds();
599 if (needsGlyphTransform) {
600 // Distance field text is positioned with the (X,Y) as part of the glyph position,
601 // and currently the view matrix is applied on the GPU
Herb Derby5bf5b042019-12-12 16:37:03 -0500602 outBounds->offset(drawOrigin - fInitialOrigin);
Herb Derby1c5be7b2019-12-13 12:03:06 -0500603 drawMatrix.mapRect(outBounds);
Herb Derbya9047642019-12-06 12:12:11 -0500604 } else {
605 // Bitmap text is fully positioned on the CPU, and offset by an (X,Y) translate in
606 // device space.
Herb Derby1c5be7b2019-12-13 12:03:06 -0500607 SkMatrix boundsMatrix = fInitialMatrixInverse;
Herb Derbya9047642019-12-06 12:12:11 -0500608
609 boundsMatrix.postTranslate(-fInitialOrigin.x(), -fInitialOrigin.y());
610
Herb Derby5bf5b042019-12-12 16:37:03 -0500611 boundsMatrix.postTranslate(drawOrigin.x(), drawOrigin.y());
Herb Derbya9047642019-12-06 12:12:11 -0500612
Herb Derby1c5be7b2019-12-13 12:03:06 -0500613 boundsMatrix.postConcat(drawMatrix);
Herb Derbya9047642019-12-06 12:12:11 -0500614 boundsMatrix.mapRect(outBounds);
615
616 // Due to floating point numerical inaccuracies, we have to round out here
617 outBounds->roundOut(outBounds);
618 }
joshualitt323c2eb2016-01-20 06:48:47 -0800619}
joshualitt2e2202e2015-12-10 11:22:08 -0800620
Herb Derbya9047642019-12-06 12:12:11 -0500621const GrTextBlob::Key& GrTextBlob::key() const { return fKey; }
622size_t GrTextBlob::size() const { return fSize; }
623
624std::unique_ptr<GrDrawOp> GrTextBlob::test_makeOp(
Herb Derby1c5be7b2019-12-13 12:03:06 -0500625 int glyphCount, const SkMatrix& drawMatrix,
Herb Derby5bf5b042019-12-12 16:37:03 -0500626 SkPoint drawOrigin, const SkPaint& paint, const SkPMColor4f& filteredColor,
Herb Derbya9047642019-12-06 12:12:11 -0500627 const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable,
628 GrTextTarget* target) {
Herb Derbycb718892019-12-07 00:07:42 -0500629 SubRun* info = fFirstSubRun;
Herb Derbya9047642019-12-06 12:12:11 -0500630 SkIRect emptyRect = SkIRect::MakeEmpty();
Herb Derby5bf5b042019-12-12 16:37:03 -0500631 return this->makeOp(*info, glyphCount, drawMatrix, drawOrigin, emptyRect,
Herb Derbya9047642019-12-06 12:12:11 -0500632 paint, filteredColor, props, distanceAdjustTable, target);
633}
634
635bool GrTextBlob::hasW(GrTextBlob::SubRunType type) const {
636 if (type == kTransformedSDFT) {
637 return this->hasPerspective() || fForceWForDistanceFields;
638 } else if (type == kTransformedMask || type == kTransformedPath) {
639 return this->hasPerspective();
Herb Derbye9f691d2019-12-04 12:11:13 -0500640 }
Herb Derbya9047642019-12-06 12:12:11 -0500641
642 // The viewMatrix is implicitly SkMatrix::I when drawing kDirectMask, because it is not
643 // used.
644 return false;
645}
646
647GrTextBlob::SubRun* GrTextBlob::makeSubRun(SubRunType type,
648 const SkZip<SkGlyphVariant, SkPoint>& drawables,
649 const SkStrikeSpec& strikeSpec,
650 GrMaskFormat format) {
Herb Derbyc514e7d2019-12-11 17:00:31 -0500651 SkSpan<GrGlyph*> glyphs{fAlloc.makeArrayDefault<GrGlyph*>(drawables.size()), drawables.size()};
Herb Derbya9047642019-12-06 12:12:11 -0500652 bool hasW = this->hasW(type);
Herb Derby3d3150c2019-12-23 15:26:44 -0500653
654 SkASSERT(!fInitialMatrix.hasPerspective() || hasW);
655
Herb Derbyc514e7d2019-12-11 17:00:31 -0500656 size_t vertexDataSize = drawables.size() * GetVertexStride(format, hasW) * kVerticesPerGlyph;
657 SkSpan<char> vertexData{fAlloc.makeArrayDefault<char>(vertexDataSize), vertexDataSize};
Herb Derbya9047642019-12-06 12:12:11 -0500658
659 sk_sp<GrTextStrike> grStrike = strikeSpec.findOrCreateGrStrike(fStrikeCache);
660
Herb Derbycb718892019-12-07 00:07:42 -0500661 SubRun* subRun = fAlloc.make<SubRun>(
Herb Derbyc514e7d2019-12-11 17:00:31 -0500662 type, this, strikeSpec, format, glyphs, vertexData, std::move(grStrike));
Herb Derbya9047642019-12-06 12:12:11 -0500663
Herb Derbycb718892019-12-07 00:07:42 -0500664 subRun->appendGlyphs(drawables);
Herb Derbya9047642019-12-06 12:12:11 -0500665
Herb Derbycb718892019-12-07 00:07:42 -0500666 return subRun;
Herb Derbya9047642019-12-06 12:12:11 -0500667}
668
669void GrTextBlob::addSingleMaskFormat(
670 SubRunType type,
671 const SkZip<SkGlyphVariant, SkPoint>& drawables,
672 const SkStrikeSpec& strikeSpec,
673 GrMaskFormat format) {
674 this->makeSubRun(type, drawables, strikeSpec, format);
675}
676
677void GrTextBlob::addMultiMaskFormat(
678 SubRunType type,
679 const SkZip<SkGlyphVariant, SkPoint>& drawables,
680 const SkStrikeSpec& strikeSpec) {
681 this->setHasBitmap();
682 if (drawables.empty()) { return; }
683
684 auto glyphSpan = drawables.get<0>();
685 SkGlyph* glyph = glyphSpan[0];
686 GrMaskFormat format = GrGlyph::FormatFromSkGlyph(glyph->maskFormat());
687 size_t startIndex = 0;
688 for (size_t i = 1; i < drawables.size(); i++) {
689 glyph = glyphSpan[i];
690 GrMaskFormat nextFormat = GrGlyph::FormatFromSkGlyph(glyph->maskFormat());
691 if (format != nextFormat) {
692 auto sameFormat = drawables.subspan(startIndex, i - startIndex);
693 this->addSingleMaskFormat(type, sameFormat, strikeSpec, format);
694 format = nextFormat;
695 startIndex = i;
696 }
697 }
698 auto sameFormat = drawables.last(drawables.size() - startIndex);
699 this->addSingleMaskFormat(type, sameFormat, strikeSpec, format);
700}
701
702void GrTextBlob::addSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables,
703 const SkStrikeSpec& strikeSpec,
704 const SkFont& runFont,
705 SkScalar minScale,
706 SkScalar maxScale) {
707 this->setHasDistanceField();
708 this->setMinAndMaxScale(minScale, maxScale);
709
710 SubRun* subRun = this->makeSubRun(kTransformedSDFT, drawables, strikeSpec, kA8_GrMaskFormat);
711 subRun->setUseLCDText(runFont.getEdging() == SkFont::Edging::kSubpixelAntiAlias);
712 subRun->setAntiAliased(runFont.hasSomeAntiAliasing());
Herb Derbye9f691d2019-12-04 12:11:13 -0500713}
714
Herb Derbycb718892019-12-07 00:07:42 -0500715GrTextBlob::GrTextBlob(size_t allocSize,
Herb Derbyeba195f2019-12-03 16:44:47 -0500716 GrStrikeCache* strikeCache,
Herb Derby1c5be7b2019-12-13 12:03:06 -0500717 const SkMatrix& drawMatrix,
Herb Derbyeba195f2019-12-03 16:44:47 -0500718 SkPoint origin,
719 GrColor color,
Herb Derbyaebc5f82019-12-10 14:07:10 -0500720 SkColor initialLuminance,
Herb Derby00ae9592019-12-03 15:55:56 -0500721 bool forceWForDistanceFields)
Herb Derbycb718892019-12-07 00:07:42 -0500722 : fSize{allocSize}
Herb Derby00ae9592019-12-03 15:55:56 -0500723 , fStrikeCache{strikeCache}
Herb Derby1c5be7b2019-12-13 12:03:06 -0500724 , fInitialMatrix{drawMatrix}
725 , fInitialMatrixInverse{make_inverse(drawMatrix)}
Herb Derbyeba195f2019-12-03 16:44:47 -0500726 , fInitialOrigin{origin}
Herb Derby00ae9592019-12-03 15:55:56 -0500727 , fForceWForDistanceFields{forceWForDistanceFields}
Herb Derbycb718892019-12-07 00:07:42 -0500728 , fColor{color}
Herb Derbyaebc5f82019-12-10 14:07:10 -0500729 , fInitialLuminance{initialLuminance}
Herb Derbycb718892019-12-07 00:07:42 -0500730 , fAlloc{SkTAddOffset<char>(this, sizeof(GrTextBlob)), allocSize, allocSize/2} { }
Herb Derby00ae9592019-12-03 15:55:56 -0500731
Herb Derbycb718892019-12-07 00:07:42 -0500732void GrTextBlob::insertSubRun(SubRun* subRun) {
733 if (fFirstSubRun == nullptr) {
734 fFirstSubRun = subRun;
735 fLastSubRun = subRun;
736 } else {
737 fLastSubRun->fNextSubRun = subRun;
738 fLastSubRun = subRun;
739 }
740}
741
742std::unique_ptr<GrAtlasTextOp> GrTextBlob::makeOp(
Herb Derbya9047642019-12-06 12:12:11 -0500743 SubRun& info, int glyphCount,
Herb Derby5bf5b042019-12-12 16:37:03 -0500744 const SkMatrix& drawMatrix, SkPoint drawOrigin, const SkIRect& clipRect,
Herb Derbya9047642019-12-06 12:12:11 -0500745 const SkPaint& paint, const SkPMColor4f& filteredColor, const SkSurfaceProps& props,
746 const GrDistanceFieldAdjustTable* distanceAdjustTable, GrTextTarget* target) {
747 GrMaskFormat format = info.maskFormat();
748
749 GrPaint grPaint;
Herb Derby1c5be7b2019-12-13 12:03:06 -0500750 target->makeGrPaint(info.maskFormat(), paint, drawMatrix, &grPaint);
Herb Derbya9047642019-12-06 12:12:11 -0500751 std::unique_ptr<GrAtlasTextOp> op;
752 if (info.drawAsDistanceFields()) {
753 // TODO: Can we be even smarter based on the dest transfer function?
754 op = GrAtlasTextOp::MakeDistanceField(
755 target->getContext(), std::move(grPaint), glyphCount, distanceAdjustTable,
756 target->colorInfo().isLinearlyBlended(), SkPaintPriv::ComputeLuminanceColor(paint),
757 props, info.isAntiAliased(), info.hasUseLCDText());
Herb Derbyeba195f2019-12-03 16:44:47 -0500758 } else {
Herb Derbya9047642019-12-06 12:12:11 -0500759 op = GrAtlasTextOp::MakeBitmap(target->getContext(), std::move(grPaint), format, glyphCount,
760 info.needsTransform());
761 }
762 GrAtlasTextOp::Geometry& geometry = op->geometry();
Herb Derby1c5be7b2019-12-13 12:03:06 -0500763 geometry.fDrawMatrix = drawMatrix;
Herb Derbya9047642019-12-06 12:12:11 -0500764 geometry.fClipRect = clipRect;
765 geometry.fBlob = SkRef(this);
766 geometry.fSubRunPtr = &info;
767 geometry.fColor = info.maskFormat() == kARGB_GrMaskFormat ? SK_PMColor4fWHITE : filteredColor;
Herb Derby5bf5b042019-12-12 16:37:03 -0500768 geometry.fDrawOrigin = drawOrigin;
Herb Derbya9047642019-12-06 12:12:11 -0500769 op->init();
770 return op;
771}
Herb Derbyeba195f2019-12-03 16:44:47 -0500772
Herb Derbya9047642019-12-06 12:12:11 -0500773void GrTextBlob::processDeviceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
774 const SkStrikeSpec& strikeSpec) {
775 this->addMultiMaskFormat(kDirectMask, drawables, strikeSpec);
776}
Herb Derbyeba195f2019-12-03 16:44:47 -0500777
Herb Derbya9047642019-12-06 12:12:11 -0500778void GrTextBlob::processSourcePaths(const SkZip<SkGlyphVariant, SkPoint>& drawables,
779 const SkFont& runFont,
780 const SkStrikeSpec& strikeSpec) {
781 this->setHasBitmap();
Herb Derbycb718892019-12-07 00:07:42 -0500782 SubRun* subRun = fAlloc.make<SubRun>(this, strikeSpec);
783 subRun->setAntiAliased(runFont.hasSomeAntiAliasing());
Herb Derbya9047642019-12-06 12:12:11 -0500784 for (auto [variant, pos] : drawables) {
Herb Derbycb718892019-12-07 00:07:42 -0500785 subRun->fPaths.emplace_back(*variant.path(), pos);
Herb Derbyeba195f2019-12-03 16:44:47 -0500786 }
787}
788
Herb Derbya9047642019-12-06 12:12:11 -0500789void GrTextBlob::processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables,
790 const SkStrikeSpec& strikeSpec,
791 const SkFont& runFont,
792 SkScalar minScale,
793 SkScalar maxScale) {
794 this->addSDFT(drawables, strikeSpec, runFont, minScale, maxScale);
joshualitt8e0ef292016-02-19 14:13:03 -0800795}
Herb Derbya9047642019-12-06 12:12:11 -0500796
797void GrTextBlob::processSourceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
798 const SkStrikeSpec& strikeSpec) {
799 this->addMultiMaskFormat(kTransformedMask, drawables, strikeSpec);
800}
801
802// -- GrTextBlob::VertexRegenerator ----------------------------------------------------------------
Herb Derbya9047642019-12-06 12:12:11 -0500803static void regen_texcoords(char* vertex, size_t vertexStride, const GrGlyph* glyph,
804 bool useDistanceFields) {
805 // This is a bit wonky, but sometimes we have LCD text, in which case we won't have color
806 // vertices, hence vertexStride - sizeof(SkIPoint16)
807 size_t texCoordOffset = vertexStride - sizeof(SkIPoint16);
808
809 uint16_t u0, v0, u1, v1;
810 SkASSERT(glyph);
811 int width = glyph->fBounds.width();
812 int height = glyph->fBounds.height();
813
814 if (useDistanceFields) {
815 u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset;
816 v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset;
817 u1 = u0 + width - 2 * SK_DistanceFieldInset;
818 v1 = v0 + height - 2 * SK_DistanceFieldInset;
819 } else {
820 u0 = glyph->fAtlasLocation.fX;
821 v0 = glyph->fAtlasLocation.fY;
822 u1 = u0 + width;
823 v1 = v0 + height;
824 }
825 // We pack the 2bit page index in the low bit of the u and v texture coords
826 uint32_t pageIndex = glyph->pageIndex();
827 SkASSERT(pageIndex < 4);
828 uint16_t uBit = (pageIndex >> 1) & 0x1;
829 uint16_t vBit = pageIndex & 0x1;
830 u0 <<= 1;
831 u0 |= uBit;
832 v0 <<= 1;
833 v0 |= vBit;
834 u1 <<= 1;
835 u1 |= uBit;
836 v1 <<= 1;
837 v1 |= vBit;
838
839 uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
840 textureCoords[0] = u0;
841 textureCoords[1] = v0;
842 textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
843 textureCoords[0] = u0;
844 textureCoords[1] = v1;
845 textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
846 textureCoords[0] = u1;
847 textureCoords[1] = v0;
848 textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
849 textureCoords[0] = u1;
850 textureCoords[1] = v1;
851
852#ifdef DISPLAY_PAGE_INDEX
853 // Enable this to visualize the page from which each glyph is being drawn.
854 // Green Red Magenta Cyan -> 0 1 2 3; Black -> error
855 GrColor hackColor;
856 switch (pageIndex) {
857 case 0:
858 hackColor = GrColorPackRGBA(0, 255, 0, 255);
859 break;
860 case 1:
861 hackColor = GrColorPackRGBA(255, 0, 0, 255);;
862 break;
863 case 2:
864 hackColor = GrColorPackRGBA(255, 0, 255, 255);
865 break;
866 case 3:
867 hackColor = GrColorPackRGBA(0, 255, 255, 255);
868 break;
869 default:
870 hackColor = GrColorPackRGBA(0, 0, 0, 255);
871 break;
872 }
873 regen_colors(vertex, vertexStride, hackColor);
874#endif
875}
876
877GrTextBlob::VertexRegenerator::VertexRegenerator(GrResourceProvider* resourceProvider,
Herb Derbya9047642019-12-06 12:12:11 -0500878 GrTextBlob::SubRun* subRun,
Herb Derby5bf5b042019-12-12 16:37:03 -0500879 const SkMatrix& drawMatrix,
880 SkPoint drawOrigin,
Herb Derbya9047642019-12-06 12:12:11 -0500881 GrColor color,
882 GrDeferredUploadTarget* uploadTarget,
883 GrStrikeCache* grStrikeCache,
884 GrAtlasManager* fullAtlasManager)
885 : fResourceProvider(resourceProvider)
Herb Derby1c5be7b2019-12-13 12:03:06 -0500886 , fDrawMatrix(drawMatrix)
Herb Derbya9047642019-12-06 12:12:11 -0500887 , fUploadTarget(uploadTarget)
888 , fGrStrikeCache(grStrikeCache)
889 , fFullAtlasManager(fullAtlasManager)
890 , fSubRun(subRun)
891 , fColor(color) {
892 // Compute translation if any
Herb Derby5bf5b042019-12-12 16:37:03 -0500893 fDrawTranslation = fSubRun->computeTranslation(fDrawMatrix, drawOrigin);
Herb Derbya9047642019-12-06 12:12:11 -0500894
895 // Because the GrStrikeCache may evict the strike a blob depends on using for
896 // generating its texture coords, we have to track whether or not the strike has
897 // been abandoned. If it hasn't been abandoned, then we can use the GrGlyph*s as is
898 // otherwise we have to get the new strike, and use that to get the correct glyphs.
899 // Because we do not have the packed ids, and thus can't look up our glyphs in the
900 // new strike, we instead keep our ref to the old strike and use the packed ids from
901 // it. These ids will still be valid as long as we hold the ref. When we are done
902 // updating our cache of the GrGlyph*s, we drop our ref on the old strike
Herb Derby73630212019-12-13 16:29:14 -0500903 fActions.regenTextureCoordinates = fSubRun->strike()->isAbandoned();
904 fActions.regenStrike = fSubRun->strike()->isAbandoned();
Herb Derby6ca4f312019-12-26 15:23:49 -0500905 if (kARGB_GrMaskFormat != fSubRun->maskFormat() && fSubRun->color() != color) {
906 fSubRun->updateColor(color);
907 }
Herb Derby91fd46a2019-12-26 11:36:30 -0500908 if (fDrawTranslation.x() != 0.f || fDrawTranslation.y() != 0.f) {
909 fSubRun->updateTranslation(fDrawTranslation);
910 }
Herb Derbya9047642019-12-06 12:12:11 -0500911}
912
Herb Derby73630212019-12-13 16:29:14 -0500913bool GrTextBlob::VertexRegenerator::doRegen(GrTextBlob::VertexRegenerator::Result* result) {
914 SkASSERT(!fActions.regenStrike || fActions.regenTextureCoordinates);
915 if (fActions.regenTextureCoordinates) {
Herb Derbya9047642019-12-06 12:12:11 -0500916 fSubRun->resetBulkUseToken();
917
918 const SkStrikeSpec& strikeSpec = fSubRun->strikeSpec();
919
920 if (!fMetricsAndImages.isValid()
921 || fMetricsAndImages->descriptor() != strikeSpec.descriptor()) {
922 fMetricsAndImages.init(strikeSpec);
923 }
924
Herb Derby73630212019-12-13 16:29:14 -0500925 if (fActions.regenStrike) {
Herb Derbya9047642019-12-06 12:12:11 -0500926 // Take the glyphs from the old strike, and translate them a new strike.
927 sk_sp<GrTextStrike> newStrike = strikeSpec.findOrCreateGrStrike(fGrStrikeCache);
928
929 // Start this batch at the start of the subRun plus any glyphs that were previously
930 // processed.
Herb Derbyc514e7d2019-12-11 17:00:31 -0500931 SkSpan<GrGlyph*> glyphs = fSubRun->fGlyphs.last(fSubRun->fGlyphs.size() - fCurrGlyph);
Herb Derbya9047642019-12-06 12:12:11 -0500932
933 // Convert old glyphs to newStrike.
934 for (auto& glyph : glyphs) {
935 SkPackedGlyphID id = glyph->fPackedID;
936 glyph = newStrike->getGlyph(id, fMetricsAndImages.get());
937 SkASSERT(id == glyph->fPackedID);
938 }
939
940 fSubRun->setStrike(newStrike);
941 }
942 }
943
Herb Derby7cf4a2e2019-12-23 14:51:55 -0500944 GrTextStrike* grStrike = fSubRun->strike();
Herb Derbya2d72252019-12-23 15:02:33 -0500945 auto vertexStride = fSubRun->vertexStride();
Herb Derbyc514e7d2019-12-11 17:00:31 -0500946 char* currVertex = fSubRun->fVertexData.data() + fCurrGlyph * kVerticesPerGlyph * vertexStride;
Herb Derbya9047642019-12-06 12:12:11 -0500947 result->fFirstVertex = currVertex;
948
Herb Derbyc514e7d2019-12-11 17:00:31 -0500949 for (int glyphIdx = fCurrGlyph; glyphIdx < (int)fSubRun->fGlyphs.size(); glyphIdx++) {
Herb Derbya9047642019-12-06 12:12:11 -0500950 GrGlyph* glyph = nullptr;
Herb Derby73630212019-12-13 16:29:14 -0500951 if (fActions.regenTextureCoordinates) {
Herb Derbyc514e7d2019-12-11 17:00:31 -0500952 glyph = fSubRun->fGlyphs[glyphIdx];
Herb Derbya9047642019-12-06 12:12:11 -0500953 SkASSERT(glyph && glyph->fMaskFormat == fSubRun->maskFormat());
954
955 if (!fFullAtlasManager->hasGlyph(glyph)) {
Herb Derby7cf4a2e2019-12-23 14:51:55 -0500956 GrDrawOpAtlas::ErrorCode code = grStrike->addGlyphToAtlas(
957 fResourceProvider, fUploadTarget, fGrStrikeCache, fFullAtlasManager, glyph,
958 fMetricsAndImages.get(), fSubRun->maskFormat(), fSubRun->needsTransform());
Herb Derbya9047642019-12-06 12:12:11 -0500959 if (GrDrawOpAtlas::ErrorCode::kError == code) {
960 // Something horrible has happened - drop the op
961 return false;
962 }
963 else if (GrDrawOpAtlas::ErrorCode::kTryAgain == code) {
964 fBrokenRun = glyphIdx > 0;
965 result->fFinished = false;
966 return true;
967 }
968 }
969 auto tokenTracker = fUploadTarget->tokenTracker();
970 fFullAtlasManager->addGlyphToBulkAndSetUseToken(fSubRun->bulkUseToken(), glyph,
971 tokenTracker->nextDrawToken());
972 }
973
Herb Derby73630212019-12-13 16:29:14 -0500974 if (fActions.regenTextureCoordinates) {
Herb Derbya9047642019-12-06 12:12:11 -0500975 regen_texcoords(currVertex, vertexStride, glyph, fSubRun->drawAsDistanceFields());
976 }
977
978 currVertex += vertexStride * GrAtlasTextOp::kVerticesPerGlyph;
979 ++result->fGlyphsRegenerated;
980 ++fCurrGlyph;
981 }
982
983 // We may have changed the color so update it here
984 fSubRun->setColor(fColor);
Herb Derby73630212019-12-13 16:29:14 -0500985 if (fActions.regenTextureCoordinates) {
Herb Derbya9047642019-12-06 12:12:11 -0500986 fSubRun->setAtlasGeneration(fBrokenRun
987 ? GrDrawOpAtlas::kInvalidAtlasGeneration
988 : fFullAtlasManager->atlasGeneration(fSubRun->maskFormat()));
989 } else {
990 // For the non-texCoords case we need to ensure that we update the associated use tokens
991 fFullAtlasManager->setUseTokenBulk(*fSubRun->bulkUseToken(),
992 fUploadTarget->tokenTracker()->nextDrawToken(),
993 fSubRun->maskFormat());
994 }
995 return true;
996}
997
998bool GrTextBlob::VertexRegenerator::regenerate(GrTextBlob::VertexRegenerator::Result* result) {
999 uint64_t currentAtlasGen = fFullAtlasManager->atlasGeneration(fSubRun->maskFormat());
1000 // If regenerate() is called multiple times then the atlas gen may have changed. So we check
1001 // this each time.
Herb Derby73630212019-12-13 16:29:14 -05001002 fActions.regenTextureCoordinates |= fSubRun->atlasGeneration() != currentAtlasGen;
Herb Derbya9047642019-12-06 12:12:11 -05001003
Herb Derby73630212019-12-13 16:29:14 -05001004 if (fActions.regenStrike
Herb Derby6ca4f312019-12-26 15:23:49 -05001005 |fActions.regenTextureCoordinates) {
Herb Derby73630212019-12-13 16:29:14 -05001006 return this->doRegen(result);
Herb Derbya9047642019-12-06 12:12:11 -05001007 } else {
Herb Derbya2d72252019-12-23 15:02:33 -05001008 auto vertexStride = fSubRun->vertexStride();
Herb Derbya9047642019-12-06 12:12:11 -05001009 result->fFinished = true;
Herb Derbyc514e7d2019-12-11 17:00:31 -05001010 result->fGlyphsRegenerated = fSubRun->fGlyphs.size() - fCurrGlyph;
1011 result->fFirstVertex = fSubRun->fVertexData.data() +
1012 fCurrGlyph * kVerticesPerGlyph * vertexStride;
1013 fCurrGlyph = fSubRun->fGlyphs.size();
Herb Derbya9047642019-12-06 12:12:11 -05001014
1015 // set use tokens for all of the glyphs in our subrun. This is only valid if we
1016 // have a valid atlas generation
1017 fFullAtlasManager->setUseTokenBulk(*fSubRun->bulkUseToken(),
1018 fUploadTarget->tokenTracker()->nextDrawToken(),
1019 fSubRun->maskFormat());
1020 return true;
1021 }
1022 SK_ABORT("Should not get here");
1023}
1024
1025
1026
1027