15ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt/*
25ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt * Copyright 2013 Google Inc.
35ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt *
45ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt * Use of this source code is governed by a BSD-style license that can be
55ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt * found in the LICENSE file.
65ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt */
75ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt#include "gm.h"
833d2055e594177b27360f84e0631b26d74a55a9bMike Klein#include "sk_tool_utils.h"
95ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt#include "SkBitmap.h"
10d3ebb48320cf1b7e969974673e4bd7743816985ebungeman#include "SkPath.h"
115ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt#include "SkRandom.h"
125ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt#include "SkShader.h"
138336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon#include "SkSurface.h"
145ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt
155ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualittnamespace skiagm {
165ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt
175ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt/**
185ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt * Renders overlapping shapes with colorburn against a checkerboard.
195ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt */
205ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualittclass DstReadShuffle : public GM {
215ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualittpublic:
22d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon    DstReadShuffle() { this->setBGColor(kBackground); }
235ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt
245ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualittprotected:
255ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt    enum ShapeType {
265ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt        kCircle_ShapeType,
275ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt        kRoundRect_ShapeType,
285ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt        kRect_ShapeType,
295ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt        kConvexPath_ShapeType,
305ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt        kConcavePath_ShapeType,
315ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt        kText_ShapeType,
325ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt        kNumShapeTypes
335ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt    };
345ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt
3536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkString onShortName() override {
365ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt        return SkString("dstreadshuffle");
375ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt    }
385ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt
3936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkISize onISize() override {
408336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        return SkISize::Make(530, 680);
415ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt    }
425ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt
438336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon    void drawShape(SkCanvas* canvas, SkPaint* paint, ShapeType type) {
448336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        const SkRect kRect = SkRect::MakeXYWH(0, 0, 75.f, 85.f);
455ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt        switch (type) {
465ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt            case kCircle_ShapeType:
478336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                canvas->drawCircle(kRect.centerX(), kRect.centerY(), kRect.width() / 2.f, *paint);
485ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                break;
495ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt            case kRoundRect_ShapeType:
508336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                canvas->drawRoundRect(kRect, 15.f, 15.f, *paint);
515ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                break;
525ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt            case kRect_ShapeType:
535ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                canvas->drawRect(kRect, *paint);
545ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                break;
555ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt            case kConvexPath_ShapeType:
565ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                if (fConvexPath.isEmpty()) {
575ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                    SkPoint points[4];
585ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                    kRect.toQuad(points);
595ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                    fConvexPath.moveTo(points[0]);
605ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                    fConvexPath.quadTo(points[1], points[2]);
615ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                    fConvexPath.quadTo(points[3], points[0]);
625ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                    SkASSERT(fConvexPath.isConvex());
635ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                }
645ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                canvas->drawPath(fConvexPath, *paint);
655ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                break;
665ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt            case kConcavePath_ShapeType:
675ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                if (fConcavePath.isEmpty()) {
688336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                    SkPoint points[5] = {{50.f, 0.f}};
695ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                    SkMatrix rot;
708336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                    rot.setRotate(360.f / 5, 50.f, 70.f);
715ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                    for (int i = 1; i < 5; ++i) {
725ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                        rot.mapPoints(points + i, points + i - 1, 1);
735ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                    }
745ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                    fConcavePath.moveTo(points[0]);
755ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                    for (int i = 0; i < 5; ++i) {
765ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                        fConcavePath.lineTo(points[(2 * i) % 5]);
775ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                    }
785ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                    fConcavePath.setFillType(SkPath::kEvenOdd_FillType);
795ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                    SkASSERT(!fConcavePath.isConvex());
805ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                }
815ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                canvas->drawPath(fConcavePath, *paint);
825ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                break;
835ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt            case kText_ShapeType: {
848336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                const char* text = "N";
858336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                paint->setTextSize(100.f);
868336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                paint->setFakeBoldText(true);
87f1f8bd58513848440d76e49cc3fde585bc888ff5caryclark                sk_tool_utils::set_portable_typeface(paint);
888336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                canvas->drawText(text, strlen(text), 0.f, 100.f, *paint);
895ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt            }
905ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt            default:
915ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt                break;
925ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt        }
935ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt    }
945ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt
958336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon    static SkColor GetColor(SkRandom* random) {
968336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        SkColor color = sk_tool_utils::color_to_565(random->nextU() | 0xFF000000);
978336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        return SkColorSetA(color, 0x80);
985ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt    }
995ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt
1008336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon    static void DrawHairlines(SkCanvas* canvas) {
101d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon        if (canvas->imageInfo().alphaType() == kOpaque_SkAlphaType) {
102d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon            canvas->clear(kBackground);
103d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon        } else {
104d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon            canvas->clear(SK_ColorTRANSPARENT);
105d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon        }
1068336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        SkPaint hairPaint;
1078336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        hairPaint.setStyle(SkPaint::kStroke_Style);
1088336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        hairPaint.setStrokeWidth(0);
1098336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        hairPaint.setAntiAlias(true);
1108336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        static constexpr int kNumHairlines = 12;
1118336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        SkPoint pts[] = {{3.f, 7.f}, {29.f, 7.f}};
1128336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        SkRandom colorRandom;
1138336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        SkMatrix rot;
1148336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        rot.setRotate(360.f / kNumHairlines, 15.5f, 12.f);
1158336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        rot.postTranslate(3.f, 0);
1168336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        for (int i = 0; i < 12; ++i) {
1178336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon            hairPaint.setColor(GetColor(&colorRandom));
1188336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon            canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, hairPaint);
1198336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon            rot.mapPoints(pts, 2);
1205ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt        }
1215ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt    }
1225ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt
12336352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onDraw(SkCanvas* canvas) override {
1248336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        SkScalar y = 5;
1255ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt        for (int i = 0; i < kNumShapeTypes; i++) {
1268336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon            SkRandom colorRandom;
1275ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt            ShapeType shapeType = static_cast<ShapeType>(i);
1288336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon            SkScalar x = 5;
1298336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon            for (int r = 0; r <= 15; r++) {
1308336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                SkPaint p;
1318336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                p.setAntiAlias(true);
1328336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                p.setColor(GetColor(&colorRandom));
1338336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                // In order to get some op combining on the GPU backend we do 2 src over
1348336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                // for each xfer mode which requires a dst read
1358336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                p.setBlendMode(r % 3 == 0 ? SkBlendMode::kColorBurn : SkBlendMode::kSrcOver);
1368336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                canvas->save();
1378336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                canvas->translate(x, y);
1388336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                this->drawShape(canvas, &p, shapeType);
1398336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                canvas->restore();
1408336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                x += 15;
1415ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt            }
1428336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon            y += 110;
1438336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        }
1448336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        // Draw hairlines to a surface and then draw that to the main canvas with a zoom so that
1458336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        // it is easier to see how they blend.
1468336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        SkImageInfo info;
147d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon        // Recording canvases don't have a color type.
148d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon        if (SkColorType::kUnknown_SkColorType == canvas->imageInfo().colorType()) {
149d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon            info = SkImageInfo::MakeN32Premul(35, 35);
150d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon        } else {
1518336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon            info = SkImageInfo::Make(35, 35,
1528336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                                     canvas->imageInfo().colorType(),
1538336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                                     canvas->imageInfo().alphaType(),
1548336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon                                     canvas->imageInfo().refColorSpace());
1555ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt        }
1568336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        auto surf = canvas->makeSurface(info);
1578336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        if (!surf) {
158d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon            // Fall back to raster. Raster supports only one of the 8 bit per-channel RGBA or BGRA
159d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon            // formats. This fall back happens when running with --preAbandonGpuContext.
160d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon            if ((info.colorType() == kRGBA_8888_SkColorType ||
161d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon                 info.colorType() == kBGRA_8888_SkColorType) &&
162d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon                info.colorType() != kN32_SkColorType) {
163d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon                info = SkImageInfo::Make(35, 35,
164d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon                                         kN32_SkColorType,
165d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon                                         canvas->imageInfo().alphaType(),
166d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon                                         canvas->imageInfo().refColorSpace());
167d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon            }
1688336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon            surf = SkSurface::MakeRaster(info);
1698336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        }
1708336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        canvas->scale(5.f, 5.f);
1718336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        canvas->translate(67.f, 10.f);
1728336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        DrawHairlines(surf->getCanvas());
1738336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon        canvas->drawImage(surf->makeImageSnapshot(), 0.f, 0.f);
1745ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt    }
1755ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt
1765ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualittprivate:
177d02b6f331bca054b0654e213ea6a7ddd94257bf7Brian Salomon    static constexpr SkColor kBackground = SK_ColorLTGRAY;
1788336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon    SkPath fConcavePath;
1798336e949b8aecc664a4f2690b56369d3821b2a1bBrian Salomon    SkPath fConvexPath;
1805ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt    typedef GM INHERITED;
1815ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt};
1825ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt
1835ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt//////////////////////////////////////////////////////////////////////////////
1845ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt
1855ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualittstatic GM* MyFactory(void*) { return new DstReadShuffle; }
1865ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualittstatic GMRegistry reg(MyFactory);
1875ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt
1885ce33c17afb9f10e8faf6907f030268d97fdf1d8joshualitt}
189