blob: 70028226b82aa7b8f677ce16ad354e6bab95d02d [file] [log] [blame]
Brian Salomoncf3fa752022-11-02 17:19:44 -04001/*
2 * Copyright 2022 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "gm/gm.h"
9#include "include/core/SkCanvas.h"
10#include "include/core/SkImage.h"
11#include "include/core/SkPaint.h"
12#include "include/core/SkPixmap.h"
Kevin Lubick08fc9882023-01-30 16:05:54 -050013#include "include/core/SkShader.h"
Brian Salomoncf3fa752022-11-02 17:19:44 -040014#include "include/core/SkSurface.h"
15
16/**
17 * Tests drawing images are half pixel offsets in device space with nearest filtering to show how
18 * rasterization and image sample snapping at boundary points interact. Both drawImage and drawRect
19 * with an image shader are tested. Scale factors 1 and -1 are tested. The images are all two pixels
20 * wide or tall so we either get both values once each or one value repeated twice.
21 */
22DEF_SIMPLE_GM_CAN_FAIL(nearest_half_pixel_image, canvas, errorMsg, 264, 235) {
23 // We don't run this test on the GPU because we're at the driver/hw's mercy for how this
24 // is handled.
25 if (canvas->recordingContext() || (canvas->getSurface() && canvas->getSurface()->recorder())) {
26 *errorMsg = "Test is only relevant to CPU backend";
27 return skiagm::DrawResult::kSkip;
28 }
29
30 // We make 2x1 and 1x2 images for each color type.
31 struct Images {
32 sk_sp<SkImage> imageX;
33 sk_sp<SkImage> imageY;
34 };
35
36 Images images[2];
37 uint32_t colors[] {0xFFFF0000, 0xFF0000FF};
38 SkPixmap cpmx(SkImageInfo::Make({2, 1},
39 kRGBA_8888_SkColorType,
40 kPremul_SkAlphaType),
41 colors,
42 sizeof(colors));
43 SkPixmap cpmy(SkImageInfo::Make({1, 2},
44 kRGBA_8888_SkColorType,
45 kPremul_SkAlphaType),
46 colors,
47 sizeof(colors[0]));
Kevin Lubick77472bf2023-03-24 07:11:17 -040048 images[0] = {SkImages::RasterFromPixmapCopy(cpmx), SkImages::RasterFromPixmapCopy(cpmy)};
Brian Salomoncf3fa752022-11-02 17:19:44 -040049
50 uint8_t alphas[] {0xFF, 0xAA};
51 SkPixmap apmx(SkImageInfo::Make({2, 1},
52 kAlpha_8_SkColorType,
53 kPremul_SkAlphaType),
54 alphas,
55 sizeof(alphas));
56 SkPixmap apmy(SkImageInfo::Make({1, 2},
57 kAlpha_8_SkColorType,
58 kPremul_SkAlphaType),
59 alphas,
60 sizeof(alphas[0]));
Kevin Lubick77472bf2023-03-24 07:11:17 -040061 images[1] = {SkImages::RasterFromPixmapCopy(apmx), SkImages::RasterFromPixmapCopy(apmy)};
Brian Salomoncf3fa752022-11-02 17:19:44 -040062
63 // We draw offscreen and then zoom that up to make the result clear.
64 auto surf = canvas->makeSurface(canvas->imageInfo().makeWH(80, 80));
65 if (!surf) {
66 *errorMsg = "Test only works with SkSurface backed canvases";
67 return skiagm::DrawResult::kSkip;
68 }
69 auto* c = surf->getCanvas();
Brian Salomonbc4d60c2022-11-03 11:34:14 -040070 c->clear(SK_ColorWHITE);
Brian Salomoncf3fa752022-11-02 17:19:44 -040071
72 // We scale up in the direction not being tested, the one with image dimension of 1, to make the
73 // result more easily visible.
74 static const float kOffAxisScale = 4;
75
76 auto draw = [&](sk_sp<SkImage> image, bool shader, bool doX, bool mirror, uint8_t alpha) {
77 c->save();
78 SkPaint paint;
79 paint.setAlpha(alpha);
80 if (shader) {
Michael Ludwig2c49e602023-05-30 13:12:19 -040081 paint.setShader(image->makeShader(SkFilterMode::kNearest));
Brian Salomoncf3fa752022-11-02 17:19:44 -040082 }
83 if (doX) {
84 c->scale(mirror ? -1 : 1, kOffAxisScale);
85 c->translate(mirror ? -2.5 : 0.5, 0);
86 } else {
87 c->scale(kOffAxisScale, mirror ? -1 : 1);
88 c->translate(0, mirror ? -2.5 : 0.5);
89 }
90
91 if (shader) {
92 c->drawRect(SkRect::Make(image->dimensions()), paint);
93 } else {
Michael Ludwig2c49e602023-05-30 13:12:19 -040094 c->drawImage(image, 0, 0, SkFilterMode::kNearest, &paint);
Brian Salomoncf3fa752022-11-02 17:19:44 -040095 }
96 c->restore();
97 };
98
99 for (bool shader : {false, true})
100 for (uint8_t alpha : {0xFF , 0x70}) {
101 c->save();
102 for (const auto& i : images)
103 for (auto mirror : {false, true}) {
104 draw(i.imageX, shader, /*doX=*/true, mirror, alpha);
105 c->save();
106 c->translate(4, 0);
107 draw(i.imageY, shader, /*doX=*/false, mirror, alpha);
108 c->restore();
109 c->translate(0, kOffAxisScale*2);
110 }
111 c->restore();
112 c->translate(kOffAxisScale*2, 0);
113 }
114 canvas->scale(8, 8);
115 canvas->drawImage(surf->makeImageSnapshot(), 0, 0);
116
117 return skiagm::DrawResult::kOk;
118}