reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 1 | #include "SampleCode.h" |
reed@android.com | cb60844 | 2009-12-04 21:32:27 +0000 | [diff] [blame] | 2 | #include "SkDumpCanvas.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 3 | #include "SkView.h" |
| 4 | #include "SkCanvas.h" |
| 5 | #include "Sk64.h" |
| 6 | #include "SkGradientShader.h" |
| 7 | #include "SkGraphics.h" |
| 8 | #include "SkImageDecoder.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 9 | #include "SkPath.h" |
| 10 | #include "SkPicture.h" |
| 11 | #include "SkRandom.h" |
| 12 | #include "SkRegion.h" |
| 13 | #include "SkShader.h" |
| 14 | #include "SkUtils.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 15 | #include "SkColorPriv.h" |
| 16 | #include "SkColorFilter.h" |
reed@android.com | 7d970c7 | 2010-04-22 16:07:49 +0000 | [diff] [blame] | 17 | #include "SkShape.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 18 | #include "SkTime.h" |
| 19 | #include "SkTypeface.h" |
| 20 | #include "SkXfermode.h" |
| 21 | |
| 22 | #include "SkStream.h" |
| 23 | #include "SkXMLParser.h" |
| 24 | |
reed@android.com | 7d970c7 | 2010-04-22 16:07:49 +0000 | [diff] [blame] | 25 | class SignalShape : public SkShape { |
| 26 | public: |
| 27 | SignalShape() : fSignal(0) {} |
| 28 | |
| 29 | SkShape* setSignal(int n) { |
| 30 | fSignal = n; |
| 31 | return this; |
| 32 | } |
| 33 | |
| 34 | protected: |
| 35 | virtual void onDraw(SkCanvas* canvas) { |
| 36 | SkDebugf("---- sc %d\n", canvas->getSaveCount() - 1); |
| 37 | } |
| 38 | |
| 39 | private: |
| 40 | int fSignal; |
| 41 | }; |
| 42 | |
| 43 | static SkPMColor SignalProc(SkPMColor src, SkPMColor dst) { |
| 44 | return dst; |
| 45 | } |
| 46 | |
| 47 | /* Picture playback will skip blocks of draw calls that follow a clip() call |
| 48 | that returns empty, and jump down to the corresponding restore() call. |
| 49 | |
| 50 | This is a great preformance win for drawing very large/tall pictures with |
| 51 | a small visible window (think scrolling a long document). These tests make |
| 52 | sure that (a) we are performing the culling, and (b) we don't get confused |
| 53 | by nested save() calls, nor by calls to restoreToCount(). |
| 54 | */ |
| 55 | static void test_saveRestoreCulling() { |
| 56 | SkPaint signalPaint; |
| 57 | SignalShape signalShape; |
| 58 | |
| 59 | SkPicture pic; |
| 60 | SkRect r = SkRect::MakeWH(0, 0); |
| 61 | int n; |
| 62 | SkCanvas* canvas = pic.beginRecording(100, 100); |
| 63 | int startN = canvas->getSaveCount(); |
| 64 | SkDebugf("---- start sc %d\n", startN); |
| 65 | canvas->drawShape(signalShape.setSignal(1)); |
| 66 | canvas->save(); |
| 67 | canvas->drawShape(signalShape.setSignal(2)); |
| 68 | n = canvas->save(); |
| 69 | canvas->drawShape(signalShape.setSignal(3)); |
| 70 | canvas->save(); |
| 71 | canvas->clipRect(r); |
| 72 | canvas->drawShape(signalShape.setSignal(4)); |
| 73 | canvas->restoreToCount(n); |
| 74 | canvas->drawShape(signalShape.setSignal(5)); |
| 75 | canvas->restore(); |
| 76 | canvas->drawShape(signalShape.setSignal(6)); |
| 77 | SkASSERT(canvas->getSaveCount() == startN); |
| 78 | |
| 79 | SkBitmap bm; |
| 80 | bm.setConfig(SkBitmap::kARGB_8888_Config, 100, 100); |
| 81 | bm.allocPixels(); |
| 82 | SkCanvas c(bm); |
| 83 | c.drawPicture(pic); |
| 84 | } |
| 85 | |
| 86 | /////////////////////////////////////////////////////////////////////////////// |
| 87 | |
reed@android.com | c6ddc11 | 2009-11-10 15:54:55 +0000 | [diff] [blame] | 88 | #include "SkImageRef_GlobalPool.h" |
| 89 | |
| 90 | static SkBitmap load_bitmap() { |
| 91 | SkStream* stream = new SkFILEStream("/skimages/sesame_street_ensemble-hp.jpg"); |
| 92 | SkAutoUnref aur(stream); |
| 93 | |
| 94 | SkBitmap bm; |
| 95 | if (SkImageDecoder::DecodeStream(stream, &bm, SkBitmap::kNo_Config, |
| 96 | SkImageDecoder::kDecodeBounds_Mode)) { |
| 97 | SkPixelRef* pr = new SkImageRef_GlobalPool(stream, bm.config(), 1); |
| 98 | bm.setPixelRef(pr)->unref(); |
| 99 | } |
| 100 | return bm; |
| 101 | } |
| 102 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 103 | static void drawCircle(SkCanvas* canvas, int r, SkColor color) { |
| 104 | SkPaint paint; |
| 105 | paint.setAntiAlias(true); |
| 106 | paint.setColor(color); |
| 107 | |
| 108 | canvas->drawCircle(SkIntToScalar(r), SkIntToScalar(r), SkIntToScalar(r), |
| 109 | paint); |
| 110 | } |
| 111 | |
| 112 | class PictureView : public SkView { |
reed@android.com | c6ddc11 | 2009-11-10 15:54:55 +0000 | [diff] [blame] | 113 | SkBitmap fBitmap; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 114 | public: |
| 115 | PictureView() { |
reed@android.com | c6ddc11 | 2009-11-10 15:54:55 +0000 | [diff] [blame] | 116 | SkImageRef_GlobalPool::SetRAMBudget(16 * 1024); |
| 117 | |
| 118 | fBitmap = load_bitmap(); |
| 119 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 120 | fPicture = new SkPicture; |
| 121 | SkCanvas* canvas = fPicture->beginRecording(100, 100); |
| 122 | SkPaint paint; |
| 123 | paint.setAntiAlias(true); |
| 124 | |
reed@android.com | c6ddc11 | 2009-11-10 15:54:55 +0000 | [diff] [blame] | 125 | canvas->drawBitmap(fBitmap, 0, 0, NULL); |
| 126 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 127 | drawCircle(canvas, 50, SK_ColorBLACK); |
| 128 | fSubPicture = new SkPicture; |
| 129 | canvas->drawPicture(*fSubPicture); |
| 130 | canvas->translate(SkIntToScalar(50), 0); |
| 131 | canvas->drawPicture(*fSubPicture); |
| 132 | canvas->translate(0, SkIntToScalar(50)); |
| 133 | canvas->drawPicture(*fSubPicture); |
| 134 | canvas->translate(SkIntToScalar(-50), 0); |
| 135 | canvas->drawPicture(*fSubPicture); |
| 136 | // fPicture now has (4) references to us. We can release ours, and just |
| 137 | // unref fPicture in our destructor, and it will in turn take care of |
| 138 | // the other references to fSubPicture |
| 139 | fSubPicture->unref(); |
reed@android.com | 7d970c7 | 2010-04-22 16:07:49 +0000 | [diff] [blame] | 140 | |
| 141 | test_saveRestoreCulling(); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 142 | } |
| 143 | |
| 144 | virtual ~PictureView() { |
| 145 | fPicture->unref(); |
| 146 | } |
| 147 | |
| 148 | protected: |
| 149 | // overrides from SkEventSink |
| 150 | virtual bool onQuery(SkEvent* evt) { |
| 151 | if (SampleCode::TitleQ(*evt)) { |
| 152 | SampleCode::TitleR(evt, "Picture"); |
| 153 | return true; |
| 154 | } |
| 155 | return this->INHERITED::onQuery(evt); |
| 156 | } |
| 157 | |
| 158 | void drawBG(SkCanvas* canvas) { |
| 159 | // canvas->drawColor(0xFFDDDDDD); |
| 160 | canvas->drawColor(SK_ColorWHITE); |
| 161 | // canvas->drawColor(SK_ColorBLACK); |
| 162 | } |
| 163 | |
| 164 | void drawSomething(SkCanvas* canvas) { |
| 165 | SkPaint paint; |
reed@android.com | c6ddc11 | 2009-11-10 15:54:55 +0000 | [diff] [blame] | 166 | |
| 167 | canvas->save(); |
| 168 | canvas->scale(0.5f, 0.5f); |
| 169 | canvas->drawBitmap(fBitmap, 0, 0, NULL); |
| 170 | canvas->restore(); |
| 171 | |
reed@android.com | cb60844 | 2009-12-04 21:32:27 +0000 | [diff] [blame] | 172 | const char beforeStr[] = "before circle"; |
| 173 | const char afterStr[] = "after circle"; |
| 174 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 175 | paint.setAntiAlias(true); |
| 176 | |
| 177 | paint.setColor(SK_ColorRED); |
reed@android.com | cb60844 | 2009-12-04 21:32:27 +0000 | [diff] [blame] | 178 | canvas->drawData(beforeStr, sizeof(beforeStr)); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 179 | canvas->drawCircle(SkIntToScalar(50), SkIntToScalar(50), |
| 180 | SkIntToScalar(40), paint); |
reed@android.com | cb60844 | 2009-12-04 21:32:27 +0000 | [diff] [blame] | 181 | canvas->drawData(afterStr, sizeof(afterStr)); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 182 | paint.setColor(SK_ColorBLACK); |
| 183 | paint.setTextSize(SkIntToScalar(40)); |
| 184 | canvas->drawText("Picture", 7, SkIntToScalar(50), SkIntToScalar(62), |
| 185 | paint); |
reed@android.com | cb60844 | 2009-12-04 21:32:27 +0000 | [diff] [blame] | 186 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 187 | } |
| 188 | |
| 189 | virtual void onDraw(SkCanvas* canvas) { |
| 190 | this->drawBG(canvas); |
| 191 | |
| 192 | drawSomething(canvas); |
reed@android.com | 149e2f6 | 2009-05-22 14:39:03 +0000 | [diff] [blame] | 193 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 194 | SkPicture* pict = new SkPicture; |
| 195 | SkAutoUnref aur(pict); |
| 196 | |
| 197 | drawSomething(pict->beginRecording(100, 100)); |
| 198 | pict->endRecording(); |
reed@android.com | 149e2f6 | 2009-05-22 14:39:03 +0000 | [diff] [blame] | 199 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 200 | canvas->save(); |
| 201 | canvas->translate(SkIntToScalar(300), SkIntToScalar(50)); |
| 202 | canvas->scale(-SK_Scalar1, -SK_Scalar1); |
| 203 | canvas->translate(-SkIntToScalar(100), -SkIntToScalar(50)); |
| 204 | canvas->drawPicture(*pict); |
| 205 | canvas->restore(); |
| 206 | |
| 207 | canvas->save(); |
| 208 | canvas->translate(SkIntToScalar(200), SkIntToScalar(150)); |
| 209 | canvas->scale(SK_Scalar1, -SK_Scalar1); |
| 210 | canvas->translate(0, -SkIntToScalar(50)); |
| 211 | canvas->drawPicture(*pict); |
| 212 | canvas->restore(); |
| 213 | |
| 214 | canvas->save(); |
| 215 | canvas->translate(SkIntToScalar(100), SkIntToScalar(100)); |
| 216 | canvas->scale(-SK_Scalar1, SK_Scalar1); |
| 217 | canvas->translate(-SkIntToScalar(100), 0); |
| 218 | canvas->drawPicture(*pict); |
| 219 | canvas->restore(); |
reed@android.com | cb60844 | 2009-12-04 21:32:27 +0000 | [diff] [blame] | 220 | |
| 221 | if (false) { |
| 222 | SkDebugfDumper dumper; |
| 223 | SkDumpCanvas dumpCanvas(&dumper); |
| 224 | dumpCanvas.drawPicture(*pict); |
| 225 | } |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 226 | |
| 227 | // test that we can re-record a subpicture, and see the results |
| 228 | |
reed@android.com | 4417740 | 2009-11-23 21:07:51 +0000 | [diff] [blame] | 229 | SkRandom rand(SampleCode::GetAnimTime()); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 230 | canvas->translate(SkIntToScalar(10), SkIntToScalar(250)); |
| 231 | drawCircle(fSubPicture->beginRecording(50, 50), 25, |
reed@android.com | 4417740 | 2009-11-23 21:07:51 +0000 | [diff] [blame] | 232 | rand.nextU() | 0xFF000000); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 233 | canvas->drawPicture(*fPicture); |
| 234 | delayInval(500); |
| 235 | } |
| 236 | |
| 237 | private: |
| 238 | #define INVAL_ALL_TYPE "inval-all" |
| 239 | |
| 240 | void delayInval(SkMSec delay) { |
| 241 | (new SkEvent(INVAL_ALL_TYPE))->post(this->getSinkID(), delay); |
| 242 | } |
| 243 | |
| 244 | virtual bool onEvent(const SkEvent& evt) { |
| 245 | if (evt.isType(INVAL_ALL_TYPE)) { |
| 246 | this->inval(NULL); |
| 247 | return true; |
| 248 | } |
| 249 | return this->INHERITED::onEvent(evt); |
| 250 | } |
| 251 | |
| 252 | SkPicture* fPicture; |
| 253 | SkPicture* fSubPicture; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 254 | |
| 255 | typedef SkView INHERITED; |
| 256 | }; |
| 257 | |
| 258 | ////////////////////////////////////////////////////////////////////////////// |
| 259 | |
| 260 | static SkView* MyFactory() { return new PictureView; } |
| 261 | static SkViewRegister reg(MyFactory); |
| 262 | |