Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: src/gpu/text/GrTextUtils.cpp

Issue 1521633002: Move distance field text positioning into GrTextUtils (Closed) Base URL: https://skia.googlesource.com/skia.git@cleanuptext15
Patch Set: tweaks Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/gpu/text/GrTextUtils.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "GrTextUtils.h" 8 #include "GrTextUtils.h"
9 9
10 #include "GrAtlasTextBlob.h" 10 #include "GrAtlasTextBlob.h"
11 #include "GrBatchFontCache.h" 11 #include "GrBatchFontCache.h"
12 #include "GrBlurUtils.h" 12 #include "GrBlurUtils.h"
13 #include "GrCaps.h"
13 #include "GrContext.h" 14 #include "GrContext.h"
14 #include "GrDrawContext.h" 15 #include "GrDrawContext.h"
15 #include "GrTextContext.h" 16 #include "GrTextContext.h"
17
18 #include "SkDistanceFieldGen.h"
16 #include "SkDrawProcs.h" 19 #include "SkDrawProcs.h"
17 #include "SkFindAndPlaceGlyph.h" 20 #include "SkFindAndPlaceGlyph.h"
18 #include "SkGlyphCache.h" 21 #include "SkGlyphCache.h"
19 #include "SkPaint.h" 22 #include "SkPaint.h"
20 #include "SkRect.h" 23 #include "SkRect.h"
21 #include "SkTextMapStateProc.h" 24 #include "SkTextMapStateProc.h"
22 #include "SkTextToPathIter.h" 25 #include "SkTextToPathIter.h"
23 26
27 namespace {
28 static const int kMinDFFontSize = 18;
29 static const int kSmallDFFontSize = 32;
30 static const int kSmallDFFontLimit = 32;
31 static const int kMediumDFFontSize = 72;
32 static const int kMediumDFFontLimit = 72;
33 static const int kLargeDFFontSize = 162;
34 #ifdef SK_BUILD_FOR_ANDROID
35 static const int kLargeDFFontLimit = 384;
36 #else
37 static const int kLargeDFFontLimit = 2 * kLargeDFFontSize;
38 #endif
39 };
40
24 void GrTextUtils::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, 41 void GrTextUtils::DrawBmpText(GrAtlasTextBlob* blob, int runIndex,
25 GrBatchFontCache* fontCache, 42 GrBatchFontCache* fontCache,
26 const SkSurfaceProps& props, const SkPaint& skPain t, 43 const SkSurfaceProps& props, const SkPaint& skPain t,
27 GrColor color, 44 GrColor color,
28 const SkMatrix& viewMatrix, 45 const SkMatrix& viewMatrix,
29 const char text[], size_t byteLength, 46 const char text[], size_t byteLength,
30 SkScalar x, SkScalar y) { 47 SkScalar x, SkScalar y) {
31 SkASSERT(byteLength == 0 || text != nullptr); 48 SkASSERT(byteLength == 0 || text != nullptr);
32 49
33 // nothing to draw 50 // nothing to draw
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 SkRect r; 145 SkRect r;
129 r.fLeft = SkIntToScalar(x); 146 r.fLeft = SkIntToScalar(x);
130 r.fTop = SkIntToScalar(y); 147 r.fTop = SkIntToScalar(y);
131 r.fRight = r.fLeft + SkIntToScalar(width); 148 r.fRight = r.fLeft + SkIntToScalar(width);
132 r.fBottom = r.fTop + SkIntToScalar(height); 149 r.fBottom = r.fTop + SkIntToScalar(height);
133 150
134 blob->appendGlyph(runIndex, r, color, *strike, glyph, scaler, skGlyph, 151 blob->appendGlyph(runIndex, r, color, *strike, glyph, scaler, skGlyph,
135 SkIntToScalar(vx), SkIntToScalar(vy), 1.0f, false); 152 SkIntToScalar(vx), SkIntToScalar(vy), 1.0f, false);
136 } 153 }
137 154
155 bool GrTextUtils::CanDrawAsDistanceFields(const SkPaint& skPaint, const SkMatrix & viewMatrix,
156 const SkSurfaceProps& props, const GrS haderCaps& caps) {
157 // TODO: support perspective (need getMaxScale replacement)
158 if (viewMatrix.hasPerspective()) {
159 return false;
160 }
161
162 SkScalar maxScale = viewMatrix.getMaxScale();
163 SkScalar scaledTextSize = maxScale*skPaint.getTextSize();
164 // Hinted text looks far better at small resolutions
165 // Scaling up beyond 2x yields undesireable artifacts
166 if (scaledTextSize < kMinDFFontSize ||
167 scaledTextSize > kLargeDFFontLimit) {
168 return false;
169 }
170
171 bool useDFT = props.isUseDeviceIndependentFonts();
172 #if SK_FORCE_DISTANCE_FIELD_TEXT
173 useDFT = true;
174 #endif
175
176 if (!useDFT && scaledTextSize < kLargeDFFontSize) {
177 return false;
178 }
179
180 // rasterizers and mask filters modify alpha, which doesn't
181 // translate well to distance
182 if (skPaint.getRasterizer() || skPaint.getMaskFilter() || !caps.shaderDeriva tiveSupport()) {
183 return false;
184 }
185
186 // TODO: add some stroking support
187 if (skPaint.getStyle() != SkPaint::kFill_Style) {
188 return false;
189 }
190
191 return true;
192 }
193
194 void GrTextUtils::InitDistanceFieldPaint(GrAtlasTextBlob* blob,
195 SkPaint* skPaint,
196 SkScalar* textRatio,
197 const SkMatrix& viewMatrix) {
198 // getMaxScale doesn't support perspective, so neither do we at the moment
199 SkASSERT(!viewMatrix.hasPerspective());
200 SkScalar maxScale = viewMatrix.getMaxScale();
201 SkScalar textSize = skPaint->getTextSize();
202 SkScalar scaledTextSize = textSize;
203 // if we have non-unity scale, we need to choose our base text size
204 // based on the SkPaint's text size multiplied by the max scale factor
205 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)?
206 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) {
207 scaledTextSize *= maxScale;
208 }
209
210 // We have three sizes of distance field text, and within each size 'bucket' there is a floor
211 // and ceiling. A scale outside of this range would require regenerating th e distance fields
212 SkScalar dfMaskScaleFloor;
213 SkScalar dfMaskScaleCeil;
214 if (scaledTextSize <= kSmallDFFontLimit) {
215 dfMaskScaleFloor = kMinDFFontSize;
216 dfMaskScaleCeil = kSmallDFFontLimit;
217 *textRatio = textSize / kSmallDFFontSize;
218 skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize));
219 } else if (scaledTextSize <= kMediumDFFontLimit) {
220 dfMaskScaleFloor = kSmallDFFontLimit;
221 dfMaskScaleCeil = kMediumDFFontLimit;
222 *textRatio = textSize / kMediumDFFontSize;
223 skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize));
224 } else {
225 dfMaskScaleFloor = kMediumDFFontLimit;
226 dfMaskScaleCeil = kLargeDFFontLimit;
227 *textRatio = textSize / kLargeDFFontSize;
228 skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize));
229 }
230
231 // Because there can be multiple runs in the blob, we want the overall maxMi nScale, and
232 // minMaxScale to make regeneration decisions. Specifically, we want the ma ximum minimum scale
233 // we can tolerate before we'd drop to a lower mip size, and the minimum max imum scale we can
234 // tolerate before we'd have to move to a large mip size. When we actually test these values
235 // we look at the delta in scale between the new viewmatrix and the old view matrix, and test
236 // against these values to decide if we can reuse or not(ie, will a given sc ale change our mip
237 // level)
238 SkASSERT(dfMaskScaleFloor <= scaledTextSize && scaledTextSize <= dfMaskScale Ceil);
239 blob->fMaxMinScale = SkMaxScalar(dfMaskScaleFloor / scaledTextSize, blob->fM axMinScale);
240 blob->fMinMaxScale = SkMinScalar(dfMaskScaleCeil / scaledTextSize, blob->fMi nMaxScale);
241
242 skPaint->setLCDRenderText(false);
243 skPaint->setAutohinted(false);
244 skPaint->setHinting(SkPaint::kNormal_Hinting);
245 skPaint->setSubpixelText(true);
246 }
247
248 void GrTextUtils::DrawDFText(GrAtlasTextBlob* blob, int runIndex,
249 GrBatchFontCache* fontCache, const SkSurfaceProps& props,
250 const SkPaint& skPaint, GrColor color,
251 const SkMatrix& viewMatrix,
252 const char text[], size_t byteLength,
253 SkScalar x, SkScalar y) {
254 SkASSERT(byteLength == 0 || text != nullptr);
255
256 // nothing to draw
257 if (text == nullptr || byteLength == 0) {
258 return;
259 }
260
261 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc();
262 SkAutoDescriptor desc;
263 skPaint.getScalerContextDescriptor(&desc, props, nullptr, true);
264 SkGlyphCache* origPaintCache = SkGlyphCache::DetachCache(skPaint.getTypeface (),
265 desc.getDesc());
266
267 SkTArray<SkScalar> positions;
268
269 const char* textPtr = text;
270 SkFixed stopX = 0;
271 SkFixed stopY = 0;
272 SkFixed origin = 0;
273 switch (skPaint.getTextAlign()) {
274 case SkPaint::kRight_Align: origin = SK_Fixed1; break;
275 case SkPaint::kCenter_Align: origin = SK_FixedHalf; break;
276 case SkPaint::kLeft_Align: origin = 0; break;
277 }
278
279 SkAutoKern autokern;
280 const char* stop = text + byteLength;
281 while (textPtr < stop) {
282 // don't need x, y here, since all subpixel variants will have the
283 // same advance
284 const SkGlyph& glyph = glyphCacheProc(origPaintCache, &textPtr, 0, 0);
285
286 SkFixed width = glyph.fAdvanceX + autokern.adjust(glyph);
287 positions.push_back(SkFixedToScalar(stopX + SkFixedMul(origin, width)));
288
289 SkFixed height = glyph.fAdvanceY;
290 positions.push_back(SkFixedToScalar(stopY + SkFixedMul(origin, height))) ;
291
292 stopX += width;
293 stopY += height;
294 }
295 SkASSERT(textPtr == stop);
296
297 SkGlyphCache::AttachCache(origPaintCache);
298
299 // now adjust starting point depending on alignment
300 SkScalar alignX = SkFixedToScalar(stopX);
301 SkScalar alignY = SkFixedToScalar(stopY);
302 if (skPaint.getTextAlign() == SkPaint::kCenter_Align) {
303 alignX = SkScalarHalf(alignX);
304 alignY = SkScalarHalf(alignY);
305 } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) {
306 alignX = 0;
307 alignY = 0;
308 }
309 x -= alignX;
310 y -= alignY;
311 SkPoint offset = SkPoint::Make(x, y);
312
313 DrawDFPosText(blob, runIndex, fontCache, props, skPaint, color, viewMatrix, text, byteLength,
314 positions.begin(), 2, offset);
315 }
316
317 void GrTextUtils::DrawDFPosText(GrAtlasTextBlob* blob, int runIndex,
318 GrBatchFontCache* fontCache, const SkSurfaceProp s& props,
319 const SkPaint& origPaint,
320 GrColor color, const SkMatrix& viewMatrix,
321 const char text[], size_t byteLength,
322 const SkScalar pos[], int scalarsPerPosition,
323 const SkPoint& offset) {
324 SkASSERT(byteLength == 0 || text != nullptr);
325 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
326
327 // nothing to draw
328 if (text == nullptr || byteLength == 0) {
329 return;
330 }
331
332 SkTDArray<char> fallbackTxt;
333 SkTDArray<SkScalar> fallbackPos;
334
335 // Setup distance field paint and text ratio
336 SkScalar textRatio;
337 SkPaint dfPaint(origPaint);
338 GrTextUtils::InitDistanceFieldPaint(blob, &dfPaint, &textRatio, viewMatrix);
339 blob->setHasDistanceField();
340 blob->setSubRunHasDistanceFields(runIndex, origPaint.isLCDRenderText());
341
342 GrBatchTextStrike* currStrike = nullptr;
343
344 SkGlyphCache* cache = blob->setupCache(runIndex, props, dfPaint, nullptr, tr ue);
345 SkDrawCacheProc glyphCacheProc = dfPaint.getDrawCacheProc();
346 GrFontScaler* fontScaler = GrTextContext::GetGrFontScaler(cache);
347
348 const char* stop = text + byteLength;
349
350 if (SkPaint::kLeft_Align == dfPaint.getTextAlign()) {
351 while (text < stop) {
352 const char* lastText = text;
353 // the last 2 parameters are ignored
354 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
355
356 if (glyph.fWidth) {
357 SkScalar x = offset.x() + pos[0];
358 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0) ;
359
360 if (!DfAppendGlyph(blob,
361 runIndex,
362 fontCache,
363 &currStrike,
364 glyph,
365 x, y, color, fontScaler,
366 textRatio, viewMatrix)) {
367 // couldn't append, send to fallback
368 fallbackTxt.append(SkToInt(text-lastText), lastText);
369 *fallbackPos.append() = pos[0];
370 if (2 == scalarsPerPosition) {
371 *fallbackPos.append() = pos[1];
372 }
373 }
374 }
375 pos += scalarsPerPosition;
376 }
377 } else {
378 SkScalar alignMul = SkPaint::kCenter_Align == dfPaint.getTextAlign() ? S K_ScalarHalf
379 : S K_Scalar1;
380 while (text < stop) {
381 const char* lastText = text;
382 // the last 2 parameters are ignored
383 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
384
385 if (glyph.fWidth) {
386 SkScalar x = offset.x() + pos[0];
387 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0) ;
388
389 SkScalar advanceX = SkFixedToScalar(glyph.fAdvanceX) * alignMul * textRatio;
390 SkScalar advanceY = SkFixedToScalar(glyph.fAdvanceY) * alignMul * textRatio;
391
392 if (!DfAppendGlyph(blob,
393 runIndex,
394 fontCache,
395 &currStrike,
396 glyph,
397 x - advanceX, y - advanceY, color,
398 fontScaler,
399 textRatio,
400 viewMatrix)) {
401 // couldn't append, send to fallback
402 fallbackTxt.append(SkToInt(text-lastText), lastText);
403 *fallbackPos.append() = pos[0];
404 if (2 == scalarsPerPosition) {
405 *fallbackPos.append() = pos[1];
406 }
407 }
408 }
409 pos += scalarsPerPosition;
410 }
411 }
412
413 SkGlyphCache::AttachCache(cache);
414 if (fallbackTxt.count()) {
415 blob->initOverride(runIndex);
416 GrTextUtils::DrawBmpPosText(blob, runIndex, fontCache, props,
417 origPaint, origPaint.getColor(), viewMatrix,
418 fallbackTxt.begin(), fallbackTxt.count(),
419 fallbackPos.begin(), scalarsPerPosition, off set);
420 }
421 }
422
423 bool GrTextUtils::DfAppendGlyph(GrAtlasTextBlob* blob, int runIndex, GrBatchFont Cache* cache,
424 GrBatchTextStrike** strike, const SkGlyph& skGly ph,
425 SkScalar sx, SkScalar sy, GrColor color,
426 GrFontScaler* scaler,
427 SkScalar textRatio, const SkMatrix& viewMatrix) {
428 if (!*strike) {
429 *strike = cache->getStrike(scaler);
430 }
431
432 GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(),
433 skGlyph.getSubXFixed(),
434 skGlyph.getSubYFixed(),
435 GrGlyph::kDistance_MaskStyle);
436 GrGlyph* glyph = (*strike)->getGlyph(skGlyph, id, scaler);
437 if (!glyph) {
438 return true;
439 }
440
441 // fallback to color glyph support
442 if (kA8_GrMaskFormat != glyph->fMaskFormat) {
443 return false;
444 }
445
446 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
447 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
448 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2 * SK_DistanceField Inset);
449 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2 * SK_DistanceFie ldInset);
450
451 SkScalar scale = textRatio;
452 dx *= scale;
453 dy *= scale;
454 width *= scale;
455 height *= scale;
456 sx += dx;
457 sy += dy;
458 SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height);
459
460 blob->appendGlyph(runIndex, glyphRect, color, *strike, glyph, scaler, skGlyp h,
461 sx - dx, sy - dy, scale, true);
462 return true;
463 }
464
138 void GrTextUtils::DrawTextAsPath(GrContext* context, GrDrawContext* dc, 465 void GrTextUtils::DrawTextAsPath(GrContext* context, GrDrawContext* dc,
139 const GrClip& clip, 466 const GrClip& clip,
140 const SkPaint& skPaint, const SkMatrix& viewMat rix, 467 const SkPaint& skPaint, const SkMatrix& viewMat rix,
141 const char text[], size_t byteLength, SkScalar x, SkScalar y, 468 const char text[], size_t byteLength, SkScalar x, SkScalar y,
142 const SkIRect& clipBounds) { 469 const SkIRect& clipBounds) {
143 SkTextToPathIter iter(text, byteLength, skPaint, true); 470 SkTextToPathIter iter(text, byteLength, skPaint, true);
144 471
145 SkMatrix matrix; 472 SkMatrix matrix;
146 matrix.setScale(iter.getPathScale(), iter.getPathScale()); 473 matrix.setScale(iter.getPathScale(), iter.getPathScale());
147 matrix.postTranslate(x, y); 474 matrix.postTranslate(x, y);
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 530
204 matrix[SkMatrix::kMTransX] = loc.fX; 531 matrix[SkMatrix::kMTransX] = loc.fX;
205 matrix[SkMatrix::kMTransY] = loc.fY; 532 matrix[SkMatrix::kMTransY] = loc.fY;
206 GrBlurUtils::drawPathWithMaskFilter(context, dc, clip, *path, pa int, 533 GrBlurUtils::drawPathWithMaskFilter(context, dc, clip, *path, pa int,
207 viewMatrix, &matrix, clipBou nds, false); 534 viewMatrix, &matrix, clipBou nds, false);
208 } 535 }
209 } 536 }
210 pos += scalarsPerPosition; 537 pos += scalarsPerPosition;
211 } 538 }
212 } 539 }
OLDNEW
« no previous file with comments | « src/gpu/text/GrTextUtils.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698