1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2015 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 "tools/ToolUtils.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include <string> 11cb93a386Sopenharmony_ci 12cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h" 13cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 14cb93a386Sopenharmony_ci#include "include/core/SkFontMgr.h" 15cb93a386Sopenharmony_ci#include "include/core/SkGraphics.h" 16cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 17cb93a386Sopenharmony_ci#include "include/core/SkPoint.h" 18cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 19cb93a386Sopenharmony_ci#include "include/core/SkTextBlob.h" 20cb93a386Sopenharmony_ci#include "include/core/SkTypeface.h" 21cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 22cb93a386Sopenharmony_ci#include "src/core/SkGlyphRun.h" 23cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 24cb93a386Sopenharmony_ci#include "tools/fonts/RandomScalerContext.h" 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_WIN 27cb93a386Sopenharmony_ci #include "include/ports/SkTypeface_win.h" 28cb93a386Sopenharmony_ci#endif 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci#include "tests/Test.h" 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 33cb93a386Sopenharmony_ci#include "src/gpu/text/GrAtlasManager.h" 34cb93a386Sopenharmony_ci#include "src/gpu/text/GrTextBlobCache.h" 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_cistatic void draw(SkCanvas* canvas, int redraw, const SkTArray<sk_sp<SkTextBlob>>& blobs) { 37cb93a386Sopenharmony_ci int yOffset = 0; 38cb93a386Sopenharmony_ci for (int r = 0; r < redraw; r++) { 39cb93a386Sopenharmony_ci for (int i = 0; i < blobs.count(); i++) { 40cb93a386Sopenharmony_ci const auto& blob = blobs[i]; 41cb93a386Sopenharmony_ci const SkRect& bounds = blob->bounds(); 42cb93a386Sopenharmony_ci yOffset += SkScalarCeilToInt(bounds.height()); 43cb93a386Sopenharmony_ci SkPaint paint; 44cb93a386Sopenharmony_ci canvas->drawTextBlob(blob, 0, SkIntToScalar(yOffset), paint); 45cb93a386Sopenharmony_ci } 46cb93a386Sopenharmony_ci } 47cb93a386Sopenharmony_ci} 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_cistatic const int kWidth = 1024; 50cb93a386Sopenharmony_cistatic const int kHeight = 768; 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_cistatic void setup_always_evict_atlas(GrDirectContext* dContext) { 53cb93a386Sopenharmony_ci dContext->priv().getAtlasManager()->setAtlasDimensionsToMinimum_ForTesting(); 54cb93a386Sopenharmony_ci} 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ciclass GrTextBlobTestingPeer { 57cb93a386Sopenharmony_cipublic: 58cb93a386Sopenharmony_ci static void SetBudget(GrTextBlobCache* cache, size_t budget) { 59cb93a386Sopenharmony_ci SkAutoSpinlock lock{cache->fSpinLock}; 60cb93a386Sopenharmony_ci cache->fSizeBudget = budget; 61cb93a386Sopenharmony_ci cache->internalCheckPurge(); 62cb93a386Sopenharmony_ci } 63cb93a386Sopenharmony_ci}; 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci// This test hammers the GPU textblobcache and font atlas 66cb93a386Sopenharmony_cistatic void text_blob_cache_inner(skiatest::Reporter* reporter, GrDirectContext* dContext, 67cb93a386Sopenharmony_ci int maxTotalText, int maxGlyphID, int maxFamilies, bool normal, 68cb93a386Sopenharmony_ci bool stressTest) { 69cb93a386Sopenharmony_ci // setup surface 70cb93a386Sopenharmony_ci uint32_t flags = 0; 71cb93a386Sopenharmony_ci SkSurfaceProps props(flags, kRGB_H_SkPixelGeometry); 72cb93a386Sopenharmony_ci 73cb93a386Sopenharmony_ci // configure our context for maximum stressing of cache and atlas 74cb93a386Sopenharmony_ci if (stressTest) { 75cb93a386Sopenharmony_ci setup_always_evict_atlas(dContext); 76cb93a386Sopenharmony_ci GrTextBlobTestingPeer::SetBudget(dContext->priv().getTextBlobCache(), 0); 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, 80cb93a386Sopenharmony_ci kPremul_SkAlphaType); 81cb93a386Sopenharmony_ci auto surface(SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, info, 0, &props)); 82cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, surface); 83cb93a386Sopenharmony_ci if (!surface) { 84cb93a386Sopenharmony_ci return; 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ci SkCanvas* canvas = surface->getCanvas(); 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault()); 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_ci int count = std::min(fm->countFamilies(), maxFamilies); 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_ci // make a ton of text 94cb93a386Sopenharmony_ci SkAutoTArray<uint16_t> text(maxTotalText); 95cb93a386Sopenharmony_ci for (int i = 0; i < maxTotalText; i++) { 96cb93a386Sopenharmony_ci text[i] = i % maxGlyphID; 97cb93a386Sopenharmony_ci } 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci // generate textblobs 100cb93a386Sopenharmony_ci SkTArray<sk_sp<SkTextBlob>> blobs; 101cb93a386Sopenharmony_ci for (int i = 0; i < count; i++) { 102cb93a386Sopenharmony_ci SkFont font; 103cb93a386Sopenharmony_ci font.setSize(48); // draw big glyphs to really stress the atlas 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci SkString familyName; 106cb93a386Sopenharmony_ci fm->getFamilyName(i, &familyName); 107cb93a386Sopenharmony_ci sk_sp<SkFontStyleSet> set(fm->createStyleSet(i)); 108cb93a386Sopenharmony_ci for (int j = 0; j < set->count(); ++j) { 109cb93a386Sopenharmony_ci SkFontStyle fs; 110cb93a386Sopenharmony_ci set->getStyle(j, &fs, nullptr); 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci // We use a typeface which randomy returns unexpected mask formats to fuzz 113cb93a386Sopenharmony_ci sk_sp<SkTypeface> orig(set->createTypeface(j)); 114cb93a386Sopenharmony_ci if (normal) { 115cb93a386Sopenharmony_ci font.setTypeface(orig); 116cb93a386Sopenharmony_ci } else { 117cb93a386Sopenharmony_ci font.setTypeface(sk_make_sp<SkRandomTypeface>(orig, SkPaint(), true)); 118cb93a386Sopenharmony_ci } 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_ci SkTextBlobBuilder builder; 121cb93a386Sopenharmony_ci for (int aa = 0; aa < 2; aa++) { 122cb93a386Sopenharmony_ci for (int subpixel = 0; subpixel < 2; subpixel++) { 123cb93a386Sopenharmony_ci for (int lcd = 0; lcd < 2; lcd++) { 124cb93a386Sopenharmony_ci font.setEdging(SkFont::Edging::kAlias); 125cb93a386Sopenharmony_ci if (aa) { 126cb93a386Sopenharmony_ci font.setEdging(SkFont::Edging::kAntiAlias); 127cb93a386Sopenharmony_ci if (lcd) { 128cb93a386Sopenharmony_ci font.setEdging(SkFont::Edging::kSubpixelAntiAlias); 129cb93a386Sopenharmony_ci } 130cb93a386Sopenharmony_ci } 131cb93a386Sopenharmony_ci font.setSubpixel(SkToBool(subpixel)); 132cb93a386Sopenharmony_ci if (!SkToBool(lcd)) { 133cb93a386Sopenharmony_ci font.setSize(160); 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci const SkTextBlobBuilder::RunBuffer& run = builder.allocRun(font, 136cb93a386Sopenharmony_ci maxTotalText, 137cb93a386Sopenharmony_ci 0, 0, 138cb93a386Sopenharmony_ci nullptr); 139cb93a386Sopenharmony_ci memcpy(run.glyphs, text.get(), maxTotalText * sizeof(uint16_t)); 140cb93a386Sopenharmony_ci } 141cb93a386Sopenharmony_ci } 142cb93a386Sopenharmony_ci } 143cb93a386Sopenharmony_ci blobs.emplace_back(builder.make()); 144cb93a386Sopenharmony_ci } 145cb93a386Sopenharmony_ci } 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci // create surface where LCD is impossible 148cb93a386Sopenharmony_ci info = SkImageInfo::Make(kWidth, kHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 149cb93a386Sopenharmony_ci SkSurfaceProps propsNoLCD(0, kUnknown_SkPixelGeometry); 150cb93a386Sopenharmony_ci auto surfaceNoLCD(canvas->makeSurface(info, &propsNoLCD)); 151cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, surface); 152cb93a386Sopenharmony_ci if (!surface) { 153cb93a386Sopenharmony_ci return; 154cb93a386Sopenharmony_ci } 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ci SkCanvas* canvasNoLCD = surfaceNoLCD->getCanvas(); 157cb93a386Sopenharmony_ci 158cb93a386Sopenharmony_ci // test redraw 159cb93a386Sopenharmony_ci draw(canvas, 2, blobs); 160cb93a386Sopenharmony_ci draw(canvasNoLCD, 2, blobs); 161cb93a386Sopenharmony_ci 162cb93a386Sopenharmony_ci // test draw after free 163cb93a386Sopenharmony_ci dContext->freeGpuResources(); 164cb93a386Sopenharmony_ci draw(canvas, 1, blobs); 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ci dContext->freeGpuResources(); 167cb93a386Sopenharmony_ci draw(canvasNoLCD, 1, blobs); 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci // test draw after abandon 170cb93a386Sopenharmony_ci dContext->abandonContext(); 171cb93a386Sopenharmony_ci draw(canvas, 1, blobs); 172cb93a386Sopenharmony_ci} 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ci#ifdef SK_ENABLE_SMALL_PAGE 175cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_MOCK_CONTEXT(TextBlobCache, reporter, ctxInfo) { 176cb93a386Sopenharmony_ci text_blob_cache_inner(reporter, ctxInfo.directContext(), 1024, 256, 30, true, true); 177cb93a386Sopenharmony_ci} 178cb93a386Sopenharmony_ci#else 179cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_MOCK_CONTEXT(TextBlobCache, reporter, ctxInfo) { 180cb93a386Sopenharmony_ci text_blob_cache_inner(reporter, ctxInfo.directContext(), 1024, 256, 30, true, false); 181cb93a386Sopenharmony_ci} 182cb93a386Sopenharmony_ci#endif 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_MOCK_CONTEXT(TextBlobStressCache, reporter, ctxInfo) { 185cb93a386Sopenharmony_ci text_blob_cache_inner(reporter, ctxInfo.directContext(), 256, 256, 10, true, true); 186cb93a386Sopenharmony_ci} 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ci#ifdef SK_ENABLE_SMALL_PAGE 189cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_MOCK_CONTEXT(TextBlobAbnormal, reporter, ctxInfo) { 190cb93a386Sopenharmony_ci text_blob_cache_inner(reporter, ctxInfo.directContext(), 256, 256, 10, false, true); 191cb93a386Sopenharmony_ci} 192cb93a386Sopenharmony_ci#else 193cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_MOCK_CONTEXT(TextBlobAbnormal, reporter, ctxInfo) { 194cb93a386Sopenharmony_ci text_blob_cache_inner(reporter, ctxInfo.directContext(), 256, 256, 10, false, false); 195cb93a386Sopenharmony_ci} 196cb93a386Sopenharmony_ci#endif 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_MOCK_CONTEXT(TextBlobStressAbnormal, reporter, ctxInfo) { 199cb93a386Sopenharmony_ci text_blob_cache_inner(reporter, ctxInfo.directContext(), 256, 256, 10, false, true); 200cb93a386Sopenharmony_ci} 201cb93a386Sopenharmony_ci 202cb93a386Sopenharmony_cistatic const int kScreenDim = 160; 203cb93a386Sopenharmony_ci 204cb93a386Sopenharmony_cistatic SkBitmap draw_blob(SkTextBlob* blob, SkSurface* surface, SkPoint offset) { 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci SkPaint paint; 207cb93a386Sopenharmony_ci 208cb93a386Sopenharmony_ci SkCanvas* canvas = surface->getCanvas(); 209cb93a386Sopenharmony_ci canvas->save(); 210cb93a386Sopenharmony_ci canvas->drawColor(SK_ColorWHITE, SkBlendMode::kSrc); 211cb93a386Sopenharmony_ci canvas->translate(offset.fX, offset.fY); 212cb93a386Sopenharmony_ci canvas->drawTextBlob(blob, 0, 0, paint); 213cb93a386Sopenharmony_ci SkBitmap bitmap; 214cb93a386Sopenharmony_ci bitmap.allocN32Pixels(kScreenDim, kScreenDim); 215cb93a386Sopenharmony_ci surface->readPixels(bitmap, 0, 0); 216cb93a386Sopenharmony_ci canvas->restore(); 217cb93a386Sopenharmony_ci return bitmap; 218cb93a386Sopenharmony_ci} 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_cistatic bool compare_bitmaps(const SkBitmap& expected, const SkBitmap& actual) { 221cb93a386Sopenharmony_ci SkASSERT(expected.width() == actual.width()); 222cb93a386Sopenharmony_ci SkASSERT(expected.height() == actual.height()); 223cb93a386Sopenharmony_ci for (int i = 0; i < expected.width(); ++i) { 224cb93a386Sopenharmony_ci for (int j = 0; j < expected.height(); ++j) { 225cb93a386Sopenharmony_ci SkColor expectedColor = expected.getColor(i, j); 226cb93a386Sopenharmony_ci SkColor actualColor = actual.getColor(i, j); 227cb93a386Sopenharmony_ci if (expectedColor != actualColor) { 228cb93a386Sopenharmony_ci return false; 229cb93a386Sopenharmony_ci } 230cb93a386Sopenharmony_ci } 231cb93a386Sopenharmony_ci } 232cb93a386Sopenharmony_ci return true; 233cb93a386Sopenharmony_ci} 234cb93a386Sopenharmony_ci 235cb93a386Sopenharmony_cistatic sk_sp<SkTextBlob> make_blob() { 236cb93a386Sopenharmony_ci auto tf = SkTypeface::MakeFromName("Roboto2-Regular", SkFontStyle()); 237cb93a386Sopenharmony_ci SkFont font; 238cb93a386Sopenharmony_ci font.setTypeface(tf); 239cb93a386Sopenharmony_ci font.setSubpixel(false); 240cb93a386Sopenharmony_ci font.setEdging(SkFont::Edging::kAlias); 241cb93a386Sopenharmony_ci font.setSize(24); 242cb93a386Sopenharmony_ci 243cb93a386Sopenharmony_ci static char text[] = "HekpqB"; 244cb93a386Sopenharmony_ci static const int maxGlyphLen = sizeof(text) * 4; 245cb93a386Sopenharmony_ci SkGlyphID glyphs[maxGlyphLen]; 246cb93a386Sopenharmony_ci int glyphCount = 247cb93a386Sopenharmony_ci font.textToGlyphs(text, sizeof(text), SkTextEncoding::kUTF8, glyphs, maxGlyphLen); 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci SkTextBlobBuilder builder; 250cb93a386Sopenharmony_ci const auto& runBuffer = builder.allocRun(font, glyphCount, 0, 0); 251cb93a386Sopenharmony_ci for (int i = 0; i < glyphCount; i++) { 252cb93a386Sopenharmony_ci runBuffer.glyphs[i] = glyphs[i]; 253cb93a386Sopenharmony_ci } 254cb93a386Sopenharmony_ci return builder.make(); 255cb93a386Sopenharmony_ci} 256cb93a386Sopenharmony_ci 257cb93a386Sopenharmony_ci// Turned off to pass on android and ios devices, which were running out of memory.. 258cb93a386Sopenharmony_ci#if 0 259cb93a386Sopenharmony_cistatic sk_sp<SkTextBlob> make_large_blob() { 260cb93a386Sopenharmony_ci auto tf = SkTypeface::MakeFromName("Roboto2-Regular", SkFontStyle()); 261cb93a386Sopenharmony_ci SkFont font; 262cb93a386Sopenharmony_ci font.setTypeface(tf); 263cb93a386Sopenharmony_ci font.setSubpixel(false); 264cb93a386Sopenharmony_ci font.setEdging(SkFont::Edging::kAlias); 265cb93a386Sopenharmony_ci font.setSize(24); 266cb93a386Sopenharmony_ci 267cb93a386Sopenharmony_ci const int mallocSize = 0x3c3c3bd; // x86 size 268cb93a386Sopenharmony_ci std::unique_ptr<char[]> text{new char[mallocSize + 1]}; 269cb93a386Sopenharmony_ci if (text == nullptr) { 270cb93a386Sopenharmony_ci return nullptr; 271cb93a386Sopenharmony_ci } 272cb93a386Sopenharmony_ci for (int i = 0; i < mallocSize; i++) { 273cb93a386Sopenharmony_ci text[i] = 'x'; 274cb93a386Sopenharmony_ci } 275cb93a386Sopenharmony_ci text[mallocSize] = 0; 276cb93a386Sopenharmony_ci 277cb93a386Sopenharmony_ci static const int maxGlyphLen = mallocSize; 278cb93a386Sopenharmony_ci std::unique_ptr<SkGlyphID[]> glyphs{new SkGlyphID[maxGlyphLen]}; 279cb93a386Sopenharmony_ci int glyphCount = 280cb93a386Sopenharmony_ci font.textToGlyphs( 281cb93a386Sopenharmony_ci text.get(), mallocSize, SkTextEncoding::kUTF8, glyphs.get(), maxGlyphLen); 282cb93a386Sopenharmony_ci SkTextBlobBuilder builder; 283cb93a386Sopenharmony_ci const auto& runBuffer = builder.allocRun(font, glyphCount, 0, 0); 284cb93a386Sopenharmony_ci for (int i = 0; i < glyphCount; i++) { 285cb93a386Sopenharmony_ci runBuffer.glyphs[i] = glyphs[i]; 286cb93a386Sopenharmony_ci } 287cb93a386Sopenharmony_ci return builder.make(); 288cb93a386Sopenharmony_ci} 289cb93a386Sopenharmony_ci 290cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextBlobIntegerOverflowTest, reporter, ctxInfo) { 291cb93a386Sopenharmony_ci auto dContext = ctxInfo.directContext(); 292cb93a386Sopenharmony_ci const SkImageInfo info = 293cb93a386Sopenharmony_ci SkImageInfo::Make(kScreenDim, kScreenDim, kN32_SkColorType, kPremul_SkAlphaType); 294cb93a386Sopenharmony_ci auto surface = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, info); 295cb93a386Sopenharmony_ci 296cb93a386Sopenharmony_ci auto blob = make_large_blob(); 297cb93a386Sopenharmony_ci int y = 40; 298cb93a386Sopenharmony_ci SkBitmap base = draw_blob(blob.get(), surface.get(), {40, y + 0.0f}); 299cb93a386Sopenharmony_ci} 300cb93a386Sopenharmony_ci#endif 301cb93a386Sopenharmony_ci 302cb93a386Sopenharmony_cistatic const bool kDumpPngs = true; 303cb93a386Sopenharmony_ci// dump pngs needs a "good" and a "bad" directory to put the results in. This allows the use of the 304cb93a386Sopenharmony_ci// skdiff tool to visualize the differences. 305cb93a386Sopenharmony_ci 306cb93a386Sopenharmony_civoid write_png(const std::string& filename, const SkBitmap& bitmap) { 307cb93a386Sopenharmony_ci auto data = SkEncodeBitmap(bitmap, SkEncodedImageFormat::kPNG, 0); 308cb93a386Sopenharmony_ci SkFILEWStream w{filename.c_str()}; 309cb93a386Sopenharmony_ci w.write(data->data(), data->size()); 310cb93a386Sopenharmony_ci w.fsync(); 311cb93a386Sopenharmony_ci} 312cb93a386Sopenharmony_ci 313cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextBlobJaggedGlyph, reporter, ctxInfo) { 314cb93a386Sopenharmony_ci auto direct = ctxInfo.directContext(); 315cb93a386Sopenharmony_ci const SkImageInfo info = 316cb93a386Sopenharmony_ci SkImageInfo::Make(kScreenDim, kScreenDim, kN32_SkColorType, kPremul_SkAlphaType); 317cb93a386Sopenharmony_ci auto surface = SkSurface::MakeRenderTarget(direct, SkBudgeted::kNo, info); 318cb93a386Sopenharmony_ci 319cb93a386Sopenharmony_ci auto blob = make_blob(); 320cb93a386Sopenharmony_ci 321cb93a386Sopenharmony_ci for (int y = 40; y < kScreenDim - 40; y++) { 322cb93a386Sopenharmony_ci SkBitmap base = draw_blob(blob.get(), surface.get(), {40, y + 0.0f}); 323cb93a386Sopenharmony_ci SkBitmap half = draw_blob(blob.get(), surface.get(), {40, y + 0.5f}); 324cb93a386Sopenharmony_ci SkBitmap unit = draw_blob(blob.get(), surface.get(), {40, y + 1.0f}); 325cb93a386Sopenharmony_ci bool isOk = compare_bitmaps(base, half) || compare_bitmaps(unit, half); 326cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, isOk); 327cb93a386Sopenharmony_ci if (!isOk) { 328cb93a386Sopenharmony_ci if (kDumpPngs) { 329cb93a386Sopenharmony_ci { 330cb93a386Sopenharmony_ci std::string filename = "bad/half-y" + std::to_string(y) + ".png"; 331cb93a386Sopenharmony_ci write_png(filename, half); 332cb93a386Sopenharmony_ci } 333cb93a386Sopenharmony_ci { 334cb93a386Sopenharmony_ci std::string filename = "good/half-y" + std::to_string(y) + ".png"; 335cb93a386Sopenharmony_ci write_png(filename, base); 336cb93a386Sopenharmony_ci } 337cb93a386Sopenharmony_ci } 338cb93a386Sopenharmony_ci break; 339cb93a386Sopenharmony_ci } 340cb93a386Sopenharmony_ci } 341cb93a386Sopenharmony_ci 342cb93a386Sopenharmony_ci // Testing the x direction across all platforms does not workout, because letter spacing can 343cb93a386Sopenharmony_ci // change based on non-integer advance widths, but this has been useful for diagnosing problems. 344cb93a386Sopenharmony_ci#if 0 345cb93a386Sopenharmony_ci blob = make_blob(); 346cb93a386Sopenharmony_ci for (int x = 40; x < kScreenDim - 40; x++) { 347cb93a386Sopenharmony_ci SkBitmap base = draw_blob(blob.get(), surface.get(), {x + 0.0f, 40}); 348cb93a386Sopenharmony_ci SkBitmap half = draw_blob(blob.get(), surface.get(), {x + 0.5f, 40}); 349cb93a386Sopenharmony_ci SkBitmap unit = draw_blob(blob.get(), surface.get(), {x + 1.0f, 40}); 350cb93a386Sopenharmony_ci bool isOk = compare_bitmaps(base, half) || compare_bitmaps(unit, half); 351cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, isOk); 352cb93a386Sopenharmony_ci if (!isOk) { 353cb93a386Sopenharmony_ci if (kDumpPngs) { 354cb93a386Sopenharmony_ci { 355cb93a386Sopenharmony_ci std::string filename = "bad/half-x" + std::to_string(x) + ".png"; 356cb93a386Sopenharmony_ci write_png(filename, half); 357cb93a386Sopenharmony_ci } 358cb93a386Sopenharmony_ci { 359cb93a386Sopenharmony_ci std::string filename = "good/half-x" + std::to_string(x) + ".png"; 360cb93a386Sopenharmony_ci write_png(filename, base); 361cb93a386Sopenharmony_ci } 362cb93a386Sopenharmony_ci } 363cb93a386Sopenharmony_ci break; 364cb93a386Sopenharmony_ci } 365cb93a386Sopenharmony_ci } 366cb93a386Sopenharmony_ci#endif 367cb93a386Sopenharmony_ci} 368cb93a386Sopenharmony_ci 369cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextBlobSmoothScroll, reporter, ctxInfo) { 370cb93a386Sopenharmony_ci auto direct = ctxInfo.directContext(); 371cb93a386Sopenharmony_ci const SkImageInfo info = 372cb93a386Sopenharmony_ci SkImageInfo::Make(kScreenDim, kScreenDim, kN32_SkColorType, kPremul_SkAlphaType); 373cb93a386Sopenharmony_ci auto surface = SkSurface::MakeRenderTarget(direct, SkBudgeted::kNo, info); 374cb93a386Sopenharmony_ci 375cb93a386Sopenharmony_ci auto movingBlob = make_blob(); 376cb93a386Sopenharmony_ci 377cb93a386Sopenharmony_ci for (SkScalar y = 40; y < 50; y += 1.0/8.0) { 378cb93a386Sopenharmony_ci auto expectedBlob = make_blob(); 379cb93a386Sopenharmony_ci auto expectedBitMap = draw_blob(expectedBlob.get(), surface.get(), {40, y}); 380cb93a386Sopenharmony_ci auto movingBitmap = draw_blob(movingBlob.get(), surface.get(), {40, y}); 381cb93a386Sopenharmony_ci bool isOk = compare_bitmaps(expectedBitMap, movingBitmap); 382cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, isOk); 383cb93a386Sopenharmony_ci if (!isOk) { 384cb93a386Sopenharmony_ci if (kDumpPngs) { 385cb93a386Sopenharmony_ci { 386cb93a386Sopenharmony_ci std::string filename = "bad/scroll-y" + std::to_string(y) + ".png"; 387cb93a386Sopenharmony_ci write_png(filename, movingBitmap); 388cb93a386Sopenharmony_ci } 389cb93a386Sopenharmony_ci { 390cb93a386Sopenharmony_ci std::string filename = "good/scroll-y" + std::to_string(y) + ".png"; 391cb93a386Sopenharmony_ci write_png(filename, expectedBitMap); 392cb93a386Sopenharmony_ci } 393cb93a386Sopenharmony_ci } 394cb93a386Sopenharmony_ci break; 395cb93a386Sopenharmony_ci } 396cb93a386Sopenharmony_ci } 397cb93a386Sopenharmony_ci} 398