Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Classes | Functions
TextBlobTest.cpp File Reference
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkData.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontStyle.h"
#include "include/core/SkFontTypes.h"
#include "include/core/SkImage.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSerialProcs.h"
#include "include/core/SkSurface.h"
#include "include/core/SkTextBlob.h"
#include "include/core/SkTypeface.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkTArray.h"
#include "include/private/base/SkTemplates.h"
#include "include/private/base/SkTo.h"
#include "src/core/SkFontPriv.h"
#include "src/core/SkTextBlobPriv.h"
#include "tests/Test.h"
#include "tools/ToolUtils.h"
#include "tools/fonts/FontToolUtils.h"
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <string>

Go to the source code of this file.

Classes

class  TextBlobTester
 

Functions

 DEF_TEST (TextBlob_builder, reporter)
 
 DEF_TEST (TextBlob_paint, reporter)
 
 DEF_TEST (TextBlob_extended, reporter)
 
static void add_run (SkTextBlobBuilder *builder, const char text[], SkScalar x, SkScalar y, sk_sp< SkTypeface > tf)
 
static sk_sp< SkImagerender (const SkTextBlob *blob)
 
static sk_sp< SkDataSerializeTypeface (SkTypeface *tf, void *ctx)
 
static sk_sp< SkTypefaceDeserializeTypeface (const void *data, size_t length, void *ctx)
 
 DEF_TEST (TextBlob_serialize, reporter)
 
 DEF_TEST (TextBlob_MakeAsDrawText, reporter)
 
 DEF_TEST (TextBlob_iter, reporter)
 
 DEF_TEST (TextBlob_getIntercepts, reporter)
 

Function Documentation

◆ add_run()

static void add_run ( SkTextBlobBuilder builder,
const char  text[],
SkScalar  x,
SkScalar  y,
sk_sp< SkTypeface tf 
)
static

Definition at line 370 of file TextBlobTest.cpp.

371 {
372 SkFont font;
374 font.setSubpixel(true);
375 font.setSize(16);
376 font.setTypeface(tf);
377
378 int glyphCount = font.countText(text, strlen(text), SkTextEncoding::kUTF8);
379
380 SkTextBlobBuilder::RunBuffer buffer = builder->allocRun(font, glyphCount, x, y);
381
382 (void)font.textToGlyphs(text, strlen(text), SkTextEncoding::kUTF8, buffer.glyphs, glyphCount);
383}
@ kUTF8
uses bytes to represent UTF-8 or ASCII
@ kAntiAlias
may have transparent pixels on glyph edges
static const uint8_t buffer[]
std::u16string text
double y
double x
font
Font Metadata and Metrics.

◆ DEF_TEST() [1/7]

DEF_TEST ( TextBlob_builder  ,
reporter   
)

Definition at line 325 of file TextBlobTest.cpp.

325 {
328}
reporter
static void TestBounds(skiatest::Reporter *reporter)
static void TestBuilder(skiatest::Reporter *reporter)

◆ DEF_TEST() [2/7]

DEF_TEST ( TextBlob_extended  ,
reporter   
)

Definition at line 334 of file TextBlobTest.cpp.

