1 /* 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" 13 #include "include/core/SkShader.h" 14 #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 */ 22 DEF_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])); 48 images[0] = {SkImages::RasterFromPixmapCopy(cpmx), SkImages::RasterFromPixmapCopy(cpmy)}; 49 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])); 61 images[1] = {SkImages::RasterFromPixmapCopy(apmx), SkImages::RasterFromPixmapCopy(apmy)}; 62 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(); 70 c->clear(SK_ColorWHITE); 71 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 __anon67dc9d240102(sk_sp<SkImage> image, bool shader, bool doX, bool mirror, uint8_t alpha) 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) { 81 paint.setShader(image->makeShader(SkFilterMode::kNearest)); 82 } 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 { 94 c->drawImage(image, 0, 0, SkFilterMode::kNearest, &paint); 95 } 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 } 119