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