1 /* 2 * Copyright 2011 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 "SkBitmap.h" 9 #include "SkCanvas.h" 10 #include "SkColorPriv.h" 11 #include "SkGradientShader.h" 12 #include "SkRect.h" 13 #include "Test.h" 14 15 #include "sk_tool_utils.h" 16 17 // these are in the same order as the SkColorType enum 18 static const char* gColorTypeName[] = { 19 "None", "A8", "565", "4444", "RGBA", "BGRA", "Index8" 20 }; 21 22 /** Returns -1 on success, else the x coord of the first bad pixel, return its 23 value in bad 24 */ 25 typedef int (*Proc)(const void*, int width, uint32_t expected, uint32_t* bad); 26 27 static int proc_32(const void* ptr, int w, uint32_t expected, uint32_t* bad) { 28 const SkPMColor* addr = static_cast<const SkPMColor*>(ptr); 29 for (int x = 0; x < w; x++) { 30 if (addr[x] != expected) { 31 *bad = addr[x]; 32 return x; 33 } 34 } 35 return -1; 36 } 37 38 static int proc_16(const void* ptr, int w, uint32_t expected, uint32_t* bad) { 39 const uint16_t* addr = static_cast<const uint16_t*>(ptr); 40 for (int x = 0; x < w; x++) { 41 if (addr[x] != expected) { 42 *bad = addr[x]; 43 return x; 44 } 45 } 46 return -1; 47 } 48 49 static int proc_8(const void* ptr, int w, uint32_t expected, uint32_t* bad) { 50 const SkPMColor* addr = static_cast<const SkPMColor*>(ptr); 51 for (int x = 0; x < w; x++) { 52 if (SkGetPackedA32(addr[x]) != expected) { 53 *bad = SkGetPackedA32(addr[x]); 54 return x; 55 } 56 } 57 return -1; 58 } 59 60 static int proc_bad(const void*, int, uint32_t, uint32_t* bad) { 61 *bad = 0; 62 return 0; 63 } 64 65 static Proc find_proc(const SkBitmap& bm, SkPMColor expect32, uint16_t expect16, 66 uint8_t expect8, uint32_t* expect) { 67 switch (bm.colorType()) { 68 case kN32_SkColorType: 69 *expect = expect32; 70 return proc_32; 71 case kARGB_4444_SkColorType: 72 case kRGB_565_SkColorType: 73 *expect = expect16; 74 return proc_16; 75 case kAlpha_8_SkColorType: 76 *expect = expect8; 77 return proc_8; 78 default: 79 *expect = 0; 80 return proc_bad; 81 } 82 } 83 84 static bool check_color(const SkBitmap& bm, SkPMColor expect32, 85 uint16_t expect16, uint8_t expect8, 86 skiatest::Reporter* reporter) { 87 uint32_t expect; 88 Proc proc = find_proc(bm, expect32, expect16, expect8, &expect); 89 for (int y = 0; y < bm.height(); y++) { 90 uint32_t bad; 91 int x = proc(bm.getAddr(0, y), bm.width(), expect, &bad); 92 if (x >= 0) { 93 ERRORF(reporter, "BlitRow colortype=%s [%d %d] expected %x got %x", 94 gColorTypeName[bm.colorType()], x, y, expect, bad); 95 return false; 96 } 97 } 98 return true; 99 } 100 101 // Make sure our blits always map src==0 to a noop, and src==FF to full opaque 102 static void test_00_FF(skiatest::Reporter* reporter) { 103 static const int W = 256; 104 105 static const SkColorType gDstColorType[] = { 106 kN32_SkColorType, 107 kRGB_565_SkColorType, 108 }; 109 110 static const struct { 111 SkColor fSrc; 112 SkColor fDst; 113 SkPMColor fResult32; 114 uint16_t fResult16; 115 uint8_t fResult8; 116 } gSrcRec[] = { 117 { 0, 0, 0, 0, 0 }, 118 { 0, 0xFFFFFFFF, SkPackARGB32(0xFF, 0xFF, 0xFF, 0xFF), 0xFFFF, 0xFF }, 119 { 0xFFFFFFFF, 0, SkPackARGB32(0xFF, 0xFF, 0xFF, 0xFF), 0xFFFF, 0xFF }, 120 { 0xFFFFFFFF, 0xFFFFFFFF, SkPackARGB32(0xFF, 0xFF, 0xFF, 0xFF), 0xFFFF, 0xFF }, 121 }; 122 123 SkPaint paint; 124 125 SkBitmap srcBM; 126 srcBM.allocN32Pixels(W, 1); 127 128 for (size_t i = 0; i < SK_ARRAY_COUNT(gDstColorType); i++) { 129 SkImageInfo info = SkImageInfo::Make(W, 1, gDstColorType[i], 130 kPremul_SkAlphaType); 131 SkBitmap dstBM; 132 dstBM.allocPixels(info); 133 134 SkCanvas canvas(dstBM); 135 for (size_t j = 0; j < SK_ARRAY_COUNT(gSrcRec); j++) { 136 srcBM.eraseColor(gSrcRec[j].fSrc); 137 dstBM.eraseColor(gSrcRec[j].fDst); 138 139 for (int k = 0; k < 4; k++) { 140 bool dither = (k & 1) != 0; 141 bool blend = (k & 2) != 0; 142 if (gSrcRec[j].fSrc != 0 && blend) { 143 // can't make a numerical promise about blending anything 144 // but 0 145 // continue; 146 } 147 paint.setDither(dither); 148 paint.setAlpha(blend ? 0x80 : 0xFF); 149 canvas.drawBitmap(srcBM, 0, 0, &paint); 150 if (!check_color(dstBM, gSrcRec[j].fResult32, gSrcRec[j].fResult16, 151 gSrcRec[j].fResult8, reporter)) { 152 SkDebugf("--- src index %d dither %d blend %d\n", j, dither, blend); 153 } 154 } 155 } 156 } 157 } 158 159 /////////////////////////////////////////////////////////////////////////////// 160 161 struct Mesh { 162 SkPoint fPts[4]; 163 164 Mesh(const SkBitmap& bm, SkPaint* paint) { 165 const SkScalar w = SkIntToScalar(bm.width()); 166 const SkScalar h = SkIntToScalar(bm.height()); 167 fPts[0].set(0, 0); 168 fPts[1].set(w, 0); 169 fPts[2].set(w, h); 170 fPts[3].set(0, h); 171 paint->setShader(SkShader::MakeBitmapShader(bm, SkShader::kClamp_TileMode, 172 SkShader::kClamp_TileMode)); 173 } 174 175 void draw(SkCanvas* canvas, SkPaint* paint) { 176 canvas->drawVertices(SkCanvas::kTriangleFan_VertexMode, 4, fPts, fPts, 177 nullptr, SkBlendMode::kModulate, nullptr, 0, *paint); 178 } 179 }; 180 181 #include "SkImageEncoder.h" 182 static void save_bm(const SkBitmap& bm, const char name[]) { 183 sk_tool_utils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100); 184 } 185 186 static bool gOnce; 187 188 // Make sure our blits are invariant with the width of the blit (i.e. that 189 // special case for 8 at a time have the same results as narrower blits) 190 static void test_diagonal(skiatest::Reporter* reporter) { 191 static const int W = 64; 192 static const int H = W; 193 194 static const SkColorType gDstColorType[] = { 195 kN32_SkColorType, 196 kRGB_565_SkColorType, 197 }; 198 199 static const SkColor gDstBG[] = { 0, 0xFFFFFFFF }; 200 const SkRect srcR = SkRect::MakeIWH(W, H); 201 202 SkBitmap srcBM; 203 srcBM.allocN32Pixels(W, H); 204 SkImageInfo info = SkImageInfo::Make(W, H, kUnknown_SkColorType, kPremul_SkAlphaType); 205 206 for (size_t i = 0; i < SK_ARRAY_COUNT(gDstColorType); i++) { 207 info = info.makeColorType(gDstColorType[i]); 208 209 SkBitmap dstBM0, dstBM1; 210 dstBM0.allocPixels(info); 211 dstBM1.allocPixels(info); 212 213 SkCanvas canvas0(dstBM0); 214 SkCanvas canvas1(dstBM1); 215 SkColor bgColor; 216 217 for (size_t j = 0; j < SK_ARRAY_COUNT(gDstBG); j++) { 218 bgColor = gDstBG[j]; 219 220 for (int c = 0; c <= 0xFF; c++) { 221 // cons up a mesh to draw the bitmap with 222 SkPaint paint; 223 srcBM.eraseARGB(0xFF, c, c, c); 224 Mesh mesh(srcBM, &paint); 225 226 for (int k = 0; k < 4; k++) { 227 bool dither = (k & 1) != 0; 228 uint8_t alpha = (k & 2) ? 0x80 : 0xFF; 229 paint.setDither(dither); 230 paint.setAlpha(alpha); 231 232 dstBM0.eraseColor(bgColor); 233 dstBM1.eraseColor(bgColor); 234 235 canvas0.drawRect(srcR, paint); 236 mesh.draw(&canvas1, &paint); 237 238 if (!gOnce && false) { 239 save_bm(dstBM0, "drawBitmap.png"); 240 save_bm(dstBM1, "drawMesh.png"); 241 gOnce = true; 242 } 243 244 if (memcmp(dstBM0.getPixels(), dstBM1.getPixels(), dstBM0.getSize())) { 245 ERRORF(reporter, "Diagonal colortype=%s bg=0x%x dither=%d" 246 " alpha=0x%x src=0x%x", 247 gColorTypeName[gDstColorType[i]], bgColor, dither, 248 alpha, c); 249 } 250 } 251 } 252 } 253 } 254 } 255 256 DEF_TEST(BlitRow, reporter) { 257 test_00_FF(reporter); 258 test_diagonal(reporter); 259 } 260