blob: aadc2dc0c18c66d86dc02c23a08339678b93e8d1 [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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 }
Brian Salomon52db9402017-11-07 14:58:55 -0500387 GrAtlasTextStrike* currStrike = nullptr;
Brian Salomon52db9402017-11-07 14:58:55 -0500388 SkGlyphCache* cache = blob->setupCache(runIndex, props, scalerContextFlags, paint, &viewMatrix);
389 SkFindAndPlaceGlyph::ProcessText(paint.skPaint().getTextEncoding(), text, byteLength, {x, y},
390 viewMatrix, paint.skPaint().getTextAlign(), cache,
391 [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
392 position += rounding;
Robert Phillipsacf17902018-02-27 16:43:18 -0500393 BmpAppendGlyph(blob, runIndex, glyphCache, &currStrike,
Jim Van Verthc65b65d2018-01-16 16:26:35 -0500394 glyph, SkScalarFloorToScalar(position.fX),
395 SkScalarFloorToScalar(position.fY),
Jim Van Verthf4c13162018-01-11 16:40:24 -0500396 paint.filteredPremulColor(), cache,
397 SK_Scalar1);
Brian Salomon52db9402017-11-07 14:58:55 -0500398 });
399
400 SkGlyphCache::AttachCache(cache);
401}
402
403void GrAtlasTextContext::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex,
Robert Phillipsacf17902018-02-27 16:43:18 -0500404 GrGlyphCache* glyphCache, const SkSurfaceProps& props,
Brian Salomon52db9402017-11-07 14:58:55 -0500405 const GrTextUtils::Paint& paint,
Herb Derbyd8327a82018-01-22 14:39:27 -0500406 SkScalerContextFlags scalerContextFlags,
407 const SkMatrix& viewMatrix,
Brian Salomon52db9402017-11-07 14:58:55 -0500408 const char text[], size_t byteLength, const SkScalar pos[],
Jim Van Verthc401bb92018-02-15 14:05:24 -0500409 int scalarsPerPosition, const SkPoint& offset) {
Brian Salomon52db9402017-11-07 14:58:55 -0500410 SkASSERT(byteLength == 0 || text != nullptr);
411 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
412
413 // nothing to draw
414 if (text == nullptr || byteLength == 0) {
415 return;
416 }
417
418 // Ensure the blob is set for bitmaptext
419 blob->setHasBitmap();
420
Jim Van Verth54d9c882018-02-08 16:14:48 -0500421 if (SkDraw::ShouldDrawTextAsPaths(paint, viewMatrix)) {
Robert Phillipsacf17902018-02-27 16:43:18 -0500422 DrawBmpPosTextAsPaths(blob, runIndex, glyphCache, props, paint, scalerContextFlags,
Jim Van Verthc401bb92018-02-15 14:05:24 -0500423 viewMatrix, text, byteLength, pos, scalarsPerPosition, offset);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500424 return;
425 }
426
Brian Salomon52db9402017-11-07 14:58:55 -0500427 GrAtlasTextStrike* currStrike = nullptr;
428
429 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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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);
462 FallbackTextHelper fallbackTextHelper(viewMatrix, pathPaint.getTextSize(),
Robert Phillipsacf17902018-02-27 16:43:18 -0500463 glyphCache->getGlyphSizeLimit(),
Jim Van Verthc401bb92018-02-15 14:05:24 -0500464 iter.getPathScale());
465
466 const SkGlyph* iterGlyph;
Jim Van Verth54d9c882018-02-08 16:14:48 -0500467 const SkPath* iterPath;
468 SkScalar xpos = 0;
Jim Van Verthc401bb92018-02-15 14:05:24 -0500469 const char* lastText = text;
470 while (iter.next(&iterGlyph, &iterPath, &xpos)) {
471 if (iterGlyph) {
472 SkPoint pos = SkPoint::Make(xpos + x, y);
473 fallbackTextHelper.appendText(*iterGlyph, iter.getText() - lastText, lastText, pos);
474 } else if (iterPath) {
Jim Van Verth54d9c882018-02-08 16:14:48 -0500475 blob->appendPathGlyph(runIndex, *iterPath, xpos + x, y, iter.getPathScale(), false);
476 }
Jim Van Verthc401bb92018-02-15 14:05:24 -0500477 lastText = iter.getText();
Jim Van Verth54d9c882018-02-08 16:14:48 -0500478 }
Jim Van Verthc401bb92018-02-15 14:05:24 -0500479
Robert Phillipsacf17902018-02-27 16:43:18 -0500480 fallbackTextHelper.drawText(blob, runIndex, glyphCache, props, origPaint, scalerContextFlags);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500481}
482
483void GrAtlasTextContext::DrawBmpPosTextAsPaths(GrAtlasTextBlob* blob, int runIndex,
Robert Phillipsacf17902018-02-27 16:43:18 -0500484 GrGlyphCache* glyphCache,
Jim Van Verth54d9c882018-02-08 16:14:48 -0500485 const SkSurfaceProps& props,
486 const GrTextUtils::Paint& origPaint,
Jim Van Verthc401bb92018-02-15 14:05:24 -0500487 SkScalerContextFlags scalerContextFlags,
488 const SkMatrix& viewMatrix,
Jim Van Verth54d9c882018-02-08 16:14:48 -0500489 const char text[], size_t byteLength,
490 const SkScalar pos[], int scalarsPerPosition,
Jim Van Verthc401bb92018-02-15 14:05:24 -0500491 const SkPoint& offset) {
Jim Van Verth54d9c882018-02-08 16:14:48 -0500492 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
493
494 // nothing to draw
495 if (text == nullptr || byteLength == 0) {
496 return;
497 }
498
499 // setup our std paint, in hopes of getting hits in the cache
Jim Van Verthc401bb92018-02-15 14:05:24 -0500500 SkPaint pathPaint(origPaint);
501 SkScalar matrixScale = pathPaint.setupForAsPaths();
502 FallbackTextHelper fallbackTextHelper(viewMatrix, pathPaint.getTextSize(), matrixScale,
Robert Phillipsacf17902018-02-27 16:43:18 -0500503 glyphCache->getGlyphSizeLimit());
Jim Van Verth54d9c882018-02-08 16:14:48 -0500504
505 // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
Jim Van Verthc401bb92018-02-15 14:05:24 -0500506 pathPaint.setStyle(SkPaint::kFill_Style);
507 pathPaint.setPathEffect(nullptr);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500508
Jim Van Verthc401bb92018-02-15 14:05:24 -0500509 SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(pathPaint.getTextEncoding(),
510 pathPaint.isDevKernText(),
511 true);
512 SkAutoGlyphCache autoCache(pathPaint, &props, nullptr);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500513 SkGlyphCache* cache = autoCache.getCache();
514
515 const char* stop = text + byteLength;
Jim Van Verthc401bb92018-02-15 14:05:24 -0500516 const char* lastText = text;
517 SkTextAlignProc alignProc(pathPaint.getTextAlign());
Jim Van Verth54d9c882018-02-08 16:14:48 -0500518 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
519
520 while (text < stop) {
521 const SkGlyph& glyph = glyphCacheProc(cache, &text);
522 if (glyph.fWidth) {
Jim Van Verthc401bb92018-02-15 14:05:24 -0500523 SkPoint tmsLoc;
524 tmsProc(pos, &tmsLoc);
525 SkPoint loc;
526 alignProc(tmsLoc, glyph, &loc);
527 if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
528 fallbackTextHelper.appendText(glyph, text - lastText, lastText, loc);
529 } else {
530 const SkPath* path = cache->findPath(glyph);
531 if (path) {
532 blob->appendPathGlyph(runIndex, *path, loc.fX, loc.fY, matrixScale, false);
533 }
Jim Van Verth54d9c882018-02-08 16:14:48 -0500534 }
535 }
Jim Van Verthc401bb92018-02-15 14:05:24 -0500536 lastText = text;
Jim Van Verth54d9c882018-02-08 16:14:48 -0500537 pos += scalarsPerPosition;
538 }
Jim Van Verthc401bb92018-02-15 14:05:24 -0500539
Robert Phillipsacf17902018-02-27 16:43:18 -0500540 fallbackTextHelper.drawText(blob, runIndex, glyphCache, props, origPaint, scalerContextFlags);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500541}
542
Brian Salomon52db9402017-11-07 14:58:55 -0500543void GrAtlasTextContext::BmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex,
Robert Phillipsacf17902018-02-27 16:43:18 -0500544 GrGlyphCache* grGlyphCache, GrAtlasTextStrike** strike,
Jim Van Verthc65b65d2018-01-16 16:26:35 -0500545 const SkGlyph& skGlyph, SkScalar sx, SkScalar sy,
Robert Phillipsacf17902018-02-27 16:43:18 -0500546 GrColor color, SkGlyphCache* skGlyphCache,
Jim Van Verthc65b65d2018-01-16 16:26:35 -0500547 SkScalar textRatio) {
Brian Salomon52db9402017-11-07 14:58:55 -0500548 if (!*strike) {
Robert Phillipsacf17902018-02-27 16:43:18 -0500549 *strike = grGlyphCache->getStrike(skGlyphCache);
Brian Salomon52db9402017-11-07 14:58:55 -0500550 }
551
552 GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(),
553 skGlyph.getSubXFixed(),
554 skGlyph.getSubYFixed(),
555 GrGlyph::kCoverage_MaskStyle);
Robert Phillipsacf17902018-02-27 16:43:18 -0500556 GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, skGlyphCache);
Brian Salomon52db9402017-11-07 14:58:55 -0500557 if (!glyph) {
558 return;
559 }
560
Jim Van Verthc65b65d2018-01-16 16:26:35 -0500561 SkASSERT(skGlyph.fWidth == glyph->width());
562 SkASSERT(skGlyph.fHeight == glyph->height());
563
Jim Van Verthf4c13162018-01-11 16:40:24 -0500564 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft);
565 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop);
566 SkScalar width = SkIntToScalar(glyph->fBounds.width());
567 SkScalar height = SkIntToScalar(glyph->fBounds.height());
Brian Salomon52db9402017-11-07 14:58:55 -0500568
Jim Van Verthf4c13162018-01-11 16:40:24 -0500569 dx *= textRatio;
570 dy *= textRatio;
571 width *= textRatio;
572 height *= textRatio;
Brian Salomon52db9402017-11-07 14:58:55 -0500573
Jim Van Verthf4c13162018-01-11 16:40:24 -0500574 SkRect glyphRect = SkRect::MakeXYWH(sx + dx, sy + dy, width, height);
Brian Salomon52db9402017-11-07 14:58:55 -0500575
Robert Phillipsacf17902018-02-27 16:43:18 -0500576 blob->appendGlyph(runIndex, glyphRect, color, *strike, glyph, skGlyphCache, skGlyph, sx, sy,
Jim Van Verthf4c13162018-01-11 16:40:24 -0500577 textRatio, true);
Brian Salomon52db9402017-11-07 14:58:55 -0500578}
579
Brian Salomonaf597482017-11-07 16:23:34 -0500580bool GrAtlasTextContext::canDrawAsDistanceFields(const SkPaint& skPaint, const SkMatrix& viewMatrix,
Brian Salomon52db9402017-11-07 14:58:55 -0500581 const SkSurfaceProps& props,
Brian Salomonaf597482017-11-07 16:23:34 -0500582 const GrShaderCaps& caps) const {
Brian Salomon52db9402017-11-07 14:58:55 -0500583 if (!viewMatrix.hasPerspective()) {
584 SkScalar maxScale = viewMatrix.getMaxScale();
585 SkScalar scaledTextSize = maxScale * skPaint.getTextSize();
586 // Hinted text looks far better at small resolutions
587 // Scaling up beyond 2x yields undesireable artifacts
Brian Salomonaf597482017-11-07 16:23:34 -0500588 if (scaledTextSize < fMinDistanceFieldFontSize ||
589 scaledTextSize > fMaxDistanceFieldFontSize) {
Brian Salomon52db9402017-11-07 14:58:55 -0500590 return false;
591 }
592
593 bool useDFT = props.isUseDeviceIndependentFonts();
594#if SK_FORCE_DISTANCE_FIELD_TEXT
595 useDFT = true;
596#endif
597
598 if (!useDFT && scaledTextSize < kLargeDFFontSize) {
599 return false;
600 }
601 }
602
Mike Reed8ad91a92018-01-19 19:09:32 -0500603 // mask filters modify alpha, which doesn't translate well to distance
604 if (skPaint.getMaskFilter() || !caps.shaderDerivativeSupport()) {
Brian Salomon52db9402017-11-07 14:58:55 -0500605 return false;
606 }
607
608 // TODO: add some stroking support
609 if (skPaint.getStyle() != SkPaint::kFill_Style) {
610 return false;
611 }
612
613 return true;
614}
615
Brian Salomonaf597482017-11-07 16:23:34 -0500616void GrAtlasTextContext::initDistanceFieldPaint(GrAtlasTextBlob* blob,
Brian Salomon52db9402017-11-07 14:58:55 -0500617 SkPaint* skPaint,
618 SkScalar* textRatio,
Brian Salomonaf597482017-11-07 16:23:34 -0500619 const SkMatrix& viewMatrix) const {
Brian Salomon52db9402017-11-07 14:58:55 -0500620 SkScalar textSize = skPaint->getTextSize();
621 SkScalar scaledTextSize = textSize;
622
623 if (viewMatrix.hasPerspective()) {
624 // for perspective, we simply force to the medium size
625 // TODO: compute a size based on approximate screen area
626 scaledTextSize = kMediumDFFontLimit;
627 } else {
628 SkScalar maxScale = viewMatrix.getMaxScale();
629 // if we have non-unity scale, we need to choose our base text size
630 // based on the SkPaint's text size multiplied by the max scale factor
631 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)?
632 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) {
633 scaledTextSize *= maxScale;
634 }
635 }
636
637 // We have three sizes of distance field text, and within each size 'bucket' there is a floor
638 // and ceiling. A scale outside of this range would require regenerating the distance fields
639 SkScalar dfMaskScaleFloor;
640 SkScalar dfMaskScaleCeil;
641 if (scaledTextSize <= kSmallDFFontLimit) {
Brian Salomonaf597482017-11-07 16:23:34 -0500642 dfMaskScaleFloor = fMinDistanceFieldFontSize;
Brian Salomon52db9402017-11-07 14:58:55 -0500643 dfMaskScaleCeil = kSmallDFFontLimit;
644 *textRatio = textSize / kSmallDFFontSize;
645 skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize));
646 } else if (scaledTextSize <= kMediumDFFontLimit) {
647 dfMaskScaleFloor = kSmallDFFontLimit;
648 dfMaskScaleCeil = kMediumDFFontLimit;
649 *textRatio = textSize / kMediumDFFontSize;
650 skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize));
651 } else {
652 dfMaskScaleFloor = kMediumDFFontLimit;
Brian Salomonaf597482017-11-07 16:23:34 -0500653 dfMaskScaleCeil = fMaxDistanceFieldFontSize;
Brian Salomon52db9402017-11-07 14:58:55 -0500654 *textRatio = textSize / kLargeDFFontSize;
655 skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize));
656 }
657
658 // Because there can be multiple runs in the blob, we want the overall maxMinScale, and
659 // minMaxScale to make regeneration decisions. Specifically, we want the maximum minimum scale
660 // we can tolerate before we'd drop to a lower mip size, and the minimum maximum scale we can
661 // tolerate before we'd have to move to a large mip size. When we actually test these values
662 // we look at the delta in scale between the new viewmatrix and the old viewmatrix, and test
663 // against these values to decide if we can reuse or not(ie, will a given scale change our mip
664 // level)
665 SkASSERT(dfMaskScaleFloor <= scaledTextSize && scaledTextSize <= dfMaskScaleCeil);
666 blob->setMinAndMaxScale(dfMaskScaleFloor / scaledTextSize, dfMaskScaleCeil / scaledTextSize);
667
668 skPaint->setAntiAlias(true);
669 skPaint->setLCDRenderText(false);
670 skPaint->setAutohinted(false);
671 skPaint->setHinting(SkPaint::kNormal_Hinting);
672 skPaint->setSubpixelText(true);
673}
674
Brian Salomonaf597482017-11-07 16:23:34 -0500675void GrAtlasTextContext::drawDFText(GrAtlasTextBlob* blob, int runIndex,
Robert Phillipsacf17902018-02-27 16:43:18 -0500676 GrGlyphCache* glyphCache, const SkSurfaceProps& props,
Herb Derbyd8327a82018-01-22 14:39:27 -0500677 const GrTextUtils::Paint& paint,
678 SkScalerContextFlags scalerContextFlags,
Brian Salomon52db9402017-11-07 14:58:55 -0500679 const SkMatrix& viewMatrix, const char text[],
Brian Salomonaf597482017-11-07 16:23:34 -0500680 size_t byteLength, SkScalar x, SkScalar y) const {
Brian Salomon52db9402017-11-07 14:58:55 -0500681 SkASSERT(byteLength == 0 || text != nullptr);
682
683 // nothing to draw
684 if (text == nullptr || byteLength == 0) {
685 return;
686 }
687
688 const SkPaint& skPaint = paint.skPaint();
689 SkPaint::GlyphCacheProc glyphCacheProc =
690 SkPaint::GetGlyphCacheProc(skPaint.getTextEncoding(), skPaint.isDevKernText(), true);
691 SkAutoDescriptor desc;
692 SkScalerContextEffects effects;
693 // We apply the fake-gamma by altering the distance in the shader, so we ignore the
694 // passed-in scaler context flags. (It's only used when we fall-back to bitmap text).
Herb Derby980a48d2018-01-23 13:39:21 -0500695 SkScalerContext::CreateDescriptorAndEffectsUsingPaint(
696 skPaint, &props, SkScalerContextFlags::kNone, nullptr, &desc, &effects);
Brian Salomon52db9402017-11-07 14:58:55 -0500697 SkGlyphCache* origPaintCache =
698 SkGlyphCache::DetachCache(skPaint.getTypeface(), effects, desc.getDesc());
699
700 SkTArray<SkScalar> positions;
701
702 const char* textPtr = text;
703 SkScalar stopX = 0;
704 SkScalar stopY = 0;
705 SkScalar origin = 0;
706 switch (skPaint.getTextAlign()) {
707 case SkPaint::kRight_Align: origin = SK_Scalar1; break;
708 case SkPaint::kCenter_Align: origin = SK_ScalarHalf; break;
709 case SkPaint::kLeft_Align: origin = 0; break;
710 }
711
712 SkAutoKern autokern;
713 const char* stop = text + byteLength;
714 while (textPtr < stop) {
715 // don't need x, y here, since all subpixel variants will have the
716 // same advance
717 const SkGlyph& glyph = glyphCacheProc(origPaintCache, &textPtr);
718
719 SkScalar width = SkFloatToScalar(glyph.fAdvanceX) + autokern.adjust(glyph);
720 positions.push_back(stopX + origin * width);
721
722 SkScalar height = SkFloatToScalar(glyph.fAdvanceY);
723 positions.push_back(stopY + origin * height);
724
725 stopX += width;
726 stopY += height;
727 }
728 SkASSERT(textPtr == stop);
729
730 SkGlyphCache::AttachCache(origPaintCache);
731
732 // now adjust starting point depending on alignment
733 SkScalar alignX = stopX;
734 SkScalar alignY = stopY;
735 if (skPaint.getTextAlign() == SkPaint::kCenter_Align) {
736 alignX = SkScalarHalf(alignX);
737 alignY = SkScalarHalf(alignY);
738 } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) {
739 alignX = 0;
740 alignY = 0;
741 }
742 x -= alignX;
743 y -= alignY;
744 SkPoint offset = SkPoint::Make(x, y);
745
Robert Phillipsacf17902018-02-27 16:43:18 -0500746 this->drawDFPosText(blob, runIndex, glyphCache, props, paint, scalerContextFlags, viewMatrix,
Brian Salomonaf597482017-11-07 16:23:34 -0500747 text, byteLength, positions.begin(), 2, offset);
Brian Salomon52db9402017-11-07 14:58:55 -0500748}
749
Brian Salomonaf597482017-11-07 16:23:34 -0500750void GrAtlasTextContext::drawDFPosText(GrAtlasTextBlob* blob, int runIndex,
Robert Phillipsacf17902018-02-27 16:43:18 -0500751 GrGlyphCache* glyphCache, const SkSurfaceProps& props,
Herb Derbyd8327a82018-01-22 14:39:27 -0500752 const GrTextUtils::Paint& paint,
753 SkScalerContextFlags scalerContextFlags,
Brian Salomon52db9402017-11-07 14:58:55 -0500754 const SkMatrix& viewMatrix, const char text[],
755 size_t byteLength, const SkScalar pos[],
Brian Salomonaf597482017-11-07 16:23:34 -0500756 int scalarsPerPosition, const SkPoint& offset) const {
Brian Salomon52db9402017-11-07 14:58:55 -0500757 SkASSERT(byteLength == 0 || text != nullptr);
758 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
759
760 // nothing to draw
761 if (text == nullptr || byteLength == 0) {
762 return;
763 }
764
Brian Salomonb5086962017-12-13 10:59:33 -0500765 bool hasWCoord = viewMatrix.hasPerspective() || fDistanceFieldVerticesAlwaysHaveW;
766
Brian Salomon52db9402017-11-07 14:58:55 -0500767 // Setup distance field paint and text ratio
768 SkScalar textRatio;
769 SkPaint dfPaint(paint);
Brian Salomonaf597482017-11-07 16:23:34 -0500770 this->initDistanceFieldPaint(blob, &dfPaint, &textRatio, viewMatrix);
Brian Salomon52db9402017-11-07 14:58:55 -0500771 blob->setHasDistanceField();
772 blob->setSubRunHasDistanceFields(runIndex, paint.skPaint().isLCDRenderText(),
Brian Salomon5c6ac642017-12-19 11:09:32 -0500773 paint.skPaint().isAntiAlias(), hasWCoord);
Brian Salomon52db9402017-11-07 14:58:55 -0500774
Jim Van Verthc401bb92018-02-15 14:05:24 -0500775 FallbackTextHelper fallbackTextHelper(viewMatrix,
776 paint.skPaint().getTextSize(),
Robert Phillipsacf17902018-02-27 16:43:18 -0500777 glyphCache->getGlyphSizeLimit(),
Jim Van Verthc401bb92018-02-15 14:05:24 -0500778 textRatio);
779
Brian Salomon52db9402017-11-07 14:58:55 -0500780 GrAtlasTextStrike* currStrike = nullptr;
781
782 // We apply the fake-gamma by altering the distance in the shader, so we ignore the
783 // passed-in scaler context flags. (It's only used when we fall-back to bitmap text).
784 SkGlyphCache* cache =
Herb Derbyd8327a82018-01-22 14:39:27 -0500785 blob->setupCache(runIndex, props, SkScalerContextFlags::kNone, dfPaint, nullptr);
Brian Salomon52db9402017-11-07 14:58:55 -0500786 SkPaint::GlyphCacheProc glyphCacheProc =
787 SkPaint::GetGlyphCacheProc(dfPaint.getTextEncoding(), dfPaint.isDevKernText(), true);
788
789 const char* stop = text + byteLength;
790
Jim Van Verthf4c13162018-01-11 16:40:24 -0500791 SkPaint::Align align = dfPaint.getTextAlign();
792 SkScalar alignMul = SkPaint::kCenter_Align == align ? SK_ScalarHalf :
793 (SkPaint::kRight_Align == align ? SK_Scalar1 : 0);
794 while (text < stop) {
795 const char* lastText = text;
796 // the last 2 parameters are ignored
797 const SkGlyph& glyph = glyphCacheProc(cache, &text);
Brian Salomon52db9402017-11-07 14:58:55 -0500798
Jim Van Verthf4c13162018-01-11 16:40:24 -0500799 if (glyph.fWidth) {
Jim Van Verthc401bb92018-02-15 14:05:24 -0500800 SkPoint glyphPos(offset);
801 glyphPos.fX += pos[0] - SkFloatToScalar(glyph.fAdvanceX) * alignMul * textRatio;
802 glyphPos.fY += (2 == scalarsPerPosition ? pos[1] : 0) -
803 SkFloatToScalar(glyph.fAdvanceY) * alignMul * textRatio;
Jim Van Verthf4c13162018-01-11 16:40:24 -0500804
805 if (glyph.fMaskFormat != SkMask::kARGB32_Format) {
Robert Phillipsacf17902018-02-27 16:43:18 -0500806 DfAppendGlyph(blob, runIndex, glyphCache, &currStrike, glyph, glyphPos.fX,
Jim Van Verthc401bb92018-02-15 14:05:24 -0500807 glyphPos.fY, paint.filteredPremulColor(), cache, textRatio);
Jim Van Verthf4c13162018-01-11 16:40:24 -0500808 } else {
809 // can't append color glyph to SDF batch, send to fallback
Jim Van Verthc401bb92018-02-15 14:05:24 -0500810 fallbackTextHelper.appendText(glyph, SkToInt(text - lastText), lastText, glyphPos);
Brian Salomon52db9402017-11-07 14:58:55 -0500811 }
Brian Salomon52db9402017-11-07 14:58:55 -0500812 }
Jim Van Verthf4c13162018-01-11 16:40:24 -0500813 pos += scalarsPerPosition;
Brian Salomon52db9402017-11-07 14:58:55 -0500814 }
815
816 SkGlyphCache::AttachCache(cache);
Jim Van Verth54d9c882018-02-08 16:14:48 -0500817
Robert Phillipsacf17902018-02-27 16:43:18 -0500818 fallbackTextHelper.drawText(blob, runIndex, glyphCache, props, paint, scalerContextFlags);
Brian Salomon52db9402017-11-07 14:58:55 -0500819}
820
Jim Van Verthf4c13162018-01-11 16:40:24 -0500821// TODO: merge with BmpAppendGlyph
822void GrAtlasTextContext::DfAppendGlyph(GrAtlasTextBlob* blob, int runIndex,
Robert Phillipsacf17902018-02-27 16:43:18 -0500823 GrGlyphCache* grGlyphCache, GrAtlasTextStrike** strike,
Brian Salomon52db9402017-11-07 14:58:55 -0500824 const SkGlyph& skGlyph, SkScalar sx, SkScalar sy,
Robert Phillipsacf17902018-02-27 16:43:18 -0500825 GrColor color, SkGlyphCache* skGlyphCache,
Jim Van Verthf4c13162018-01-11 16:40:24 -0500826 SkScalar textRatio) {
Brian Salomon52db9402017-11-07 14:58:55 -0500827 if (!*strike) {
Robert Phillipsacf17902018-02-27 16:43:18 -0500828 *strike = grGlyphCache->getStrike(skGlyphCache);
Brian Salomon52db9402017-11-07 14:58:55 -0500829 }
830
831 GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(),
832 skGlyph.getSubXFixed(),
833 skGlyph.getSubYFixed(),
834 GrGlyph::kDistance_MaskStyle);
Robert Phillipsacf17902018-02-27 16:43:18 -0500835 GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, skGlyphCache);
Brian Salomon52db9402017-11-07 14:58:55 -0500836 if (!glyph) {
Jim Van Verthf4c13162018-01-11 16:40:24 -0500837 return;
Brian Salomon52db9402017-11-07 14:58:55 -0500838 }
839
840 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
841 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
842 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2 * SK_DistanceFieldInset);
843 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2 * SK_DistanceFieldInset);
844
Jim Van Verthf4c13162018-01-11 16:40:24 -0500845 dx *= textRatio;
846 dy *= textRatio;
847 width *= textRatio;
848 height *= textRatio;
849 SkRect glyphRect = SkRect::MakeXYWH(sx + dx, sy + dy, width, height);
Brian Salomon52db9402017-11-07 14:58:55 -0500850
Robert Phillipsacf17902018-02-27 16:43:18 -0500851 blob->appendGlyph(runIndex, glyphRect, color, *strike, glyph, skGlyphCache, skGlyph, sx, sy,
Jim Van Verthf4c13162018-01-11 16:40:24 -0500852 textRatio, false);
Brian Salomon52db9402017-11-07 14:58:55 -0500853}
854
joshualitt79dfb2b2015-05-11 08:58:08 -0700855///////////////////////////////////////////////////////////////////////////////////////////////////
856
Jim Van Verthc401bb92018-02-15 14:05:24 -0500857void GrAtlasTextContext::FallbackTextHelper::appendText(const SkGlyph& glyph, int count,
858 const char* text, SkPoint glyphPos) {
859 SkScalar maxDim = SkTMax(glyph.fWidth, glyph.fHeight)*fTextRatio;
860 if (!fUseScaledFallback) {
861 SkScalar scaledGlyphSize = maxDim * fMaxScale;
862 if (!fViewMatrix.hasPerspective() && scaledGlyphSize > fMaxTextSize) {
863 fUseScaledFallback = true;
864 }
865 }
866
867 fFallbackTxt.append(count, text);
868 if (fUseScaledFallback) {
869 SkScalar glyphTextSize = SkScalarFloorToScalar(fMaxTextSize*fTextSize / maxDim);
870 fScaledFallbackTextSize = SkTMin(glyphTextSize, fScaledFallbackTextSize);
871 }
872 *fFallbackPos.append() = glyphPos;
873}
874
875void GrAtlasTextContext::FallbackTextHelper::drawText(GrAtlasTextBlob* blob, int runIndex,
Robert Phillipsacf17902018-02-27 16:43:18 -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
908 GrAtlasTextStrike* currStrike = nullptr;
909 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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -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 Phillipsacf17902018-02-27 16:43:18 -0500979 gTextContext->dfAdjustTable(), restrictedAtlasManager,
Brian Salomonf18b1d82017-10-27 11:30:49 -0400980 rtc->textTarget());
joshualitt79dfb2b2015-05-11 08:58:08 -0700981}
982
983#endif