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