1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 9cb93a386Sopenharmony_ci#include "include/core/SkPoint.h" 10cb93a386Sopenharmony_ci#include "include/core/SkSerialProcs.h" 11cb93a386Sopenharmony_ci#include "include/core/SkTypeface.h" 12cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 13cb93a386Sopenharmony_ci#include "src/core/SkTextBlobPriv.h" 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ci#include "tests/Test.h" 16cb93a386Sopenharmony_ci#include "tools/ToolUtils.h" 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_ciclass TextBlobTester { 19cb93a386Sopenharmony_cipublic: 20cb93a386Sopenharmony_ci // This unit test feeds an SkTextBlobBuilder various runs then checks to see if 21cb93a386Sopenharmony_ci // the result contains the provided data and merges runs when appropriate. 22cb93a386Sopenharmony_ci static void TestBuilder(skiatest::Reporter* reporter) { 23cb93a386Sopenharmony_ci SkTextBlobBuilder builder; 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ci // empty run set 26cb93a386Sopenharmony_ci RunBuilderTest(reporter, builder, nullptr, 0, nullptr, 0); 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ci RunDef set1[] = { 29cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 100 }, 30cb93a386Sopenharmony_ci }; 31cb93a386Sopenharmony_ci RunBuilderTest(reporter, builder, set1, SK_ARRAY_COUNT(set1), set1, SK_ARRAY_COUNT(set1)); 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_ci RunDef set2[] = { 34cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 100, 100 }, 35cb93a386Sopenharmony_ci }; 36cb93a386Sopenharmony_ci RunBuilderTest(reporter, builder, set2, SK_ARRAY_COUNT(set2), set2, SK_ARRAY_COUNT(set2)); 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci RunDef set3[] = { 39cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kFull_Positioning, 100, 100 }, 40cb93a386Sopenharmony_ci }; 41cb93a386Sopenharmony_ci RunBuilderTest(reporter, builder, set3, SK_ARRAY_COUNT(set3), set3, SK_ARRAY_COUNT(set3)); 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci RunDef set4[] = { 44cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 150 }, 45cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 150 }, 46cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 150 }, 47cb93a386Sopenharmony_ci }; 48cb93a386Sopenharmony_ci RunBuilderTest(reporter, builder, set4, SK_ARRAY_COUNT(set4), set4, SK_ARRAY_COUNT(set4)); 49cb93a386Sopenharmony_ci 50cb93a386Sopenharmony_ci RunDef set5[] = { 51cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 100, 150 }, 52cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 200, 150 }, 53cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 300, 250 }, 54cb93a386Sopenharmony_ci }; 55cb93a386Sopenharmony_ci RunDef mergedSet5[] = { 56cb93a386Sopenharmony_ci { 256, SkTextBlobRunIterator::kHorizontal_Positioning, 0, 150 }, 57cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 0, 250 }, 58cb93a386Sopenharmony_ci }; 59cb93a386Sopenharmony_ci RunBuilderTest(reporter, builder, set5, SK_ARRAY_COUNT(set5), mergedSet5, 60cb93a386Sopenharmony_ci SK_ARRAY_COUNT(mergedSet5)); 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_ci RunDef set6[] = { 63cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kFull_Positioning, 100, 100 }, 64cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kFull_Positioning, 200, 200 }, 65cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kFull_Positioning, 300, 300 }, 66cb93a386Sopenharmony_ci }; 67cb93a386Sopenharmony_ci RunDef mergedSet6[] = { 68cb93a386Sopenharmony_ci { 384, SkTextBlobRunIterator::kFull_Positioning, 0, 0 }, 69cb93a386Sopenharmony_ci }; 70cb93a386Sopenharmony_ci RunBuilderTest(reporter, builder, set6, SK_ARRAY_COUNT(set6), mergedSet6, 71cb93a386Sopenharmony_ci SK_ARRAY_COUNT(mergedSet6)); 72cb93a386Sopenharmony_ci 73cb93a386Sopenharmony_ci RunDef set7[] = { 74cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 150 }, 75cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 150 }, 76cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 100, 150 }, 77cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 200, 150 }, 78cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kFull_Positioning, 400, 350 }, 79cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kFull_Positioning, 400, 350 }, 80cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 450 }, 81cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 450 }, 82cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 100, 550 }, 83cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 200, 650 }, 84cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kFull_Positioning, 400, 750 }, 85cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kFull_Positioning, 400, 850 }, 86cb93a386Sopenharmony_ci }; 87cb93a386Sopenharmony_ci RunDef mergedSet7[] = { 88cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 150 }, 89cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 150 }, 90cb93a386Sopenharmony_ci { 256, SkTextBlobRunIterator::kHorizontal_Positioning, 0, 150 }, 91cb93a386Sopenharmony_ci { 256, SkTextBlobRunIterator::kFull_Positioning, 0, 0 }, 92cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 450 }, 93cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 450 }, 94cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 0, 550 }, 95cb93a386Sopenharmony_ci { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 0, 650 }, 96cb93a386Sopenharmony_ci { 256, SkTextBlobRunIterator::kFull_Positioning, 0, 0 }, 97cb93a386Sopenharmony_ci }; 98cb93a386Sopenharmony_ci RunBuilderTest(reporter, builder, set7, SK_ARRAY_COUNT(set7), mergedSet7, 99cb93a386Sopenharmony_ci SK_ARRAY_COUNT(mergedSet7)); 100cb93a386Sopenharmony_ci } 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ci // This unit test verifies blob bounds computation. 103cb93a386Sopenharmony_ci static void TestBounds(skiatest::Reporter* reporter) { 104cb93a386Sopenharmony_ci SkTextBlobBuilder builder; 105cb93a386Sopenharmony_ci SkFont font; 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci // Explicit bounds. 108cb93a386Sopenharmony_ci { 109cb93a386Sopenharmony_ci sk_sp<SkTextBlob> blob(builder.make()); 110cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !blob); 111cb93a386Sopenharmony_ci } 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_ci { 114cb93a386Sopenharmony_ci SkRect r1 = SkRect::MakeXYWH(10, 10, 20, 20); 115cb93a386Sopenharmony_ci builder.allocRun(font, 16, 0, 0, &r1); 116cb93a386Sopenharmony_ci sk_sp<SkTextBlob> blob(builder.make()); 117cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, blob->bounds() == r1); 118cb93a386Sopenharmony_ci } 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_ci { 121cb93a386Sopenharmony_ci SkRect r1 = SkRect::MakeXYWH(10, 10, 20, 20); 122cb93a386Sopenharmony_ci builder.allocRunPosH(font, 16, 0, &r1); 123cb93a386Sopenharmony_ci sk_sp<SkTextBlob> blob(builder.make()); 124cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, blob->bounds() == r1); 125cb93a386Sopenharmony_ci } 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_ci { 128cb93a386Sopenharmony_ci SkRect r1 = SkRect::MakeXYWH(10, 10, 20, 20); 129cb93a386Sopenharmony_ci builder.allocRunPos(font, 16, &r1); 130cb93a386Sopenharmony_ci sk_sp<SkTextBlob> blob(builder.make()); 131cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, blob->bounds() == r1); 132cb93a386Sopenharmony_ci } 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci { 135cb93a386Sopenharmony_ci SkRect r1 = SkRect::MakeXYWH(10, 10, 20, 20); 136cb93a386Sopenharmony_ci SkRect r2 = SkRect::MakeXYWH(15, 20, 50, 50); 137cb93a386Sopenharmony_ci SkRect r3 = SkRect::MakeXYWH(0, 5, 10, 5); 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci builder.allocRun(font, 16, 0, 0, &r1); 140cb93a386Sopenharmony_ci builder.allocRunPosH(font, 16, 0, &r2); 141cb93a386Sopenharmony_ci builder.allocRunPos(font, 16, &r3); 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci sk_sp<SkTextBlob> blob(builder.make()); 144cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, blob->bounds() == SkRect::MakeXYWH(0, 5, 65, 65)); 145cb93a386Sopenharmony_ci } 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci { 148cb93a386Sopenharmony_ci sk_sp<SkTextBlob> blob(builder.make()); 149cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !blob); 150cb93a386Sopenharmony_ci } 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ci // Implicit bounds 153cb93a386Sopenharmony_ci 154cb93a386Sopenharmony_ci { 155cb93a386Sopenharmony_ci // Exercise the empty bounds path, and ensure that RunRecord-aligned pos buffers 156cb93a386Sopenharmony_ci // don't trigger asserts (http://crbug.com/542643). 157cb93a386Sopenharmony_ci font.setSize(0); 158cb93a386Sopenharmony_ci 159cb93a386Sopenharmony_ci const char* txt = "BOOO"; 160cb93a386Sopenharmony_ci const size_t txtLen = strlen(txt); 161cb93a386Sopenharmony_ci const int glyphCount = font.countText(txt, txtLen, SkTextEncoding::kUTF8); 162cb93a386Sopenharmony_ci const SkTextBlobBuilder::RunBuffer& buffer = builder.allocRunPos(font, glyphCount); 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_ci font.textToGlyphs(txt, txtLen, SkTextEncoding::kUTF8, buffer.glyphs, glyphCount); 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ci memset(buffer.pos, 0, sizeof(SkScalar) * glyphCount * 2); 167cb93a386Sopenharmony_ci sk_sp<SkTextBlob> blob(builder.make()); 168cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, blob->bounds().isEmpty()); 169cb93a386Sopenharmony_ci } 170cb93a386Sopenharmony_ci } 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_ci // Verify that text-related properties are captured in run paints. 173cb93a386Sopenharmony_ci static void TestPaintProps(skiatest::Reporter* reporter) { 174cb93a386Sopenharmony_ci SkFont font; 175cb93a386Sopenharmony_ci // Kitchen sink font. 176cb93a386Sopenharmony_ci font.setSize(42); 177cb93a386Sopenharmony_ci font.setScaleX(4.2f); 178cb93a386Sopenharmony_ci font.setTypeface(ToolUtils::create_portable_typeface()); 179cb93a386Sopenharmony_ci font.setSkewX(0.42f); 180cb93a386Sopenharmony_ci font.setHinting(SkFontHinting::kFull); 181cb93a386Sopenharmony_ci font.setEdging(SkFont::Edging::kSubpixelAntiAlias); 182cb93a386Sopenharmony_ci font.setEmbolden(true); 183cb93a386Sopenharmony_ci font.setLinearMetrics(true); 184cb93a386Sopenharmony_ci font.setSubpixel(true); 185cb93a386Sopenharmony_ci font.setEmbeddedBitmaps(true); 186cb93a386Sopenharmony_ci font.setForceAutoHinting(true); 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ci // Ensure we didn't pick default values by mistake. 189cb93a386Sopenharmony_ci SkFont defaultFont; 190cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, defaultFont.getSize() != font.getSize()); 191cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, defaultFont.getScaleX() != font.getScaleX()); 192cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, defaultFont.getTypefaceOrDefault() != font.getTypefaceOrDefault()); 193cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, defaultFont.getSkewX() != font.getSkewX()); 194cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, defaultFont.getHinting() != font.getHinting()); 195cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, defaultFont.getEdging() != font.getEdging()); 196cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, defaultFont.isEmbolden() != font.isEmbolden()); 197cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, defaultFont.isLinearMetrics() != font.isLinearMetrics()); 198cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, defaultFont.isSubpixel() != font.isSubpixel()); 199cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 200cb93a386Sopenharmony_ci defaultFont.isEmbeddedBitmaps() != font.isEmbeddedBitmaps()); 201cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, defaultFont.isForceAutoHinting() != font.isForceAutoHinting()); 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ci SkTextBlobBuilder builder; 204cb93a386Sopenharmony_ci AddRun(font, 1, SkTextBlobRunIterator::kDefault_Positioning, SkPoint::Make(0, 0), builder); 205cb93a386Sopenharmony_ci AddRun(font, 1, SkTextBlobRunIterator::kHorizontal_Positioning, SkPoint::Make(0, 0), 206cb93a386Sopenharmony_ci builder); 207cb93a386Sopenharmony_ci AddRun(font, 1, SkTextBlobRunIterator::kFull_Positioning, SkPoint::Make(0, 0), builder); 208cb93a386Sopenharmony_ci sk_sp<SkTextBlob> blob(builder.make()); 209cb93a386Sopenharmony_ci 210cb93a386Sopenharmony_ci SkTextBlobRunIterator it(blob.get()); 211cb93a386Sopenharmony_ci while (!it.done()) { 212cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, it.font() == font); 213cb93a386Sopenharmony_ci it.next(); 214cb93a386Sopenharmony_ci } 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci } 217cb93a386Sopenharmony_ci 218cb93a386Sopenharmony_ciprivate: 219cb93a386Sopenharmony_ci struct RunDef { 220cb93a386Sopenharmony_ci unsigned count; 221cb93a386Sopenharmony_ci SkTextBlobRunIterator::GlyphPositioning pos; 222cb93a386Sopenharmony_ci SkScalar x, y; 223cb93a386Sopenharmony_ci }; 224cb93a386Sopenharmony_ci 225cb93a386Sopenharmony_ci static void RunBuilderTest(skiatest::Reporter* reporter, SkTextBlobBuilder& builder, 226cb93a386Sopenharmony_ci const RunDef in[], unsigned inCount, 227cb93a386Sopenharmony_ci const RunDef out[], unsigned outCount) { 228cb93a386Sopenharmony_ci SkFont font; 229cb93a386Sopenharmony_ci 230cb93a386Sopenharmony_ci for (unsigned i = 0; i < inCount; ++i) { 231cb93a386Sopenharmony_ci AddRun(font, in[i].count, in[i].pos, SkPoint::Make(in[i].x, in[i].y), builder); 232cb93a386Sopenharmony_ci } 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci sk_sp<SkTextBlob> blob(builder.make()); 235cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (inCount > 0) == SkToBool(blob)); 236cb93a386Sopenharmony_ci if (!blob) { 237cb93a386Sopenharmony_ci return; 238cb93a386Sopenharmony_ci } 239cb93a386Sopenharmony_ci 240cb93a386Sopenharmony_ci SkTextBlobRunIterator it(blob.get()); 241cb93a386Sopenharmony_ci for (unsigned i = 0; i < outCount; ++i) { 242cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !it.done()); 243cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, out[i].pos == it.positioning()); 244cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, out[i].count == it.glyphCount()); 245cb93a386Sopenharmony_ci if (SkTextBlobRunIterator::kDefault_Positioning == out[i].pos) { 246cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, out[i].x == it.offset().x()); 247cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, out[i].y == it.offset().y()); 248cb93a386Sopenharmony_ci } else if (SkTextBlobRunIterator::kHorizontal_Positioning == out[i].pos) { 249cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, out[i].y == it.offset().y()); 250cb93a386Sopenharmony_ci } 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_ci for (unsigned k = 0; k < it.glyphCount(); ++k) { 253cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, k % 128 == it.glyphs()[k]); 254cb93a386Sopenharmony_ci if (SkTextBlobRunIterator::kHorizontal_Positioning == it.positioning()) { 255cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkIntToScalar(k % 128) == it.pos()[k]); 256cb93a386Sopenharmony_ci } else if (SkTextBlobRunIterator::kFull_Positioning == it.positioning()) { 257cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkIntToScalar(k % 128) == it.pos()[k * 2]); 258cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, -SkIntToScalar(k % 128) == it.pos()[k * 2 + 1]); 259cb93a386Sopenharmony_ci } 260cb93a386Sopenharmony_ci } 261cb93a386Sopenharmony_ci 262cb93a386Sopenharmony_ci it.next(); 263cb93a386Sopenharmony_ci } 264cb93a386Sopenharmony_ci 265cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, it.done()); 266cb93a386Sopenharmony_ci } 267cb93a386Sopenharmony_ci 268cb93a386Sopenharmony_ci static void AddRun(const SkFont& font, int count, SkTextBlobRunIterator::GlyphPositioning pos, 269cb93a386Sopenharmony_ci const SkPoint& offset, SkTextBlobBuilder& builder, 270cb93a386Sopenharmony_ci const SkRect* bounds = nullptr) { 271cb93a386Sopenharmony_ci switch (pos) { 272cb93a386Sopenharmony_ci case SkTextBlobRunIterator::kDefault_Positioning: { 273cb93a386Sopenharmony_ci const SkTextBlobBuilder::RunBuffer& rb = builder.allocRun(font, count, offset.x(), 274cb93a386Sopenharmony_ci offset.y(), bounds); 275cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 276cb93a386Sopenharmony_ci rb.glyphs[i] = i; 277cb93a386Sopenharmony_ci } 278cb93a386Sopenharmony_ci } break; 279cb93a386Sopenharmony_ci case SkTextBlobRunIterator::kHorizontal_Positioning: { 280cb93a386Sopenharmony_ci const SkTextBlobBuilder::RunBuffer& rb = builder.allocRunPosH(font, count, offset.y(), 281cb93a386Sopenharmony_ci bounds); 282cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 283cb93a386Sopenharmony_ci rb.glyphs[i] = i; 284cb93a386Sopenharmony_ci rb.pos[i] = SkIntToScalar(i); 285cb93a386Sopenharmony_ci } 286cb93a386Sopenharmony_ci } break; 287cb93a386Sopenharmony_ci case SkTextBlobRunIterator::kFull_Positioning: { 288cb93a386Sopenharmony_ci const SkTextBlobBuilder::RunBuffer& rb = builder.allocRunPos(font, count, bounds); 289cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 290cb93a386Sopenharmony_ci rb.glyphs[i] = i; 291cb93a386Sopenharmony_ci rb.pos[i * 2] = SkIntToScalar(i); 292cb93a386Sopenharmony_ci rb.pos[i * 2 + 1] = -SkIntToScalar(i); 293cb93a386Sopenharmony_ci } 294cb93a386Sopenharmony_ci } break; 295cb93a386Sopenharmony_ci default: 296cb93a386Sopenharmony_ci SK_ABORT("unhandled positioning value"); 297cb93a386Sopenharmony_ci } 298cb93a386Sopenharmony_ci } 299cb93a386Sopenharmony_ci}; 300cb93a386Sopenharmony_ci 301cb93a386Sopenharmony_ciDEF_TEST(TextBlob_builder, reporter) { 302cb93a386Sopenharmony_ci TextBlobTester::TestBuilder(reporter); 303cb93a386Sopenharmony_ci TextBlobTester::TestBounds(reporter); 304cb93a386Sopenharmony_ci} 305cb93a386Sopenharmony_ci 306cb93a386Sopenharmony_ciDEF_TEST(TextBlob_paint, reporter) { 307cb93a386Sopenharmony_ci TextBlobTester::TestPaintProps(reporter); 308cb93a386Sopenharmony_ci} 309cb93a386Sopenharmony_ci 310cb93a386Sopenharmony_ciDEF_TEST(TextBlob_extended, reporter) { 311cb93a386Sopenharmony_ci SkTextBlobBuilder textBlobBuilder; 312cb93a386Sopenharmony_ci SkFont font; 313cb93a386Sopenharmony_ci const char text1[] = "Foo"; 314cb93a386Sopenharmony_ci const char text2[] = "Bar"; 315cb93a386Sopenharmony_ci 316cb93a386Sopenharmony_ci int glyphCount = font.countText(text1, strlen(text1), SkTextEncoding::kUTF8); 317cb93a386Sopenharmony_ci SkAutoTMalloc<uint16_t> glyphs(glyphCount); 318cb93a386Sopenharmony_ci (void)font.textToGlyphs(text1, strlen(text1), SkTextEncoding::kUTF8, glyphs.get(), glyphCount); 319cb93a386Sopenharmony_ci 320cb93a386Sopenharmony_ci auto run = textBlobBuilder.allocRunText(font, glyphCount, 0, 0, SkToInt(strlen(text2))); 321cb93a386Sopenharmony_ci memcpy(run.glyphs, glyphs.get(), sizeof(uint16_t) * glyphCount); 322cb93a386Sopenharmony_ci memcpy(run.utf8text, text2, strlen(text2)); 323cb93a386Sopenharmony_ci for (int i = 0; i < glyphCount; ++i) { 324cb93a386Sopenharmony_ci run.clusters[i] = std::min(SkToU32(i), SkToU32(strlen(text2))); 325cb93a386Sopenharmony_ci } 326cb93a386Sopenharmony_ci sk_sp<SkTextBlob> blob(textBlobBuilder.make()); 327cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, blob); 328cb93a386Sopenharmony_ci 329cb93a386Sopenharmony_ci for (SkTextBlobRunIterator it(blob.get()); !it.done(); it.next()) { 330cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, it.glyphCount() == (uint32_t)glyphCount); 331cb93a386Sopenharmony_ci for (uint32_t i = 0; i < it.glyphCount(); ++i) { 332cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, it.glyphs()[i] == glyphs[i]); 333cb93a386Sopenharmony_ci } 334cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkTextBlobRunIterator::kDefault_Positioning == it.positioning()); 335cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (SkPoint{0.0f, 0.0f}) == it.offset()); 336cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, it.textSize() > 0); 337cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, it.clusters()); 338cb93a386Sopenharmony_ci for (uint32_t i = 0; i < it.glyphCount(); ++i) { 339cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, i == it.clusters()[i]); 340cb93a386Sopenharmony_ci } 341cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == strncmp(text2, it.text(), it.textSize())); 342cb93a386Sopenharmony_ci } 343cb93a386Sopenharmony_ci} 344cb93a386Sopenharmony_ci 345cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////// 346cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 347cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 348cb93a386Sopenharmony_ci#include "include/private/SkTArray.h" 349cb93a386Sopenharmony_ci 350cb93a386Sopenharmony_cistatic void add_run(SkTextBlobBuilder* builder, const char text[], SkScalar x, SkScalar y, 351cb93a386Sopenharmony_ci sk_sp<SkTypeface> tf) { 352cb93a386Sopenharmony_ci SkFont font; 353cb93a386Sopenharmony_ci font.setEdging(SkFont::Edging::kAntiAlias); 354cb93a386Sopenharmony_ci font.setSubpixel(true); 355cb93a386Sopenharmony_ci font.setSize(16); 356cb93a386Sopenharmony_ci font.setTypeface(tf); 357cb93a386Sopenharmony_ci 358cb93a386Sopenharmony_ci int glyphCount = font.countText(text, strlen(text), SkTextEncoding::kUTF8); 359cb93a386Sopenharmony_ci 360cb93a386Sopenharmony_ci SkTextBlobBuilder::RunBuffer buffer = builder->allocRun(font, glyphCount, x, y); 361cb93a386Sopenharmony_ci 362cb93a386Sopenharmony_ci (void)font.textToGlyphs(text, strlen(text), SkTextEncoding::kUTF8, buffer.glyphs, glyphCount); 363cb93a386Sopenharmony_ci} 364cb93a386Sopenharmony_ci 365cb93a386Sopenharmony_cistatic sk_sp<SkImage> render(const SkTextBlob* blob) { 366cb93a386Sopenharmony_ci auto surf = SkSurface::MakeRasterN32Premul(SkScalarRoundToInt(blob->bounds().width()), 367cb93a386Sopenharmony_ci SkScalarRoundToInt(blob->bounds().height())); 368cb93a386Sopenharmony_ci if (!surf) { 369cb93a386Sopenharmony_ci return nullptr; // bounds are empty? 370cb93a386Sopenharmony_ci } 371cb93a386Sopenharmony_ci surf->getCanvas()->clear(SK_ColorWHITE); 372cb93a386Sopenharmony_ci surf->getCanvas()->drawTextBlob(blob, -blob->bounds().left(), -blob->bounds().top(), SkPaint()); 373cb93a386Sopenharmony_ci return surf->makeImageSnapshot(); 374cb93a386Sopenharmony_ci} 375cb93a386Sopenharmony_ci 376cb93a386Sopenharmony_cistatic sk_sp<SkData> SerializeTypeface(SkTypeface* tf, void* ctx) { 377cb93a386Sopenharmony_ci auto array = (SkTArray<sk_sp<SkTypeface>>*)ctx; 378cb93a386Sopenharmony_ci const size_t idx = array->size(); 379cb93a386Sopenharmony_ci array->emplace_back(sk_ref_sp(tf)); 380cb93a386Sopenharmony_ci // In this test, we are deserializing on the same machine, so we don't worry about endianness. 381cb93a386Sopenharmony_ci return SkData::MakeWithCopy(&idx, sizeof(idx)); 382cb93a386Sopenharmony_ci} 383cb93a386Sopenharmony_ci 384cb93a386Sopenharmony_cistatic sk_sp<SkTypeface> DeserializeTypeface(const void* data, size_t length, void* ctx) { 385cb93a386Sopenharmony_ci auto array = (SkTArray<sk_sp<SkTypeface>>*)ctx; 386cb93a386Sopenharmony_ci if (length != sizeof(size_t)) { 387cb93a386Sopenharmony_ci SkASSERT(false); 388cb93a386Sopenharmony_ci return nullptr; 389cb93a386Sopenharmony_ci } 390cb93a386Sopenharmony_ci size_t idx = *reinterpret_cast<const size_t*>(data); 391cb93a386Sopenharmony_ci if (idx >= array->size()) { 392cb93a386Sopenharmony_ci SkASSERT(false); 393cb93a386Sopenharmony_ci return nullptr; 394cb93a386Sopenharmony_ci } 395cb93a386Sopenharmony_ci return (*array)[idx]; 396cb93a386Sopenharmony_ci} 397cb93a386Sopenharmony_ci 398cb93a386Sopenharmony_ci/* 399cb93a386Sopenharmony_ci * Build a blob with more than one typeface. 400cb93a386Sopenharmony_ci * Draw it into an offscreen, 401cb93a386Sopenharmony_ci * then serialize and deserialize, 402cb93a386Sopenharmony_ci * Then draw the new instance and assert it draws the same as the original. 403cb93a386Sopenharmony_ci */ 404cb93a386Sopenharmony_ciDEF_TEST(TextBlob_serialize, reporter) { 405cb93a386Sopenharmony_ci sk_sp<SkTextBlob> blob0 = []() { 406cb93a386Sopenharmony_ci sk_sp<SkTypeface> tf = SkTypeface::MakeFromName(nullptr, SkFontStyle::BoldItalic()); 407cb93a386Sopenharmony_ci 408cb93a386Sopenharmony_ci SkTextBlobBuilder builder; 409cb93a386Sopenharmony_ci add_run(&builder, "Hello", 10, 20, nullptr); // don't flatten a typeface 410cb93a386Sopenharmony_ci add_run(&builder, "World", 10, 40, tf); // do flatten this typeface 411cb93a386Sopenharmony_ci return builder.make(); 412cb93a386Sopenharmony_ci }(); 413cb93a386Sopenharmony_ci 414cb93a386Sopenharmony_ci SkTArray<sk_sp<SkTypeface>> array; 415cb93a386Sopenharmony_ci SkSerialProcs serializeProcs; 416cb93a386Sopenharmony_ci serializeProcs.fTypefaceProc = &SerializeTypeface; 417cb93a386Sopenharmony_ci serializeProcs.fTypefaceCtx = (void*) &array; 418cb93a386Sopenharmony_ci sk_sp<SkData> data = blob0->serialize(serializeProcs); 419cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, array.count() == 1); 420cb93a386Sopenharmony_ci SkDeserialProcs deserializeProcs; 421cb93a386Sopenharmony_ci deserializeProcs.fTypefaceProc = &DeserializeTypeface; 422cb93a386Sopenharmony_ci deserializeProcs.fTypefaceCtx = (void*) &array; 423cb93a386Sopenharmony_ci sk_sp<SkTextBlob> blob1 = SkTextBlob::Deserialize(data->data(), data->size(), deserializeProcs); 424cb93a386Sopenharmony_ci 425cb93a386Sopenharmony_ci sk_sp<SkImage> img0 = render(blob0.get()); 426cb93a386Sopenharmony_ci sk_sp<SkImage> img1 = render(blob1.get()); 427cb93a386Sopenharmony_ci if (img0 && img1) { 428cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, ToolUtils::equal_pixels(img0.get(), img1.get())); 429cb93a386Sopenharmony_ci } 430cb93a386Sopenharmony_ci} 431cb93a386Sopenharmony_ci 432cb93a386Sopenharmony_ciDEF_TEST(TextBlob_MakeAsDrawText, reporter) { 433cb93a386Sopenharmony_ci const char text[] = "Hello"; 434cb93a386Sopenharmony_ci auto blob = SkTextBlob::MakeFromString(text, SkFont(), SkTextEncoding::kUTF8); 435cb93a386Sopenharmony_ci 436cb93a386Sopenharmony_ci int runs = 0; 437cb93a386Sopenharmony_ci for(SkTextBlobRunIterator it(blob.get()); !it.done(); it.next()) { 438cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, it.glyphCount() == strlen(text)); 439cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, it.positioning() == SkTextBlobRunIterator::kFull_Positioning); 440cb93a386Sopenharmony_ci runs += 1; 441cb93a386Sopenharmony_ci } 442cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, runs == 1); 443cb93a386Sopenharmony_ci 444cb93a386Sopenharmony_ci} 445cb93a386Sopenharmony_ci 446cb93a386Sopenharmony_ciDEF_TEST(TextBlob_iter, reporter) { 447cb93a386Sopenharmony_ci sk_sp<SkTypeface> tf = SkTypeface::MakeFromName(nullptr, SkFontStyle::BoldItalic()); 448cb93a386Sopenharmony_ci 449cb93a386Sopenharmony_ci SkTextBlobBuilder builder; 450cb93a386Sopenharmony_ci add_run(&builder, "Hello", 10, 20, nullptr); 451cb93a386Sopenharmony_ci add_run(&builder, "World", 10, 40, tf); 452cb93a386Sopenharmony_ci auto blob = builder.make(); 453cb93a386Sopenharmony_ci 454cb93a386Sopenharmony_ci SkTextBlob::Iter::Run expected[] = { 455cb93a386Sopenharmony_ci { nullptr, 5, nullptr }, 456cb93a386Sopenharmony_ci { tf.get(), 5, nullptr }, 457cb93a386Sopenharmony_ci }; 458cb93a386Sopenharmony_ci 459cb93a386Sopenharmony_ci SkTextBlob::Iter iter(*blob); 460cb93a386Sopenharmony_ci SkTextBlob::Iter::Run run; 461cb93a386Sopenharmony_ci for (auto exp : expected) { 462cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, iter.next(&run)); 463cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, run.fTypeface == exp.fTypeface); 464cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, run.fGlyphCount == exp.fGlyphCount); 465cb93a386Sopenharmony_ci for (int i = 0; i < run.fGlyphCount; ++i) { 466cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, run.fGlyphIndices[i] != 0); 467cb93a386Sopenharmony_ci } 468cb93a386Sopenharmony_ci } 469cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !iter.next(&run)); // we're done 470cb93a386Sopenharmony_ci 471cb93a386Sopenharmony_ci SkTextBlob::Iter iter2(*blob); 472cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, iter2.next(&run)); 473cb93a386Sopenharmony_ci // Hello should have the same glyph repeated for the 'l' 474cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, run.fGlyphIndices[2] == run.fGlyphIndices[3]); 475cb93a386Sopenharmony_ci} 476cb93a386Sopenharmony_ci 477cb93a386Sopenharmony_ciDEF_TEST(TextBlob_getIntercepts, reporter) { 478cb93a386Sopenharmony_ci SkFont font; 479cb93a386Sopenharmony_ci font.setSize(16); 480cb93a386Sopenharmony_ci 481cb93a386Sopenharmony_ci SkPoint lowPos[1] = { SkPoint::Make(0, 5) }; 482cb93a386Sopenharmony_ci SkPoint highPos[1] = { SkPoint::Make(0, -8) }; 483cb93a386Sopenharmony_ci SkPoint zeroPos[1] = { SkPoint::Make(0, 0) }; 484cb93a386Sopenharmony_ci 485cb93a386Sopenharmony_ci // 'x' sitting on baseline 486cb93a386Sopenharmony_ci auto blobZeroX = SkTextBlob::MakeFromPosText("x", 1, zeroPos, font); 487cb93a386Sopenharmony_ci // 'x' lowered to intersect baseline 488cb93a386Sopenharmony_ci auto blobLowX = SkTextBlob::MakeFromPosText("x", 1, lowPos, font); 489cb93a386Sopenharmony_ci // 'y' sitting on baseline 490cb93a386Sopenharmony_ci auto blobZeroY = SkTextBlob::MakeFromPosText("y", 1, zeroPos, font); 491cb93a386Sopenharmony_ci // 'y' raised to not intersect baseline 492cb93a386Sopenharmony_ci auto blobHighY = SkTextBlob::MakeFromPosText("y", 1, highPos, font); 493cb93a386Sopenharmony_ci 494cb93a386Sopenharmony_ci // bounds right below baseline 495cb93a386Sopenharmony_ci SkScalar bounds[2] = { 1, 2 }; 496cb93a386Sopenharmony_ci 497cb93a386Sopenharmony_ci // 'x' on baseline should not intersect 498cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, blobZeroX->getIntercepts(bounds, nullptr) == 0); 499cb93a386Sopenharmony_ci // lowered 'x' should intersect 500cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, blobLowX->getIntercepts(bounds, nullptr) == 2); 501cb93a386Sopenharmony_ci // 'y' on baseline should intersect 502cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, blobZeroY->getIntercepts(bounds, nullptr) == 2); 503cb93a386Sopenharmony_ci // raised 'y' should not intersect 504cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, blobHighY->getIntercepts(bounds, nullptr) == 0); 505cb93a386Sopenharmony_ci} 506