1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/* 2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Copyright 2013 Google Inc. 3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * 4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Use of this source code is governed by a BSD-style license that can be 5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * found in the LICENSE file. 6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "gm.h" 9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "Resources.h" 11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SampleCode.h" 12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkBlurMask.h" 13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkBlurDrawLooper.h" 1446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "SkCanvas.h" 15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkColorPriv.h" 1646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "SkForceLinking.h" 17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkImageDecoder.h" 18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkOSFile.h" 19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkStream.h" 20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkString.h" 21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkSystemEventTypes.h" 22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkTypes.h" 2346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "SkUtils.h" 24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkView.h" 25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)__SK_FORCE_IMAGE_DECODER_LINKING; 27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Defined in SampleColorFilter.cpp 29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)extern SkShader* createChecker(); 30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/** 32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Interprets c as an unpremultiplied color, and returns the 33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * premultiplied equivalent. 3446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) */ 3546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)static SkPMColor premultiply_unpmcolor(SkPMColor c) { 3646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) U8CPU a = SkGetPackedA32(c); 3746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) U8CPU r = SkGetPackedR32(c); 3846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) U8CPU g = SkGetPackedG32(c); 3946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) U8CPU b = SkGetPackedB32(c); 4046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return SkPreMultiplyARGB(a, r, g, b); 4146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)class UnpremulView : public SampleView { 4446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)public: 4546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) UnpremulView(SkString res) 4646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) : fResPath(res) 4746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) , fPremul(true) 4846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) , fDecodeSucceeded(false) { 4946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) this->nextImage(); 5046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)protected: 53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // overrides from SkEventSink 54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) virtual bool onQuery(SkEvent* evt) SK_OVERRIDE { 55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (SampleCode::TitleQ(*evt)) { 56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SampleCode::TitleR(evt, "unpremul"); 57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return true; 58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkUnichar uni; 60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (SampleCode::CharQ(*evt, &uni)) { 61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) char utf8[kMaxBytesInUTF8Sequence]; 62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t size = SkUTF8_FromUnichar(uni, utf8); 63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Only consider events for single char keys 64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (1 == size) { 65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) switch (utf8[0]) { 66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case fNextImageChar: 67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this->nextImage(); 68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return true; 69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case fTogglePremulChar: 70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this->togglePremul(); 71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return true; 72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) default: 73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return this->INHERITED::onQuery(evt); 78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) virtual void onDrawBackground(SkCanvas* canvas) SK_OVERRIDE { 81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkPaint paint; 82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkAutoTUnref<SkShader> shader(createChecker()); 83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) paint.setShader(shader.get()); 84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) canvas->drawPaint(paint); 85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) virtual void onDrawContent(SkCanvas* canvas) SK_OVERRIDE { 88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkPaint paint; 89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) paint.setAntiAlias(true); 90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) paint.setTextSize(SkIntToScalar(24)); 91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkAutoTUnref<SkBlurDrawLooper> looper( 92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkBlurDrawLooper::Create(SK_ColorBLUE, 93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(2)), 94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 0, 0)); 95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) paint.setLooper(looper); 96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkScalar height = paint.getFontMetrics(NULL); 97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!fDecodeSucceeded) { 98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkString failure; 99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (fResPath.size() == 0) { 100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) failure.printf("resource path is required!"); 101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) failure.printf("Failed to decode %s", fCurrFile.c_str()); 103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) canvas->drawText(failure.c_str(), failure.size(), 0, height, paint); 105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Name, size of the file, and whether or not it is premultiplied. 109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkString header(SkOSPath::Basename(fCurrFile.c_str())); 110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) header.appendf(" [%dx%d] %s", fBitmap.width(), fBitmap.height(), 111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) (fPremul ? "premultiplied" : "unpremultiplied")); 112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) canvas->drawText(header.c_str(), header.size(), 0, height, paint); 113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) canvas->translate(0, height); 11446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Help messages 116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch header.printf("Press '%c' to move to the next image.'", fNextImageChar); 117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch canvas->drawText(header.c_str(), header.size(), 0, height, paint); 118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch canvas->translate(0, height); 119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch header.printf("Press '%c' to toggle premultiplied decode.", fTogglePremulChar); 121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) canvas->drawText(header.c_str(), header.size(), 0, height, paint); 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Now draw the image itself. 124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) canvas->translate(height * 2, height * 2); 125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!fPremul) { 126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // A premultiplied bitmap cannot currently be drawn. 127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkAutoLockPixels alp(fBitmap); 128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Copy it to a bitmap which can be drawn, converting 129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // to premultiplied: 130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkBitmap bm; 131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bm.allocN32Pixels(fBitmap.width(), fBitmap.height()); 132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (int i = 0; i < fBitmap.width(); ++i) { 133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for (int j = 0; j < fBitmap.height(); ++j) { 134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *bm.getAddr32(i, j) = premultiply_unpmcolor(*fBitmap.getAddr32(i, j)); 135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch canvas->drawBitmap(bm, 0, 0); 138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) canvas->drawBitmap(fBitmap, 0, 0); 140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 143116680a4aac90f2aa7413d9095a592090648e557Ben Murdochprivate: 144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const SkString fResPath; 145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkString fCurrFile; 146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bool fPremul; 147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bool fDecodeSucceeded; 148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkBitmap fBitmap; 149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch SkOSFile::Iter fFileIter; 150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) static const char fNextImageChar = 'j'; 152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) static const char fTogglePremulChar = 'h'; 153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void nextImage() { 155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (fResPath.size() == 0) { 156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 15746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch SkString basename; 159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!fFileIter.next(&basename)) { 160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fFileIter.reset(fResPath.c_str()); 161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!fFileIter.next(&basename)) { 162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Perhaps this should draw some error message? 163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; 164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch fCurrFile = SkOSPath::Join(fResPath.c_str(), basename.c_str()); 167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this->decodeCurrFile(); 168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void decodeCurrFile() { 171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (fCurrFile.size() == 0) { 172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fDecodeSucceeded = false; 173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkFILEStream stream(fCurrFile.c_str()); 176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream)); 177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (NULL == decoder.get()) { 178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fDecodeSucceeded = false; 179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!fPremul) { 182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) decoder->setRequireUnpremultipliedColors(true); 183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fDecodeSucceeded = decoder->decode(&stream, &fBitmap, kN32_SkColorType, 185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkImageDecoder::kDecodePixels_Mode); 186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this->inval(NULL); 187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 18846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void togglePremul() { 190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) fPremul = !fPremul; 191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this->decodeCurrFile(); 192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) typedef SampleView INHERITED; 195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////// 198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)static SkView* MyFactory() { 200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return new UnpremulView(GetResourcePath()); 201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)static SkViewRegister reg(MyFactory); 203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)