RecordDrawTest.cpp revision 271a030f5d0d3c59715fbeffb31c761279f3f8ca
1/* 2 * Copyright 2014 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 "Test.h" 9#include "RecordTestUtils.h" 10 11#include "SkDebugCanvas.h" 12#include "SkDrawPictureCallback.h" 13#include "SkDropShadowImageFilter.h" 14#include "SkRecord.h" 15#include "SkRecordDraw.h" 16#include "SkRecordOpts.h" 17#include "SkRecorder.h" 18#include "SkRecords.h" 19 20static const int W = 1920, H = 1080; 21 22class JustOneDraw : public SkDrawPictureCallback { 23public: 24 JustOneDraw() : fCalls(0) {} 25 26 virtual bool abortDrawing() SK_OVERRIDE { return fCalls++ > 0; } 27private: 28 int fCalls; 29}; 30 31DEF_TEST(RecordDraw_Abort, r) { 32 // Record two commands. 33 SkRecord record; 34 SkRecorder recorder(&record, W, H); 35 recorder.drawRect(SkRect::MakeWH(200, 300), SkPaint()); 36 recorder.clipRect(SkRect::MakeWH(100, 200)); 37 38 SkRecord rerecord; 39 SkRecorder canvas(&rerecord, W, H); 40 41 JustOneDraw callback; 42 SkRecordDraw(record, &canvas, NULL/*bbh*/, &callback); 43 44 REPORTER_ASSERT(r, 3 == rerecord.count()); 45 assert_type<SkRecords::Save> (r, rerecord, 0); 46 assert_type<SkRecords::DrawRect>(r, rerecord, 1); 47 assert_type<SkRecords::Restore> (r, rerecord, 2); 48} 49 50DEF_TEST(RecordDraw_Unbalanced, r) { 51 SkRecord record; 52 SkRecorder recorder(&record, W, H); 53 recorder.save(); // We won't balance this, but SkRecordDraw will for us. 54 55 SkRecord rerecord; 56 SkRecorder canvas(&rerecord, W, H); 57 SkRecordDraw(record, &canvas, NULL/*bbh*/, NULL/*callback*/); 58 59 REPORTER_ASSERT(r, 4 == rerecord.count()); 60 assert_type<SkRecords::Save> (r, rerecord, 0); 61 assert_type<SkRecords::Save> (r, rerecord, 1); 62 assert_type<SkRecords::Restore> (r, rerecord, 2); 63 assert_type<SkRecords::Restore> (r, rerecord, 3); 64} 65 66DEF_TEST(RecordDraw_SetMatrixClobber, r) { 67 // Set up an SkRecord that just scales by 2x,3x. 68 SkRecord scaleRecord; 69 SkRecorder scaleCanvas(&scaleRecord, W, H); 70 SkMatrix scale; 71 scale.setScale(2, 3); 72 scaleCanvas.setMatrix(scale); 73 74 // Set up an SkRecord with an initial +20, +20 translate. 75 SkRecord translateRecord; 76 SkRecorder translateCanvas(&translateRecord, W, H); 77 SkMatrix translate; 78 translate.setTranslate(20, 20); 79 translateCanvas.setMatrix(translate); 80 81 SkRecordDraw(scaleRecord, &translateCanvas, NULL/*bbh*/, NULL/*callback*/); 82 REPORTER_ASSERT(r, 4 == translateRecord.count()); 83 assert_type<SkRecords::SetMatrix>(r, translateRecord, 0); 84 assert_type<SkRecords::Save> (r, translateRecord, 1); 85 assert_type<SkRecords::SetMatrix>(r, translateRecord, 2); 86 assert_type<SkRecords::Restore> (r, translateRecord, 3); 87 88 // When we look at translateRecord now, it should have its first +20,+20 translate, 89 // then a 2x,3x scale that's been concatted with that +20,+20 translate. 90 const SkRecords::SetMatrix* setMatrix; 91 setMatrix = assert_type<SkRecords::SetMatrix>(r, translateRecord, 0); 92 REPORTER_ASSERT(r, setMatrix->matrix == translate); 93 94 setMatrix = assert_type<SkRecords::SetMatrix>(r, translateRecord, 2); 95 SkMatrix expected = scale; 96 expected.postConcat(translate); 97 REPORTER_ASSERT(r, setMatrix->matrix == expected); 98} 99 100struct TestBBH : public SkBBoxHierarchy { 101 virtual void insert(void* data, const SkRect& bounds, bool defer) SK_OVERRIDE { 102 Entry e = { (uintptr_t)data, bounds }; 103 entries.push(e); 104 } 105 virtual int getCount() const SK_OVERRIDE { return entries.count(); } 106 107 virtual void flushDeferredInserts() SK_OVERRIDE {} 108 109 virtual void search(const SkRect& query, SkTDArray<void*>* results) const SK_OVERRIDE {} 110 virtual void clear() SK_OVERRIDE {} 111 virtual void rewindInserts() SK_OVERRIDE {} 112 virtual int getDepth() const SK_OVERRIDE { return -1; } 113 114 struct Entry { 115 uintptr_t data; 116 SkRect bounds; 117 }; 118 SkTDArray<Entry> entries; 119}; 120 121// Like a==b, with a little slop recognizing that float equality can be weird. 122static bool sloppy_rect_eq(SkRect a, SkRect b) { 123 SkRect inset(a), outset(a); 124 inset.inset(1, 1); 125 outset.outset(1, 1); 126 return outset.contains(b) && !inset.contains(b); 127} 128 129// This test is not meant to make total sense yet. It's testing the status quo 130// of SkRecordFillBounds(), which itself doesn't make total sense yet. 131DEF_TEST(RecordDraw_BBH, r) { 132 SkRecord record; 133 SkRecorder recorder(&record, W, H); 134 recorder.save(); 135 recorder.clipRect(SkRect::MakeWH(400, 500)); 136 recorder.scale(2, 2); 137 recorder.drawRect(SkRect::MakeWH(320, 240), SkPaint()); 138 recorder.restore(); 139 140 TestBBH bbh; 141 SkRecordFillBounds(record, &bbh); 142 143 REPORTER_ASSERT(r, bbh.entries.count() == 5); 144 for (int i = 0; i < bbh.entries.count(); i++) { 145 REPORTER_ASSERT(r, bbh.entries[i].data == (uintptr_t)i); 146 147 REPORTER_ASSERT(r, sloppy_rect_eq(SkRect::MakeWH(400, 480), bbh.entries[i].bounds)); 148 } 149} 150 151// A regression test for crbug.com/409110. 152DEF_TEST(RecordDraw_TextBounds, r) { 153 SkRecord record; 154 SkRecorder recorder(&record, W, H); 155 156 // Two Chinese characters in UTF-8. 157 const char text[] = { '\xe6', '\xbc', '\xa2', '\xe5', '\xad', '\x97' }; 158 const size_t bytes = SK_ARRAY_COUNT(text); 159 160 const SkScalar xpos[] = { 10, 20 }; 161 recorder.drawPosTextH(text, bytes, xpos, 30, SkPaint()); 162 163 const SkPoint pos[] = { {40, 50}, {60, 70} }; 164 recorder.drawPosText(text, bytes, pos, SkPaint()); 165 166 TestBBH bbh; 167 SkRecordFillBounds(record, &bbh); 168 REPORTER_ASSERT(r, bbh.entries.count() == 2); 169 170 // We can make these next assertions confidently because SkRecordFillBounds 171 // builds its bounds by overestimating font metrics in a platform-independent way. 172 // If that changes, these tests will need to be more flexible. 173 REPORTER_ASSERT(r, sloppy_rect_eq(bbh.entries[0].bounds, SkRect::MakeLTRB(-86, 6, 116, 54))); 174 REPORTER_ASSERT(r, sloppy_rect_eq(bbh.entries[1].bounds, SkRect::MakeLTRB(-56, 26, 156, 94))); 175} 176 177// Base test to ensure start/stop range is respected 178DEF_TEST(RecordDraw_PartialStartStop, r) { 179 static const int kWidth = 10, kHeight = 10; 180 181 SkRect r1 = { 0, 0, kWidth, kHeight }; 182 SkRect r2 = { 0, 0, kWidth, kHeight/2 }; 183 SkRect r3 = { 0, 0, kWidth/2, kHeight }; 184 SkPaint p; 185 186 SkRecord record; 187 SkRecorder recorder(&record, kWidth, kHeight); 188 recorder.drawRect(r1, p); 189 recorder.drawRect(r2, p); 190 recorder.drawRect(r3, p); 191 192 SkRecord rerecord; 193 SkRecorder canvas(&rerecord, kWidth, kHeight); 194 SkRecordPartialDraw(record, &canvas, r1, 1, 2, SkMatrix::I()); // replay just drawRect of r2 195 196 REPORTER_ASSERT(r, 3 == rerecord.count()); 197 assert_type<SkRecords::Save> (r, rerecord, 0); 198 assert_type<SkRecords::DrawRect> (r, rerecord, 1); 199 assert_type<SkRecords::Restore> (r, rerecord, 2); 200 201 const SkRecords::DrawRect* drawRect = assert_type<SkRecords::DrawRect>(r, rerecord, 1); 202 REPORTER_ASSERT(r, drawRect->rect == r2); 203} 204 205// Check that clears are converted to drawRects 206DEF_TEST(RecordDraw_PartialClear, r) { 207 static const int kWidth = 10, kHeight = 10; 208 209 SkRect rect = { 0, 0, kWidth, kHeight }; 210 211 SkRecord record; 212 SkRecorder recorder(&record, kWidth, kHeight); 213 recorder.clear(SK_ColorRED); 214 215 SkRecord rerecord; 216 SkRecorder canvas(&rerecord, kWidth, kHeight); 217 SkRecordPartialDraw(record, &canvas, rect, 0, 1, SkMatrix::I()); // replay just the clear 218 219 REPORTER_ASSERT(r, 3 == rerecord.count()); 220 assert_type<SkRecords::Save> (r, rerecord, 0); 221 assert_type<SkRecords::DrawRect>(r, rerecord, 1); 222 assert_type<SkRecords::Restore> (r, rerecord, 2); 223 224 const SkRecords::DrawRect* drawRect = assert_type<SkRecords::DrawRect>(r, rerecord, 1); 225 REPORTER_ASSERT(r, drawRect->rect == rect); 226 REPORTER_ASSERT(r, drawRect->paint.getColor() == SK_ColorRED); 227} 228 229// A regression test for crbug.com/415468 and skbug.com/2957. 230DEF_TEST(RecordDraw_SaveLayerAffectsClipBounds, r) { 231 SkRecord record; 232 SkRecorder recorder(&record, 50, 50); 233 234 // We draw a rectangle with a long drop shadow. We used to not update the clip 235 // bounds based on SaveLayer paints, so the drop shadow could be cut off. 236 SkPaint paint; 237 paint.setImageFilter(SkDropShadowImageFilter::Create(20, 0, 0, 0, SK_ColorBLACK))->unref(); 238 239 recorder.saveLayer(NULL, &paint); 240 recorder.clipRect(SkRect::MakeWH(20, 40)); 241 recorder.drawRect(SkRect::MakeWH(20, 40), SkPaint()); 242 recorder.restore(); 243 244 // Under the original bug, all the right edge values would be 20 less than asserted here 245 // because we intersected them with a clip that had not been adjusted for the drop shadow. 246 TestBBH bbh; 247 SkRecordFillBounds(record, &bbh); 248 REPORTER_ASSERT(r, bbh.entries.count() == 4); 249 REPORTER_ASSERT(r, sloppy_rect_eq(bbh.entries[0].bounds, SkRect::MakeLTRB(0, 0, 70, 50))); 250 REPORTER_ASSERT(r, sloppy_rect_eq(bbh.entries[1].bounds, SkRect::MakeLTRB(0, 0, 70, 50))); 251 REPORTER_ASSERT(r, sloppy_rect_eq(bbh.entries[2].bounds, SkRect::MakeLTRB(0, 0, 40, 40))); 252 REPORTER_ASSERT(r, sloppy_rect_eq(bbh.entries[3].bounds, SkRect::MakeLTRB(0, 0, 70, 50))); 253} 254