blob: 6cb646a350fa5bc71f05f6d4c3419aae6710891c [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"
Herb Derby4a1f5fc2020-07-10 16:39:28 -04009#include "include/gpu/GrRecordingContext.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"
Michael Ludwigfbe28592020-06-26 16:02:15 -040012#include "src/core/SkMatrixPriv.h"
Brian Osman449b1152020-04-15 16:43:00 -040013#include "src/core/SkMatrixProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/core/SkPaintPriv.h"
Herb Derby3e8b57d2020-06-02 10:43:41 -040015#include "src/core/SkStrikeSpec.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/gpu/GrBlurUtils.h"
17#include "src/gpu/GrClip.h"
Herb Derby4a1f5fc2020-07-10 16:39:28 -040018#include "src/gpu/GrMemoryPool.h"
19#include "src/gpu/GrRecordingContextPriv.h"
20#include "src/gpu/GrRenderTargetContext.h"
21#include "src/gpu/GrRenderTargetContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "src/gpu/GrStyle.h"
Herb Derby4a1f5fc2020-07-10 16:39:28 -040023#include "src/gpu/SkGr.h"
24#include "src/gpu/effects/GrDistanceFieldGeoProc.h"
Michael Ludwig2686d692020-04-17 20:21:37 +000025#include "src/gpu/geometry/GrStyledShape.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050026#include "src/gpu/ops/GrAtlasTextOp.h"
Herb Derbya9047642019-12-06 12:12:11 -050027#include "src/gpu/text/GrAtlasManager.h"
Robert Phillips41bd97d2020-04-07 14:19:37 -040028#include "src/gpu/text/GrStrikeCache.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050029#include "src/gpu/text/GrTextBlob.h"
Ben Wagner75d6db72018-09-20 14:39:39 -040030
Herb Derby3d3150c2019-12-23 15:26:44 -050031#include <cstddef>
Mike Klein79aea6a2018-06-11 10:45:26 -040032#include <new>
joshualitt2e2202e2015-12-10 11:22:08 -080033
Herb Derbya9047642019-12-06 12:12:11 -050034// -- GrTextBlob::Key ------------------------------------------------------------------------------
35GrTextBlob::Key::Key() { sk_bzero(this, sizeof(Key)); }
36
37bool GrTextBlob::Key::operator==(const GrTextBlob::Key& other) const {
38 return 0 == memcmp(this, &other, sizeof(Key));
39}
40
Herb Derbyb2db9792020-07-14 15:39:25 -040041// -- GrPathSubRun::PathGlyph ----------------------------------------------------------------------
42GrPathSubRun::PathGlyph::PathGlyph(const SkPath& path, SkPoint origin)
Herb Derbya9047642019-12-06 12:12:11 -050043 : fPath(path)
44 , fOrigin(origin) {}
45
Herb Derbyb2db9792020-07-14 15:39:25 -040046// -- GrPathSubRun ---------------------------------------------------------------------------------
47GrPathSubRun::GrPathSubRun(bool isAntiAliased,
48 const SkStrikeSpec& strikeSpec,
49 SkSpan<PathGlyph> paths)
50 : fIsAntiAliased{isAntiAliased}
51 , fStrikeSpec{strikeSpec}
52 , fPaths{paths} {}
53
54void GrPathSubRun::draw(const GrClip* clip,
55 const SkMatrixProvider& viewMatrix,
56 const SkGlyphRunList& glyphRunList,
Herb Derby43ad7912020-07-20 16:14:19 -040057 GrRenderTargetContext* rtc) const {
Herb Derbyb2db9792020-07-14 15:39:25 -040058 SkASSERT(!fPaths.empty());
59 SkPoint drawOrigin = glyphRunList.origin();
60 const SkPaint& drawPaint = glyphRunList.paint();
61 SkPaint runPaint{drawPaint};
62 runPaint.setAntiAlias(fIsAntiAliased);
63 // If there are shaders, blurs or styles, the path must be scaled into source
64 // space independently of the CTM. This allows the CTM to be correct for the
65 // different effects.
66 GrStyle style(runPaint);
67
68 bool needsExactCTM = runPaint.getShader()
69 || style.applies()
70 || runPaint.getMaskFilter();
71
72 // Calculate the matrix that maps the path glyphs from their size in the strike to
73 // the graphics source space.
74 SkScalar scale = this->fStrikeSpec.strikeToSourceRatio();
75 SkMatrix strikeToSource = SkMatrix::Scale(scale, scale);
76 strikeToSource.postTranslate(drawOrigin.x(), drawOrigin.y());
77 if (!needsExactCTM) {
78 for (const auto& pathPos : fPaths) {
79 const SkPath& path = pathPos.fPath;
80 const SkPoint pos = pathPos.fOrigin; // Transform the glyph to source space.
81 SkMatrix pathMatrix = strikeToSource;
82 pathMatrix.postTranslate(pos.x(), pos.y());
83 SkPreConcatMatrixProvider strikeToDevice(viewMatrix, pathMatrix);
84
85 GrStyledShape shape(path, drawPaint);
86 GrBlurUtils::drawShapeWithMaskFilter(
Robert Phillipsa9306eb2020-07-21 13:01:25 -040087 rtc->priv().recordingContext(), rtc, clip, runPaint, strikeToDevice, shape);
Herb Derbyb2db9792020-07-14 15:39:25 -040088 }
89 } else {
90 // Transform the path to device because the deviceMatrix must be unchanged to
91 // draw effect, filter or shader paths.
92 for (const auto& pathPos : fPaths) {
93 const SkPath& path = pathPos.fPath;
94 const SkPoint pos = pathPos.fOrigin;
95 // Transform the glyph to source space.
96 SkMatrix pathMatrix = strikeToSource;
97 pathMatrix.postTranslate(pos.x(), pos.y());
98
99 SkPath deviceOutline;
100 path.transform(pathMatrix, &deviceOutline);
101 deviceOutline.setIsVolatile(true);
102 GrStyledShape shape(deviceOutline, drawPaint);
103 GrBlurUtils::drawShapeWithMaskFilter(
Robert Phillipsa9306eb2020-07-21 13:01:25 -0400104 rtc->priv().recordingContext(), rtc, clip, runPaint, viewMatrix, shape);
Herb Derbyb2db9792020-07-14 15:39:25 -0400105 }
106 }
107}
108
Herb Derbyaf3ae692020-07-14 20:46:23 -0400109auto GrPathSubRun::Make(
Herb Derbyb2db9792020-07-14 15:39:25 -0400110 const SkZip<SkGlyphVariant, SkPoint>& drawables,
111 bool isAntiAliased,
112 const SkStrikeSpec& strikeSpec,
113 SkArenaAlloc* alloc) -> GrSubRun* {
114 PathGlyph* pathData = alloc->makeInitializedArray<PathGlyph>(
115 drawables.size(),
116 [&](size_t i) -> PathGlyph {
117 auto [variant, pos] = drawables[i];
118 return {*variant.path(), pos};
119 });
120
121 return alloc->make<GrPathSubRun>(
122 isAntiAliased, strikeSpec, SkMakeSpan(pathData, drawables.size()));
123};
124
Herb Derbyc1cde362020-07-17 14:07:00 -0400125// -- GrGlyphVector --------------------------------------------------------------------------------
126GrGlyphVector::GrGlyphVector(const SkStrikeSpec& spec, SkSpan<Variant> glyphs)
127 : fStrikeSpec{spec}
128 , fGlyphs{glyphs} { }
129
130GrGlyphVector GrGlyphVector::Make(
131 const SkStrikeSpec &spec, SkSpan<SkGlyphVariant> glyphs, SkArenaAlloc *alloc) {
132
133 Variant* variants = alloc->makeInitializedArray<Variant>(glyphs.size(),
134 [&](int i) {
135 return Variant{glyphs[i].glyph()->getPackedID()};
136 });
137
138 return GrGlyphVector{spec, SkMakeSpan(variants, glyphs.size())};
139}
140
Herb Derbyc1cde362020-07-17 14:07:00 -0400141SkSpan<const GrGlyph*> GrGlyphVector::glyphs() const {
142 return SkMakeSpan(reinterpret_cast<const GrGlyph**>(fGlyphs.data()), fGlyphs.size());
143}
144
Herb Derby43ad7912020-07-20 16:14:19 -0400145std::tuple<bool, int> GrGlyphVector::regenerateAtlas(int begin, int end,
146 GrMaskFormat maskFormat,
Herb Derbya2800c42020-07-31 15:16:55 -0400147 GrMeshDrawOp::Target* target,
148 bool bilerpPadding) {
Herb Derbyc1cde362020-07-17 14:07:00 -0400149 GrAtlasManager* atlasManager = target->atlasManager();
150 GrDeferredUploadTarget* uploadTarget = target->deferredUploadTarget();
151
152 uint64_t currentAtlasGen = atlasManager->atlasGeneration(maskFormat);
153
Herb Derbyb9b3b052020-07-21 11:21:57 -0400154 if (fStrike == nullptr) {
155 fStrike = fStrikeSpec.findOrCreateGrStrike(target->strikeCache());
156
157 for (auto& variant : fGlyphs) {
158 variant.grGlyph = fStrike->getGlyph(variant.packedGlyphID);
159 }
160 }
Herb Derbyc1cde362020-07-17 14:07:00 -0400161
162 if (fAtlasGeneration != currentAtlasGen) {
163 // Calculate the texture coordinates for the vertexes during first use (fAtlasGeneration
164 // is set to kInvalidAtlasGeneration) or the atlas has changed in subsequent calls..
165 fBulkUseToken.reset();
166
167 SkBulkGlyphMetricsAndImages metricsAndImages{fStrikeSpec};
168
169 // Update the atlas information in the GrStrike.
170 auto tokenTracker = uploadTarget->tokenTracker();
171 auto glyphs = fGlyphs.subspan(begin, end - begin);
172 int glyphsPlacedInAtlas = 0;
173 bool success = true;
174 for (const Variant& variant : glyphs) {
175 GrGlyph* grGlyph = variant.grGlyph;
176 SkASSERT(grGlyph != nullptr);
177
178 if (!atlasManager->hasGlyph(maskFormat, grGlyph)) {
179 const SkGlyph& skGlyph = *metricsAndImages.glyph(grGlyph->fPackedID);
180 auto code = atlasManager->addGlyphToAtlas(
Herb Derbya2800c42020-07-31 15:16:55 -0400181 skGlyph, grGlyph, target->resourceProvider(),
182 uploadTarget, bilerpPadding);
Herb Derbyc1cde362020-07-17 14:07:00 -0400183 if (code != GrDrawOpAtlas::ErrorCode::kSucceeded) {
184 success = code != GrDrawOpAtlas::ErrorCode::kError;
185 break;
186 }
187 }
188 atlasManager->addGlyphToBulkAndSetUseToken(
189 &fBulkUseToken, maskFormat, grGlyph,
190 tokenTracker->nextDrawToken());
191 glyphsPlacedInAtlas++;
192 }
193
194 // Update atlas generation if there are no more glyphs to put in the atlas.
195 if (success && begin + glyphsPlacedInAtlas == fGlyphs.count()) {
196 // Need to get the freshest value of the atlas' generation because
197 // updateTextureCoordinates may have changed it.
198 fAtlasGeneration = atlasManager->atlasGeneration(maskFormat);
199 }
200
201 return {success, glyphsPlacedInAtlas};
202 } else {
203 // The atlas hasn't changed, so our texture coordinates are still valid.
204 if (end == fGlyphs.count()) {
205 // The atlas hasn't changed and the texture coordinates are all still valid. Update
206 // all the plots used to the new use token.
207 atlasManager->setUseTokenBulk(fBulkUseToken,
208 uploadTarget->tokenTracker()->nextDrawToken(),
209 maskFormat);
210 }
211 return {true, end - begin};
212 }
213}
214
Herb Derby53453f72020-07-24 15:03:54 -0400215// -- GrAtlasSubRun --------------------------------------------------------------------------------
216static GrAtlasTextOp::MaskType op_mask_type(GrMaskFormat grMaskFormat) {
217 switch (grMaskFormat) {
218 case kA8_GrMaskFormat: return GrAtlasTextOp::kGrayscaleCoverageMask_MaskType;
219 case kA565_GrMaskFormat: return GrAtlasTextOp::kLCDCoverageMask_MaskType;
220 case kARGB_GrMaskFormat: return GrAtlasTextOp::kColorBitmapMask_MaskType;
221 // Needed to placate some compilers.
222 default: return GrAtlasTextOp::kGrayscaleCoverageMask_MaskType;
223 }
224}
225
Herb Derby09357cc2020-07-20 09:55:48 -0400226// -- GrDirectMaskSubRun ---------------------------------------------------------------------------
227GrDirectMaskSubRun::GrDirectMaskSubRun(GrMaskFormat format,
228 GrTextBlob* blob,
229 const SkRect& bounds,
230 SkSpan<const VertexData> vertexData,
231 GrGlyphVector glyphs)
232 : fMaskFormat{format}
233 , fBlob{blob}
234 , fVertexBounds{bounds}
235 , fVertexData{vertexData}
236 , fGlyphs{glyphs} { }
237
238GrSubRun* GrDirectMaskSubRun::Make(const SkZip<SkGlyphVariant, SkPoint>& drawables,
239 const SkStrikeSpec& strikeSpec,
240 GrMaskFormat format,
241 GrTextBlob* blob,
242 SkArenaAlloc* alloc) {
243 size_t vertexCount = drawables.size();
244 SkRect bounds = SkRectPriv::MakeLargestInverted();
245 auto initializer = [&, strikeToSource=strikeSpec.strikeToSourceRatio()](size_t i) {
246 auto [variant, pos] = drawables[i];
247 SkGlyph* skGlyph = variant;
248 int16_t l = skGlyph->left();
249 int16_t t = skGlyph->top();
250 int16_t r = l + skGlyph->width();
251 int16_t b = t + skGlyph->height();
252 SkPoint lt = SkPoint::Make(l, t) * strikeToSource + pos,
253 rb = SkPoint::Make(r, b) * strikeToSource + pos;
254
255 bounds.joinPossiblyEmptyRect(SkRect::MakeLTRB(lt.x(), lt.y(), rb.x(), rb.y()));
256 return VertexData{pos, {l, t, r, b}};
257 };
258
259 SkSpan<const VertexData> vertexData{
260 alloc->makeInitializedArray<VertexData>(vertexCount, initializer), vertexCount};
261
262 GrDirectMaskSubRun* subRun = alloc->make<GrDirectMaskSubRun>(
263 format, blob, bounds, vertexData,
264 GrGlyphVector::Make(strikeSpec, drawables.get<0>(), alloc));
265
266 return subRun;
267}
268
269void GrDirectMaskSubRun::draw(const GrClip* clip, const SkMatrixProvider& viewMatrix,
Herb Derby43ad7912020-07-20 16:14:19 -0400270 const SkGlyphRunList& glyphRunList, GrRenderTargetContext* rtc) const{
Herb Derby09357cc2020-07-20 09:55:48 -0400271 auto[drawingClip, op] = this->makeAtlasTextOp(clip, viewMatrix, glyphRunList, rtc);
272 if (op != nullptr) {
273 rtc->priv().addDrawOp(drawingClip, std::move(op));
274 }
275}
276
277size_t GrDirectMaskSubRun::vertexStride() const {
278 if (fMaskFormat != kARGB_GrMaskFormat) {
279 return sizeof(Mask2DVertex);
280 } else {
281 return sizeof(ARGB2DVertex);
282 }
283}
284
285int GrDirectMaskSubRun::glyphCount() const {
286 return fGlyphs.glyphs().count();
287}
288
Herb Derby09357cc2020-07-20 09:55:48 -0400289static SkPMColor4f calculate_colors(GrRenderTargetContext* rtc,
290 const SkPaint& paint,
291 const SkMatrixProvider& matrix,
292 GrMaskFormat grMaskFormat,
293 GrPaint* grPaint) {
Robert Phillipsa9306eb2020-07-21 13:01:25 -0400294 GrRecordingContext* rContext = rtc->priv().recordingContext();
Herb Derby09357cc2020-07-20 09:55:48 -0400295 const GrColorInfo& colorInfo = rtc->colorInfo();
296 if (grMaskFormat == kARGB_GrMaskFormat) {
Robert Phillipsa9306eb2020-07-21 13:01:25 -0400297 SkPaintToGrPaintWithPrimitiveColor(rContext, colorInfo, paint, matrix, grPaint);
Herb Derby09357cc2020-07-20 09:55:48 -0400298 return SK_PMColor4fWHITE;
299 } else {
Robert Phillipsa9306eb2020-07-21 13:01:25 -0400300 SkPaintToGrPaint(rContext, colorInfo, paint, matrix, grPaint);
Brian Osmande53ba52020-07-30 09:37:20 -0400301 return grPaint->getColor4f();
Herb Derby09357cc2020-07-20 09:55:48 -0400302 }
303}
304
305std::tuple<const GrClip*, std::unique_ptr<GrDrawOp>>
306GrDirectMaskSubRun::makeAtlasTextOp(const GrClip* clip, const SkMatrixProvider& viewMatrix,
307 const SkGlyphRunList& glyphRunList,
Herb Derby43ad7912020-07-20 16:14:19 -0400308 GrRenderTargetContext* rtc) const {
Herb Derby09357cc2020-07-20 09:55:48 -0400309 SkASSERT(this->glyphCount() != 0);
310
311 const SkMatrix& drawMatrix = viewMatrix.localToDevice();
312 const SkPoint drawOrigin = glyphRunList.origin();
313
314 // We can clip geometrically using clipRect and ignore clip if we're not using SDFs or
315 // transformed glyphs, and we have an axis-aligned rectangular non-AA clip.
316 SkIRect clipRect = SkIRect::MakeEmpty();
317
318 // We only need to do clipping work if the SubRun isn't contained by the clip
319 const SkRect subRunBounds = this->deviceRect(drawMatrix, drawOrigin);
320 const SkRect renderTargetBounds = SkRect::MakeWH(rtc->width(), rtc->height());
321
322 if (clip == nullptr && !renderTargetBounds.intersects(subRunBounds)) {
323 // If the SubRun is completely outside, don't add an op for it.
324 return {nullptr, nullptr};
325 } else if (clip != nullptr) {
326 const GrClip::PreClipResult result = clip->preApply(subRunBounds);
327 if (result.fEffect == GrClip::Effect::kClipped) {
328 if (result.fIsRRect && result.fRRect.isRect() && result.fAA == GrAA::kNo) {
329 // Clip geometrically during onPrepare using clipRect.
330 result.fRRect.getBounds().round(&clipRect);
331 clip = nullptr;
332 }
333 } else if (result.fEffect == GrClip::Effect::kClippedOut) {
334 return {nullptr, nullptr};
335 }
336 }
337
338 if (!clipRect.isEmpty()) { SkASSERT(clip == nullptr); }
339
340 GrPaint grPaint;
341 const SkPaint& drawPaint = glyphRunList.paint();
342 const SkPMColor4f drawingColor =
343 calculate_colors(rtc, drawPaint, viewMatrix, fMaskFormat, &grPaint);
344 GrAtlasTextOp::Geometry geometry = {
Herb Derby43ad7912020-07-20 16:14:19 -0400345 *this,
Herb Derby09357cc2020-07-20 09:55:48 -0400346 drawMatrix,
347 drawOrigin,
348 clipRect,
Herb Derby1d17e492020-07-21 11:45:04 -0400349 SkRef(fBlob),
Herb Derby09357cc2020-07-20 09:55:48 -0400350 drawingColor
351 };
352
Robert Phillipsa9306eb2020-07-21 13:01:25 -0400353 GrOpMemoryPool* const pool = rtc->priv().recordingContext()->priv().opMemoryPool();
Herb Derby09357cc2020-07-20 09:55:48 -0400354 std::unique_ptr<GrDrawOp> op = pool->allocate<GrAtlasTextOp>(op_mask_type(fMaskFormat),
355 false,
356 this->glyphCount(),
357 subRunBounds,
Herb Derby1d17e492020-07-21 11:45:04 -0400358 geometry,
359 std::move(grPaint));
Herb Derby09357cc2020-07-20 09:55:48 -0400360
361 return {clip, std::move(op)};
362}
363
364std::tuple<bool, int>
Herb Derby43ad7912020-07-20 16:14:19 -0400365GrDirectMaskSubRun::regenerateAtlas(int begin, int end, GrMeshDrawOp::Target* target) const {
Herb Derbya2800c42020-07-31 15:16:55 -0400366 return fGlyphs.regenerateAtlas(begin, end, fMaskFormat, target);
Herb Derby09357cc2020-07-20 09:55:48 -0400367}
368
369template <typename Rect>
370static auto ltbr(const Rect& r) {
371 return std::make_tuple(r.left(), r.top(), r.right(), r.bottom());
372}
373
374void GrDirectMaskSubRun::fillVertexData(void* vertexDst, int offset, int count, GrColor color,
375 const SkMatrix& drawMatrix, SkPoint drawOrigin,
376 SkIRect clip) const {
377 SkMatrix matrix = drawMatrix;
378 matrix.preTranslate(drawOrigin.x(), drawOrigin.y());
379
380 auto vertices = [&](auto dst) {
381 return SkMakeZip(dst,
382 fGlyphs.glyphs().subspan(offset, count),
383 fVertexData.subspan(offset, count));
384 };
385
386 auto direct2D = [&](auto dst, SkIRect* clip) {
387 // Rectangles in device space
388 SkPoint originInDeviceSpace = matrix.mapXY(0, 0);
389 for (auto[quad, glyph, vertexData] : vertices(dst)) {
390 auto[pos, rect] = vertexData;
391 auto[l, t, r, b] = rect;
392 auto[fx, fy] = pos + originInDeviceSpace;
393 auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs(0);
394 if (clip == nullptr) {
395 SkScalar dx = SkScalarRoundToScalar(fx),
396 dy = SkScalarRoundToScalar(fy);
397 auto[dl, dt, dr, db] = SkRect::MakeLTRB(l + dx, t + dy, r + dx, b + dy);
398 quad[0] = {{dl, dt}, color, {al, at}}; // L,T
399 quad[1] = {{dl, db}, color, {al, ab}}; // L,B
400 quad[2] = {{dr, dt}, color, {ar, at}}; // R,T
401 quad[3] = {{dr, db}, color, {ar, ab}}; // R,B
402 } else {
403 int dx = SkScalarRoundToInt(fx),
404 dy = SkScalarRoundToInt(fy);
405 SkIRect devIRect = SkIRect::MakeLTRB(l + dx, t + dy, r + dx, b + dy);
406 SkScalar dl, dt, dr, db;
407 uint16_t tl, tt, tr, tb;
408 if (!clip->containsNoEmptyCheck(devIRect)) {
409 if (SkIRect clipped; clipped.intersect(devIRect, *clip)) {
410 int lD = clipped.left() - devIRect.left();
411 int tD = clipped.top() - devIRect.top();
412 int rD = clipped.right() - devIRect.right();
413 int bD = clipped.bottom() - devIRect.bottom();
414 int indexLT, indexRB;
415 std::tie(dl, dt, dr, db) = ltbr(clipped);
416 std::tie(tl, tt, indexLT) =
417 GrDrawOpAtlas::UnpackIndexFromTexCoords(al, at);
418 std::tie(tr, tb, indexRB) =
419 GrDrawOpAtlas::UnpackIndexFromTexCoords(ar, ab);
420 std::tie(tl, tt) =
421 GrDrawOpAtlas::PackIndexInTexCoords(tl + lD, tt + tD, indexLT);
422 std::tie(tr, tb) =
423 GrDrawOpAtlas::PackIndexInTexCoords(tr + rD, tb + bD, indexRB);
424 } else {
425 // TODO: omit generating any vertex data for fully clipped glyphs ?
426 std::tie(dl, dt, dr, db) = std::make_tuple(0, 0, 0, 0);
427 std::tie(tl, tt, tr, tb) = std::make_tuple(0, 0, 0, 0);
428 }
429
430 } else {
431 std::tie(dl, dt, dr, db) = ltbr(devIRect);
432 std::tie(tl, tt, tr, tb) = std::tie(al, at, ar, ab);
433 }
434 quad[0] = {{dl, dt}, color, {tl, tt}}; // L,T
435 quad[1] = {{dl, db}, color, {tl, tb}}; // L,B
436 quad[2] = {{dr, dt}, color, {tr, tt}}; // R,T
437 quad[3] = {{dr, db}, color, {tr, tb}}; // R,B
438 }
439 }
440 };
441
442 if (clip.isEmpty()) {
443 if (fMaskFormat != kARGB_GrMaskFormat) {
444 using Quad = Mask2DVertex[4];
445 SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
446 direct2D((Quad*) vertexDst, nullptr);
447 } else {
448 using Quad = ARGB2DVertex[4];
449 SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
450 direct2D((Quad*) vertexDst, nullptr);
451 }
452 } else {
453 if (fMaskFormat != kARGB_GrMaskFormat) {
454 using Quad = Mask2DVertex[4];
455 SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
456 direct2D((Quad*) vertexDst, &clip);
457 } else {
458 using Quad = ARGB2DVertex[4];
459 SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
460 direct2D((Quad*) vertexDst, &clip);
461 }
462 }
463
464}
465
466SkRect GrDirectMaskSubRun::deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const {
467 SkRect outBounds = fVertexBounds;
468
469 SkPoint offset = drawMatrix.mapXY(drawOrigin.x(), drawOrigin.y());
470 // The vertex bounds are already {0, 0} based, so just add the new origin offset.
471 outBounds.offset(offset);
472
473 // Due to floating point numerical inaccuracies, we have to round out here
474 outBounds.roundOut();
475
476 return outBounds;
477}
478
Herb Derby53453f72020-07-24 15:03:54 -0400479// -- GrTransformedMaskSubRun ----------------------------------------------------------------------
480GrTransformedMaskSubRun::GrTransformedMaskSubRun(GrMaskFormat format,
481 GrTextBlob* blob,
482 const SkRect& bounds,
483 SkSpan<const VertexData> vertexData,
484 GrGlyphVector glyphs)
485 : fMaskFormat{format}
486 , fBlob{blob}
487 , fVertexBounds{bounds}
488 , fVertexData{vertexData}
489 , fGlyphs{glyphs} { }
Herb Derbya9047642019-12-06 12:12:11 -0500490
Herb Derby53453f72020-07-24 15:03:54 -0400491GrSubRun* GrTransformedMaskSubRun::Make(const SkZip<SkGlyphVariant, SkPoint>& drawables,
492 const SkStrikeSpec& strikeSpec,
493 GrMaskFormat format,
494 GrTextBlob* blob,
495 SkArenaAlloc* alloc) {
496 size_t vertexCount = drawables.size();
497 SkRect bounds = SkRectPriv::MakeLargestInverted();
498 auto initializer = [&, strikeToSource=strikeSpec.strikeToSourceRatio()](size_t i) {
499 auto [variant, pos] = drawables[i];
500 SkGlyph* skGlyph = variant;
501 int16_t l = skGlyph->left();
502 int16_t t = skGlyph->top();
503 int16_t r = l + skGlyph->width();
504 int16_t b = t + skGlyph->height();
505 SkPoint lt = SkPoint::Make(l, t) * strikeToSource + pos,
506 rb = SkPoint::Make(r, b) * strikeToSource + pos;
507
508 bounds.joinPossiblyEmptyRect(SkRect::MakeLTRB(lt.x(), lt.y(), rb.x(), rb.y()));
509 return VertexData{pos, {l, t, r, b}};
510 };
511
512 SkSpan<VertexData> vertexData{
513 alloc->makeInitializedArray<VertexData>(vertexCount, initializer), vertexCount};
514
515 GrAtlasSubRun* subRun = alloc->make<GrTransformedMaskSubRun>(
516 format, blob, bounds, vertexData,
517 GrGlyphVector::Make(strikeSpec, drawables.get<0>(), alloc));
518
519 return subRun;
520}
521
522void GrTransformedMaskSubRun::draw(const GrClip* clip,
523 const SkMatrixProvider& viewMatrix,
524 const SkGlyphRunList& glyphRunList,
525 GrRenderTargetContext* rtc) const {
526 auto[drawingClip, op] = this->makeAtlasTextOp(clip, viewMatrix, glyphRunList, rtc);
527 if (op != nullptr) {
528 rtc->priv().addDrawOp(drawingClip, std::move(op));
529 }
530}
531
532std::tuple<const GrClip*, std::unique_ptr<GrDrawOp>>
533GrTransformedMaskSubRun::makeAtlasTextOp(const GrClip* clip,
534 const SkMatrixProvider& viewMatrix,
535 const SkGlyphRunList& glyphRunList,
536 GrRenderTargetContext* rtc) const {
Herb Derby4a1f5fc2020-07-10 16:39:28 -0400537 SkASSERT(this->glyphCount() != 0);
538
539 SkPoint drawOrigin = glyphRunList.origin();
540 const SkPaint& drawPaint = glyphRunList.paint();
541 const SkMatrix& drawMatrix = viewMatrix.localToDevice();
Herb Derby53453f72020-07-24 15:03:54 -0400542 GrOpMemoryPool* pool = rtc->priv().recordingContext()->priv().opMemoryPool();
Herb Derby4a1f5fc2020-07-10 16:39:28 -0400543
Herb Derby4a1f5fc2020-07-10 16:39:28 -0400544 GrPaint grPaint;
Herb Derby09357cc2020-07-20 09:55:48 -0400545 SkPMColor4f drawingColor = calculate_colors(rtc, drawPaint, viewMatrix, fMaskFormat, &grPaint);
Herb Derby4a1f5fc2020-07-10 16:39:28 -0400546
547 // We can clip geometrically using clipRect and ignore clip if we're not using SDFs or
548 // transformed glyphs, and we have an axis-aligned rectangular non-AA clip.
Herb Derby09357cc2020-07-20 09:55:48 -0400549 GrAtlasTextOp::Geometry geometry = {
Herb Derby43ad7912020-07-20 16:14:19 -0400550 *this,
Herb Derby09357cc2020-07-20 09:55:48 -0400551 drawMatrix,
552 drawOrigin,
553 SkIRect::MakeEmpty(),
Herb Derby1d17e492020-07-21 11:45:04 -0400554 SkRef(fBlob),
Herb Derby09357cc2020-07-20 09:55:48 -0400555 drawingColor
556 };
Herb Derby4a1f5fc2020-07-10 16:39:28 -0400557
Herb Derby53453f72020-07-24 15:03:54 -0400558 std::unique_ptr<GrDrawOp> op = pool->allocate<GrAtlasTextOp>(
559 op_mask_type(fMaskFormat),
560 true,
561 this->glyphCount(),
562 this->deviceRect(drawMatrix, drawOrigin),
563 geometry,
564 std::move(grPaint));
Herb Derby4a1f5fc2020-07-10 16:39:28 -0400565 return {clip, std::move(op)};
566}
567
Herb Derby53453f72020-07-24 15:03:54 -0400568std::tuple<bool, int> GrTransformedMaskSubRun::regenerateAtlas(int begin, int end,
569 GrMeshDrawOp::Target* target) const {
Herb Derbya2800c42020-07-31 15:16:55 -0400570 return fGlyphs.regenerateAtlas(begin, end, fMaskFormat, target, true);
Herb Derby53453f72020-07-24 15:03:54 -0400571}
572
Herb Derbybad09142020-07-27 11:00:43 -0400573template<typename Quad, typename VertexData>
574static void fill_transformed_vertices_2D(SkZip<Quad, const GrGlyph*, const VertexData> quadData,
575 SkScalar dstPadding,
576 SkScalar srcPadding,
577 SkScalar strikeToSource,
578 GrColor color,
579 const SkMatrix& matrix) {
580 SkPoint inset = {dstPadding, dstPadding};
581 for (auto[quad, glyph, vertexData] : quadData) {
582 auto[pos, rect] = vertexData;
583 auto[l, t, r, b] = rect;
584 SkPoint sLT = (SkPoint::Make(l, t) + inset) * strikeToSource + pos,
585 sRB = (SkPoint::Make(r, b) - inset) * strikeToSource + pos;
586 SkPoint lt = matrix.mapXY(sLT.x(), sLT.y()),
587 lb = matrix.mapXY(sLT.x(), sRB.y()),
588 rt = matrix.mapXY(sRB.x(), sLT.y()),
589 rb = matrix.mapXY(sRB.x(), sRB.y());
590 auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs(srcPadding);
591 quad[0] = {lt, color, {al, at}}; // L,T
592 quad[1] = {lb, color, {al, ab}}; // L,B
593 quad[2] = {rt, color, {ar, at}}; // R,T
594 quad[3] = {rb, color, {ar, ab}}; // R,B
595 }
596}
597
598template<typename Quad, typename VertexData>
599static void fill_transformed_vertices_3D(SkZip<Quad, const GrGlyph*, const VertexData> quadData,
600 SkScalar dstPadding,
601 SkScalar srcPadding,
602 SkScalar strikeToSource,
603 GrColor color,
604 const SkMatrix& matrix) {
605 SkPoint inset = {dstPadding, dstPadding};
606 auto mapXYZ = [&](SkScalar x, SkScalar y) {
607 SkPoint pt{x, y};
608 SkPoint3 result;
609 matrix.mapHomogeneousPoints(&result, &pt, 1);
610 return result;
611 };
612 for (auto[quad, glyph, vertexData] : quadData) {
613 auto[pos, rect] = vertexData;
614 auto [l, t, r, b] = rect;
615 SkPoint sLT = (SkPoint::Make(l, t) + inset) * strikeToSource + pos,
616 sRB = (SkPoint::Make(r, b) - inset) * strikeToSource + pos;
617 SkPoint3 lt = mapXYZ(sLT.x(), sLT.y()),
618 lb = mapXYZ(sLT.x(), sRB.y()),
619 rt = mapXYZ(sRB.x(), sLT.y()),
620 rb = mapXYZ(sRB.x(), sRB.y());
621 auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs(srcPadding);
622 quad[0] = {lt, color, {al, at}}; // L,T
623 quad[1] = {lb, color, {al, ab}}; // L,B
624 quad[2] = {rt, color, {ar, at}}; // R,T
625 quad[3] = {rb, color, {ar, ab}}; // R,B
626 }
627}
628
Herb Derby53453f72020-07-24 15:03:54 -0400629void GrTransformedMaskSubRun::fillVertexData(void* vertexDst,
630 int offset, int count,
631 GrColor color,
632 const SkMatrix& drawMatrix, SkPoint drawOrigin,
633 SkIRect clip) const {
Herb Derbybad09142020-07-27 11:00:43 -0400634 constexpr SkScalar kDstPadding = 0.f;
635 constexpr SkScalar kSrcPadding = 1.f;
Herb Derby53453f72020-07-24 15:03:54 -0400636 SkMatrix matrix = drawMatrix;
637 matrix.preTranslate(drawOrigin.x(), drawOrigin.y());
638
Herb Derbybad09142020-07-27 11:00:43 -0400639 auto quadData = [&](auto dst) {
Herb Derby53453f72020-07-24 15:03:54 -0400640 return SkMakeZip(dst,
641 fGlyphs.glyphs().subspan(offset, count),
642 fVertexData.subspan(offset, count));
643 };
644
Herb Derby53453f72020-07-24 15:03:54 -0400645 if (!this->hasW()) {
646 if (fMaskFormat == GrMaskFormat::kARGB_GrMaskFormat) {
647 using Quad = ARGB2DVertex[4];
648 SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
Herb Derbybad09142020-07-27 11:00:43 -0400649 fill_transformed_vertices_2D(
650 quadData((Quad*) vertexDst),
651 kDstPadding, kSrcPadding,
652 fGlyphs.strikeToSourceRatio(),
653 color,
654 matrix);
Herb Derby53453f72020-07-24 15:03:54 -0400655 } else {
656 using Quad = Mask2DVertex[4];
657 SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
Herb Derbybad09142020-07-27 11:00:43 -0400658 fill_transformed_vertices_2D(
659 quadData((Quad*) vertexDst),
660 kDstPadding, kSrcPadding,
661 fGlyphs.strikeToSourceRatio(),
662 color,
663 matrix);
Herb Derby53453f72020-07-24 15:03:54 -0400664 }
665 } else {
666 if (fMaskFormat == GrMaskFormat::kARGB_GrMaskFormat) {
667 using Quad = ARGB3DVertex[4];
668 SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
Herb Derbybad09142020-07-27 11:00:43 -0400669 fill_transformed_vertices_3D(
670 quadData((Quad*) vertexDst),
671 kDstPadding, kSrcPadding,
672 fGlyphs.strikeToSourceRatio(),
673 color,
674 matrix);
Herb Derby53453f72020-07-24 15:03:54 -0400675 } else {
676 using Quad = Mask3DVertex[4];
677 SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
Herb Derbybad09142020-07-27 11:00:43 -0400678 fill_transformed_vertices_3D(
679 quadData((Quad*) vertexDst),
680 kDstPadding, kSrcPadding,
681 fGlyphs.strikeToSourceRatio(),
682 color,
683 matrix);
Herb Derby53453f72020-07-24 15:03:54 -0400684 }
Herb Derby2604a892020-07-13 12:13:30 -0400685 }
686}
687
Herb Derby53453f72020-07-24 15:03:54 -0400688size_t GrTransformedMaskSubRun::vertexStride() const {
689 switch (fMaskFormat) {
Herb Derbya56a1d72019-12-27 12:12:47 -0500690 case kA8_GrMaskFormat:
Herb Derby64391c42020-05-16 14:32:15 -0400691 return this->hasW() ? sizeof(Mask3DVertex) : sizeof(Mask2DVertex);
Herb Derbya56a1d72019-12-27 12:12:47 -0500692 case kARGB_GrMaskFormat:
Herb Derby64391c42020-05-16 14:32:15 -0400693 return this->hasW() ? sizeof(ARGB3DVertex) : sizeof(ARGB2DVertex);
Herb Derbya56a1d72019-12-27 12:12:47 -0500694 default:
695 SkASSERT(!this->hasW());
Herb Derby64391c42020-05-16 14:32:15 -0400696 return sizeof(Mask2DVertex);
Herb Derbya56a1d72019-12-27 12:12:47 -0500697 }
Herb Derby64391c42020-05-16 14:32:15 -0400698 SkUNREACHABLE;
Herb Derby23f29762020-01-10 16:26:14 -0500699}
700
Herb Derby53453f72020-07-24 15:03:54 -0400701int GrTransformedMaskSubRun::glyphCount() const {
702 return fVertexData.count();
703}
704
705bool GrTransformedMaskSubRun::hasW() const {
706 return fBlob->hasPerspective();
707}
708
709SkRect GrTransformedMaskSubRun::deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const {
710 SkRect outBounds = fVertexBounds;
711 outBounds.offset(drawOrigin);
712 return drawMatrix.mapRect(outBounds);
713}
714
715// -- GrSDFTSubRun ---------------------------------------------------------------------------------
716GrSDFTSubRun::GrSDFTSubRun(GrMaskFormat format,
717 GrTextBlob* textBlob,
718 SkRect vertexBounds,
719 SkSpan<const VertexData> vertexData,
720 GrGlyphVector glyphs,
721 bool useLCDText,
722 bool antiAliased)
723 : fMaskFormat{format}
724 , fBlob{textBlob}
725 , fVertexBounds{vertexBounds}
726 , fVertexData{vertexData}
727 , fGlyphs{glyphs}
728 , fUseLCDText{useLCDText}
729 , fAntiAliased{antiAliased} { }
730
731GrSubRun* GrSDFTSubRun::Make(
732 const SkZip<SkGlyphVariant, SkPoint>& drawables,
733 const SkFont& runFont,
734 const SkStrikeSpec& strikeSpec,
735 GrTextBlob* blob,
736 SkArenaAlloc* alloc) {
737
738 size_t vertexCount = drawables.size();
739 SkRect bounds = SkRectPriv::MakeLargestInverted();
740 auto initializer = [&, strikeToSource=strikeSpec.strikeToSourceRatio()](size_t i) {
741 auto [variant, pos] = drawables[i];
742 SkGlyph* skGlyph = variant;
743 int16_t l = skGlyph->left();
744 int16_t t = skGlyph->top();
745 int16_t r = l + skGlyph->width();
746 int16_t b = t + skGlyph->height();
747 SkPoint lt = SkPoint::Make(l, t) * strikeToSource + pos,
748 rb = SkPoint::Make(r, b) * strikeToSource + pos;
749
750 bounds.joinPossiblyEmptyRect(SkRect::MakeLTRB(lt.x(), lt.y(), rb.x(), rb.y()));
751 return VertexData{pos, {l, t, r, b}};
752 };
753
754 SkSpan<VertexData> vertexData{
755 alloc->makeInitializedArray<VertexData>(vertexCount, initializer), vertexCount};
756
757 return alloc->make<GrSDFTSubRun>(
758 kA8_GrMaskFormat,
759 blob,
760 bounds,
761 vertexData,
762 GrGlyphVector::Make(strikeSpec, drawables.get<0>(), alloc),
763 runFont.getEdging() == SkFont::Edging::kSubpixelAntiAlias,
764 runFont.hasSomeAntiAliasing());
765}
766
767std::tuple<const GrClip*, std::unique_ptr<GrDrawOp> >
768GrSDFTSubRun::makeAtlasTextOp(const GrClip* clip,
769 const SkMatrixProvider& viewMatrix,
770 const SkGlyphRunList& glyphRunList,
771 GrRenderTargetContext* rtc) const {
772 SkASSERT(this->glyphCount() != 0);
773
774 SkPoint drawOrigin = glyphRunList.origin();
775 const SkPaint& drawPaint = glyphRunList.paint();
776 const SkMatrix& drawMatrix = viewMatrix.localToDevice();
777 GrOpMemoryPool* pool = rtc->priv().recordingContext()->priv().opMemoryPool();
778
779 GrPaint grPaint;
780 SkPMColor4f drawingColor = calculate_colors(rtc, drawPaint, viewMatrix, fMaskFormat, &grPaint);
781
782 const GrColorInfo& colorInfo = rtc->colorInfo();
783 const SkSurfaceProps& props = rtc->surfaceProps();
784 bool isBGR = SkPixelGeometryIsBGR(props.pixelGeometry());
785 bool isLCD = fUseLCDText && SkPixelGeometryIsH(props.pixelGeometry());
786 using MT = GrAtlasTextOp::MaskType;
787 MT maskType = !fAntiAliased ? MT::kAliasedDistanceField_MaskType
788 : isLCD ? (isBGR ? MT::kLCDBGRDistanceField_MaskType
789 : MT::kLCDDistanceField_MaskType)
790 : MT::kGrayscaleDistanceField_MaskType;
791
792 bool useGammaCorrectDistanceTable = colorInfo.isLinearlyBlended();
793 uint32_t DFGPFlags = drawMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
794 DFGPFlags |= drawMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
795 DFGPFlags |= drawMatrix.hasPerspective() ? kPerspective_DistanceFieldEffectFlag : 0;
796 DFGPFlags |= useGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
797 DFGPFlags |= MT::kAliasedDistanceField_MaskType == maskType ?
798 kAliased_DistanceFieldEffectFlag : 0;
799
800 if (isLCD) {
801 DFGPFlags |= kUseLCD_DistanceFieldEffectFlag;
802 DFGPFlags |= MT::kLCDBGRDistanceField_MaskType == maskType ?
803 kBGR_DistanceFieldEffectFlag : 0;
804 }
805
806 GrAtlasTextOp::Geometry geometry = {
807 *this,
808 drawMatrix,
809 drawOrigin,
810 SkIRect::MakeEmpty(),
811 SkRef(fBlob),
812 drawingColor
813 };
814
815 std::unique_ptr<GrDrawOp> op = pool->allocate<GrAtlasTextOp>(
816 maskType,
817 true,
818 this->glyphCount(),
819 this->deviceRect(drawMatrix, drawOrigin),
820 SkPaintPriv::ComputeLuminanceColor(drawPaint),
821 useGammaCorrectDistanceTable,
822 DFGPFlags,
823 geometry,
824 std::move(grPaint));
825
826 return {clip, std::move(op)};
827}
828
829void GrSDFTSubRun::draw(const GrClip* clip,
830 const SkMatrixProvider& viewMatrix,
831 const SkGlyphRunList& glyphRunList,
832 GrRenderTargetContext* rtc) const {
833 auto[drawingClip, op] = this->makeAtlasTextOp(clip, viewMatrix, glyphRunList, rtc);
834 if (op != nullptr) {
835 rtc->priv().addDrawOp(drawingClip, std::move(op));
836 }
837}
838
839std::tuple<bool, int> GrSDFTSubRun::regenerateAtlas(
840 int begin, int end, GrMeshDrawOp::Target *target) const {
841
Herb Derbya2800c42020-07-31 15:16:55 -0400842 return fGlyphs.regenerateAtlas(begin, end, fMaskFormat, target);
Herb Derby53453f72020-07-24 15:03:54 -0400843}
844
845size_t GrSDFTSubRun::vertexStride() const {
846 return this->hasW() ? sizeof(Mask3DVertex) : sizeof(Mask2DVertex);
847}
848
849void GrSDFTSubRun::fillVertexData(
Herb Derby64391c42020-05-16 14:32:15 -0400850 void *vertexDst, int offset, int count,
851 GrColor color, const SkMatrix& drawMatrix, SkPoint drawOrigin, SkIRect clip) const {
852
853 SkMatrix matrix = drawMatrix;
854 matrix.preTranslate(drawOrigin.x(), drawOrigin.y());
855
Herb Derbybad09142020-07-27 11:00:43 -0400856 auto quadData = [&](auto dst) {
Herb Derbyc1cde362020-07-17 14:07:00 -0400857 return SkMakeZip(dst,
858 fGlyphs.glyphs().subspan(offset, count),
859 fVertexData.subspan(offset, count));
860 };
861
Herb Derby53453f72020-07-24 15:03:54 -0400862 if (!this->hasW()) {
863 using Quad = Mask2DVertex[4];
864 SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
Herb Derbybad09142020-07-27 11:00:43 -0400865 fill_transformed_vertices_2D(
866 quadData((Quad*) vertexDst),
867 SK_DistanceFieldInset, SK_DistanceFieldInset,
868 fGlyphs.strikeToSourceRatio(),
869 color,
870 matrix);
Herb Derby53453f72020-07-24 15:03:54 -0400871 } else {
872 using Quad = Mask3DVertex[4];
873 SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph);
Herb Derbybad09142020-07-27 11:00:43 -0400874 fill_transformed_vertices_3D(
875 quadData((Quad*) vertexDst),
876 SK_DistanceFieldInset, SK_DistanceFieldInset,
877 fGlyphs.strikeToSourceRatio(),
878 color,
879 matrix);
Herb Derby64391c42020-05-16 14:32:15 -0400880 }
881}
882
Herb Derby53453f72020-07-24 15:03:54 -0400883int GrSDFTSubRun::glyphCount() const {
Herb Derby64391c42020-05-16 14:32:15 -0400884 return fVertexData.count();
Herb Derbya9047642019-12-06 12:12:11 -0500885}
886
Herb Derby53453f72020-07-24 15:03:54 -0400887bool GrSDFTSubRun::hasW() const {
Herb Derbya7271222020-05-29 10:44:39 -0400888 return fBlob->hasPerspective();
Herb Derbya9047642019-12-06 12:12:11 -0500889}
890
Herb Derby53453f72020-07-24 15:03:54 -0400891SkRect GrSDFTSubRun::deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const {
Herb Derbybe6c7132020-04-28 14:28:04 -0400892 SkRect outBounds = fVertexBounds;
Herb Derby09357cc2020-07-20 09:55:48 -0400893 outBounds.offset(drawOrigin);
894 return drawMatrix.mapRect(outBounds);
Herb Derbybe6c7132020-04-28 14:28:04 -0400895}
896
Herb Derbya9047642019-12-06 12:12:11 -0500897// -- GrTextBlob -----------------------------------------------------------------------------------
898void GrTextBlob::operator delete(void* p) { ::operator delete(p); }
899void* GrTextBlob::operator new(size_t) { SK_ABORT("All blobs are created by placement new."); }
900void* GrTextBlob::operator new(size_t, void* p) { return p; }
901
902GrTextBlob::~GrTextBlob() = default;
903
Herb Derbybe202052020-06-05 17:22:38 -0400904sk_sp<GrTextBlob> GrTextBlob::Make(const SkGlyphRunList& glyphRunList, const SkMatrix& drawMatrix) {
Herb Derby64391c42020-05-16 14:32:15 -0400905 // The difference in alignment from the storage of VertexData to SubRun;
Herb Derby72257882020-07-31 13:07:34 -0400906 using AllSubRuns = std::aligned_union_t<1,
907 GrDirectMaskSubRun,
908 GrTransformedMaskSubRun,
909 GrSDFTSubRun,
910 GrPathSubRun>;
911
912 using AllVertexData = std::aligned_union<1,
913 GrDirectMaskSubRun::VertexData,
914 GrTransformedMaskSubRun::VertexData,
915 GrSDFTSubRun::VertexData>;
916 constexpr size_t alignDiff = alignof(AllSubRuns) - alignof(AllVertexData);
Herb Derby64391c42020-05-16 14:32:15 -0400917 constexpr size_t vertexDataToSubRunPadding = alignDiff > 0 ? alignDiff : 0;
Herb Derbyb42706c2020-07-23 14:55:38 -0400918 size_t totalGlyphCount = glyphRunList.totalGlyphCount();
919 size_t arenaSize =
Herb Derby72257882020-07-31 13:07:34 -0400920 totalGlyphCount * sizeof(AllVertexData)
Herb Derbyb42706c2020-07-23 14:55:38 -0400921 + GrGlyphVector::GlyphVectorSize(totalGlyphCount)
922 + glyphRunList.runCount() * (sizeof(AllSubRuns) + vertexDataToSubRunPadding)
923 + 32; // Misc arena overhead.
Herb Derbyc514e7d2019-12-11 17:00:31 -0500924
925 size_t allocationSize = sizeof(GrTextBlob) + arenaSize;
Ben Wagner75d6db72018-09-20 14:39:39 -0400926
Herb Derbycb718892019-12-07 00:07:42 -0500927 void* allocation = ::operator new (allocationSize);
Herb Derbyb12175f2018-05-23 16:38:09 -0400928
Herb Derbyaebc5f82019-12-10 14:07:10 -0500929 SkColor initialLuminance = SkPaintPriv::ComputeLuminanceColor(glyphRunList.paint());
Herb Derby00ae9592019-12-03 15:55:56 -0500930 sk_sp<GrTextBlob> blob{new (allocation) GrTextBlob{
Herb Derbybe202052020-06-05 17:22:38 -0400931 arenaSize, drawMatrix, glyphRunList.origin(), initialLuminance}};
joshualitt92303772016-02-10 11:55:52 -0800932
Herb Derbyf7d5d742018-11-16 13:24:32 -0500933 return blob;
joshualitt92303772016-02-10 11:55:52 -0800934}
935
Herb Derbya9047642019-12-06 12:12:11 -0500936void GrTextBlob::setupKey(const GrTextBlob::Key& key, const SkMaskFilterBase::BlurRec& blurRec,
937 const SkPaint& paint) {
938 fKey = key;
939 if (key.fHasBlur) {
940 fBlurRec = blurRec;
941 }
942 if (key.fStyle != SkPaint::kFill_Style) {
943 fStrokeInfo.fFrameWidth = paint.getStrokeWidth();
944 fStrokeInfo.fMiterLimit = paint.getStrokeMiter();
945 fStrokeInfo.fJoin = paint.getStrokeJoin();
946 }
947}
948const GrTextBlob::Key& GrTextBlob::GetKey(const GrTextBlob& blob) { return blob.fKey; }
949uint32_t GrTextBlob::Hash(const GrTextBlob::Key& key) { return SkOpts::hash(&key, sizeof(Key)); }
950
Herb Derbycb718892019-12-07 00:07:42 -0500951bool GrTextBlob::hasDistanceField() const {
952 return SkToBool(fTextType & kHasDistanceField_TextType);
953}
Herb Derbya9047642019-12-06 12:12:11 -0500954bool GrTextBlob::hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); }
Herb Derby1c5be7b2019-12-13 12:03:06 -0500955bool GrTextBlob::hasPerspective() const { return fInitialMatrix.hasPerspective(); }
Herb Derbya9047642019-12-06 12:12:11 -0500956
957void GrTextBlob::setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
958void GrTextBlob::setHasBitmap() { fTextType |= kHasBitmap_TextType; }
959void GrTextBlob::setMinAndMaxScale(SkScalar scaledMin, SkScalar scaledMax) {
960 // we init fMaxMinScale and fMinMaxScale in the constructor
Brian Osman116b33e2020-02-05 13:34:09 -0500961 fMaxMinScale = std::max(scaledMin, fMaxMinScale);
962 fMinMaxScale = std::min(scaledMax, fMinMaxScale);
Herb Derbya9047642019-12-06 12:12:11 -0500963}
964
Herb Derby64688222020-06-08 14:19:57 -0400965bool GrTextBlob::canReuse(const SkPaint& paint,
966 const SkMaskFilterBase::BlurRec& blurRec,
967 const SkMatrix& drawMatrix,
968 SkPoint drawOrigin) {
Herb Derbya5b98602020-07-13 11:18:12 -0400969 // A singular matrix will create a GrTextBlob with no SubRuns, but unknown glyphs can
970 // also cause empty runs. If there are no subRuns, and the matrix is complicated, then
971 // regenerate.
972 if (fSubRunList.isEmpty() && !fInitialMatrix.rectStaysRect()) {
Herb Derbyafa90362020-07-08 12:20:11 -0400973 return false;
974 }
975
joshualittfd5f6c12015-12-10 07:44:50 -0800976 // If we have LCD text then our canonical color will be set to transparent, in this case we have
977 // to regenerate the blob on any color change
978 // We use the grPaint to get any color filter effects
979 if (fKey.fCanonicalColor == SK_ColorTRANSPARENT &&
Herb Derbyaebc5f82019-12-10 14:07:10 -0500980 fInitialLuminance != SkPaintPriv::ComputeLuminanceColor(paint)) {
Herb Derby64688222020-06-08 14:19:57 -0400981 return false;
joshualittfd5f6c12015-12-10 07:44:50 -0800982 }
983
Herb Derby1c5be7b2019-12-13 12:03:06 -0500984 if (fInitialMatrix.hasPerspective() != drawMatrix.hasPerspective()) {
Herb Derby64688222020-06-08 14:19:57 -0400985 return false;
joshualittfd5f6c12015-12-10 07:44:50 -0800986 }
987
Brian Salomon5c6ac642017-12-19 11:09:32 -0500988 /** This could be relaxed for blobs with only distance field glyphs. */
Mike Reed2c383152019-12-18 16:47:47 -0500989 if (fInitialMatrix.hasPerspective() && !SkMatrixPriv::CheapEqual(fInitialMatrix, drawMatrix)) {
Herb Derby64688222020-06-08 14:19:57 -0400990 return false;
joshualittfd5f6c12015-12-10 07:44:50 -0800991 }
992
993 // We only cache one masked version
994 if (fKey.fHasBlur &&
Mike Reed1be1f8d2018-03-14 13:01:17 -0400995 (fBlurRec.fSigma != blurRec.fSigma || fBlurRec.fStyle != blurRec.fStyle)) {
Herb Derby64688222020-06-08 14:19:57 -0400996 return false;
joshualittfd5f6c12015-12-10 07:44:50 -0800997 }
998
999 // Similarly, we only cache one version for each style
1000 if (fKey.fStyle != SkPaint::kFill_Style &&
Herb Derbybc6f9c92018-08-08 13:58:45 -04001001 (fStrokeInfo.fFrameWidth != paint.getStrokeWidth() ||
1002 fStrokeInfo.fMiterLimit != paint.getStrokeMiter() ||
1003 fStrokeInfo.fJoin != paint.getStrokeJoin())) {
Herb Derby64688222020-06-08 14:19:57 -04001004 return false;
joshualittfd5f6c12015-12-10 07:44:50 -08001005 }
1006
1007 // Mixed blobs must be regenerated. We could probably figure out a way to do integer scrolls
1008 // for mixed blobs if this becomes an issue.
1009 if (this->hasBitmap() && this->hasDistanceField()) {
Herb Derbyeba195f2019-12-03 16:44:47 -05001010 // Identical view matrices and we can reuse in all cases
Herb Derby64688222020-06-08 14:19:57 -04001011 return SkMatrixPriv::CheapEqual(fInitialMatrix, drawMatrix) && drawOrigin == fInitialOrigin;
joshualittfd5f6c12015-12-10 07:44:50 -08001012 }
1013
1014 if (this->hasBitmap()) {
Herb Derby1c5be7b2019-12-13 12:03:06 -05001015 if (fInitialMatrix.getScaleX() != drawMatrix.getScaleX() ||
1016 fInitialMatrix.getScaleY() != drawMatrix.getScaleY() ||
1017 fInitialMatrix.getSkewX() != drawMatrix.getSkewX() ||
1018 fInitialMatrix.getSkewY() != drawMatrix.getSkewY()) {
Herb Derby64688222020-06-08 14:19:57 -04001019 return false;
joshualittfd5f6c12015-12-10 07:44:50 -08001020 }
1021
Herb Derby9830fc42019-09-12 10:58:26 -04001022 // TODO(herb): this is not needed for full pixel glyph choice, but is needed to adjust
1023 // the quads properly. Devise a system that regenerates the quads from original data
1024 // using the transform to allow this to be used in general.
1025
1026 // We can update the positions in the text blob without regenerating the whole
1027 // blob, but only for integer translations.
Herb Derby435adfe2020-01-14 15:12:04 -05001028 // Calculate the translation in source space to a translation in device space by mapping
1029 // (0, 0) through both the initial matrix and the draw matrix; take the difference.
1030 SkMatrix initialMatrix{fInitialMatrix};
1031 initialMatrix.preTranslate(fInitialOrigin.x(), fInitialOrigin.y());
1032 SkPoint initialDeviceOrigin{0, 0};
1033 initialMatrix.mapPoints(&initialDeviceOrigin, 1);
1034 SkMatrix completeDrawMatrix{drawMatrix};
1035 completeDrawMatrix.preTranslate(drawOrigin.x(), drawOrigin.y());
1036 SkPoint drawDeviceOrigin{0, 0};
1037 completeDrawMatrix.mapPoints(&drawDeviceOrigin, 1);
1038 SkPoint translation = drawDeviceOrigin - initialDeviceOrigin;
1039
1040 if (!SkScalarIsInt(translation.x()) || !SkScalarIsInt(translation.y())) {
Herb Derby64688222020-06-08 14:19:57 -04001041 return false;
joshualittfd5f6c12015-12-10 07:44:50 -08001042 }
joshualittfd5f6c12015-12-10 07:44:50 -08001043 } else if (this->hasDistanceField()) {
1044 // A scale outside of [blob.fMaxMinScale, blob.fMinMaxScale] would result in a different
1045 // distance field being generated, so we have to regenerate in those cases
Herb Derby1c5be7b2019-12-13 12:03:06 -05001046 SkScalar newMaxScale = drawMatrix.getMaxScale();
1047 SkScalar oldMaxScale = fInitialMatrix.getMaxScale();
joshualittfd5f6c12015-12-10 07:44:50 -08001048 SkScalar scaleAdjust = newMaxScale / oldMaxScale;
1049 if (scaleAdjust < fMaxMinScale || scaleAdjust > fMinMaxScale) {
Herb Derby64688222020-06-08 14:19:57 -04001050 return false;
joshualittfd5f6c12015-12-10 07:44:50 -08001051 }
joshualittfd5f6c12015-12-10 07:44:50 -08001052 }
1053
Herb Derby64688222020-06-08 14:19:57 -04001054 // If the blob is all paths, there is no reason to regenerate.
1055 return true;
joshualittfd5f6c12015-12-10 07:44:50 -08001056}
1057
Herb Derbya9047642019-12-06 12:12:11 -05001058const GrTextBlob::Key& GrTextBlob::key() const { return fKey; }
1059size_t GrTextBlob::size() const { return fSize; }
1060
Herb Derby31adbc62020-05-29 12:59:22 -04001061template<typename AddSingleMaskFormat>
Herb Derbya9047642019-12-06 12:12:11 -05001062void GrTextBlob::addMultiMaskFormat(
Herb Derby31adbc62020-05-29 12:59:22 -04001063 AddSingleMaskFormat addSingle,
Herb Derbya9047642019-12-06 12:12:11 -05001064 const SkZip<SkGlyphVariant, SkPoint>& drawables,
1065 const SkStrikeSpec& strikeSpec) {
1066 this->setHasBitmap();
1067 if (drawables.empty()) { return; }
1068
1069 auto glyphSpan = drawables.get<0>();
1070 SkGlyph* glyph = glyphSpan[0];
1071 GrMaskFormat format = GrGlyph::FormatFromSkGlyph(glyph->maskFormat());
1072 size_t startIndex = 0;
1073 for (size_t i = 1; i < drawables.size(); i++) {
1074 glyph = glyphSpan[i];
1075 GrMaskFormat nextFormat = GrGlyph::FormatFromSkGlyph(glyph->maskFormat());
1076 if (format != nextFormat) {
1077 auto sameFormat = drawables.subspan(startIndex, i - startIndex);
Herb Derby3d00a972020-07-14 11:43:14 -04001078 GrSubRun* subRun = addSingle(sameFormat, strikeSpec, format, this, &fAlloc);
Herb Derby31adbc62020-05-29 12:59:22 -04001079 this->insertSubRun(subRun);
Herb Derbya9047642019-12-06 12:12:11 -05001080 format = nextFormat;
1081 startIndex = i;
1082 }
1083 }
1084 auto sameFormat = drawables.last(drawables.size() - startIndex);
Herb Derby3d00a972020-07-14 11:43:14 -04001085 GrSubRun* subRun = addSingle(sameFormat, strikeSpec, format, this, &fAlloc);
Herb Derby31adbc62020-05-29 12:59:22 -04001086 this->insertSubRun(subRun);
Herb Derbye9f691d2019-12-04 12:11:13 -05001087}
1088
Herb Derbycb718892019-12-07 00:07:42 -05001089GrTextBlob::GrTextBlob(size_t allocSize,
Herb Derby1c5be7b2019-12-13 12:03:06 -05001090 const SkMatrix& drawMatrix,
Herb Derbyeba195f2019-12-03 16:44:47 -05001091 SkPoint origin,
Herb Derby692e59d2020-06-05 11:37:16 -04001092 SkColor initialLuminance)
Herb Derbycb718892019-12-07 00:07:42 -05001093 : fSize{allocSize}
Herb Derby1c5be7b2019-12-13 12:03:06 -05001094 , fInitialMatrix{drawMatrix}
Herb Derbyeba195f2019-12-03 16:44:47 -05001095 , fInitialOrigin{origin}
Herb Derbyaebc5f82019-12-10 14:07:10 -05001096 , fInitialLuminance{initialLuminance}
Herb Derbycb718892019-12-07 00:07:42 -05001097 , fAlloc{SkTAddOffset<char>(this, sizeof(GrTextBlob)), allocSize, allocSize/2} { }
Herb Derby00ae9592019-12-03 15:55:56 -05001098
Herb Derby3d00a972020-07-14 11:43:14 -04001099void GrTextBlob::insertSubRun(GrSubRun* subRun) {
Herb Derbyd94e71e2020-07-07 11:10:09 -04001100 fSubRunList.addToTail(subRun);
Herb Derbycb718892019-12-07 00:07:42 -05001101}
1102
Herb Derbya9047642019-12-06 12:12:11 -05001103void GrTextBlob::processDeviceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
1104 const SkStrikeSpec& strikeSpec) {
Herb Derby31adbc62020-05-29 12:59:22 -04001105
Herb Derby09357cc2020-07-20 09:55:48 -04001106 this->addMultiMaskFormat(GrDirectMaskSubRun::Make, drawables, strikeSpec);
Herb Derbya9047642019-12-06 12:12:11 -05001107}
Herb Derbyeba195f2019-12-03 16:44:47 -05001108
Herb Derbya9047642019-12-06 12:12:11 -05001109void GrTextBlob::processSourcePaths(const SkZip<SkGlyphVariant, SkPoint>& drawables,
1110 const SkFont& runFont,
1111 const SkStrikeSpec& strikeSpec) {
1112 this->setHasBitmap();
Herb Derbyaf3ae692020-07-14 20:46:23 -04001113 GrSubRun* subRun = GrPathSubRun::Make(drawables,
1114 runFont.hasSomeAntiAliasing(),
1115 strikeSpec,
1116 &fAlloc);
Herb Derby31adbc62020-05-29 12:59:22 -04001117 this->insertSubRun(subRun);
Herb Derbyeba195f2019-12-03 16:44:47 -05001118}
1119
Herb Derbya9047642019-12-06 12:12:11 -05001120void GrTextBlob::processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables,
1121 const SkStrikeSpec& strikeSpec,
1122 const SkFont& runFont,
1123 SkScalar minScale,
1124 SkScalar maxScale) {
Herb Derby31adbc62020-05-29 12:59:22 -04001125 this->setHasDistanceField();
1126 this->setMinAndMaxScale(minScale, maxScale);
Herb Derby53453f72020-07-24 15:03:54 -04001127 GrSubRun* subRun = GrSDFTSubRun::Make(drawables, runFont, strikeSpec, this, &fAlloc);
Herb Derby31adbc62020-05-29 12:59:22 -04001128 this->insertSubRun(subRun);
joshualitt8e0ef292016-02-19 14:13:03 -08001129}
Herb Derbya9047642019-12-06 12:12:11 -05001130
1131void GrTextBlob::processSourceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
1132 const SkStrikeSpec& strikeSpec) {
Herb Derby53453f72020-07-24 15:03:54 -04001133 this->addMultiMaskFormat(GrTransformedMaskSubRun::Make, drawables, strikeSpec);
Herb Derbya9047642019-12-06 12:12:11 -05001134}