blob: 5ac683e6f3b63f007c783e0fc227f369cda04e0a [file] [log] [blame]
joshualitt1d89e8d2015-04-01 12:40:54 -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#include "GrAtlasTextContext.h"
robertphillips73c4e642016-03-02 11:36:59 -08008#include "GrContext.h"
Robert Phillipsf35fd8d2018-01-22 10:48:15 -05009#include "GrContextPriv.h"
joshualittb7133be2015-04-08 09:08:31 -070010#include "GrTextBlobCache.h"
Brian Salomon52db9402017-11-07 14:58:55 -050011#include "SkDistanceFieldGen.h"
joshualitt1d89e8d2015-04-01 12:40:54 -070012#include "SkDraw.h"
13#include "SkDrawFilter.h"
Jim Van Verth54d9c882018-02-08 16:14:48 -050014#include "SkDrawProcs.h"
Brian Salomon52db9402017-11-07 14:58:55 -050015#include "SkFindAndPlaceGlyph.h"
Brian Osman3b655982017-03-07 16:58:08 -050016#include "SkGr.h"
Jim Van Verthc65b65d2018-01-16 16:26:35 -050017#include "SkGraphics.h"
Brian Salomonaf597482017-11-07 16:23:34 -050018#include "SkMakeUnique.h"
Mike Reed80747ef2018-01-23 15:29:32 -050019#include "SkMaskFilterBase.h"
Jim Van Verth54d9c882018-02-08 16:14:48 -050020#include "SkTextMapStateProc.h"
Jim Van Verth54d9c882018-02-08 16:14:48 -050021
Brian Salomon649a3412017-03-09 13:50:43 -050022#include "ops/GrMeshDrawOp.h"
joshualitt1d89e8d2015-04-01 12:40:54 -070023
Brian Salomonaf597482017-11-07 16:23:34 -050024// DF sizes and thresholds for usage of the small and medium sizes. For example, above
25// kSmallDFFontLimit we will use the medium size. The large size is used up until the size at
26// which we switch over to drawing as paths as controlled by Options.
27static const int kSmallDFFontSize = 32;
28static const int kSmallDFFontLimit = 32;
Jim Van Verth825d4d72018-01-30 20:37:03 +000029static const int kMediumDFFontSize = 72;
30static const int kMediumDFFontLimit = 72;
31static const int kLargeDFFontSize = 162;
Brian Salomonaf597482017-11-07 16:23:34 -050032
33static const int kDefaultMinDistanceFieldFontSize = 18;
34#ifdef SK_BUILD_FOR_ANDROID
35static const int kDefaultMaxDistanceFieldFontSize = 384;
36#else
37static const int kDefaultMaxDistanceFieldFontSize = 2 * kLargeDFFontSize;
38#endif
39
40GrAtlasTextContext::GrAtlasTextContext(const Options& options)
41 : fDistanceAdjustTable(new GrDistanceFieldAdjustTable) {
42 fMaxDistanceFieldFontSize = options.fMaxDistanceFieldFontSize < 0.f
43 ? kDefaultMaxDistanceFieldFontSize
44 : options.fMaxDistanceFieldFontSize;
45 fMinDistanceFieldFontSize = options.fMinDistanceFieldFontSize < 0.f
46 ? kDefaultMinDistanceFieldFontSize
47 : options.fMinDistanceFieldFontSize;
Brian Salomonb5086962017-12-13 10:59:33 -050048 fDistanceFieldVerticesAlwaysHaveW = options.fDistanceFieldVerticesAlwaysHaveW;
joshualitt9bd2daf2015-04-17 09:30:06 -070049}
50
Brian Salomonaf597482017-11-07 16:23:34 -050051std::unique_ptr<GrAtlasTextContext> GrAtlasTextContext::Make(const Options& options) {
52 return std::unique_ptr<GrAtlasTextContext>(new GrAtlasTextContext(options));
joshualitt1d89e8d2015-04-01 12:40:54 -070053}
54
Brian Salomon6f1d36c2017-01-13 12:02:17 -050055SkColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd) {
56 SkColor canonicalColor = paint.computeLuminanceColor();
joshualitt9e36c1a2015-04-14 12:17:27 -070057 if (lcd) {
58 // This is the correct computation, but there are tons of cases where LCD can be overridden.
59 // For now we just regenerate if any run in a textblob has LCD.
60 // TODO figure out where all of these overrides are and see if we can incorporate that logic
61 // at a higher level *OR* use sRGB
62 SkASSERT(false);
63 //canonicalColor = SkMaskGamma::CanonicalColor(canonicalColor);
64 } else {
65 // A8, though can have mixed BMP text but it shouldn't matter because BMP text won't have
66 // gamma corrected masks anyways, nor color
67 U8CPU lum = SkComputeLuminance(SkColorGetR(canonicalColor),
68 SkColorGetG(canonicalColor),
69 SkColorGetB(canonicalColor));
70 // reduce to our finite number of bits
71 canonicalColor = SkMaskGamma::CanonicalColor(SkColorSetRGB(lum, lum, lum));
72 }
73 return canonicalColor;
74}
75
Herb Derbyd8327a82018-01-22 14:39:27 -050076SkScalerContextFlags GrAtlasTextContext::ComputeScalerContextFlags(
77 const GrColorSpaceInfo& colorSpaceInfo) {
brianosman5280dcb2016-04-14 06:02:59 -070078 // If we're doing gamma-correct rendering, then we can disable the gamma hacks.
79 // Otherwise, leave them on. In either case, we still want the contrast boost:
Brian Salomonf3569f02017-10-24 12:52:33 -040080 if (colorSpaceInfo.isGammaCorrect()) {
Herb Derbyd8327a82018-01-22 14:39:27 -050081 return SkScalerContextFlags::kBoostContrast;
brianosman32f77822016-04-07 06:25:45 -070082 } else {
Herb Derbyd8327a82018-01-22 14:39:27 -050083 return SkScalerContextFlags::kFakeGammaAndBoostContrast;
brianosman32f77822016-04-07 06:25:45 -070084 }
85}
86
joshualitt9e36c1a2015-04-14 12:17:27 -070087// TODO if this function ever shows up in profiling, then we can compute this value when the
88// textblob is being built and cache it. However, for the time being textblobs mostly only have 1
89// run so this is not a big deal to compute here.
90bool GrAtlasTextContext::HasLCD(const SkTextBlob* blob) {
halcanary33779752015-10-27 14:01:05 -070091 SkTextBlobRunIterator it(blob);
joshualitt9e36c1a2015-04-14 12:17:27 -070092 for (; !it.done(); it.next()) {
93 if (it.isLCD()) {
94 return true;
95 }
96 }
97 return false;
98}
99
Brian Salomonf18b1d82017-10-27 11:30:49 -0400100void GrAtlasTextContext::drawTextBlob(GrContext* context, GrTextUtils::Target* target,
robertphillipsccb1b572015-05-27 11:02:55 -0700101 const GrClip& clip, const SkPaint& skPaint,
Brian Salomonf18b1d82017-10-27 11:30:49 -0400102 const SkMatrix& viewMatrix, const SkSurfaceProps& props,
103 const SkTextBlob* blob, SkScalar x, SkScalar y,
joshualittdbd35932015-04-02 09:19:04 -0700104 SkDrawFilter* drawFilter, const SkIRect& clipBounds) {
joshualitt9b8e79e2015-04-24 09:57:12 -0700105 // If we have been abandoned, then don't draw
joshualitt27004b72016-02-11 12:00:33 -0800106 if (context->abandoned()) {
robertphillipsea461502015-05-26 11:38:03 -0700107 return;
108 }
109
Hal Canary144caf52016-11-07 17:57:18 -0500110 sk_sp<GrAtlasTextBlob> cacheBlob;
Mike Reed80747ef2018-01-23 15:29:32 -0500111 SkMaskFilterBase::BlurRec blurRec;
joshualitt374b2f72015-07-21 08:05:03 -0700112 GrAtlasTextBlob::Key key;
joshualitt53b5f442015-04-13 06:33:59 -0700113 // It might be worth caching these things, but its not clear at this time
114 // TODO for animated mask filters, this will fill up our cache. We need a safeguard here
115 const SkMaskFilter* mf = skPaint.getMaskFilter();
joshualitt2a0e9f32015-04-13 06:12:21 -0700116 bool canCache = !(skPaint.getPathEffect() ||
Mike Reed80747ef2018-01-23 15:29:32 -0500117 (mf && !as_MFB(mf)->asABlur(&blurRec)) ||
joshualitt2a0e9f32015-04-13 06:12:21 -0700118 drawFilter);
Herb Derbyd8327a82018-01-22 14:39:27 -0500119 SkScalerContextFlags scalerContextFlags = ComputeScalerContextFlags(target->colorSpaceInfo());
joshualitt2a0e9f32015-04-13 06:12:21 -0700120
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500121 auto glyphCache = context->contextPriv().getGlyphCache();
122 auto restrictedAtlasManager = context->contextPriv().getRestrictedAtlasManager();
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500123 GrTextBlobCache* textBlobCache = context->contextPriv().getTextBlobCache();
124
joshualitt2a0e9f32015-04-13 06:12:21 -0700125 if (canCache) {
joshualitt9e36c1a2015-04-14 12:17:27 -0700126 bool hasLCD = HasLCD(blob);
joshualitte4cee1f2015-05-11 13:04:28 -0700127
128 // We canonicalize all non-lcd draws to use kUnknown_SkPixelGeometry
joshualitt2c89bc12016-02-11 05:42:30 -0800129 SkPixelGeometry pixelGeometry = hasLCD ? props.pixelGeometry() :
joshualitte4cee1f2015-05-11 13:04:28 -0700130 kUnknown_SkPixelGeometry;
131
joshualitt9e36c1a2015-04-14 12:17:27 -0700132 // TODO we want to figure out a way to be able to use the canonical color on LCD text,
133 // see the note on ComputeCanonicalColor above. We pick a dummy value for LCD text to
134 // ensure we always match the same key
135 GrColor canonicalColor = hasLCD ? SK_ColorTRANSPARENT :
136 ComputeCanonicalColor(skPaint, hasLCD);
137
joshualitte4cee1f2015-05-11 13:04:28 -0700138 key.fPixelGeometry = pixelGeometry;
joshualitt53b5f442015-04-13 06:33:59 -0700139 key.fUniqueID = blob->uniqueID();
140 key.fStyle = skPaint.getStyle();
141 key.fHasBlur = SkToBool(mf);
joshualitt9e36c1a2015-04-14 12:17:27 -0700142 key.fCanonicalColor = canonicalColor;
brianosman8d7ffce2016-04-21 08:29:06 -0700143 key.fScalerContextFlags = scalerContextFlags;
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500144 cacheBlob = textBlobCache->find(key);
joshualitt2a0e9f32015-04-13 06:12:21 -0700145 }
146
Brian Salomonf18b1d82017-10-27 11:30:49 -0400147 GrTextUtils::Paint paint(&skPaint, &target->colorSpaceInfo());
joshualittb7133be2015-04-08 09:08:31 -0700148 if (cacheBlob) {
Brian Salomon6f1d36c2017-01-13 12:02:17 -0500149 if (cacheBlob->mustRegenerate(paint, blurRec, viewMatrix, x, y)) {
joshualitt1d89e8d2015-04-01 12:40:54 -0700150 // We have to remake the blob because changes may invalidate our masks.
151 // TODO we could probably get away reuse most of the time if the pointer is unique,
152 // but we'd have to clear the subrun information
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500153 textBlobCache->remove(cacheBlob.get());
154 cacheBlob = textBlobCache->makeCachedBlob(blob, key, blurRec, skPaint);
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500155 this->regenerateTextBlob(cacheBlob.get(), glyphCache,
Brian Salomonaf597482017-11-07 16:23:34 -0500156 *context->caps()->shaderCaps(), paint, scalerContextFlags,
157 viewMatrix, props, blob, x, y, drawFilter);
joshualittb7133be2015-04-08 09:08:31 -0700158 } else {
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500159 textBlobCache->makeMRU(cacheBlob.get());
joshualitt2f2ee832016-02-10 08:52:24 -0800160
161 if (CACHE_SANITY_CHECK) {
joshualitt259fbf12015-07-21 11:39:34 -0700162 int glyphCount = 0;
163 int runCount = 0;
164 GrTextBlobCache::BlobGlyphCount(&glyphCount, &runCount, blob);
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500165 sk_sp<GrAtlasTextBlob> sanityBlob(textBlobCache->makeBlob(glyphCount, runCount));
joshualitt92303772016-02-10 11:55:52 -0800166 sanityBlob->setupKey(key, blurRec, skPaint);
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500167 this->regenerateTextBlob(sanityBlob.get(), glyphCache,
Brian Salomonaf597482017-11-07 16:23:34 -0500168 *context->caps()->shaderCaps(), paint, scalerContextFlags,
169 viewMatrix, props, blob, x, y, drawFilter);
joshualitt259fbf12015-07-21 11:39:34 -0700170 GrAtlasTextBlob::AssertEqual(*sanityBlob, *cacheBlob);
171 }
joshualitt1d89e8d2015-04-01 12:40:54 -0700172 }
173 } else {
joshualitt2a0e9f32015-04-13 06:12:21 -0700174 if (canCache) {
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500175 cacheBlob = textBlobCache->makeCachedBlob(blob, key, blurRec, skPaint);
joshualitt2a0e9f32015-04-13 06:12:21 -0700176 } else {
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500177 cacheBlob = textBlobCache->makeBlob(blob);
joshualitt2a0e9f32015-04-13 06:12:21 -0700178 }
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500179 this->regenerateTextBlob(cacheBlob.get(), glyphCache,
Brian Salomonaf597482017-11-07 16:23:34 -0500180 *context->caps()->shaderCaps(), paint, scalerContextFlags,
181 viewMatrix, props, blob, x, y, drawFilter);
joshualitt1d89e8d2015-04-01 12:40:54 -0700182 }
183
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500184 cacheBlob->flush(restrictedAtlasManager, target, props, fDistanceAdjustTable.get(), paint,
Jim Van Verth54d9c882018-02-08 16:14:48 -0500185 clip, viewMatrix, clipBounds, x, y);
joshualitt1d89e8d2015-04-01 12:40:54 -0700186}
187
Brian Salomonaf597482017-11-07 16:23:34 -0500188void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500189 GrGlyphCache* glyphCache,
joshualitt27004b72016-02-11 12:00:33 -0800190 const GrShaderCaps& shaderCaps,
Brian Salomon6f1d36c2017-01-13 12:02:17 -0500191 const GrTextUtils::Paint& paint,
Herb Derbyd8327a82018-01-22 14:39:27 -0500192 SkScalerContextFlags scalerContextFlags,
Jim Van Verth58c3cce2017-10-19 15:50:24 -0400193 const SkMatrix& viewMatrix,
Brian Salomon6f1d36c2017-01-13 12:02:17 -0500194 const SkSurfaceProps& props, const SkTextBlob* blob,
Brian Salomonaf597482017-11-07 16:23:34 -0500195 SkScalar x, SkScalar y,
196 SkDrawFilter* drawFilter) const {
Jim Van Verthbc2cdd12017-06-08 11:14:35 -0400197 cacheBlob->initReusableBlob(paint.luminanceColor(), viewMatrix, x, y);
joshualitt1d89e8d2015-04-01 12:40:54 -0700198
199 // Regenerate textblob
halcanary33779752015-10-27 14:01:05 -0700200 SkTextBlobRunIterator it(blob);
Brian Salomon6f1d36c2017-01-13 12:02:17 -0500201 GrTextUtils::RunPaint runPaint(&paint, drawFilter, props);
joshualitt1d89e8d2015-04-01 12:40:54 -0700202 for (int run = 0; !it.done(); it.next(), run++) {
203 int glyphCount = it.glyphCount();
204 size_t textLen = glyphCount * sizeof(uint16_t);
205 const SkPoint& offset = it.offset();
Brian Salomon6f1d36c2017-01-13 12:02:17 -0500206 cacheBlob->push_back_run(run);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500207 if (!runPaint.modifyForRun([it](SkPaint* p) { it.applyFontToPaint(p); })) {
joshualitt1d89e8d2015-04-01 12:40:54 -0700208 continue;
209 }
Jim Van Verth54d9c882018-02-08 16:14:48 -0500210 cacheBlob->setRunPaintFlags(run, runPaint.skPaint().getFlags());
211
Brian Salomonaf597482017-11-07 16:23:34 -0500212 if (this->canDrawAsDistanceFields(runPaint, viewMatrix, props, shaderCaps)) {
joshualittfcfb9fc2015-04-21 07:35:10 -0700213 switch (it.positioning()) {
214 case SkTextBlob::kDefault_Positioning: {
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500215 this->drawDFText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags,
Brian Salomonaf597482017-11-07 16:23:34 -0500216 viewMatrix, (const char*)it.glyphs(), textLen, x + offset.x(),
217 y + offset.y());
joshualittfcfb9fc2015-04-21 07:35:10 -0700218 break;
219 }
220 case SkTextBlob::kHorizontal_Positioning: {
joshualitt5425a9a2015-12-11 11:05:43 -0800221 SkPoint dfOffset = SkPoint::Make(x, y + offset.y());
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500222 this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint,
Brian Salomonaf597482017-11-07 16:23:34 -0500223 scalerContextFlags, viewMatrix, (const char*)it.glyphs(),
224 textLen, it.pos(), 1, dfOffset);
joshualittfcfb9fc2015-04-21 07:35:10 -0700225 break;
226 }
227 case SkTextBlob::kFull_Positioning: {
joshualitt5425a9a2015-12-11 11:05:43 -0800228 SkPoint dfOffset = SkPoint::Make(x, y);
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500229 this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint,
Brian Salomonaf597482017-11-07 16:23:34 -0500230 scalerContextFlags, viewMatrix, (const char*)it.glyphs(),
231 textLen, it.pos(), 2, dfOffset);
joshualittfcfb9fc2015-04-21 07:35:10 -0700232 break;
233 }
234 }
joshualittfcfb9fc2015-04-21 07:35:10 -0700235 } else {
joshualittfcfb9fc2015-04-21 07:35:10 -0700236 switch (it.positioning()) {
237 case SkTextBlob::kDefault_Positioning:
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500238 DrawBmpText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags,
Brian Salomon52db9402017-11-07 14:58:55 -0500239 viewMatrix, (const char*)it.glyphs(), textLen, x + offset.x(),
240 y + offset.y());
joshualittfcfb9fc2015-04-21 07:35:10 -0700241 break;
242 case SkTextBlob::kHorizontal_Positioning:
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500243 DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags,
Brian Salomon52db9402017-11-07 14:58:55 -0500244 viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 1,
Jim Van Verthc401bb92018-02-15 14:05:24 -0500245 SkPoint::Make(x, y + offset.y()));
joshualittfcfb9fc2015-04-21 07:35:10 -0700246 break;
247 case SkTextBlob::kFull_Positioning:
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500248 DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags,
Brian Salomon52db9402017-11-07 14:58:55 -0500249 viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 2,
Jim Van Verthc401bb92018-02-15 14:05:24 -0500250 SkPoint::Make(x, y));
joshualittfcfb9fc2015-04-21 07:35:10 -0700251 break;
252 }
joshualitt1d89e8d2015-04-01 12:40:54 -0700253 }
joshualitt1d89e8d2015-04-01 12:40:54 -0700254 }
255}
256
Florin Malitac337c9e2017-03-10 18:02:29 +0000257inline sk_sp<GrAtlasTextBlob>
Brian Salomonaf597482017-11-07 16:23:34 -0500258GrAtlasTextContext::makeDrawTextBlob(GrTextBlobCache* blobCache,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500259 GrGlyphCache* glyphCache,
Florin Malitac337c9e2017-03-10 18:02:29 +0000260 const GrShaderCaps& shaderCaps,
261 const GrTextUtils::Paint& paint,
Herb Derbyd8327a82018-01-22 14:39:27 -0500262 SkScalerContextFlags scalerContextFlags,
Florin Malitac337c9e2017-03-10 18:02:29 +0000263 const SkMatrix& viewMatrix,
264 const SkSurfaceProps& props,
265 const char text[], size_t byteLength,
Brian Salomonaf597482017-11-07 16:23:34 -0500266 SkScalar x, SkScalar y) const {
Brian Salomon6f1d36c2017-01-13 12:02:17 -0500267 int glyphCount = paint.skPaint().countText(text, byteLength);
Brian Salomonb3f6ac42017-07-31 08:00:25 -0400268 if (!glyphCount) {
269 return nullptr;
270 }
Florin Malitac337c9e2017-03-10 18:02:29 +0000271 sk_sp<GrAtlasTextBlob> blob = blobCache->makeBlob(glyphCount, 1);
joshualitt7481e752016-01-22 06:08:48 -0800272 blob->initThrowawayBlob(viewMatrix, x, y);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500273 blob->setRunPaintFlags(0, paint.skPaint().getFlags());
joshualitta6bf4c52016-01-19 06:59:29 -0800274
Brian Salomonaf597482017-11-07 16:23:34 -0500275 if (this->canDrawAsDistanceFields(paint, viewMatrix, props, shaderCaps)) {
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500276 this->drawDFText(blob.get(), 0, glyphCache, props, paint, scalerContextFlags, viewMatrix,
Brian Salomonaf597482017-11-07 16:23:34 -0500277 text, byteLength, x, y);
joshualitt9bd2daf2015-04-17 09:30:06 -0700278 } else {
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500279 DrawBmpText(blob.get(), 0, glyphCache, props, paint, scalerContextFlags, viewMatrix, text,
Brian Salomon52db9402017-11-07 14:58:55 -0500280 byteLength, x, y);
joshualitt9bd2daf2015-04-17 09:30:06 -0700281 }
joshualitt79dfb2b2015-05-11 08:58:08 -0700282 return blob;
joshualitt1d89e8d2015-04-01 12:40:54 -0700283}
284
Florin Malitac337c9e2017-03-10 18:02:29 +0000285inline sk_sp<GrAtlasTextBlob>
Brian Salomonaf597482017-11-07 16:23:34 -0500286GrAtlasTextContext::makeDrawPosTextBlob(GrTextBlobCache* blobCache,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500287 GrGlyphCache* glyphCache,
Florin Malitac337c9e2017-03-10 18:02:29 +0000288 const GrShaderCaps& shaderCaps,
289 const GrTextUtils::Paint& paint,
Herb Derbyd8327a82018-01-22 14:39:27 -0500290 SkScalerContextFlags scalerContextFlags,
Florin Malitac337c9e2017-03-10 18:02:29 +0000291 const SkMatrix& viewMatrix,
292 const SkSurfaceProps& props,
293 const char text[], size_t byteLength,
294 const SkScalar pos[], int scalarsPerPosition, const
Brian Salomonaf597482017-11-07 16:23:34 -0500295 SkPoint& offset) const {
Brian Salomon6f1d36c2017-01-13 12:02:17 -0500296 int glyphCount = paint.skPaint().countText(text, byteLength);
Brian Salomonb3f6ac42017-07-31 08:00:25 -0400297 if (!glyphCount) {
298 return nullptr;
299 }
joshualitt9bd2daf2015-04-17 09:30:06 -0700300
Florin Malitac337c9e2017-03-10 18:02:29 +0000301 sk_sp<GrAtlasTextBlob> blob = blobCache->makeBlob(glyphCount, 1);
joshualitt7481e752016-01-22 06:08:48 -0800302 blob->initThrowawayBlob(viewMatrix, offset.x(), offset.y());
Jim Van Verth54d9c882018-02-08 16:14:48 -0500303 blob->setRunPaintFlags(0, paint.skPaint().getFlags());
joshualitt9bd2daf2015-04-17 09:30:06 -0700304
Brian Salomonaf597482017-11-07 16:23:34 -0500305 if (this->canDrawAsDistanceFields(paint, viewMatrix, props, shaderCaps)) {
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500306 this->drawDFPosText(blob.get(), 0, glyphCache, props, paint, scalerContextFlags, viewMatrix,
Brian Salomonaf597482017-11-07 16:23:34 -0500307 text, byteLength, pos, scalarsPerPosition, offset);
joshualitt9bd2daf2015-04-17 09:30:06 -0700308 } else {
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500309 DrawBmpPosText(blob.get(), 0, glyphCache, props, paint, scalerContextFlags, viewMatrix,
310 text, byteLength, pos, scalarsPerPosition, offset);
joshualitt9bd2daf2015-04-17 09:30:06 -0700311 }
joshualitt79dfb2b2015-05-11 08:58:08 -0700312 return blob;
313}
314
Brian Salomonf18b1d82017-10-27 11:30:49 -0400315void GrAtlasTextContext::drawText(GrContext* context, GrTextUtils::Target* target,
Brian Salomon6f1d36c2017-01-13 12:02:17 -0500316 const GrClip& clip, const SkPaint& skPaint,
Brian Salomon82f44312017-01-11 13:42:54 -0500317 const SkMatrix& viewMatrix, const SkSurfaceProps& props,
318 const char text[], size_t byteLength, SkScalar x, SkScalar y,
319 const SkIRect& regionClipBounds) {
joshualitt27004b72016-02-11 12:00:33 -0800320 if (context->abandoned()) {
joshualitte55750e2016-02-10 12:52:21 -0800321 return;
Brian Salomon6f1d36c2017-01-13 12:02:17 -0500322 }
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500323
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500324 auto glyphCache = context->contextPriv().getGlyphCache();
325 auto restrictedAtlasManager = context->contextPriv().getRestrictedAtlasManager();
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500326 auto textBlobCache = context->contextPriv().getTextBlobCache();
327
Brian Salomonf18b1d82017-10-27 11:30:49 -0400328 GrTextUtils::Paint paint(&skPaint, &target->colorSpaceInfo());
Jim Van Verth54d9c882018-02-08 16:14:48 -0500329 sk_sp<GrAtlasTextBlob> blob(
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500330 this->makeDrawTextBlob(textBlobCache, glyphCache,
Jim Van Verth54d9c882018-02-08 16:14:48 -0500331 *context->caps()->shaderCaps(), paint,
332 ComputeScalerContextFlags(target->colorSpaceInfo()),
333 viewMatrix, props, text, byteLength, x, y));
334 if (blob) {
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500335 blob->flush(restrictedAtlasManager, target, props, fDistanceAdjustTable.get(), paint,
Jim Van Verth54d9c882018-02-08 16:14:48 -0500336 clip, viewMatrix, regionClipBounds, x, y);
joshualitte55750e2016-02-10 12:52:21 -0800337 }
joshualitt79dfb2b2015-05-11 08:58:08 -0700338}
339
Brian Salomonf18b1d82017-10-27 11:30:49 -0400340void GrAtlasTextContext::drawPosText(GrContext* context, GrTextUtils::Target* target,
Brian Salomon6f1d36c2017-01-13 12:02:17 -0500341 const GrClip& clip, const SkPaint& skPaint,
Brian Salomon82f44312017-01-11 13:42:54 -0500342 const SkMatrix& viewMatrix, const SkSurfaceProps& props,
343 const char text[], size_t byteLength, const SkScalar pos[],
344 int scalarsPerPosition, const SkPoint& offset,
345 const SkIRect& regionClipBounds) {
Brian Salomonf18b1d82017-10-27 11:30:49 -0400346 GrTextUtils::Paint paint(&skPaint, &target->colorSpaceInfo());
joshualitt27004b72016-02-11 12:00:33 -0800347 if (context->abandoned()) {
joshualitte55750e2016-02-10 12:52:21 -0800348 return;
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500349 }
350
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500351 auto glyphCache = context->contextPriv().getGlyphCache();
352 auto restrictedAtlasManager = context->contextPriv().getRestrictedAtlasManager();
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500353 auto textBlobCache = context->contextPriv().getTextBlobCache();
354
Jim Van Verth54d9c882018-02-08 16:14:48 -0500355 sk_sp<GrAtlasTextBlob> blob(this->makeDrawPosTextBlob(
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500356 textBlobCache, glyphCache,
Jim Van Verth54d9c882018-02-08 16:14:48 -0500357 *context->caps()->shaderCaps(), paint,
358 ComputeScalerContextFlags(target->colorSpaceInfo()), viewMatrix, props, text,
359 byteLength, pos, scalarsPerPosition, offset));
360 if (blob) {
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500361 blob->flush(restrictedAtlasManager, target, props, fDistanceAdjustTable.get(), paint,
Jim Van Verth54d9c882018-02-08 16:14:48 -0500362 clip, viewMatrix, regionClipBounds, offset.fX, offset.fY);
joshualitte55750e2016-02-10 12:52:21 -0800363 }
joshualitt9bd2daf2015-04-17 09:30:06 -0700364}
365
Brian Salomon52db9402017-11-07 14:58:55 -0500366void GrAtlasTextContext::DrawBmpText(GrAtlasTextBlob* blob, int runIndex,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500367 GrGlyphCache* glyphCache, const SkSurfaceProps& props,
Herb Derbyd8327a82018-01-22 14:39:27 -0500368 const GrTextUtils::Paint& paint,
369 SkScalerContextFlags scalerContextFlags,
Brian Salomon52db9402017-11-07 14:58:55 -0500370 const SkMatrix& viewMatrix, const char text[],
371 size_t byteLength, SkScalar x, SkScalar y) {
372 SkASSERT(byteLength == 0 || text != nullptr);
373
374 // nothing to draw
375 if (text == nullptr || byteLength == 0) {
376 return;
377 }
378
379 // Ensure the blob is set for bitmaptext
380 blob->setHasBitmap();
381
Jim Van Verth54d9c882018-02-08 16:14:48 -0500382 if (SkDraw::ShouldDrawTextAsPaths(paint, viewMatrix)) {
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500383 DrawBmpTextAsPaths(blob, runIndex, glyphCache, props, paint, scalerContextFlags, viewMatrix,
Jim Van Verthc401bb92018-02-15 14:05:24 -0500384 text, byteLength, x, y);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500385 return;
386 }
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500387
388 sk_sp<GrTextStrike> currStrike;
Brian Salomon52db9402017-11-07 14:58:55 -0500389 SkGlyphCache* cache = blob->setupCache(runIndex, props, scalerContextFlags, paint, &viewMatrix);
390 SkFindAndPlaceGlyph::ProcessText(paint.skPaint().getTextEncoding(), text, byteLength, {x, y},
391 viewMatrix, paint.skPaint().getTextAlign(), cache,
392 [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
393 position += rounding;
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500394 BmpAppendGlyph(blob, runIndex, glyphCache, &currStrike,
Jim Van Verthc65b65d2018-01-16 16:26:35 -0500395 glyph, SkScalarFloorToScalar(position.fX),
396 SkScalarFloorToScalar(position.fY),
Jim Van Verthf4c13162018-01-11 16:40:24 -0500397 paint.filteredPremulColor(), cache,
398 SK_Scalar1);
Brian Salomon52db9402017-11-07 14:58:55 -0500399 });
400
401 SkGlyphCache::AttachCache(cache);
402}
403
404void GrAtlasTextContext::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500405 GrGlyphCache* glyphCache, const SkSurfaceProps& props,
Brian Salomon52db9402017-11-07 14:58:55 -0500406 const GrTextUtils::Paint& paint,
Herb Derbyd8327a82018-01-22 14:39:27 -0500407 SkScalerContextFlags scalerContextFlags,
408 const SkMatrix& viewMatrix,
Brian Salomon52db9402017-11-07 14:58:55 -0500409 const char text[], size_t byteLength, const SkScalar pos[],
Jim Van Verthc401bb92018-02-15 14:05:24 -0500410 int scalarsPerPosition, const SkPoint& offset) {
Brian Salomon52db9402017-11-07 14:58:55 -0500411 SkASSERT(byteLength == 0 || text != nullptr);
412 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
413
414 // nothing to draw
415 if (text == nullptr || byteLength == 0) {
416 return;
417 }
418
419 // Ensure the blob is set for bitmaptext
420 blob->setHasBitmap();
421
Jim Van Verth54d9c882018-02-08 16:14:48 -0500422 if (SkDraw::ShouldDrawTextAsPaths(paint, viewMatrix)) {
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500423 DrawBmpPosTextAsPaths(blob, runIndex, glyphCache, props, paint, scalerContextFlags,
Jim Van Verthc401bb92018-02-15 14:05:24 -0500424 viewMatrix, text, byteLength, pos, scalarsPerPosition, offset);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500425 return;
426 }
427
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500428 sk_sp<GrTextStrike> currStrike;
Brian Salomon52db9402017-11-07 14:58:55 -0500429 SkGlyphCache* cache = blob->setupCache(runIndex, props, scalerContextFlags, paint, &viewMatrix);
Brian Salomon52db9402017-11-07 14:58:55 -0500430 SkFindAndPlaceGlyph::ProcessPosText(
431 paint.skPaint().getTextEncoding(), text, byteLength, offset, viewMatrix, pos,
432 scalarsPerPosition, paint.skPaint().getTextAlign(), cache,
433 [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
434 position += rounding;
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500435 BmpAppendGlyph(blob, runIndex, glyphCache, &currStrike, glyph,
Jim Van Verthc65b65d2018-01-16 16:26:35 -0500436 SkScalarFloorToScalar(position.fX),
437 SkScalarFloorToScalar(position.fY),
Jim Van Verthc401bb92018-02-15 14:05:24 -0500438 paint.filteredPremulColor(), cache, SK_Scalar1);
Brian Salomon52db9402017-11-07 14:58:55 -0500439 });
440
441 SkGlyphCache::AttachCache(cache);
442}
443
Jim Van Verth54d9c882018-02-08 16:14:48 -0500444void GrAtlasTextContext::DrawBmpTextAsPaths(GrAtlasTextBlob* blob, int runIndex,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500445 GrGlyphCache* glyphCache,
Jim Van Verthc401bb92018-02-15 14:05:24 -0500446 const SkSurfaceProps& props,
447 const GrTextUtils::Paint& origPaint,
448 SkScalerContextFlags scalerContextFlags,
449 const SkMatrix& viewMatrix, const char text[],
Jim Van Verth54d9c882018-02-08 16:14:48 -0500450 size_t byteLength, SkScalar x, SkScalar y) {
451 // nothing to draw
452 if (text == nullptr || byteLength == 0) {
453 return;
454 }
455
456 // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
Jim Van Verthc401bb92018-02-15 14:05:24 -0500457 SkPaint pathPaint(origPaint);
458 pathPaint.setStyle(SkPaint::kFill_Style);
459 pathPaint.setPathEffect(nullptr);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500460
Jim Van Verthc401bb92018-02-15 14:05:24 -0500461 GrTextUtils::PathTextIter iter(text, byteLength, pathPaint, true);
Jim Van Verth080a9282018-03-02 10:41:43 -0500462 FallbackTextHelper fallbackTextHelper(viewMatrix, pathPaint, glyphCache, iter.getPathScale());
Jim Van Verthc401bb92018-02-15 14:05:24 -0500463
464 const SkGlyph* iterGlyph;
Jim Van Verth54d9c882018-02-08 16:14:48 -0500465 const SkPath* iterPath;
466 SkScalar xpos = 0;
Jim Van Verthc401bb92018-02-15 14:05:24 -0500467 const char* lastText = text;
468 while (iter.next(&iterGlyph, &iterPath, &xpos)) {
469 if (iterGlyph) {
470 SkPoint pos = SkPoint::Make(xpos + x, y);
471 fallbackTextHelper.appendText(*iterGlyph, iter.getText() - lastText, lastText, pos);
472 } else if (iterPath) {
Jim Van Verth54d9c882018-02-08 16:14:48 -0500473 blob->appendPathGlyph(runIndex, *iterPath, xpos + x, y, iter.getPathScale(), false);
474 }
Jim Van Verthc401bb92018-02-15 14:05:24 -0500475 lastText = iter.getText();
Jim Van Verth54d9c882018-02-08 16:14:48 -0500476 }
Jim Van Verthc401bb92018-02-15 14:05:24 -0500477
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500478 fallbackTextHelper.drawText(blob, runIndex, glyphCache, props, origPaint, scalerContextFlags);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500479}
480
481void GrAtlasTextContext::DrawBmpPosTextAsPaths(GrAtlasTextBlob* blob, int runIndex,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500482 GrGlyphCache* glyphCache,
Jim Van Verth54d9c882018-02-08 16:14:48 -0500483 const SkSurfaceProps& props,
484 const GrTextUtils::Paint& origPaint,
Jim Van Verthc401bb92018-02-15 14:05:24 -0500485 SkScalerContextFlags scalerContextFlags,
486 const SkMatrix& viewMatrix,
Jim Van Verth54d9c882018-02-08 16:14:48 -0500487 const char text[], size_t byteLength,
488 const SkScalar pos[], int scalarsPerPosition,
Jim Van Verthc401bb92018-02-15 14:05:24 -0500489 const SkPoint& offset) {
Jim Van Verth54d9c882018-02-08 16:14:48 -0500490 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
491
492 // nothing to draw
493 if (text == nullptr || byteLength == 0) {
494 return;
495 }
496
497 // setup our std paint, in hopes of getting hits in the cache
Jim Van Verthc401bb92018-02-15 14:05:24 -0500498 SkPaint pathPaint(origPaint);
499 SkScalar matrixScale = pathPaint.setupForAsPaths();
Jim Van Verth080a9282018-03-02 10:41:43 -0500500 FallbackTextHelper fallbackTextHelper(viewMatrix, origPaint, glyphCache, matrixScale);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500501
502 // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
Jim Van Verthc401bb92018-02-15 14:05:24 -0500503 pathPaint.setStyle(SkPaint::kFill_Style);
504 pathPaint.setPathEffect(nullptr);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500505
Jim Van Verthc401bb92018-02-15 14:05:24 -0500506 SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(pathPaint.getTextEncoding(),
507 pathPaint.isDevKernText(),
508 true);
509 SkAutoGlyphCache autoCache(pathPaint, &props, nullptr);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500510 SkGlyphCache* cache = autoCache.getCache();
511
512 const char* stop = text + byteLength;
Jim Van Verthc401bb92018-02-15 14:05:24 -0500513 const char* lastText = text;
514 SkTextAlignProc alignProc(pathPaint.getTextAlign());
Jim Van Verth54d9c882018-02-08 16:14:48 -0500515 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
516
517 while (text < stop) {
518 const SkGlyph& glyph = glyphCacheProc(cache, &text);
519 if (glyph.fWidth) {
Jim Van Verthc401bb92018-02-15 14:05:24 -0500520 SkPoint tmsLoc;
521 tmsProc(pos, &tmsLoc);
522 SkPoint loc;
523 alignProc(tmsLoc, glyph, &loc);
524 if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
525 fallbackTextHelper.appendText(glyph, text - lastText, lastText, loc);
526 } else {
527 const SkPath* path = cache->findPath(glyph);
528 if (path) {
529 blob->appendPathGlyph(runIndex, *path, loc.fX, loc.fY, matrixScale, false);
530 }
Jim Van Verth54d9c882018-02-08 16:14:48 -0500531 }
532 }
Jim Van Verthc401bb92018-02-15 14:05:24 -0500533 lastText = text;
Jim Van Verth54d9c882018-02-08 16:14:48 -0500534 pos += scalarsPerPosition;
535 }
Jim Van Verthc401bb92018-02-15 14:05:24 -0500536
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500537 fallbackTextHelper.drawText(blob, runIndex, glyphCache, props, origPaint, scalerContextFlags);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500538}
539
Brian Salomon52db9402017-11-07 14:58:55 -0500540void GrAtlasTextContext::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex,
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500541 GrGlyphCache* grGlyphCache,
542 sk_sp<GrTextStrike>* strike,
Jim Van Verthc65b65d2018-01-16 16:26:35 -0500543 const SkGlyph& skGlyph, SkScalar sx, SkScalar sy,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500544 GrColor color, SkGlyphCache* skGlyphCache,
Jim Van Verthc65b65d2018-01-16 16:26:35 -0500545 SkScalar textRatio) {
Brian Salomon52db9402017-11-07 14:58:55 -0500546 if (!*strike) {
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500547 *strike = grGlyphCache->getStrike(skGlyphCache);
Brian Salomon52db9402017-11-07 14:58:55 -0500548 }
549
550 GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(),
551 skGlyph.getSubXFixed(),
552 skGlyph.getSubYFixed(),
553 GrGlyph::kCoverage_MaskStyle);
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500554 GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, skGlyphCache);
Brian Salomon52db9402017-11-07 14:58:55 -0500555 if (!glyph) {
556 return;
557 }
558
Jim Van Verthc65b65d2018-01-16 16:26:35 -0500559 SkASSERT(skGlyph.fWidth == glyph->width());
560 SkASSERT(skGlyph.fHeight == glyph->height());
561
Jim Van Verthf4c13162018-01-11 16:40:24 -0500562 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft);
563 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop);
564 SkScalar width = SkIntToScalar(glyph->fBounds.width());
565 SkScalar height = SkIntToScalar(glyph->fBounds.height());
Brian Salomon52db9402017-11-07 14:58:55 -0500566
Jim Van Verthf4c13162018-01-11 16:40:24 -0500567 dx *= textRatio;
568 dy *= textRatio;
569 width *= textRatio;
570 height *= textRatio;
Brian Salomon52db9402017-11-07 14:58:55 -0500571
Jim Van Verthf4c13162018-01-11 16:40:24 -0500572 SkRect glyphRect = SkRect::MakeXYWH(sx + dx, sy + dy, width, height);
Brian Salomon52db9402017-11-07 14:58:55 -0500573
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500574 blob->appendGlyph(runIndex, glyphRect, color, *strike, glyph, skGlyphCache, skGlyph, sx, sy,
Jim Van Verthf4c13162018-01-11 16:40:24 -0500575 textRatio, true);
Brian Salomon52db9402017-11-07 14:58:55 -0500576}
577
Brian Salomonaf597482017-11-07 16:23:34 -0500578bool GrAtlasTextContext::canDrawAsDistanceFields(const SkPaint& skPaint, const SkMatrix& viewMatrix,
Brian Salomon52db9402017-11-07 14:58:55 -0500579 const SkSurfaceProps& props,
Brian Salomonaf597482017-11-07 16:23:34 -0500580 const GrShaderCaps& caps) const {
Brian Salomon52db9402017-11-07 14:58:55 -0500581 if (!viewMatrix.hasPerspective()) {
582 SkScalar maxScale = viewMatrix.getMaxScale();
583 SkScalar scaledTextSize = maxScale * skPaint.getTextSize();
584 // Hinted text looks far better at small resolutions
585 // Scaling up beyond 2x yields undesireable artifacts
Brian Salomonaf597482017-11-07 16:23:34 -0500586 if (scaledTextSize < fMinDistanceFieldFontSize ||
587 scaledTextSize > fMaxDistanceFieldFontSize) {
Brian Salomon52db9402017-11-07 14:58:55 -0500588 return false;
589 }
590
591 bool useDFT = props.isUseDeviceIndependentFonts();
592#if SK_FORCE_DISTANCE_FIELD_TEXT
593 useDFT = true;
594#endif
595
596 if (!useDFT && scaledTextSize < kLargeDFFontSize) {
597 return false;
598 }
599 }
600
Mike Reed8ad91a92018-01-19 19:09:32 -0500601 // mask filters modify alpha, which doesn't translate well to distance
602 if (skPaint.getMaskFilter() || !caps.shaderDerivativeSupport()) {
Brian Salomon52db9402017-11-07 14:58:55 -0500603 return false;
604 }
605
606 // TODO: add some stroking support
607 if (skPaint.getStyle() != SkPaint::kFill_Style) {
608 return false;
609 }
610
611 return true;
612}
613
Brian Salomonaf597482017-11-07 16:23:34 -0500614void GrAtlasTextContext::initDistanceFieldPaint(GrAtlasTextBlob* blob,
Brian Salomon52db9402017-11-07 14:58:55 -0500615 SkPaint* skPaint,
616 SkScalar* textRatio,
Brian Salomonaf597482017-11-07 16:23:34 -0500617 const SkMatrix& viewMatrix) const {
Brian Salomon52db9402017-11-07 14:58:55 -0500618 SkScalar textSize = skPaint->getTextSize();
619 SkScalar scaledTextSize = textSize;
620
621 if (viewMatrix.hasPerspective()) {
622 // for perspective, we simply force to the medium size
623 // TODO: compute a size based on approximate screen area
624 scaledTextSize = kMediumDFFontLimit;
625 } else {
626 SkScalar maxScale = viewMatrix.getMaxScale();
627 // if we have non-unity scale, we need to choose our base text size
628 // based on the SkPaint's text size multiplied by the max scale factor
629 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)?
630 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) {
631 scaledTextSize *= maxScale;
632 }
633 }
634
635 // We have three sizes of distance field text, and within each size 'bucket' there is a floor
636 // and ceiling. A scale outside of this range would require regenerating the distance fields
637 SkScalar dfMaskScaleFloor;
638 SkScalar dfMaskScaleCeil;
639 if (scaledTextSize <= kSmallDFFontLimit) {
Brian Salomonaf597482017-11-07 16:23:34 -0500640 dfMaskScaleFloor = fMinDistanceFieldFontSize;
Brian Salomon52db9402017-11-07 14:58:55 -0500641 dfMaskScaleCeil = kSmallDFFontLimit;
642 *textRatio = textSize / kSmallDFFontSize;
643 skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize));
644 } else if (scaledTextSize <= kMediumDFFontLimit) {
645 dfMaskScaleFloor = kSmallDFFontLimit;
646 dfMaskScaleCeil = kMediumDFFontLimit;
647 *textRatio = textSize / kMediumDFFontSize;
648 skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize));
649 } else {
650 dfMaskScaleFloor = kMediumDFFontLimit;
Brian Salomonaf597482017-11-07 16:23:34 -0500651 dfMaskScaleCeil = fMaxDistanceFieldFontSize;
Brian Salomon52db9402017-11-07 14:58:55 -0500652 *textRatio = textSize / kLargeDFFontSize;
653 skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize));
654 }
655
656 // Because there can be multiple runs in the blob, we want the overall maxMinScale, and
657 // minMaxScale to make regeneration decisions. Specifically, we want the maximum minimum scale
658 // we can tolerate before we'd drop to a lower mip size, and the minimum maximum scale we can
659 // tolerate before we'd have to move to a large mip size. When we actually test these values
660 // we look at the delta in scale between the new viewmatrix and the old viewmatrix, and test
661 // against these values to decide if we can reuse or not(ie, will a given scale change our mip
662 // level)
663 SkASSERT(dfMaskScaleFloor <= scaledTextSize && scaledTextSize <= dfMaskScaleCeil);
664 blob->setMinAndMaxScale(dfMaskScaleFloor / scaledTextSize, dfMaskScaleCeil / scaledTextSize);
665
666 skPaint->setAntiAlias(true);
667 skPaint->setLCDRenderText(false);
668 skPaint->setAutohinted(false);
669 skPaint->setHinting(SkPaint::kNormal_Hinting);
670 skPaint->setSubpixelText(true);
671}
672
Brian Salomonaf597482017-11-07 16:23:34 -0500673void GrAtlasTextContext::drawDFText(GrAtlasTextBlob* blob, int runIndex,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500674 GrGlyphCache* glyphCache, const SkSurfaceProps& props,
Herb Derbyd8327a82018-01-22 14:39:27 -0500675 const GrTextUtils::Paint& paint,
676 SkScalerContextFlags scalerContextFlags,
Brian Salomon52db9402017-11-07 14:58:55 -0500677 const SkMatrix& viewMatrix, const char text[],
Brian Salomonaf597482017-11-07 16:23:34 -0500678 size_t byteLength, SkScalar x, SkScalar y) const {
Brian Salomon52db9402017-11-07 14:58:55 -0500679 SkASSERT(byteLength == 0 || text != nullptr);
680
681 // nothing to draw
682 if (text == nullptr || byteLength == 0) {
683 return;
684 }
685
686 const SkPaint& skPaint = paint.skPaint();
687 SkPaint::GlyphCacheProc glyphCacheProc =
688 SkPaint::GetGlyphCacheProc(skPaint.getTextEncoding(), skPaint.isDevKernText(), true);
689 SkAutoDescriptor desc;
690 SkScalerContextEffects effects;
691 // We apply the fake-gamma by altering the distance in the shader, so we ignore the
692 // passed-in scaler context flags. (It's only used when we fall-back to bitmap text).
Herb Derby980a48d2018-01-23 13:39:21 -0500693 SkScalerContext::CreateDescriptorAndEffectsUsingPaint(
694 skPaint, &props, SkScalerContextFlags::kNone, nullptr, &desc, &effects);
Brian Salomon52db9402017-11-07 14:58:55 -0500695 SkGlyphCache* origPaintCache =
696 SkGlyphCache::DetachCache(skPaint.getTypeface(), effects, desc.getDesc());
697
698 SkTArray<SkScalar> positions;
699
700 const char* textPtr = text;
701 SkScalar stopX = 0;
702 SkScalar stopY = 0;
703 SkScalar origin = 0;
704 switch (skPaint.getTextAlign()) {
705 case SkPaint::kRight_Align: origin = SK_Scalar1; break;
706 case SkPaint::kCenter_Align: origin = SK_ScalarHalf; break;
707 case SkPaint::kLeft_Align: origin = 0; break;
708 }
709
710 SkAutoKern autokern;
711 const char* stop = text + byteLength;
712 while (textPtr < stop) {
713 // don't need x, y here, since all subpixel variants will have the
714 // same advance
715 const SkGlyph& glyph = glyphCacheProc(origPaintCache, &textPtr);
716
717 SkScalar width = SkFloatToScalar(glyph.fAdvanceX) + autokern.adjust(glyph);
718 positions.push_back(stopX + origin * width);
719
720 SkScalar height = SkFloatToScalar(glyph.fAdvanceY);
721 positions.push_back(stopY + origin * height);
722
723 stopX += width;
724 stopY += height;
725 }
726 SkASSERT(textPtr == stop);
727
728 SkGlyphCache::AttachCache(origPaintCache);
729
730 // now adjust starting point depending on alignment
731 SkScalar alignX = stopX;
732 SkScalar alignY = stopY;
733 if (skPaint.getTextAlign() == SkPaint::kCenter_Align) {
734 alignX = SkScalarHalf(alignX);
735 alignY = SkScalarHalf(alignY);
736 } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) {
737 alignX = 0;
738 alignY = 0;
739 }
740 x -= alignX;
741 y -= alignY;
742 SkPoint offset = SkPoint::Make(x, y);
743
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500744 this->drawDFPosText(blob, runIndex, glyphCache, props, paint, scalerContextFlags, viewMatrix,
Brian Salomonaf597482017-11-07 16:23:34 -0500745 text, byteLength, positions.begin(), 2, offset);
Brian Salomon52db9402017-11-07 14:58:55 -0500746}
747
Brian Salomonaf597482017-11-07 16:23:34 -0500748void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500749 GrGlyphCache* glyphCache, const SkSurfaceProps& props,
Herb Derbyd8327a82018-01-22 14:39:27 -0500750 const GrTextUtils::Paint& paint,
751 SkScalerContextFlags scalerContextFlags,
Brian Salomon52db9402017-11-07 14:58:55 -0500752 const SkMatrix& viewMatrix, const char text[],
753 size_t byteLength, const SkScalar pos[],
Brian Salomonaf597482017-11-07 16:23:34 -0500754 int scalarsPerPosition, const SkPoint& offset) const {
Brian Salomon52db9402017-11-07 14:58:55 -0500755 SkASSERT(byteLength == 0 || text != nullptr);
756 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
757
758 // nothing to draw
759 if (text == nullptr || byteLength == 0) {
760 return;
761 }
762
Brian Salomonb5086962017-12-13 10:59:33 -0500763 bool hasWCoord = viewMatrix.hasPerspective() || fDistanceFieldVerticesAlwaysHaveW;
764
Brian Salomon52db9402017-11-07 14:58:55 -0500765 // Setup distance field paint and text ratio
766 SkScalar textRatio;
767 SkPaint dfPaint(paint);
Brian Salomonaf597482017-11-07 16:23:34 -0500768 this->initDistanceFieldPaint(blob, &dfPaint, &textRatio, viewMatrix);
Brian Salomon52db9402017-11-07 14:58:55 -0500769 blob->setHasDistanceField();
770 blob->setSubRunHasDistanceFields(runIndex, paint.skPaint().isLCDRenderText(),
Brian Salomon5c6ac642017-12-19 11:09:32 -0500771 paint.skPaint().isAntiAlias(), hasWCoord);
Brian Salomon52db9402017-11-07 14:58:55 -0500772
Jim Van Verth080a9282018-03-02 10:41:43 -0500773 FallbackTextHelper fallbackTextHelper(viewMatrix, paint, glyphCache, textRatio);
Jim Van Verthc401bb92018-02-15 14:05:24 -0500774
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500775 sk_sp<GrTextStrike> currStrike;
Brian Salomon52db9402017-11-07 14:58:55 -0500776
777 // We apply the fake-gamma by altering the distance in the shader, so we ignore the
778 // passed-in scaler context flags. (It's only used when we fall-back to bitmap text).
779 SkGlyphCache* cache =
Herb Derbyd8327a82018-01-22 14:39:27 -0500780 blob->setupCache(runIndex, props, SkScalerContextFlags::kNone, dfPaint, nullptr);
Brian Salomon52db9402017-11-07 14:58:55 -0500781 SkPaint::GlyphCacheProc glyphCacheProc =
782 SkPaint::GetGlyphCacheProc(dfPaint.getTextEncoding(), dfPaint.isDevKernText(), true);
783
784 const char* stop = text + byteLength;
785
Jim Van Verthf4c13162018-01-11 16:40:24 -0500786 SkPaint::Align align = dfPaint.getTextAlign();
787 SkScalar alignMul = SkPaint::kCenter_Align == align ? SK_ScalarHalf :
788 (SkPaint::kRight_Align == align ? SK_Scalar1 : 0);
789 while (text < stop) {
790 const char* lastText = text;
791 // the last 2 parameters are ignored
792 const SkGlyph& glyph = glyphCacheProc(cache, &text);
Brian Salomon52db9402017-11-07 14:58:55 -0500793
Jim Van Verthf4c13162018-01-11 16:40:24 -0500794 if (glyph.fWidth) {
Jim Van Verthc401bb92018-02-15 14:05:24 -0500795 SkPoint glyphPos(offset);
796 glyphPos.fX += pos[0] - SkFloatToScalar(glyph.fAdvanceX) * alignMul * textRatio;
797 glyphPos.fY += (2 == scalarsPerPosition ? pos[1] : 0) -
798 SkFloatToScalar(glyph.fAdvanceY) * alignMul * textRatio;
Jim Van Verthf4c13162018-01-11 16:40:24 -0500799
800 if (glyph.fMaskFormat != SkMask::kARGB32_Format) {
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500801 DfAppendGlyph(blob, runIndex, glyphCache, &currStrike, glyph, glyphPos.fX,
Jim Van Verthc401bb92018-02-15 14:05:24 -0500802 glyphPos.fY, paint.filteredPremulColor(), cache, textRatio);
Jim Van Verthf4c13162018-01-11 16:40:24 -0500803 } else {
804 // can't append color glyph to SDF batch, send to fallback
Jim Van Verthc401bb92018-02-15 14:05:24 -0500805 fallbackTextHelper.appendText(glyph, SkToInt(text - lastText), lastText, glyphPos);
Brian Salomon52db9402017-11-07 14:58:55 -0500806 }
Brian Salomon52db9402017-11-07 14:58:55 -0500807 }
Jim Van Verthf4c13162018-01-11 16:40:24 -0500808 pos += scalarsPerPosition;
Brian Salomon52db9402017-11-07 14:58:55 -0500809 }
810
811 SkGlyphCache::AttachCache(cache);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500812
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500813 fallbackTextHelper.drawText(blob, runIndex, glyphCache, props, paint, scalerContextFlags);
Brian Salomon52db9402017-11-07 14:58:55 -0500814}
815
Jim Van Verthf4c13162018-01-11 16:40:24 -0500816// TODO: merge with BmpAppendGlyph
817void GrAtlasTextContext::DfAppendGlyph(GrAtlasTextBlob* blob, int runIndex,
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500818 GrGlyphCache* grGlyphCache, sk_sp<GrTextStrike>* strike,
Brian Salomon52db9402017-11-07 14:58:55 -0500819 const SkGlyph& skGlyph, SkScalar sx, SkScalar sy,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500820 GrColor color, SkGlyphCache* skGlyphCache,
Jim Van Verthf4c13162018-01-11 16:40:24 -0500821 SkScalar textRatio) {
Brian Salomon52db9402017-11-07 14:58:55 -0500822 if (!*strike) {
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500823 *strike = grGlyphCache->getStrike(skGlyphCache);
Brian Salomon52db9402017-11-07 14:58:55 -0500824 }
825
826 GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(),
827 skGlyph.getSubXFixed(),
828 skGlyph.getSubYFixed(),
829 GrGlyph::kDistance_MaskStyle);
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500830 GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, skGlyphCache);
Brian Salomon52db9402017-11-07 14:58:55 -0500831 if (!glyph) {
Jim Van Verthf4c13162018-01-11 16:40:24 -0500832 return;
Brian Salomon52db9402017-11-07 14:58:55 -0500833 }
834
835 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
836 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
837 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2 * SK_DistanceFieldInset);
838 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2 * SK_DistanceFieldInset);
839
Jim Van Verthf4c13162018-01-11 16:40:24 -0500840 dx *= textRatio;
841 dy *= textRatio;
842 width *= textRatio;
843 height *= textRatio;
844 SkRect glyphRect = SkRect::MakeXYWH(sx + dx, sy + dy, width, height);
Brian Salomon52db9402017-11-07 14:58:55 -0500845
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500846 blob->appendGlyph(runIndex, glyphRect, color, *strike, glyph, skGlyphCache, skGlyph, sx, sy,
Jim Van Verthf4c13162018-01-11 16:40:24 -0500847 textRatio, false);
Brian Salomon52db9402017-11-07 14:58:55 -0500848}
849
joshualitt79dfb2b2015-05-11 08:58:08 -0700850///////////////////////////////////////////////////////////////////////////////////////////////////
851
Jim Van Verthc401bb92018-02-15 14:05:24 -0500852void GrAtlasTextContext::FallbackTextHelper::appendText(const SkGlyph& glyph, int count,
853 const char* text, SkPoint glyphPos) {
854 SkScalar maxDim = SkTMax(glyph.fWidth, glyph.fHeight)*fTextRatio;
855 if (!fUseScaledFallback) {
856 SkScalar scaledGlyphSize = maxDim * fMaxScale;
857 if (!fViewMatrix.hasPerspective() && scaledGlyphSize > fMaxTextSize) {
858 fUseScaledFallback = true;
859 }
860 }
861
862 fFallbackTxt.append(count, text);
863 if (fUseScaledFallback) {
Jim Van Verth080a9282018-03-02 10:41:43 -0500864 // If there's a glyph in the font that's particularly large, it's possible
865 // that fScaledFallbackTextSize may end up minimizing too much. We'd rather skip
866 // that glyph than make the others pixelated, so we set a minimum size of half the
867 // maximum text size to avoid this case.
868 SkScalar glyphTextSize = SkTMax(SkScalarFloorToScalar(fMaxTextSize*fTextSize / maxDim),
869 0.5f*fMaxTextSize);
Jim Van Verthc401bb92018-02-15 14:05:24 -0500870 fScaledFallbackTextSize = SkTMin(glyphTextSize, fScaledFallbackTextSize);
871 }
872 *fFallbackPos.append() = glyphPos;
873}
874
875void GrAtlasTextContext::FallbackTextHelper::drawText(GrAtlasTextBlob* blob, int runIndex,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500876 GrGlyphCache* glyphCache,
Jim Van Verthc401bb92018-02-15 14:05:24 -0500877 const SkSurfaceProps& props,
878 const GrTextUtils::Paint& paint,
879 SkScalerContextFlags scalerContextFlags) {
880 if (fFallbackTxt.count()) {
881 blob->initOverride(runIndex);
882 blob->setHasBitmap();
883 SkGlyphCache* cache = nullptr;
884 const SkPaint& skPaint = paint.skPaint();
885 SkPaint::GlyphCacheProc glyphCacheProc =
886 SkPaint::GetGlyphCacheProc(skPaint.getTextEncoding(),
887 skPaint.isDevKernText(), true);
888 SkColor textColor = paint.filteredPremulColor();
889 SkScalar textRatio = SK_Scalar1;
890 fViewMatrix.mapPoints(fFallbackPos.begin(), fFallbackPos.count());
891 if (fUseScaledFallback) {
892 // Set up paint and matrix to scale glyphs
893 SkPaint scaledPaint(skPaint);
894 scaledPaint.setTextSize(fScaledFallbackTextSize);
895 // remove maxScale from viewMatrix and move it into textRatio
896 // this keeps the base glyph size consistent regardless of matrix scale
897 SkMatrix modMatrix(fViewMatrix);
898 SkScalar invScale = SkScalarInvert(fMaxScale);
899 modMatrix.preScale(invScale, invScale);
900 textRatio = fTextSize * fMaxScale / fScaledFallbackTextSize;
901 cache = blob->setupCache(runIndex, props, scalerContextFlags, scaledPaint,
902 &modMatrix);
903 } else {
904 cache = blob->setupCache(runIndex, props, scalerContextFlags, paint,
905 &fViewMatrix);
906 }
907
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500908 sk_sp<GrTextStrike> currStrike;
Jim Van Verthc401bb92018-02-15 14:05:24 -0500909 const char* text = fFallbackTxt.begin();
910 const char* stop = text + fFallbackTxt.count();
911 SkPoint* glyphPos = fFallbackPos.begin();
912 while (text < stop) {
913 const SkGlyph& glyph = glyphCacheProc(cache, &text);
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500914 GrAtlasTextContext::BmpAppendGlyph(blob, runIndex, glyphCache, &currStrike, glyph,
Jim Van Verthc401bb92018-02-15 14:05:24 -0500915 glyphPos->fX, glyphPos->fY, textColor,
916 cache, textRatio);
917 glyphPos++;
918 }
919
920 SkGlyphCache::AttachCache(cache);
921 }
922}
923
924///////////////////////////////////////////////////////////////////////////////////////////////////
925
Hal Canary6f6961e2017-01-31 13:50:44 -0500926#if GR_TEST_UTILS
joshualitt79dfb2b2015-05-11 08:58:08 -0700927
Brian Salomonf18b1d82017-10-27 11:30:49 -0400928#include "GrRenderTargetContext.h"
929
Brian Salomon44acb5b2017-07-18 19:59:24 -0400930GR_DRAW_OP_TEST_DEFINE(GrAtlasTextOp) {
joshualitt79dfb2b2015-05-11 08:58:08 -0700931 static uint32_t gContextID = SK_InvalidGenID;
Brian Salomonaf597482017-11-07 16:23:34 -0500932 static std::unique_ptr<GrAtlasTextContext> gTextContext;
robertphillipsfcf78292015-06-19 11:49:52 -0700933 static SkSurfaceProps gSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType);
joshualitt79dfb2b2015-05-11 08:58:08 -0700934
935 if (context->uniqueID() != gContextID) {
936 gContextID = context->uniqueID();
Brian Salomonaf597482017-11-07 16:23:34 -0500937 gTextContext = GrAtlasTextContext::Make(GrAtlasTextContext::Options());
joshualitt79dfb2b2015-05-11 08:58:08 -0700938 }
939
Brian Osman11052242016-10-27 14:47:55 -0400940 // Setup dummy SkPaint / GrPaint / GrRenderTargetContext
Brian Osmanec8f8b02017-05-11 10:57:37 -0400941 sk_sp<GrRenderTargetContext> rtc(context->makeDeferredRenderTargetContext(
Brian Osman11052242016-10-27 14:47:55 -0400942 SkBackingFit::kApprox, 1024, 1024, kRGBA_8888_GrPixelConfig, nullptr));
brianosman8fe485b2016-07-25 12:31:51 -0700943
joshualitt6c891102015-05-13 08:51:49 -0700944 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
Brian Salomon44acb5b2017-07-18 19:59:24 -0400945
946 // Because we the GrTextUtils::Paint requires an SkPaint for font info, we ignore the GrPaint
947 // param.
joshualitt79dfb2b2015-05-11 08:58:08 -0700948 SkPaint skPaint;
Brian Salomon6f1d36c2017-01-13 12:02:17 -0500949 skPaint.setColor(random->nextU());
joshualitt79dfb2b2015-05-11 08:58:08 -0700950 skPaint.setLCDRenderText(random->nextBool());
951 skPaint.setAntiAlias(skPaint.isLCDRenderText() ? true : random->nextBool());
952 skPaint.setSubpixelText(random->nextBool());
Brian Salomon4cbb6e62017-10-25 15:12:19 -0400953 GrTextUtils::Paint utilsPaint(&skPaint, &rtc->colorSpaceInfo());
joshualitt79dfb2b2015-05-11 08:58:08 -0700954
joshualitt79dfb2b2015-05-11 08:58:08 -0700955 const char* text = "The quick brown fox jumps over the lazy dog.";
956 int textLen = (int)strlen(text);
957
joshualittb8d86492016-02-24 09:23:03 -0800958 // create some random x/y offsets, including negative offsets
959 static const int kMaxTrans = 1024;
960 int xPos = (random->nextU() % 2) * 2 - 1;
961 int yPos = (random->nextU() % 2) * 2 - 1;
962 int xInt = (random->nextU() % kMaxTrans) * xPos;
963 int yInt = (random->nextU() % kMaxTrans) * yPos;
964 SkScalar x = SkIntToScalar(xInt);
965 SkScalar y = SkIntToScalar(yInt);
halcanary9d524f22016-03-29 09:03:52 -0700966
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500967 auto glyphCache = context->contextPriv().getGlyphCache();
968 auto restrictedAtlasManager = context->contextPriv().getRestrictedAtlasManager();
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500969
Brian Salomon09d994e2016-12-21 11:14:46 -0500970 // right now we don't handle textblobs, nor do we handle drawPosText. Since we only intend to
971 // test the text op with this unit test, that is okay.
Brian Salomonaf597482017-11-07 16:23:34 -0500972 sk_sp<GrAtlasTextBlob> blob(gTextContext->makeDrawTextBlob(
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500973 context->contextPriv().getTextBlobCache(), glyphCache,
Brian Salomon44acb5b2017-07-18 19:59:24 -0400974 *context->caps()->shaderCaps(), utilsPaint,
Brian Salomon5ec9def2016-12-20 15:34:05 -0500975 GrAtlasTextContext::kTextBlobOpScalerContextFlags, viewMatrix, gSurfaceProps, text,
976 static_cast<size_t>(textLen), x, y));
joshualitt79dfb2b2015-05-11 08:58:08 -0700977
Brian Salomon44acb5b2017-07-18 19:59:24 -0400978 return blob->test_makeOp(textLen, 0, 0, viewMatrix, x, y, utilsPaint, gSurfaceProps,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500979 gTextContext->dfAdjustTable(), restrictedAtlasManager,
Brian Salomonf18b1d82017-10-27 11:30:49 -0400980 rtc->textTarget());
joshualitt79dfb2b2015-05-11 08:58:08 -0700981}
982
983#endif