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

Side by Side Diff: src/core/SkTextBlob.cpp

Issue 886473002: Conservative SkTextBlob bounds. (Closed) Base URL: https://chromium.googlesource.com/skia.git@master
Patch Set: Created 5 years, 10 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
« include/core/SkTextBlob.h ('K') | « include/core/SkTextBlob.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 2014 Google Inc. 2 * Copyright 2014 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 "SkTextBlob.h" 8 #include "SkTextBlob.h"
9 9
10 #include "SkReadBuffer.h" 10 #include "SkReadBuffer.h"
11 #include "SkTypeface.h"
11 #include "SkWriteBuffer.h" 12 #include "SkWriteBuffer.h"
12 13
13 // 14 //
14 // Textblob data is laid out into externally-managed storage as follows: 15 // Textblob data is laid out into externally-managed storage as follows:
15 // 16 //
16 // -------------------------------------------------------------------------- --- 17 // -------------------------------------------------------------------------- ---
17 // | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ... 18 // | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ...
18 // -------------------------------------------------------------------------- --- 19 // -------------------------------------------------------------------------- ---
19 // 20 //
20 // Each run record describes a text blob run, and can be used to determine the (implicit) 21 // Each run record describes a text blob run, and can be used to determine the (implicit)
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 } 298 }
298 299
299 SkTextBlobBuilder::~SkTextBlobBuilder() { 300 SkTextBlobBuilder::~SkTextBlobBuilder() {
300 if (NULL != fStorage.get()) { 301 if (NULL != fStorage.get()) {
301 // We are abandoning runs and must destruct the associated font data. 302 // We are abandoning runs and must destruct the associated font data.
302 // The easiest way to accomplish that is to use the blob destructor. 303 // The easiest way to accomplish that is to use the blob destructor.
303 build()->unref(); 304 build()->unref();
304 } 305 }
305 } 306 }
306 307
308 SkRect SkTextBlobBuilder::tightRunBounds(const SkTextBlob::RunRecord& run) {
309 SkRect bounds;
310
311 if (SkTextBlob::kDefault_Positioning == run.positioning()) {
312 run.font().measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint 16_t), &bounds);
313 return bounds;
314 }
315
316 SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() ||
317 SkTextBlob::kHorizontal_Positioning == run.positioning());
318
319 SkAutoSTArray<16, SkRect> glyphBounds(run.glyphCount());
320 run.font().getTextWidths(run.glyphBuffer(),
321 run.glyphCount() * sizeof(uint16_t),
322 NULL,
323 glyphBounds.get());
324
325 bounds = SkRect::MakeEmpty();
326 SkScalar* glyphPos = run.posBuffer();
327 for (unsigned i = 0; i < run.glyphCount(); ++i) {
328 if (SkTextBlob::kFull_Positioning == run.positioning()) {
329 // [ x, y, x, y... ]
330 glyphBounds[i].offset(glyphPos[0], glyphPos[1]);
331 SkASSERT(2 == SkTextBlob::ScalarsPerGlyph(run.positioning()));
332 glyphPos += 2;
333 } else {
334 // [ x, x, x... ], const y applied by runBounds.offset(run->offset() ) later.
335 glyphBounds[i].offset(glyphPos[0], 0);
336 SkASSERT(1 == SkTextBlob::ScalarsPerGlyph(run.positioning()));
337 glyphPos += 1;
338 }
339
340 bounds.join(glyphBounds[i]);
341 }
342
343 SkASSERT((void*)glyphPos <= SkTextBlob::RunRecord::Next(&run));
344
345 bounds.offset(run.offset());
346
347 return bounds;
348 }
349
350 SkRect SkTextBlobBuilder::conservativeRunBounds(const SkTextBlob::RunRecord& run ) {
351 const SkScalar* glyphPos = run.posBuffer();
352 int posScalars = SkTextBlob::ScalarsPerGlyph(run.positioning());
353
354 SkASSERT(1 == posScalars || 2 == posScalars);
355 SkASSERT(run.glyphCount() > 0);
356 SkASSERT((void*)(glyphPos + run.glyphCount() * posScalars) <= SkTextBlob::Ru nRecord::Next(&run));
357
358 // First, compute the glyph position bbox.
359 SkRect bounds = SkRect::MakeXYWH(glyphPos[0], (2 == posScalars) ? glyphPos[1 ] : 0, 0, 0);
360 for (unsigned i = 1; i < run.glyphCount(); ++i) {
361 bounds.growToInclude(glyphPos[i * posScalars],
362 (2 == posScalars) ? glyphPos[i * posScalars + 1] : 0);
363 }
364
365 SkScalar glyphScale = run.font().getTextSize();
366 SkRect typefaceBounds;
367 if (SkToBool(run.font().getTypeface())) {
368 typefaceBounds = run.font().getTypeface()->getBounds();
369 } else {
370 SkAutoTUnref<SkTypeface> typeface(SkTypeface::RefDefault());
371 typefaceBounds = typeface->getBounds();
372 }
373
374 // Expand by typeface glyph bounds.
375 bounds.fLeft += glyphScale * typefaceBounds.left();
376 bounds.fTop += glyphScale * typefaceBounds.top();
377 bounds.fRight += glyphScale * typefaceBounds.right();
378 bounds.fBottom += glyphScale * typefaceBounds.bottom();
379
380 // Offset by run position.
381 return bounds.makeOffset(run.offset().x(), run.offset().y());
382 }
f(malita) 2015/01/28 14:46:19 Here used to live an awesome assert: conservative
mtklein 2015/01/28 14:58:21 I actually had the same sort of problem over in th
f(malita) 2015/01/28 15:14:37 Yay for getFontBounds() - thanks for the tip! Done
383
307 void SkTextBlobBuilder::updateDeferredBounds() { 384 void SkTextBlobBuilder::updateDeferredBounds() {
308 SkASSERT(!fDeferredBounds || fRunCount > 0); 385 SkASSERT(!fDeferredBounds || fRunCount > 0);
309 386
310 if (!fDeferredBounds) { 387 if (!fDeferredBounds) {
311 return; 388 return;
312 } 389 }
313 390
314 SkASSERT(fLastRun >= sizeof(SkTextBlob)); 391 SkASSERT(fLastRun >= sizeof(SkTextBlob));
315 SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStora ge.get() + 392 SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStora ge.get() +
316 fLastR un); 393 fLastR un);
317 SkASSERT(SkPaint::kGlyphID_TextEncoding == run->font().getTextEncoding()); 394 SkASSERT(SkPaint::kGlyphID_TextEncoding == run->font().getTextEncoding());
318 395
319 SkRect runBounds = SkRect::MakeEmpty(); 396 SkRect runBounds;
397 #ifdef SK_SUPPORT_LEGACY_BLOB_BOUNDS
398 runBounds = tightRunBounds(*run);
399 #else
400 // FIXME: conservative bounds for default positioning?
320 if (SkTextBlob::kDefault_Positioning == run->positioning()) { 401 if (SkTextBlob::kDefault_Positioning == run->positioning()) {
321 run->font().measureText(run->glyphBuffer(), 402 runBounds = tightRunBounds(*run);
322 run->glyphCount() * sizeof(uint16_t),
323 &runBounds);
324 } else { 403 } else {
325 SkASSERT(SkTextBlob::kFull_Positioning == run->positioning() || 404 runBounds = conservativeRunBounds(*run);
326 SkTextBlob::kHorizontal_Positioning == run->positioning());
327
328 SkAutoSTArray<16, SkRect> glyphBounds(run->glyphCount());
329 run->font().getTextWidths(run->glyphBuffer(),
330 run->glyphCount() * sizeof(uint16_t),
331 NULL,
332 glyphBounds.get());
333
334 SkScalar* glyphOffset = run->posBuffer();
335 for (unsigned i = 0; i < run->glyphCount(); ++i) {
336 if (SkTextBlob::kFull_Positioning == run->positioning()) {
337 // [ x, y, x, y... ]
338 glyphBounds[i].offset(glyphOffset[0], glyphOffset[1]);
339 SkASSERT(2 == SkTextBlob::ScalarsPerGlyph(run->positioning()));
340 glyphOffset += 2;
341 } else {
342 // [ x, x, x... ], const y applied by runBounds.offset(run->offs et()) later.
343 glyphBounds[i].offset(glyphOffset[0], 0);
344 SkASSERT(1 == SkTextBlob::ScalarsPerGlyph(run->positioning()));
345 glyphOffset += 1;
346 }
347
348 runBounds.join(glyphBounds[i]);
349 }
350
351 SkASSERT((void*)glyphOffset <= SkTextBlob::RunRecord::Next(run));
352 } 405 }
353 406 #endif
354 runBounds.offset(run->offset());
355 407
356 fBounds.join(runBounds); 408 fBounds.join(runBounds);
357 fDeferredBounds = false; 409 fDeferredBounds = false;
358 } 410 }
359 411
360 void SkTextBlobBuilder::reserve(size_t size) { 412 void SkTextBlobBuilder::reserve(size_t size) {
361 // We don't currently pre-allocate, but maybe someday... 413 // We don't currently pre-allocate, but maybe someday...
362 if (fStorageUsed + size <= fStorageSize) { 414 if (fStorageUsed + size <= fStorageSize) {
363 return; 415 return;
364 } 416 }
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 569
518 fStorageUsed = 0; 570 fStorageUsed = 0;
519 fStorageSize = 0; 571 fStorageSize = 0;
520 fRunCount = 0; 572 fRunCount = 0;
521 fLastRun = 0; 573 fLastRun = 0;
522 fBounds.setEmpty(); 574 fBounds.setEmpty();
523 575
524 return blob; 576 return blob;
525 } 577 }
526 578
OLDNEW
« include/core/SkTextBlob.h ('K') | « include/core/SkTextBlob.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698