OLD | NEW |
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 #include "GrAtlasTextContext.h" | 7 #include "GrAtlasTextContext.h" |
8 | 8 |
9 #include "GrDrawContext.h" | 9 #include "GrDrawContext.h" |
10 #include "GrDrawTarget.h" | 10 #include "GrDrawTarget.h" |
(...skipping 16 matching lines...) Expand all Loading... |
27 #include "SkGpuDevice.h" | 27 #include "SkGpuDevice.h" |
28 #include "SkGrPriv.h" | 28 #include "SkGrPriv.h" |
29 #include "SkPath.h" | 29 #include "SkPath.h" |
30 #include "SkRTConf.h" | 30 #include "SkRTConf.h" |
31 #include "SkStrokeRec.h" | 31 #include "SkStrokeRec.h" |
32 #include "SkTextBlob.h" | 32 #include "SkTextBlob.h" |
33 #include "SkTextMapStateProc.h" | 33 #include "SkTextMapStateProc.h" |
34 | 34 |
35 #include "batches/GrAtlasTextBatch.h" | 35 #include "batches/GrAtlasTextBatch.h" |
36 | 36 |
37 namespace { | |
38 static const int kMinDFFontSize = 18; | |
39 static const int kSmallDFFontSize = 32; | |
40 static const int kSmallDFFontLimit = 32; | |
41 static const int kMediumDFFontSize = 72; | |
42 static const int kMediumDFFontLimit = 72; | |
43 static const int kLargeDFFontSize = 162; | |
44 #ifdef SK_BUILD_FOR_ANDROID | |
45 static const int kLargeDFFontLimit = 384; | |
46 #else | |
47 static const int kLargeDFFontLimit = 2 * kLargeDFFontSize; | |
48 #endif | |
49 }; | |
50 | |
51 GrAtlasTextContext::GrAtlasTextContext(GrContext* context, const SkSurfaceProps&
surfaceProps) | 37 GrAtlasTextContext::GrAtlasTextContext(GrContext* context, const SkSurfaceProps&
surfaceProps) |
52 : INHERITED(context, surfaceProps) | 38 : INHERITED(context, surfaceProps) |
53 , fDistanceAdjustTable(new GrDistanceFieldAdjustTable) { | 39 , fDistanceAdjustTable(new GrDistanceFieldAdjustTable) { |
54 // We overallocate vertices in our textblobs based on the assumption that A8
has the greatest | 40 // We overallocate vertices in our textblobs based on the assumption that A8
has the greatest |
55 // vertexStride | 41 // vertexStride |
56 static_assert(GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kColorTex
tVASize && | 42 static_assert(GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kColorTex
tVASize && |
57 GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kLCDTextV
ASize, | 43 GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kLCDTextV
ASize, |
58 "vertex_attribute_changed"); | 44 "vertex_attribute_changed"); |
59 fCurrStrike = nullptr; | 45 fCurrStrike = nullptr; |
60 fCache = context->getTextBlobCache(); | 46 fCache = context->getTextBlobCache(); |
61 } | 47 } |
62 | 48 |
63 | 49 |
64 GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context, | 50 GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context, |
65 const SkSurfaceProps& surfaceProp
s) { | 51 const SkSurfaceProps& surfaceProp
s) { |
66 return new GrAtlasTextContext(context, surfaceProps); | 52 return new GrAtlasTextContext(context, surfaceProps); |
67 } | 53 } |
68 | 54 |
69 bool GrAtlasTextContext::canDraw(const SkPaint& skPaint, const SkMatrix& viewMat
rix) { | 55 bool GrAtlasTextContext::canDraw(const SkPaint& skPaint, const SkMatrix& viewMat
rix) { |
70 return this->canDrawAsDistanceFields(skPaint, viewMatrix) || | 56 return GrTextUtils::CanDrawAsDistanceFields(skPaint, viewMatrix, fSurfacePro
ps, |
| 57 *fContext->caps()->shaderCaps())
|| |
71 !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); | 58 !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); |
72 } | 59 } |
73 | 60 |
74 GrColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd
) { | 61 GrColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd
) { |
75 GrColor canonicalColor = paint.computeLuminanceColor(); | 62 GrColor canonicalColor = paint.computeLuminanceColor(); |
76 if (lcd) { | 63 if (lcd) { |
77 // This is the correct computation, but there are tons of cases where LC
D can be overridden. | 64 // This is the correct computation, but there are tons of cases where LC
D can be overridden. |
78 // For now we just regenerate if any run in a textblob has LCD. | 65 // For now we just regenerate if any run in a textblob has LCD. |
79 // TODO figure out where all of these overrides are and see if we can in
corporate that logic | 66 // TODO figure out where all of these overrides are and see if we can in
corporate that logic |
80 // at a higher level *OR* use sRGB | 67 // at a higher level *OR* use sRGB |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 cacheBlob.reset(fCache->createBlob(blob, GrAtlasTextBlob::kGrayTextV
ASize)); | 179 cacheBlob.reset(fCache->createBlob(blob, GrAtlasTextBlob::kGrayTextV
ASize)); |
193 } | 180 } |
194 this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMat
rix, | 181 this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMat
rix, |
195 blob, x, y, drawFilter); | 182 blob, x, y, drawFilter); |
196 } | 183 } |
197 | 184 |
198 cacheBlob->flushCached(fContext, dc, blob, fSurfaceProps, fDistanceAdjustTab
le, skPaint, | 185 cacheBlob->flushCached(fContext, dc, blob, fSurfaceProps, fDistanceAdjustTab
le, skPaint, |
199 grPaint, drawFilter, clip, viewMatrix, clipBounds, x,
y, transX, transY); | 186 grPaint, drawFilter, clip, viewMatrix, clipBounds, x,
y, transX, transY); |
200 } | 187 } |
201 | 188 |
202 inline bool GrAtlasTextContext::canDrawAsDistanceFields(const SkPaint& skPaint, | |
203 const SkMatrix& viewMatr
ix) { | |
204 // TODO: support perspective (need getMaxScale replacement) | |
205 if (viewMatrix.hasPerspective()) { | |
206 return false; | |
207 } | |
208 | |
209 SkScalar maxScale = viewMatrix.getMaxScale(); | |
210 SkScalar scaledTextSize = maxScale*skPaint.getTextSize(); | |
211 // Hinted text looks far better at small resolutions | |
212 // Scaling up beyond 2x yields undesireable artifacts | |
213 if (scaledTextSize < kMinDFFontSize || scaledTextSize > kLargeDFFontLimit) { | |
214 return false; | |
215 } | |
216 | |
217 bool useDFT = fSurfaceProps.isUseDeviceIndependentFonts(); | |
218 #if SK_FORCE_DISTANCE_FIELD_TEXT | |
219 useDFT = true; | |
220 #endif | |
221 | |
222 if (!useDFT && scaledTextSize < kLargeDFFontSize) { | |
223 return false; | |
224 } | |
225 | |
226 // rasterizers and mask filters modify alpha, which doesn't | |
227 // translate well to distance | |
228 if (skPaint.getRasterizer() || skPaint.getMaskFilter() || | |
229 !fContext->caps()->shaderCaps()->shaderDerivativeSupport()) { | |
230 return false; | |
231 } | |
232 | |
233 // TODO: add some stroking support | |
234 if (skPaint.getStyle() != SkPaint::kFill_Style) { | |
235 return false; | |
236 } | |
237 | |
238 return true; | |
239 } | |
240 | |
241 void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, | 189 void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, |
242 const SkPaint& skPaint, GrColor colo
r, | 190 const SkPaint& skPaint, GrColor colo
r, |
243 const SkMatrix& viewMatrix, | 191 const SkMatrix& viewMatrix, |
244 const SkTextBlob* blob, SkScalar x,
SkScalar y, | 192 const SkTextBlob* blob, SkScalar x,
SkScalar y, |
245 SkDrawFilter* drawFilter) { | 193 SkDrawFilter* drawFilter) { |
246 // The color here is the GrPaint color, and it is used to determine whether
we | 194 // The color here is the GrPaint color, and it is used to determine whether
we |
247 // have to regenerate LCD text blobs. | 195 // have to regenerate LCD text blobs. |
248 // We use this color vs the SkPaint color because it has the colorfilter app
lied. | 196 // We use this color vs the SkPaint color because it has the colorfilter app
lied. |
249 cacheBlob->fPaintColor = color; | 197 cacheBlob->fPaintColor = color; |
250 cacheBlob->fViewMatrix = viewMatrix; | 198 cacheBlob->fViewMatrix = viewMatrix; |
(...skipping 14 matching lines...) Expand all Loading... |
265 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ
e)) { | 213 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ
e)) { |
266 // A false return from filter() means we should abort the current dr
aw. | 214 // A false return from filter() means we should abort the current dr
aw. |
267 runPaint = skPaint; | 215 runPaint = skPaint; |
268 continue; | 216 continue; |
269 } | 217 } |
270 | 218 |
271 runPaint.setFlags(FilterTextFlags(fSurfaceProps, runPaint)); | 219 runPaint.setFlags(FilterTextFlags(fSurfaceProps, runPaint)); |
272 | 220 |
273 cacheBlob->push_back_run(run); | 221 cacheBlob->push_back_run(run); |
274 | 222 |
275 if (this->canDrawAsDistanceFields(runPaint, viewMatrix)) { | 223 if (GrTextUtils::CanDrawAsDistanceFields(runPaint, viewMatrix, fSurfaceP
rops, |
| 224 *fContext->caps()->shaderCaps()
)) { |
276 switch (it.positioning()) { | 225 switch (it.positioning()) { |
277 case SkTextBlob::kDefault_Positioning: { | 226 case SkTextBlob::kDefault_Positioning: { |
278 this->internalDrawDFText(cacheBlob, run, runPaint, color, vi
ewMatrix, | 227 GrTextUtils::DrawDFText(cacheBlob, run, fContext->getBatchFo
ntCache(), |
279 (const char *)it.glyphs(), textLen, | 228 fSurfaceProps, runPaint, color, view
Matrix, |
280 x + offset.x(), y + offset.y()); | 229 (const char *)it.glyphs(), textLen, |
| 230 x + offset.x(), y + offset.y()); |
281 break; | 231 break; |
282 } | 232 } |
283 case SkTextBlob::kHorizontal_Positioning: { | 233 case SkTextBlob::kHorizontal_Positioning: { |
284 SkPoint dfOffset = SkPoint::Make(x, y + offset.y()); | 234 SkPoint dfOffset = SkPoint::Make(x, y + offset.y()); |
285 this->internalDrawDFPosText(cacheBlob, run, runPaint, color,
viewMatrix, | 235 GrTextUtils::DrawDFPosText(cacheBlob, run, fContext->getBatc
hFontCache(), |
286 (const char*)it.glyphs(), textLe
n, it.pos(), | 236 fSurfaceProps, runPaint, color, v
iewMatrix, |
287 1, dfOffset); | 237 (const char*)it.glyphs(), textLen
, it.pos(), |
| 238 1, dfOffset); |
288 break; | 239 break; |
289 } | 240 } |
290 case SkTextBlob::kFull_Positioning: { | 241 case SkTextBlob::kFull_Positioning: { |
291 SkPoint dfOffset = SkPoint::Make(x, y); | 242 SkPoint dfOffset = SkPoint::Make(x, y); |
292 this->internalDrawDFPosText(cacheBlob, run, runPaint, color,
viewMatrix, | 243 GrTextUtils::DrawDFPosText(cacheBlob, run, fContext->getBat
chFontCache(), |
293 (const char*)it.glyphs(), textLe
n, it.pos(), | 244 fSurfaceProps, runPaint, color, v
iewMatrix, |
294 2, dfOffset); | 245 (const char*)it.glyphs(), textLen
, it.pos(), |
| 246 2, dfOffset); |
295 break; | 247 break; |
296 } | 248 } |
297 } | 249 } |
298 } else if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { | 250 } else if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { |
299 cacheBlob->fRuns[run].fDrawAsPaths = true; | 251 cacheBlob->fRuns[run].fDrawAsPaths = true; |
300 } else { | 252 } else { |
301 switch (it.positioning()) { | 253 switch (it.positioning()) { |
302 case SkTextBlob::kDefault_Positioning: | 254 case SkTextBlob::kDefault_Positioning: |
303 GrTextUtils::DrawBmpText(cacheBlob, run, fContext->getBatchF
ontCache(), | 255 GrTextUtils::DrawBmpText(cacheBlob, run, fContext->getBatchF
ontCache(), |
304 fSurfaceProps, runPaint, color, vie
wMatrix, | 256 fSurfaceProps, runPaint, color, vie
wMatrix, |
(...skipping 15 matching lines...) Expand all Loading... |
320 } | 272 } |
321 } | 273 } |
322 | 274 |
323 if (drawFilter) { | 275 if (drawFilter) { |
324 // A draw filter may change the paint arbitrarily, so we must re-see
d in this case. | 276 // A draw filter may change the paint arbitrarily, so we must re-see
d in this case. |
325 runPaint = skPaint; | 277 runPaint = skPaint; |
326 } | 278 } |
327 } | 279 } |
328 } | 280 } |
329 | 281 |
330 inline void GrAtlasTextContext::initDistanceFieldPaint(GrAtlasTextBlob* blob, | |
331 SkPaint* skPaint, | |
332 SkScalar* textRatio, | |
333 const SkMatrix& viewMatri
x) { | |
334 // getMaxScale doesn't support perspective, so neither do we at the moment | |
335 SkASSERT(!viewMatrix.hasPerspective()); | |
336 SkScalar maxScale = viewMatrix.getMaxScale(); | |
337 SkScalar textSize = skPaint->getTextSize(); | |
338 SkScalar scaledTextSize = textSize; | |
339 // if we have non-unity scale, we need to choose our base text size | |
340 // based on the SkPaint's text size multiplied by the max scale factor | |
341 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)? | |
342 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) { | |
343 scaledTextSize *= maxScale; | |
344 } | |
345 | |
346 // We have three sizes of distance field text, and within each size 'bucket'
there is a floor | |
347 // and ceiling. A scale outside of this range would require regenerating th
e distance fields | |
348 SkScalar dfMaskScaleFloor; | |
349 SkScalar dfMaskScaleCeil; | |
350 if (scaledTextSize <= kSmallDFFontLimit) { | |
351 dfMaskScaleFloor = kMinDFFontSize; | |
352 dfMaskScaleCeil = kSmallDFFontLimit; | |
353 *textRatio = textSize / kSmallDFFontSize; | |
354 skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize)); | |
355 } else if (scaledTextSize <= kMediumDFFontLimit) { | |
356 dfMaskScaleFloor = kSmallDFFontLimit; | |
357 dfMaskScaleCeil = kMediumDFFontLimit; | |
358 *textRatio = textSize / kMediumDFFontSize; | |
359 skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize)); | |
360 } else { | |
361 dfMaskScaleFloor = kMediumDFFontLimit; | |
362 dfMaskScaleCeil = kLargeDFFontLimit; | |
363 *textRatio = textSize / kLargeDFFontSize; | |
364 skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize)); | |
365 } | |
366 | |
367 // Because there can be multiple runs in the blob, we want the overall maxMi
nScale, and | |
368 // minMaxScale to make regeneration decisions. Specifically, we want the ma
ximum minimum scale | |
369 // we can tolerate before we'd drop to a lower mip size, and the minimum max
imum scale we can | |
370 // tolerate before we'd have to move to a large mip size. When we actually
test these values | |
371 // we look at the delta in scale between the new viewmatrix and the old view
matrix, and test | |
372 // against these values to decide if we can reuse or not(ie, will a given sc
ale change our mip | |
373 // level) | |
374 SkASSERT(dfMaskScaleFloor <= scaledTextSize && scaledTextSize <= dfMaskScale
Ceil); | |
375 blob->fMaxMinScale = SkMaxScalar(dfMaskScaleFloor / scaledTextSize, blob->fM
axMinScale); | |
376 blob->fMinMaxScale = SkMinScalar(dfMaskScaleCeil / scaledTextSize, blob->fMi
nMaxScale); | |
377 | |
378 skPaint->setLCDRenderText(false); | |
379 skPaint->setAutohinted(false); | |
380 skPaint->setHinting(SkPaint::kNormal_Hinting); | |
381 skPaint->setSubpixelText(true); | |
382 } | |
383 | |
384 inline void GrAtlasTextContext::fallbackDrawPosText(GrAtlasTextBlob* blob, | |
385 int runIndex, | |
386 GrColor color, | |
387 const SkPaint& skPaint, | |
388 const SkMatrix& viewMatrix, | |
389 const SkTDArray<char>& fallb
ackTxt, | |
390 const SkTDArray<SkScalar>& f
allbackPos, | |
391 int scalarsPerPosition, | |
392 const SkPoint& offset) { | |
393 SkASSERT(fallbackTxt.count()); | |
394 Run& run = blob->fRuns[runIndex]; | |
395 // Push back a new subrun to fill and set the override descriptor | |
396 run.push_back(); | |
397 run.fOverrideDescriptor.reset(new SkAutoDescriptor); | |
398 GrTextUtils::DrawBmpPosText(blob, runIndex, fContext->getBatchFontCache(), f
SurfaceProps, | |
399 skPaint, color, viewMatrix, fallbackTxt.begin(),
fallbackTxt.count(), | |
400 fallbackPos.begin(), scalarsPerPosition, offset)
; | |
401 } | |
402 | |
403 inline GrAtlasTextBlob* | 282 inline GrAtlasTextBlob* |
404 GrAtlasTextContext::createDrawTextBlob(const GrPaint& paint, const SkPaint& skPa
int, | 283 GrAtlasTextContext::createDrawTextBlob(const GrPaint& paint, const SkPaint& skPa
int, |
405 const SkMatrix& viewMatrix, | 284 const SkMatrix& viewMatrix, |
406 const char text[], size_t byteLength, | 285 const char text[], size_t byteLength, |
407 SkScalar x, SkScalar y) { | 286 SkScalar x, SkScalar y) { |
408 int glyphCount = skPaint.countText(text, byteLength); | 287 int glyphCount = skPaint.countText(text, byteLength); |
409 | 288 |
410 GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBlob::k
GrayTextVASize); | 289 GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBlob::k
GrayTextVASize); |
411 blob->fViewMatrix = viewMatrix; | 290 blob->fViewMatrix = viewMatrix; |
412 | 291 |
413 if (this->canDrawAsDistanceFields(skPaint, viewMatrix)) { | 292 if (GrTextUtils::CanDrawAsDistanceFields(skPaint, viewMatrix, fSurfaceProps, |
414 this->internalDrawDFText(blob, 0, skPaint, paint.getColor(), viewMatrix,
text, | 293 *fContext->caps()->shaderCaps())) { |
415 byteLength, x, y); | 294 GrTextUtils::DrawDFText(blob, 0, fContext->getBatchFontCache(), fSurface
Props, |
| 295 skPaint, paint.getColor(), viewMatrix, text, |
| 296 byteLength, x, y); |
416 } else { | 297 } else { |
417 GrTextUtils::DrawBmpText(blob, 0, fContext->getBatchFontCache(), fSurfac
eProps, skPaint, | 298 GrTextUtils::DrawBmpText(blob, 0, fContext->getBatchFontCache(), fSurfac
eProps, skPaint, |
418 paint.getColor(), viewMatrix, text, byteLength,
x, y); | 299 paint.getColor(), viewMatrix, text, byteLength,
x, y); |
419 } | 300 } |
420 return blob; | 301 return blob; |
421 } | 302 } |
422 | 303 |
423 inline GrAtlasTextBlob* | 304 inline GrAtlasTextBlob* |
424 GrAtlasTextContext::createDrawPosTextBlob(const GrPaint& paint, const SkPaint& s
kPaint, | 305 GrAtlasTextContext::createDrawPosTextBlob(const GrPaint& paint, const SkPaint& s
kPaint, |
425 const SkMatrix& viewMatrix, | 306 const SkMatrix& viewMatrix, |
426 const char text[], size_t byteLength, | 307 const char text[], size_t byteLength, |
427 const SkScalar pos[], int scalarsPerPo
sition, | 308 const SkScalar pos[], int scalarsPerPo
sition, |
428 const SkPoint& offset) { | 309 const SkPoint& offset) { |
429 int glyphCount = skPaint.countText(text, byteLength); | 310 int glyphCount = skPaint.countText(text, byteLength); |
430 | 311 |
431 GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBlob::k
GrayTextVASize); | 312 GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBlob::k
GrayTextVASize); |
432 blob->fViewMatrix = viewMatrix; | 313 blob->fViewMatrix = viewMatrix; |
433 | 314 |
434 if (this->canDrawAsDistanceFields(skPaint, viewMatrix)) { | 315 if (GrTextUtils::CanDrawAsDistanceFields(skPaint, viewMatrix, fSurfaceProps, |
435 this->internalDrawDFPosText(blob, 0, skPaint, paint.getColor(), viewMatr
ix, text, | 316 *fContext->caps()->shaderCaps())) { |
436 byteLength, pos, scalarsPerPosition, offset)
; | 317 GrTextUtils::DrawDFPosText(blob, 0, fContext->getBatchFontCache(), fSurf
aceProps, |
| 318 skPaint, paint.getColor(), viewMatrix, text, |
| 319 byteLength, pos, scalarsPerPosition, offset); |
437 } else { | 320 } else { |
438 GrTextUtils::DrawBmpPosText(blob, 0, fContext->getBatchFontCache(), fSur
faceProps, skPaint, | 321 GrTextUtils::DrawBmpPosText(blob, 0, fContext->getBatchFontCache(), fSur
faceProps, skPaint, |
439 paint.getColor(), viewMatrix, text, | 322 paint.getColor(), viewMatrix, text, |
440 byteLength, pos, scalarsPerPosition, offset)
; | 323 byteLength, pos, scalarsPerPosition, offset)
; |
441 } | 324 } |
442 return blob; | 325 return blob; |
443 } | 326 } |
444 | 327 |
445 void GrAtlasTextContext::onDrawText(GrDrawContext* dc, | 328 void GrAtlasTextContext::onDrawText(GrDrawContext* dc, |
446 const GrClip& clip, | 329 const GrClip& clip, |
(...skipping 17 matching lines...) Expand all Loading... |
464 SkAutoTUnref<GrAtlasTextBlob> blob( | 347 SkAutoTUnref<GrAtlasTextBlob> blob( |
465 this->createDrawPosTextBlob(paint, skPaint, viewMatrix, | 348 this->createDrawPosTextBlob(paint, skPaint, viewMatrix, |
466 text, byteLength, | 349 text, byteLength, |
467 pos, scalarsPerPosition, | 350 pos, scalarsPerPosition, |
468 offset)); | 351 offset)); |
469 | 352 |
470 blob->flushThrowaway(fContext, dc, fSurfaceProps, fDistanceAdjustTable, skPa
int, paint, clip, | 353 blob->flushThrowaway(fContext, dc, fSurfaceProps, fDistanceAdjustTable, skPa
int, paint, clip, |
471 regionClipBounds); | 354 regionClipBounds); |
472 } | 355 } |
473 | 356 |
474 void GrAtlasTextContext::internalDrawDFText(GrAtlasTextBlob* blob, int runIndex, | |
475 const SkPaint& skPaint, GrColor colo
r, | |
476 const SkMatrix& viewMatrix, | |
477 const char text[], size_t byteLength
, | |
478 SkScalar x, SkScalar y) { | |
479 SkASSERT(byteLength == 0 || text != nullptr); | |
480 | |
481 // nothing to draw | |
482 if (text == nullptr || byteLength == 0) { | |
483 return; | |
484 } | |
485 | |
486 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); | |
487 SkAutoDescriptor desc; | |
488 skPaint.getScalerContextDescriptor(&desc, fSurfaceProps, nullptr, true); | |
489 SkGlyphCache* origPaintCache = SkGlyphCache::DetachCache(skPaint.getTypeface
(), | |
490 desc.getDesc()); | |
491 | |
492 SkTArray<SkScalar> positions; | |
493 | |
494 const char* textPtr = text; | |
495 SkFixed stopX = 0; | |
496 SkFixed stopY = 0; | |
497 SkFixed origin = 0; | |
498 switch (skPaint.getTextAlign()) { | |
499 case SkPaint::kRight_Align: origin = SK_Fixed1; break; | |
500 case SkPaint::kCenter_Align: origin = SK_FixedHalf; break; | |
501 case SkPaint::kLeft_Align: origin = 0; break; | |
502 } | |
503 | |
504 SkAutoKern autokern; | |
505 const char* stop = text + byteLength; | |
506 while (textPtr < stop) { | |
507 // don't need x, y here, since all subpixel variants will have the | |
508 // same advance | |
509 const SkGlyph& glyph = glyphCacheProc(origPaintCache, &textPtr, 0, 0); | |
510 | |
511 SkFixed width = glyph.fAdvanceX + autokern.adjust(glyph); | |
512 positions.push_back(SkFixedToScalar(stopX + SkFixedMul(origin, width))); | |
513 | |
514 SkFixed height = glyph.fAdvanceY; | |
515 positions.push_back(SkFixedToScalar(stopY + SkFixedMul(origin, height)))
; | |
516 | |
517 stopX += width; | |
518 stopY += height; | |
519 } | |
520 SkASSERT(textPtr == stop); | |
521 | |
522 SkGlyphCache::AttachCache(origPaintCache); | |
523 | |
524 // now adjust starting point depending on alignment | |
525 SkScalar alignX = SkFixedToScalar(stopX); | |
526 SkScalar alignY = SkFixedToScalar(stopY); | |
527 if (skPaint.getTextAlign() == SkPaint::kCenter_Align) { | |
528 alignX = SkScalarHalf(alignX); | |
529 alignY = SkScalarHalf(alignY); | |
530 } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) { | |
531 alignX = 0; | |
532 alignY = 0; | |
533 } | |
534 x -= alignX; | |
535 y -= alignY; | |
536 SkPoint offset = SkPoint::Make(x, y); | |
537 | |
538 this->internalDrawDFPosText(blob, runIndex, skPaint, color, viewMatrix, text
, byteLength, | |
539 positions.begin(), 2, offset); | |
540 } | |
541 | |
542 void GrAtlasTextContext::internalDrawDFPosText(GrAtlasTextBlob* blob, int runInd
ex, | |
543 const SkPaint& origPaint, | |
544 GrColor color, | |
545 const SkMatrix& viewMatrix, | |
546 const char text[], size_t byteLen
gth, | |
547 const SkScalar pos[], int scalars
PerPosition, | |
548 const SkPoint& offset) { | |
549 | |
550 SkASSERT(byteLength == 0 || text != nullptr); | |
551 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | |
552 | |
553 // nothing to draw | |
554 if (text == nullptr || byteLength == 0) { | |
555 return; | |
556 } | |
557 | |
558 SkTDArray<char> fallbackTxt; | |
559 SkTDArray<SkScalar> fallbackPos; | |
560 | |
561 // Setup distance field paint and text ratio | |
562 SkScalar textRatio; | |
563 SkPaint dfPaint(origPaint); | |
564 this->initDistanceFieldPaint(blob, &dfPaint, &textRatio, viewMatrix); | |
565 blob->setHasDistanceField(); | |
566 blob->setSubRunHasDistanceFields(runIndex, origPaint.isLCDRenderText()); | |
567 | |
568 fCurrStrike = nullptr; | |
569 | |
570 SkGlyphCache* cache = blob->setupCache(runIndex, fSurfaceProps, dfPaint, nul
lptr, true); | |
571 SkDrawCacheProc glyphCacheProc = dfPaint.getDrawCacheProc(); | |
572 GrFontScaler* fontScaler = GetGrFontScaler(cache); | |
573 | |
574 const char* stop = text + byteLength; | |
575 | |
576 if (SkPaint::kLeft_Align == dfPaint.getTextAlign()) { | |
577 while (text < stop) { | |
578 const char* lastText = text; | |
579 // the last 2 parameters are ignored | |
580 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | |
581 | |
582 if (glyph.fWidth) { | |
583 SkScalar x = offset.x() + pos[0]; | |
584 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0)
; | |
585 | |
586 if (!this->dfAppendGlyph(blob, | |
587 runIndex, | |
588 glyph, | |
589 x, y, color, fontScaler, | |
590 textRatio, viewMatrix)) { | |
591 // couldn't append, send to fallback | |
592 fallbackTxt.append(SkToInt(text-lastText), lastText); | |
593 *fallbackPos.append() = pos[0]; | |
594 if (2 == scalarsPerPosition) { | |
595 *fallbackPos.append() = pos[1]; | |
596 } | |
597 } | |
598 } | |
599 pos += scalarsPerPosition; | |
600 } | |
601 } else { | |
602 SkScalar alignMul = SkPaint::kCenter_Align == dfPaint.getTextAlign() ? S
K_ScalarHalf | |
603 : S
K_Scalar1; | |
604 while (text < stop) { | |
605 const char* lastText = text; | |
606 // the last 2 parameters are ignored | |
607 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | |
608 | |
609 if (glyph.fWidth) { | |
610 SkScalar x = offset.x() + pos[0]; | |
611 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0)
; | |
612 | |
613 SkScalar advanceX = SkFixedToScalar(glyph.fAdvanceX) * alignMul
* textRatio; | |
614 SkScalar advanceY = SkFixedToScalar(glyph.fAdvanceY) * alignMul
* textRatio; | |
615 | |
616 if (!this->dfAppendGlyph(blob, | |
617 runIndex, | |
618 glyph, | |
619 x - advanceX, y - advanceY, color, | |
620 fontScaler, | |
621 textRatio, | |
622 viewMatrix)) { | |
623 // couldn't append, send to fallback | |
624 fallbackTxt.append(SkToInt(text-lastText), lastText); | |
625 *fallbackPos.append() = pos[0]; | |
626 if (2 == scalarsPerPosition) { | |
627 *fallbackPos.append() = pos[1]; | |
628 } | |
629 } | |
630 } | |
631 pos += scalarsPerPosition; | |
632 } | |
633 } | |
634 | |
635 SkGlyphCache::AttachCache(cache); | |
636 if (fallbackTxt.count()) { | |
637 this->fallbackDrawPosText(blob, runIndex, origPaint.getColor(), origPain
t, viewMatrix, | |
638 fallbackTxt, fallbackPos, scalarsPerPosition,
offset); | |
639 } | |
640 } | |
641 | |
642 bool GrAtlasTextContext::dfAppendGlyph(GrAtlasTextBlob* blob, int runIndex, | |
643 const SkGlyph& skGlyph, | |
644 SkScalar sx, SkScalar sy, GrColor color, | |
645 GrFontScaler* scaler, | |
646 SkScalar textRatio, const SkMatrix& viewM
atrix) { | |
647 if (!fCurrStrike) { | |
648 fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler); | |
649 } | |
650 | |
651 GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(), | |
652 skGlyph.getSubXFixed(), | |
653 skGlyph.getSubYFixed(), | |
654 GrGlyph::kDistance_MaskStyle); | |
655 GrGlyph* glyph = fCurrStrike->getGlyph(skGlyph, id, scaler); | |
656 if (!glyph) { | |
657 return true; | |
658 } | |
659 | |
660 // fallback to color glyph support | |
661 if (kA8_GrMaskFormat != glyph->fMaskFormat) { | |
662 return false; | |
663 } | |
664 | |
665 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset); | |
666 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset); | |
667 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2 * SK_DistanceField
Inset); | |
668 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2 * SK_DistanceFie
ldInset); | |
669 | |
670 SkScalar scale = textRatio; | |
671 dx *= scale; | |
672 dy *= scale; | |
673 width *= scale; | |
674 height *= scale; | |
675 sx += dx; | |
676 sy += dy; | |
677 SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height); | |
678 | |
679 blob->appendGlyph(runIndex, glyphRect, color, fCurrStrike, glyph, scaler, sk
Glyph, | |
680 sx - dx, sy - dy, scale, true); | |
681 return true; | |
682 } | |
683 | |
684 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 357 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
685 | 358 |
686 #ifdef GR_TEST_UTILS | 359 #ifdef GR_TEST_UTILS |
687 | 360 |
688 DRAW_BATCH_TEST_DEFINE(TextBlobBatch) { | 361 DRAW_BATCH_TEST_DEFINE(TextBlobBatch) { |
689 static uint32_t gContextID = SK_InvalidGenID; | 362 static uint32_t gContextID = SK_InvalidGenID; |
690 static GrAtlasTextContext* gTextContext = nullptr; | 363 static GrAtlasTextContext* gTextContext = nullptr; |
691 static SkSurfaceProps gSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType
); | 364 static SkSurfaceProps gSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType
); |
692 | 365 |
693 if (context->uniqueID() != gContextID) { | 366 if (context->uniqueID() != gContextID) { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
728 | 401 |
729 SkScalar transX = static_cast<SkScalar>(random->nextU()); | 402 SkScalar transX = static_cast<SkScalar>(random->nextU()); |
730 SkScalar transY = static_cast<SkScalar>(random->nextU()); | 403 SkScalar transY = static_cast<SkScalar>(random->nextU()); |
731 const GrAtlasTextBlob::Run::SubRunInfo& info = blob->fRuns[0].fSubRunInfo[0]
; | 404 const GrAtlasTextBlob::Run::SubRunInfo& info = blob->fRuns[0].fSubRunInfo[0]
; |
732 return blob->createBatch(info, textLen, 0, 0, color, transX, transY, skPaint
, | 405 return blob->createBatch(info, textLen, 0, 0, color, transX, transY, skPaint
, |
733 gSurfaceProps, gTextContext->dfAdjustTable(), | 406 gSurfaceProps, gTextContext->dfAdjustTable(), |
734 context->getBatchFontCache()); | 407 context->getBatchFontCache()); |
735 } | 408 } |
736 | 409 |
737 #endif | 410 #endif |
OLD | NEW |