1 /* 2 * Copyright 2013 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.h" 9 10 #include "sk_tool_utils.h" 11 #include "DecodeFile.h" 12 #include "Resources.h" 13 #include "SampleCode.h" 14 #include "SkBlurMask.h" 15 #include "SkBlurDrawLooper.h" 16 #include "SkCanvas.h" 17 #include "SkColorPriv.h" 18 #include "SkOSFile.h" 19 #include "SkOSPath.h" 20 #include "SkStream.h" 21 #include "SkString.h" 22 #include "SkTypes.h" 23 #include "SkUtils.h" 24 #include "SkView.h" 25 26 /** 27 * Interprets c as an unpremultiplied color, and returns the 28 * premultiplied equivalent. 29 */ 30 static SkPMColor premultiply_unpmcolor(SkPMColor c) { 31 U8CPU a = SkGetPackedA32(c); 32 U8CPU r = SkGetPackedR32(c); 33 U8CPU g = SkGetPackedG32(c); 34 U8CPU b = SkGetPackedB32(c); 35 return SkPreMultiplyARGB(a, r, g, b); 36 } 37 38 class UnpremulView : public SampleView { 39 public: 40 UnpremulView(SkString res) 41 : fResPath(res) 42 , fPremul(true) 43 , fDecodeSucceeded(false) { 44 this->nextImage(); 45 } 46 47 protected: 48 // overrides from SkEventSink 49 bool onQuery(SkEvent* evt) override { 50 if (SampleCode::TitleQ(*evt)) { 51 SampleCode::TitleR(evt, "unpremul"); 52 return true; 53 } 54 SkUnichar uni; 55 if (SampleCode::CharQ(*evt, &uni)) { 56 char utf8[kMaxBytesInUTF8Sequence]; 57 size_t size = SkUTF8_FromUnichar(uni, utf8); 58 // Only consider events for single char keys 59 if (1 == size) { 60 switch (utf8[0]) { 61 case fNextImageChar: 62 this->nextImage(); 63 return true; 64 case fTogglePremulChar: 65 this->togglePremul(); 66 return true; 67 default: 68 break; 69 } 70 } 71 } 72 return this->INHERITED::onQuery(evt); 73 } 74 75 void onDrawBackground(SkCanvas* canvas) override { 76 sk_tool_utils::draw_checkerboard(canvas, 0xFFCCCCCC, 0xFFFFFFFF, 12); 77 } 78 79 void onDrawContent(SkCanvas* canvas) override { 80 SkPaint paint; 81 paint.setAntiAlias(true); 82 paint.setTextSize(SkIntToScalar(24)); 83 auto looper( 84 SkBlurDrawLooper::Make(SK_ColorBLUE, SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(2)), 85 0, 0)); 86 paint.setLooper(looper); 87 SkScalar height = paint.getFontMetrics(nullptr); 88 if (!fDecodeSucceeded) { 89 SkString failure; 90 if (fResPath.size() == 0) { 91 failure.printf("resource path is required!"); 92 } else { 93 failure.printf("Failed to decode %s", fCurrFile.c_str()); 94 } 95 canvas->drawString(failure, 0, height, paint); 96 return; 97 } 98 99 // Name, size of the file, and whether or not it is premultiplied. 100 SkString header(SkOSPath::Basename(fCurrFile.c_str())); 101 header.appendf(" [%dx%d] %s", fBitmap.width(), fBitmap.height(), 102 (fPremul ? "premultiplied" : "unpremultiplied")); 103 canvas->drawString(header, 0, height, paint); 104 canvas->translate(0, height); 105 106 // Help messages 107 header.printf("Press '%c' to move to the next image.'", fNextImageChar); 108 canvas->drawString(header, 0, height, paint); 109 canvas->translate(0, height); 110 111 header.printf("Press '%c' to toggle premultiplied decode.", fTogglePremulChar); 112 canvas->drawString(header, 0, height, paint); 113 114 // Now draw the image itself. 115 canvas->translate(height * 2, height * 2); 116 if (!fPremul) { 117 // A premultiplied bitmap cannot currently be drawn. 118 // Copy it to a bitmap which can be drawn, converting 119 // to premultiplied: 120 SkBitmap bm; 121 bm.allocN32Pixels(fBitmap.width(), fBitmap.height()); 122 for (int i = 0; i < fBitmap.width(); ++i) { 123 for (int j = 0; j < fBitmap.height(); ++j) { 124 *bm.getAddr32(i, j) = premultiply_unpmcolor(*fBitmap.getAddr32(i, j)); 125 } 126 } 127 canvas->drawBitmap(bm, 0, 0); 128 } else { 129 canvas->drawBitmap(fBitmap, 0, 0); 130 } 131 } 132 133 private: 134 const SkString fResPath; 135 SkString fCurrFile; 136 bool fPremul; 137 bool fDecodeSucceeded; 138 SkBitmap fBitmap; 139 SkOSFile::Iter fFileIter; 140 141 static const char fNextImageChar = 'j'; 142 static const char fTogglePremulChar = 'h'; 143 144 void nextImage() { 145 if (fResPath.size() == 0) { 146 return; 147 } 148 SkString basename; 149 if (!fFileIter.next(&basename)) { 150 fFileIter.reset(fResPath.c_str()); 151 if (!fFileIter.next(&basename)) { 152 // Perhaps this should draw some error message? 153 return; 154 } 155 } 156 fCurrFile = SkOSPath::Join(fResPath.c_str(), basename.c_str()); 157 this->decodeCurrFile(); 158 } 159 160 void decodeCurrFile() { 161 if (fCurrFile.size() == 0) { 162 fDecodeSucceeded = false; 163 return; 164 } 165 fDecodeSucceeded = decode_file(fCurrFile.c_str(), &fBitmap, kN32_SkColorType, !fPremul); 166 } 167 168 void togglePremul() { 169 fPremul = !fPremul; 170 this->decodeCurrFile(); 171 } 172 173 typedef SampleView INHERITED; 174 }; 175 176 ////////////////////////////////////////////////////////////////////////////// 177 178 static SkView* MyFactory() { 179 return new UnpremulView(GetResourcePath("images")); 180 } 181 static SkViewRegister reg(MyFactory); 182