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