15c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon/*
25c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon * Copyright 2017 Google Inc.
35c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon *
45c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon * Use of this source code is governed by a BSD-style license that can be
55c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon * found in the LICENSE file.
65c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon */
75c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon
85c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon#include "gm.h"
95c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon#include "Resources.h"
105c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon#include "SkCanvas.h"
115c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon#include "SkSurface.h"
125c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon#include "SkTextBlob.h"
135c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon#include "SkTypeface.h"
145c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon#include "sk_tool_utils.h"
155c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon
165c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon/**
175c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon * This GM tests reusing the same text blobs with distance fields rendering using various
185c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon * combinations of perspective and non-perspetive matrices, scissor clips, and different x,y params
195c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon * passed to the draw.
205c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon */
215c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomonclass DFTextBlobPerspGM : public skiagm::GM {
225c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomonpublic:
235c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon    DFTextBlobPerspGM() { this->setBGColor(0xFFFFFFFF); }
245c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon
255c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomonprotected:
265c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon    SkString onShortName() override {
275c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        SkString name("dftext_blob_persp");
285c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        name.append(sk_tool_utils::platform_font_manager());
295c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        return name;
305c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon    }
315c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon
325c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon    SkISize onISize() override { return SkISize::Make(900, 350); }
335c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon
345c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon    void onOnceBeforeDraw() override {
355c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        for (int i = 0; i < 3; ++i) {
365c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            SkPaint paint;
375c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            paint.setTextSize(32);
385c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            paint.setAntiAlias(i > 0);
395c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            paint.setLCDRenderText(i > 1);
405c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            paint.setSubpixelText(true);
415c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            SkTextBlobBuilder builder;
425c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            sk_tool_utils::add_to_text_blob(&builder, "SkiaText", paint, 0, 0);
435c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            fBlobs.emplace_back(builder.make());
445c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        }
455c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon    }
465c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon
475c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon    virtual void onDraw(SkCanvas* inputCanvas) override {
485c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon    // set up offscreen rendering with distance field text
495c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon#if SK_SUPPORT_GPU
505c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        GrContext* ctx = inputCanvas->getGrContext();
515c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        SkISize size = this->onISize();
525c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        if (!inputCanvas->getBaseLayerSize().isEmpty()) {
535c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            size = inputCanvas->getBaseLayerSize();
545c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        }
555c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        SkImageInfo info = SkImageInfo::MakeN32(size.width(), size.height(), kPremul_SkAlphaType,
565c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                                                inputCanvas->imageInfo().refColorSpace());
575c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        SkSurfaceProps props(SkSurfaceProps::kUseDeviceIndependentFonts_Flag,
585c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                             SkSurfaceProps::kLegacyFontHost_InitType);
595c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        auto surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info, 0, &props);
605c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        SkCanvas* canvas = surface ? surface->getCanvas() : inputCanvas;
615c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        // init our new canvas with the old canvas's matrix
625c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        canvas->setMatrix(inputCanvas->getTotalMatrix());
635c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon#else
645c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        SkCanvas* canvas = inputCanvas;
655c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon#endif
665c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        SkScalar x = 0, y = 0;
675c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        SkScalar maxH = 0;
685c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        for (auto twm : {TranslateWithMatrix::kNo, TranslateWithMatrix::kYes}) {
695c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            for (auto pm : {PerspMode::kNone, PerspMode::kX, PerspMode::kY, PerspMode::kXY}) {
705c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                for (auto& blob : fBlobs) {
715c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                    for (bool clip : {false, true}) {
725c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                        canvas->save();
735c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                        SkScalar w = blob->bounds().width();
745c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                        SkScalar h = blob->bounds().height();
755c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                        if (clip) {
765c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                            auto rect =
775c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                                    SkRect::MakeXYWH(x + 5, y + 5, w * 3.f / 4.f, h * 3.f / 4.f);
785c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                            canvas->clipRect(rect, false);
795c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                        }
805c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                        this->drawBlob(canvas, blob.get(), SK_ColorBLACK, x, y + h, pm, twm);
815c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                        x += w + 20.f;
825c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                        maxH = SkTMax(h, maxH);
835c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                        canvas->restore();
845c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                    }
855c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                }
865c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                x = 0;
875c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                y += maxH + 20.f;
885c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                maxH = 0;
895c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            }
905c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        }
915c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon#if SK_SUPPORT_GPU
925c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        // render offscreen buffer
935c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        if (surface) {
945c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            SkAutoCanvasRestore acr(inputCanvas, true);
955c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            // since we prepended this matrix already, we blit using identity
965c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            inputCanvas->resetMatrix();
975c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            inputCanvas->drawImage(surface->makeImageSnapshot().get(), 0, 0, nullptr);
985c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        }
995c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon#endif
1005c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon    }
1015c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon
1025c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomonprivate:
1035c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon    enum class PerspMode { kNone, kX, kY, kXY };
1045c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon
1055c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon    enum class TranslateWithMatrix : bool { kNo, kYes };
1065c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon
1075c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon    void drawBlob(SkCanvas* canvas, SkTextBlob* blob, SkColor color, SkScalar x, SkScalar y,
1085c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                  PerspMode perspMode, TranslateWithMatrix translateWithMatrix) {
1095c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        canvas->save();
1105c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        SkMatrix persp = SkMatrix::I();
1115c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        switch (perspMode) {
1125c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            case PerspMode::kNone:
1135c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                break;
1145c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            case PerspMode::kX:
1155c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                persp.setPerspX(0.005f);
1165c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                break;
1175c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            case PerspMode::kY:
1185c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                persp.setPerspY(00.005f);
1195c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                break;
1205c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            case PerspMode::kXY:
1215c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                persp.setPerspX(-0.001f);
1225c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                persp.setPerspY(-0.0015f);
1235c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon                break;
1245c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        }
1255c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        persp = SkMatrix::Concat(persp, SkMatrix::MakeTrans(-x, -y));
1265c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        persp = SkMatrix::Concat(SkMatrix::MakeTrans(x, y), persp);
1275c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        canvas->concat(persp);
1285c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        if (TranslateWithMatrix::kYes == translateWithMatrix) {
1295c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            canvas->translate(x, y);
1305c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            x = 0;
1315c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon            y = 0;
1325c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        }
1335c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        SkPaint paint;
1345c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        paint.setColor(color);
1355c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        canvas->drawTextBlob(blob, x, y, paint);
1365c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon        canvas->restore();
1375c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon    }
1385c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon
1395c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon    SkTArray<sk_sp<SkTextBlob>, true> fBlobs;
1405c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon    typedef skiagm::GM INHERITED;
1415c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon};
1425c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian Salomon
1435c6ac64516bb56bbdb5d7aedee1a348acc16e29bBrian SalomonDEF_GM(return new DFTextBlobPerspGM;)
144