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 "gm/gm.h" 9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 10cb93a386Sopenharmony_ci#include "include/core/SkColor.h" 11cb93a386Sopenharmony_ci#include "include/core/SkColorSpace.h" 12cb93a386Sopenharmony_ci#include "include/core/SkFont.h" 13cb93a386Sopenharmony_ci#include "include/core/SkFontStyle.h" 14cb93a386Sopenharmony_ci#include "include/core/SkFontTypes.h" 15cb93a386Sopenharmony_ci#include "include/core/SkImageInfo.h" 16cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 17cb93a386Sopenharmony_ci#include "include/core/SkRect.h" 18cb93a386Sopenharmony_ci#include "include/core/SkRefCnt.h" 19cb93a386Sopenharmony_ci#include "include/core/SkScalar.h" 20cb93a386Sopenharmony_ci#include "include/core/SkSize.h" 21cb93a386Sopenharmony_ci#include "include/core/SkString.h" 22cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 23cb93a386Sopenharmony_ci#include "include/core/SkSurfaceProps.h" 24cb93a386Sopenharmony_ci#include "include/core/SkTextBlob.h" 25cb93a386Sopenharmony_ci#include "include/core/SkTypeface.h" 26cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 27cb93a386Sopenharmony_ci#include "include/gpu/GrRecordingContext.h" 28cb93a386Sopenharmony_ci#include "tools/ToolUtils.h" 29cb93a386Sopenharmony_ci#include "tools/fonts/RandomScalerContext.h" 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ci#include <string.h> 32cb93a386Sopenharmony_ci#include <utility> 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_cinamespace skiagm { 35cb93a386Sopenharmony_ciclass TextBlobRandomFont : public GM { 36cb93a386Sopenharmony_cipublic: 37cb93a386Sopenharmony_ci // This gm tests that textblobs can be translated and scaled with a font that returns random 38cb93a386Sopenharmony_ci // but deterministic masks 39cb93a386Sopenharmony_ci TextBlobRandomFont() { } 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ciprotected: 42cb93a386Sopenharmony_ci void onOnceBeforeDraw() override { 43cb93a386Sopenharmony_ci SkTextBlobBuilder builder; 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci const char* text = "The quick brown fox jumps over the lazy dog."; 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci SkPaint paint; 48cb93a386Sopenharmony_ci paint.setAntiAlias(true); 49cb93a386Sopenharmony_ci paint.setColor(SK_ColorMAGENTA); 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci // make textbloben 52cb93a386Sopenharmony_ci SkFont font; 53cb93a386Sopenharmony_ci font.setSize(32); 54cb93a386Sopenharmony_ci font.setEdging(SkFont::Edging::kSubpixelAntiAlias); 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci // Setup our random scaler context 57cb93a386Sopenharmony_ci auto typeface = ToolUtils::create_portable_typeface("sans-serif", SkFontStyle::Bold()); 58cb93a386Sopenharmony_ci if (!typeface) { 59cb93a386Sopenharmony_ci typeface = SkTypeface::MakeDefault(); 60cb93a386Sopenharmony_ci } 61cb93a386Sopenharmony_ci font.setTypeface(sk_make_sp<SkRandomTypeface>(std::move(typeface), paint, false)); 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_ci SkScalar y = 0; 64cb93a386Sopenharmony_ci SkRect bounds; 65cb93a386Sopenharmony_ci font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds); 66cb93a386Sopenharmony_ci y -= bounds.fTop; 67cb93a386Sopenharmony_ci ToolUtils::add_to_text_blob(&builder, text, font, 0, y); 68cb93a386Sopenharmony_ci y += bounds.fBottom; 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci // A8 71cb93a386Sopenharmony_ci const char* bigtext1 = "The quick brown fox"; 72cb93a386Sopenharmony_ci const char* bigtext2 = "jumps over the lazy dog."; 73cb93a386Sopenharmony_ci font.setSize(160); 74cb93a386Sopenharmony_ci font.setSubpixel(false); 75cb93a386Sopenharmony_ci font.setEdging(SkFont::Edging::kAntiAlias); 76cb93a386Sopenharmony_ci font.measureText(bigtext1, strlen(bigtext1), SkTextEncoding::kUTF8, &bounds); 77cb93a386Sopenharmony_ci y -= bounds.fTop; 78cb93a386Sopenharmony_ci ToolUtils::add_to_text_blob(&builder, bigtext1, font, 0, y); 79cb93a386Sopenharmony_ci y += bounds.fBottom; 80cb93a386Sopenharmony_ci 81cb93a386Sopenharmony_ci font.measureText(bigtext2, strlen(bigtext2), SkTextEncoding::kUTF8, &bounds); 82cb93a386Sopenharmony_ci y -= bounds.fTop; 83cb93a386Sopenharmony_ci ToolUtils::add_to_text_blob(&builder, bigtext2, font, 0, y); 84cb93a386Sopenharmony_ci y += bounds.fBottom; 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ci // color emoji 87cb93a386Sopenharmony_ci if (sk_sp<SkTypeface> origEmoji = ToolUtils::emoji_typeface()) { 88cb93a386Sopenharmony_ci font.setTypeface(sk_make_sp<SkRandomTypeface>(origEmoji, paint, false)); 89cb93a386Sopenharmony_ci const char* emojiText = ToolUtils::emoji_sample_text(); 90cb93a386Sopenharmony_ci font.measureText(emojiText, strlen(emojiText), SkTextEncoding::kUTF8, &bounds); 91cb93a386Sopenharmony_ci y -= bounds.fTop; 92cb93a386Sopenharmony_ci ToolUtils::add_to_text_blob(&builder, emojiText, font, 0, y); 93cb93a386Sopenharmony_ci y += bounds.fBottom; 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci // build 97cb93a386Sopenharmony_ci fBlob = builder.make(); 98cb93a386Sopenharmony_ci } 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_ci SkString onShortName() override { 101cb93a386Sopenharmony_ci return SkString("textblobrandomfont"); 102cb93a386Sopenharmony_ci } 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ci SkISize onISize() override { 105cb93a386Sopenharmony_ci return SkISize::Make(kWidth, kHeight); 106cb93a386Sopenharmony_ci } 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ci DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override { 109cb93a386Sopenharmony_ci if (!canvas->recordingContext()) { 110cb93a386Sopenharmony_ci *errorMsg = "Active context required to create SkSurface"; 111cb93a386Sopenharmony_ci return DrawResult::kSkip; 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_ci auto dContext = GrAsDirectContext(canvas->recordingContext()); 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci // This GM exists to test a specific feature of the GPU backend. 117cb93a386Sopenharmony_ci // This GM uses ToolUtils::makeSurface which doesn't work well with vias. 118cb93a386Sopenharmony_ci // This GM uses SkRandomTypeface which doesn't work well with serialization. 119cb93a386Sopenharmony_ci canvas->drawColor(SK_ColorWHITE); 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, canvas->imageInfo().colorType(), 122cb93a386Sopenharmony_ci kPremul_SkAlphaType, 123cb93a386Sopenharmony_ci canvas->imageInfo().refColorSpace()); 124cb93a386Sopenharmony_ci SkSurfaceProps props(0, kUnknown_SkPixelGeometry); 125cb93a386Sopenharmony_ci auto surface(ToolUtils::makeSurface(canvas, info, &props)); 126cb93a386Sopenharmony_ci if (!surface) { 127cb93a386Sopenharmony_ci *errorMsg = "This test requires a surface"; 128cb93a386Sopenharmony_ci return DrawResult::kFail; 129cb93a386Sopenharmony_ci } 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_ci SkPaint paint; 132cb93a386Sopenharmony_ci paint.setAntiAlias(true); 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci SkCanvas* surfaceCanvas = surface->getCanvas(); 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_ci SkScalar stride = SkScalarCeilToScalar(fBlob->bounds().height()); 137cb93a386Sopenharmony_ci SkScalar yOffset = 5; 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci canvas->save(); 140cb93a386Sopenharmony_ci // Originally we would alternate between rotating and not to force blob regeneration, 141cb93a386Sopenharmony_ci // but that code seems to have rotted. Keeping the rotate to match the old GM as 142cb93a386Sopenharmony_ci // much as possible, and it seems like a reasonable stress test for transformed 143cb93a386Sopenharmony_ci // color emoji. 144cb93a386Sopenharmony_ci canvas->rotate(-0.05f); 145cb93a386Sopenharmony_ci canvas->drawTextBlob(fBlob, 10, yOffset, paint); 146cb93a386Sopenharmony_ci yOffset += stride; 147cb93a386Sopenharmony_ci canvas->restore(); 148cb93a386Sopenharmony_ci 149cb93a386Sopenharmony_ci // Rotate in the surface canvas, not the final canvas, to avoid aliasing 150cb93a386Sopenharmony_ci surfaceCanvas->rotate(-0.05f); 151cb93a386Sopenharmony_ci surfaceCanvas->drawTextBlob(fBlob, 10, yOffset, paint); 152cb93a386Sopenharmony_ci surface->draw(canvas, 0, 0); 153cb93a386Sopenharmony_ci yOffset += stride; 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci if (dContext) { 156cb93a386Sopenharmony_ci // free gpu resources and verify 157cb93a386Sopenharmony_ci dContext->freeGpuResources(); 158cb93a386Sopenharmony_ci } 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ci canvas->rotate(-0.05f); 161cb93a386Sopenharmony_ci canvas->drawTextBlob(fBlob, 10, yOffset, paint); 162cb93a386Sopenharmony_ci yOffset += stride; 163cb93a386Sopenharmony_ci return DrawResult::kOk; 164cb93a386Sopenharmony_ci } 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ciprivate: 167cb93a386Sopenharmony_ci sk_sp<SkTextBlob> fBlob; 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci inline static constexpr int kWidth = 2000; 170cb93a386Sopenharmony_ci inline static constexpr int kHeight = 1600; 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_ci using INHERITED = GM; 173cb93a386Sopenharmony_ci}; 174cb93a386Sopenharmony_ci 175cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 176cb93a386Sopenharmony_ci 177cb93a386Sopenharmony_ciDEF_GM(return new TextBlobRandomFont;) 178cb93a386Sopenharmony_ci} // namespace skiagm 179