334 {
335 SkTextBlobBuilder textBlobBuilder;
337 const char text1[] = "Foo";
338 const char text2[] = "Bar";
339
340 int glyphCount = font.countText(text1, strlen(text1), SkTextEncoding::kUTF8);
341 AutoTMalloc<uint16_t> glyphs(glyphCount);
342 (void)font.textToGlyphs(text1, strlen(text1), SkTextEncoding::kUTF8, glyphs.get(), glyphCount);
343
344 auto run = textBlobBuilder.allocRunText(font, glyphCount, 0, 0, SkToInt(strlen(text2)));
345 memcpy(run.glyphs, glyphs.get(), sizeof(uint16_t) * glyphCount);
346 memcpy(run.utf8text, text2, strlen(text2));
347 for (int i = 0; i < glyphCount; ++i) {
348 run.clusters[i] = std::min(SkToU32(i), SkToU32(strlen(text2)));
349 }
350 sk_sp<SkTextBlob> blob(textBlobBuilder.make());
352
353 for (SkTextBlobRunIterator it(blob.get()); !it.done(); it.next()) {
354 REPORTER_ASSERT(reporter, it.glyphCount() == (uint32_t)glyphCount);
355 for (uint32_t i = 0; i < it.glyphCount(); ++i) {
356 REPORTER_ASSERT(reporter, it.glyphs()[i] == glyphs[i]);
357 }
359 REPORTER_ASSERT(reporter, (SkPoint{0.0f, 0.0f}) == it.offset());
360 REPORTER_ASSERT(reporter, it.textSize() > 0);
361 REPORTER_ASSERT(reporter, it.clusters());
362 for (uint32_t i = 0; i < it.glyphCount(); ++i) {
363 REPORTER_ASSERT(reporter, i == it.clusters()[i]);
364 }
365 REPORTER_ASSERT(reporter, 0 == strncmp(text2, it.text(), it.textSize()));
366 }
367}
uint16_t glyphs[5]
constexpr int SkToInt(S x)
Definition SkTo.h:29
constexpr uint32_t SkToU32(S x)
Definition SkTo.h:26
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
const RunBuffer & allocRunText(const SkFont &font, int count, SkScalar x, SkScalar y, int textByteCount, const SkRect *bounds=nullptr)
sk_sp< SkTextBlob > make()
SkFont DefaultFont()
Definition run.py:1

◆ DEF_TEST() [3/7]

DEF_TEST ( TextBlob_getIntercepts  ,
reporter   
)

Definition at line 513 of file TextBlobTest.cpp.

513 {
515 font.setSize(16);
516
517 SkPoint lowPos[1] = { SkPoint::Make(0, 5) };
518 SkPoint highPos[1] = { SkPoint::Make(0, -8) };
519 SkPoint zeroPos[1] = { SkPoint::Make(0, 0) };
520
521 // 'x' sitting on baseline
522 auto blobZeroX = SkTextBlob::MakeFromPosText("x", 1, zeroPos, font);
523 // 'x' lowered to intersect baseline
524 auto blobLowX = SkTextBlob::MakeFromPosText("x", 1, lowPos, font);
525 // 'y' sitting on baseline
526 auto blobZeroY = SkTextBlob::MakeFromPosText("y", 1, zeroPos, font);
527 // 'y' raised to not intersect baseline
528 auto blobHighY = SkTextBlob::MakeFromPosText("y", 1, highPos, font);
529
530 // bounds right below baseline
531 SkScalar bounds[2] = { 1, 2 };
532
533 // 'x' on baseline should not intersect
534 REPORTER_ASSERT(reporter, blobZeroX->getIntercepts(bounds, nullptr) == 0);
535 // lowered 'x' should intersect
536 REPORTER_ASSERT(reporter, blobLowX->getIntercepts(bounds, nullptr) == 2);
537 // 'y' on baseline should intersect
538 REPORTER_ASSERT(reporter, blobZeroY->getIntercepts(bounds, nullptr) == 2);
539 // raised 'y' should not intersect
540 REPORTER_ASSERT(reporter, blobHighY->getIntercepts(bounds, nullptr) == 0);
541}
static sk_sp< SkTextBlob > MakeFromPosText(const void *text, size_t byteLength, const SkPoint pos[], const SkFont &font, SkTextEncoding encoding=SkTextEncoding::kUTF8)
float SkScalar
Definition extension.cpp:12
Optional< SkRect > bounds
Definition SkRecords.h:189
static constexpr SkPoint Make(float x, float y)

◆ DEF_TEST() [4/7]

DEF_TEST ( TextBlob_iter  ,
reporter   
)

Definition at line 481 of file TextBlobTest.cpp.

481 {
483
485 add_run(&builder, "Hello", 10, 20, tf);
486 add_run(&builder, "World!", 10, 40, tf);
487 auto blob = builder.make();
488
489 SkTextBlob::Iter::Run expected[] = {
490 { tf.get(), 5, nullptr },
491 { tf.get(), 6, nullptr },
492 };
493
494 SkTextBlob::Iter iter(*blob);
496 for (auto exp : expected) {
497 REPORTER_ASSERT(reporter, iter.next(&run));
498 REPORTER_ASSERT(reporter, run.fTypeface == exp.fTypeface);
499 REPORTER_ASSERT(reporter, run.fGlyphCount == exp.fGlyphCount);
500 for (int i = 0; i < run.fGlyphCount; ++i) {
501 REPORTER_ASSERT(reporter, run.fGlyphIndices[i] != 0,
502 "Glyph Index %d is unexpectedly 0", i);
503 }
504 }
505 REPORTER_ASSERT(reporter, !iter.next(&run)); // we're done
506
507 SkTextBlob::Iter iter2(*blob);
508 REPORTER_ASSERT(reporter, iter2.next(&run));
509 // Hello should have the same glyph repeated for the 'l'
510 REPORTER_ASSERT(reporter, run.fGlyphIndices[2] == run.fGlyphIndices[3]);
511}
static void add_run(SkTextBlobBuilder *builder, const char text[], SkScalar x, SkScalar y, sk_sp< SkTypeface > tf)
static constexpr SkFontStyle BoldItalic()
Definition SkFontStyle.h:75
T * get() const
Definition SkRefCnt.h:303
sk_sp< SkTypeface > CreateTestTypeface(const char *name, SkFontStyle style)

◆ DEF_TEST() [5/7]

DEF_TEST ( TextBlob_MakeAsDrawText  ,
reporter   
)

Definition at line 467 of file TextBlobTest.cpp.

467 {
468 const char text[] = "Hello";
470
471 int runs = 0;
472 for(SkTextBlobRunIterator it(blob.get()); !it.done(); it.next()) {
473 REPORTER_ASSERT(reporter, it.glyphCount() == strlen(text));
475 runs += 1;
476 }
477 REPORTER_ASSERT(reporter, runs == 1);
478
479}
static sk_sp< SkTextBlob > MakeFromString(const char *string, const SkFont &font, SkTextEncoding encoding=SkTextEncoding::kUTF8)
Definition SkTextBlob.h:115

◆ DEF_TEST() [6/7]

DEF_TEST ( TextBlob_paint  ,
reporter   
)

Definition at line 330 of file TextBlobTest.cpp.

330 {
332}
static void TestPaintProps(skiatest::Reporter *reporter)

◆ DEF_TEST() [7/7]

DEF_TEST ( TextBlob_serialize  ,
reporter   
)

Definition at line 434 of file TextBlobTest.cpp.

434 {
435 sk_sp<SkTextBlob> blob0 = [reporter]() {
437 REPORTER_ASSERT(reporter, tf, "Test typeface was nullptr");
438 REPORTER_ASSERT(reporter, tf->countGlyphs() > 0, "Test typeface had no glyphs");
439
441 add_run(&builder, "Hello", 10, 20, nullptr); // don't flatten a typeface
442 add_run(&builder, "World", 10, 40, tf); // do flatten this typeface
443 return builder.make();
444 }();
445
447 SkSerialProcs serializeProcs;
448 serializeProcs.fTypefaceProc = &SerializeTypeface;
449 serializeProcs.fTypefaceCtx = (void*) &array;
450 sk_sp<SkData> data = blob0->serialize(serializeProcs);
451 REPORTER_ASSERT(reporter, array.size() == 1,
452 "Did not serialize exactly one non-empty font, instead %d", array.size());
453 REPORTER_ASSERT(reporter, array[0]->countGlyphs() > 0, "Serialized typeface had no glyphs");
454 SkDeserialProcs deserializeProcs;
455 deserializeProcs.fTypefaceProc = &DeserializeTypeface;
456 deserializeProcs.fTypefaceCtx = (void*) &array;
457 sk_sp<SkTextBlob> blob1 = SkTextBlob::Deserialize(data->data(), data->size(), deserializeProcs);
459
460 sk_sp<SkImage> img0 = render(blob0.get());
461 sk_sp<SkImage> img1 = render(blob1.get());
462 if (img0 && img1) {
464 }
465}
static sk_sp< SkTypeface > DeserializeTypeface(const void *data, size_t length, void *ctx)
static sk_sp< SkImage > render(const SkTextBlob *blob)
static sk_sp< SkData > SerializeTypeface(SkTypeface *tf, void *ctx)
static sk_sp< SkTextBlob > Deserialize(const void *data, size_t size, const SkDeserialProcs &procs)
int size() const
Definition SkTArray.h:416
bool equal_pixels(const SkPixmap &a, const SkPixmap &b)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
SkDeserialTypefaceProc fTypefaceProc
void * fTypefaceCtx
SkSerialTypefaceProc fTypefaceProc

◆ DeserializeTypeface()

static sk_sp< SkTypeface > DeserializeTypeface ( const void *  data,
size_t  length,
void *  ctx 
)
static

Definition at line 410 of file TextBlobTest.cpp.

410 {
411 auto array = (TArray<sk_sp<SkTypeface>>*)ctx;
412 if (length != sizeof(size_t)) {
413 SkDEBUGFAIL("Did not serialize an index");
414 return nullptr;
415 }
416 if (!data) {
417 return nullptr;
418 }
419 size_t idx = 0;
420 std::memcpy(&idx, data, sizeof(size_t));
421 if (idx >= SkToSizeT(array->size())) {
422 SkDEBUGFAIL("Index too big");
423 return nullptr;
424 }
425 return (*array)[idx];
426}
#define SkDEBUGFAIL(message)
Definition SkAssert.h:118
constexpr size_t SkToSizeT(S x)
Definition SkTo.h:31
size_t length

◆ render()

static sk_sp< SkImage > render ( const SkTextBlob blob)
static

Definition at line 385 of file TextBlobTest.cpp.

385 {
386 SkASSERT(blob);
387 auto surf = SkSurfaces::Raster(
389 SkScalarRoundToInt(blob->bounds().height())));
390 if (!surf) {
391 return nullptr; // bounds are empty?
392 }
393 surf->getCanvas()->clear(SK_ColorWHITE);
394 surf->getCanvas()->drawTextBlob(blob, -blob->bounds().left(), -blob->bounds().top(), SkPaint());
395 return surf->makeImageSnapshot();
396}
#define SkASSERT(cond)
Definition SkAssert.h:116
constexpr SkColor SK_ColorWHITE
Definition SkColor.h:122
#define SkScalarRoundToInt(x)
Definition SkScalar.h:37
const SkRect & bounds() const
Definition SkTextBlob.h:53
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
static SkImageInfo MakeN32Premul(int width, int height)
constexpr float left() const
Definition SkRect.h:734
constexpr float top() const
Definition SkRect.h:741
constexpr float height() const
Definition SkRect.h:769
constexpr float width() const
Definition SkRect.h:762

◆ SerializeTypeface()

static sk_sp< SkData > SerializeTypeface ( SkTypeface tf,
void *  ctx 
)
static

Definition at line 398 of file TextBlobTest.cpp.

398 {
399 // Do not serialize the empty font.
400 if (!tf || (tf->countGlyphs() == 0 && tf->getBounds().isEmpty())) {
401 return nullptr;
402 }
403 auto array = (TArray<sk_sp<SkTypeface>>*)ctx;
404 const size_t idx = array->size();
405 array->emplace_back(sk_ref_sp(tf));
406 // In this test, we are deserializing on the same machine, so we don't worry about endianness.
407 return SkData::MakeWithCopy(&idx, sizeof(idx));
408}
sk_sp< T > sk_ref_sp(T *obj)
Definition SkRefCnt.h:381
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
Definition SkData.cpp:111
int countGlyphs() const
SkRect getBounds() const
bool isEmpty() const
Definition SkRect.h:693