OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "Test.h" | 8 #include "Test.h" |
9 | 9 |
10 #include "../include/core/SkCanvas.h" | 10 #include "../include/core/SkCanvas.h" |
11 #include "../include/core/SkPicture.h" | 11 #include "../include/core/SkPicture.h" |
12 #include "../include/core/SkStream.h" | 12 #include "../include/core/SkStream.h" |
13 #include "../include/core/SkString.h" | 13 #include "../include/core/SkString.h" |
14 #include "../include/record/SkRecording.h" | 14 #include "../include/record/SkRecording.h" |
15 #include "../include/core/SkPictureRecorder.h" | 15 #include "../include/core/SkPictureRecorder.h" |
16 #include <cstring> | 16 #include <cstring> |
17 | 17 |
18 // Verify that replay of a recording into a clipped canvas | 18 // Verify that replay of a recording into a clipped canvas |
19 // produces the correct bitmap. | 19 // produces the correct bitmap. |
20 // This arose from http://crbug.com/401593 which has | 20 // This arose from http://crbug.com/401593 which has |
21 // https://code.google.com/p/skia/issues/detail?id=1291 as its root cause. | 21 // https://code.google.com/p/skia/issues/detail?id=1291 as its root cause. |
22 | 22 |
23 | |
24 namespace { | 23 namespace { |
25 | 24 |
26 class Drawer { | 25 class Drawer { |
27 public: | 26 public: |
28 explicit Drawer() | 27 explicit Drawer() : fImageInfo(SkImageInfo::MakeN32Premul(200, 100)) { |
29 : fImageInfo(SkImageInfo::MakeN32Premul(200,100)) | 28 fCircleBM.allocPixels(SkImageInfo::MakeN32Premul(100, 100)); |
30 { | |
31 fCircleBM.allocPixels( SkImageInfo::MakeN32Premul(100,100) ); | |
32 SkCanvas canvas(fCircleBM); | 29 SkCanvas canvas(fCircleBM); |
33 canvas.clear(0xffffffff); | 30 canvas.clear(0xffffffff); |
34 SkPaint circlePaint; | 31 SkPaint circlePaint; |
35 circlePaint.setColor(0xff000000); | 32 circlePaint.setColor(0xff000000); |
36 canvas.drawCircle(50,50,50,circlePaint); | 33 canvas.drawCircle(50, 50, 50, circlePaint); |
37 } | 34 } |
38 | 35 |
39 const SkImageInfo& imageInfo() const { return fImageInfo; } | 36 const SkImageInfo& imageInfo() const { return fImageInfo; } |
40 | 37 |
41 void draw(SkCanvas* canvas, const SkRect& clipRect, SkXfermode::Mode mode) c
onst { | 38 void draw(SkCanvas* canvas, const SkRect& clipRect, SkXfermode::Mode mode) c
onst { |
42 SkPaint greenPaint; | 39 SkPaint greenPaint; |
43 greenPaint.setColor(0xff008000); | 40 greenPaint.setColor(0xff008000); |
44 SkPaint blackPaint; | 41 SkPaint blackPaint; |
45 blackPaint.setColor(0xff000000); | 42 blackPaint.setColor(0xff000000); |
46 SkPaint whitePaint; | 43 SkPaint whitePaint; |
47 whitePaint.setColor(0xffffffff); | 44 whitePaint.setColor(0xffffffff); |
48 SkPaint layerPaint; | 45 SkPaint layerPaint; |
49 layerPaint.setColor(0xff000000); | 46 layerPaint.setColor(0xff000000); |
50 layerPaint.setXfermodeMode(mode); | 47 layerPaint.setXfermodeMode(mode); |
51 SkRect canvasRect(SkRect::MakeWH(SkIntToScalar(fImageInfo.width()),SkInt
ToScalar(fImageInfo.height()))); | 48 SkRect canvasRect(SkRect::MakeWH(SkIntToScalar(fImageInfo.width()), |
| 49 SkIntToScalar(fImageInfo.height()))); |
52 | 50 |
53 canvas->clipRect(clipRect); | 51 canvas->clipRect(clipRect); |
54 canvas->clear(0xff000000); | 52 canvas->clear(0xff000000); |
55 | 53 |
56 canvas->saveLayer(NULL,&blackPaint); | 54 canvas->saveLayer(NULL, &blackPaint); |
57 canvas->drawRect(canvasRect,greenPaint); | 55 canvas->drawRect(canvasRect, greenPaint); |
58 canvas->saveLayer(NULL,&layerPaint); | 56 canvas->saveLayer(NULL, &layerPaint); |
59 canvas->drawBitmapRect(fCircleBM,SkRect::MakeXYWH(20,20,60,60),&
blackPaint); | 57 canvas->drawBitmapRect(fCircleBM, SkRect::MakeXYWH(20,20,60,60),
&blackPaint); |
60 canvas->restore(); | 58 canvas->restore(); |
61 canvas->restore(); | 59 canvas->restore(); |
62 } | 60 } |
63 | 61 |
64 private: | 62 private: |
65 const SkImageInfo fImageInfo; | 63 const SkImageInfo fImageInfo; |
66 SkBitmap fCircleBM; | 64 SkBitmap fCircleBM; |
67 }; | 65 }; |
68 | 66 |
69 class RecordingStrategy { | 67 class RecordingStrategy { |
70 public: | 68 public: |
71 virtual ~RecordingStrategy() {} | 69 virtual ~RecordingStrategy() {} |
72 virtual void init(const SkImageInfo&) = 0; | |
73 virtual const SkBitmap& recordAndReplay(const Drawer& drawer, | 70 virtual const SkBitmap& recordAndReplay(const Drawer& drawer, |
74 const SkRect& intoClip, | 71 const SkRect& intoClip, |
75 SkXfermode::Mode) = 0; | 72 SkXfermode::Mode) = 0; |
76 }; | 73 }; |
77 | 74 |
78 class BitmapBackedCanvasStrategy : public RecordingStrategy { | 75 class BitmapBackedCanvasStrategy : public RecordingStrategy { |
79 // This version just draws into a bitmap-backed canvas. | 76 // This version just draws into a bitmap-backed canvas. |
80 public: | 77 public: |
81 BitmapBackedCanvasStrategy() {} | 78 BitmapBackedCanvasStrategy(const SkImageInfo& imageInfo) { |
82 | |
83 virtual void init(const SkImageInfo& imageInfo) { | |
84 fBitmap.allocPixels(imageInfo); | 79 fBitmap.allocPixels(imageInfo); |
85 } | 80 } |
86 | 81 |
87 virtual const SkBitmap& recordAndReplay(const Drawer& drawer, | 82 virtual const SkBitmap& recordAndReplay(const Drawer& drawer, |
88 const SkRect& intoClip, | 83 const SkRect& intoClip, |
89 SkXfermode::Mode mode) { | 84 SkXfermode::Mode mode) { |
90 SkCanvas canvas(fBitmap); | 85 SkCanvas canvas(fBitmap); |
91 canvas.clear(0xffffffff); | 86 canvas.clear(0xffffffff); |
92 // Note that the scene is drawn just into the clipped region! | 87 // Note that the scene is drawn just into the clipped region! |
93 canvas.clipRect(intoClip); | 88 canvas.clipRect(intoClip); |
94 drawer.draw(&canvas, intoClip, mode); // Shouild be canvas-wide... | 89 drawer.draw(&canvas, intoClip, mode); // Shouild be canvas-wide... |
95 return fBitmap; | 90 return fBitmap; |
96 } | 91 } |
97 | 92 |
98 private: | 93 private: |
99 SkBitmap fBitmap; | 94 SkBitmap fBitmap; |
100 }; | 95 }; |
101 | 96 |
102 class DeprecatedRecorderStrategy : public RecordingStrategy { | 97 class PictureStrategy : public RecordingStrategy { |
103 // This version draws the entire scene into an SkPictureRecorder, | 98 // This version draws the entire scene into an SkPictureRecorder. |
104 // using the deprecated recording backend. | |
105 // Then it then replays the scene through a clip rectangle. | 99 // Then it then replays the scene through a clip rectangle. |
106 // This backend proved to be buggy. | 100 // This backend proved to be buggy. |
107 public: | 101 public: |
108 DeprecatedRecorderStrategy() {} | 102 PictureStrategy(const SkImageInfo& imageInfo) { |
109 | |
110 virtual void init(const SkImageInfo& imageInfo) { | |
111 fBitmap.allocPixels(imageInfo); | 103 fBitmap.allocPixels(imageInfo); |
112 fWidth = imageInfo.width(); | 104 fWidth = imageInfo.width(); |
113 fHeight= imageInfo.height(); | 105 fHeight = imageInfo.height(); |
114 } | 106 } |
115 | 107 |
116 virtual const SkBitmap& recordAndReplay(const Drawer& drawer, | 108 virtual const SkBitmap& recordAndReplay(const Drawer& drawer, |
117 const SkRect& intoClip, | |
118 SkXfermode::Mode mode) { | |
119 SkTileGridFactory::TileGridInfo tileGridInfo = { {100,100}, {0,0}, {0,0}
}; | |
120 SkTileGridFactory factory(tileGridInfo); | |
121 SkPictureRecorder recorder; | |
122 SkRect canvasRect(SkRect::MakeWH(SkIntToScalar(fWidth),SkIntToScalar(fHe
ight))); | |
123 SkCanvas* canvas = recorder.DEPRECATED_beginRecording( SkIntToScalar(fWi
dth), SkIntToScalar(fHeight), &factory); | |
124 drawer.draw(canvas, canvasRect, mode); | |
125 SkAutoTDelete<SkPicture> picture(recorder.endRecording()); | |
126 | |
127 SkCanvas replayCanvas(fBitmap); | |
128 replayCanvas.clear(0xffffffff); | |
129 replayCanvas.clipRect(intoClip); | |
130 picture->playback(&replayCanvas); | |
131 | |
132 return fBitmap; | |
133 } | |
134 | |
135 private: | |
136 SkBitmap fBitmap; | |
137 int fWidth; | |
138 int fHeight; | |
139 }; | |
140 | |
141 class NewRecordingStrategy : public RecordingStrategy { | |
142 // This version draws the entire scene into an SkPictureRecorder, | |
143 // using the new recording backend. | |
144 // Then it then replays the scene through a clip rectangle. | |
145 // This backend proved to be buggy. | |
146 public: | |
147 NewRecordingStrategy() {} | |
148 | |
149 virtual void init(const SkImageInfo& imageInfo) { | |
150 fBitmap.allocPixels(imageInfo); | |
151 fWidth = imageInfo.width(); | |
152 fHeight= imageInfo.height(); | |
153 } | |
154 | |
155 virtual const SkBitmap& recordAndReplay(const Drawer& drawer, | |
156 const SkRect& intoClip, | 109 const SkRect& intoClip, |
157 SkXfermode::Mode mode) { | 110 SkXfermode::Mode mode) { |
158 SkTileGridFactory::TileGridInfo tileGridInfo = { {100,100}, {0,0}, {0,0}
}; | 111 SkTileGridFactory::TileGridInfo tileGridInfo = { {100,100}, {0,0}, {0,0}
}; |
159 SkTileGridFactory factory(tileGridInfo); | 112 SkTileGridFactory factory(tileGridInfo); |
160 SkPictureRecorder recorder; | 113 SkPictureRecorder recorder; |
161 SkRect canvasRect(SkRect::MakeWH(SkIntToScalar(fWidth),SkIntToScalar(fHe
ight))); | 114 SkRect canvasRect(SkRect::MakeWH(SkIntToScalar(fWidth),SkIntToScalar(fHe
ight))); |
162 SkCanvas* canvas = recorder.EXPERIMENTAL_beginRecording( SkIntToScalar(f
Width), SkIntToScalar(fHeight), &factory); | 115 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(fWidth), |
163 | 116 SkIntToScalar(fHeight), |
| 117 &factory); |
164 drawer.draw(canvas, canvasRect, mode); | 118 drawer.draw(canvas, canvasRect, mode); |
165 SkAutoTDelete<SkPicture> picture(recorder.endRecording()); | 119 SkAutoTDelete<SkPicture> picture(recorder.endRecording()); |
166 | 120 |
167 SkCanvas replayCanvas(fBitmap); | 121 SkCanvas replayCanvas(fBitmap); |
168 replayCanvas.clear(0xffffffff); | 122 replayCanvas.clear(0xffffffff); |
169 replayCanvas.clipRect(intoClip); | 123 replayCanvas.clipRect(intoClip); |
170 picture->playback(&replayCanvas); | 124 picture->playback(&replayCanvas); |
171 return fBitmap; | 125 return fBitmap; |
172 } | 126 } |
173 | 127 |
174 private: | 128 private: |
175 SkBitmap fBitmap; | 129 SkBitmap fBitmap; |
176 int fWidth; | 130 int fWidth; |
177 int fHeight; | 131 int fHeight; |
178 }; | 132 }; |
179 | 133 |
180 } | 134 } // namespace |
181 | |
182 | 135 |
183 | 136 |
184 DEF_TEST(SkRecordingAccuracyXfermode, reporter) { | 137 DEF_TEST(SkRecordingAccuracyXfermode, reporter) { |
185 #define FINEGRAIN 0 | 138 #define FINEGRAIN 0 |
186 | |
187 const Drawer drawer; | 139 const Drawer drawer; |
188 | 140 |
189 BitmapBackedCanvasStrategy golden; // This is the expected result. | 141 BitmapBackedCanvasStrategy golden(drawer.imageInfo()); |
190 DeprecatedRecorderStrategy deprecatedRecording; | 142 PictureStrategy picture(drawer.imageInfo()); |
191 NewRecordingStrategy newRecording; | |
192 | |
193 golden.init(drawer.imageInfo()); | |
194 deprecatedRecording.init(drawer.imageInfo()); | |
195 newRecording.init(drawer.imageInfo()); | |
196 | 143 |
197 #if !FINEGRAIN | 144 #if !FINEGRAIN |
198 unsigned numErrors = 0; | 145 unsigned numErrors = 0; |
199 SkString errors; | 146 SkString errors; |
200 #endif | 147 #endif |
201 | 148 |
202 for (int iMode = 0; iMode < int(SkXfermode::kLastMode) ; iMode++ ) { | 149 for (int iMode = 0; iMode < int(SkXfermode::kLastMode); iMode++) { |
203 const SkRect& clip = SkRect::MakeXYWH(100,0,100,100); | 150 const SkRect& clip = SkRect::MakeXYWH(100, 0, 100, 100); |
204 SkXfermode::Mode mode = SkXfermode::Mode(iMode); | 151 SkXfermode::Mode mode = SkXfermode::Mode(iMode); |
205 | 152 |
206 const SkBitmap& goldenBM = golden.recordAndReplay(drawer, clip, mode); | 153 const SkBitmap& goldenBM = golden.recordAndReplay(drawer, clip, mode); |
207 const SkBitmap& deprecatedBM = deprecatedRecording.recordAndReplay(drawe
r, clip, mode); | 154 const SkBitmap& pictureBM = picture.recordAndReplay(drawer, clip, mode); |
208 const SkBitmap& newRecordingBM = newRecording.recordAndReplay(drawer, cl
ip, mode); | |
209 | 155 |
210 size_t pixelsSize = goldenBM.getSize(); | 156 size_t pixelsSize = goldenBM.getSize(); |
211 REPORTER_ASSERT( reporter, pixelsSize == deprecatedBM.getSize() ); | 157 REPORTER_ASSERT(reporter, pixelsSize == pictureBM.getSize()); |
212 REPORTER_ASSERT( reporter, pixelsSize == newRecordingBM.getSize() ); | |
213 | 158 |
214 // The pixel arrays should match. | 159 // The pixel arrays should match. |
215 #if FINEGRAIN | 160 #if FINEGRAIN |
216 REPORTER_ASSERT_MESSAGE( reporter, | 161 REPORTER_ASSERT(reporter, |
217 0==memcmp( goldenBM.getPixels(), deprecatedBM.g
etPixels(), pixelsSize ), | 162 0 == memcmp(goldenBM.getPixels(), pictureBM.getPixels(),
pixelsSize)); |
218 "Tiled bitmap is wrong"); | |
219 REPORTER_ASSERT_MESSAGE( reporter, | |
220 0==memcmp( goldenBM.getPixels(), recordingBM.ge
tPixels(), pixelsSize ), | |
221 "SkRecorder bitmap is wrong"); | |
222 #else | 163 #else |
223 if ( memcmp( goldenBM.getPixels(), deprecatedBM.getPixels(), pixelsSize
) ) { | 164 if (memcmp(goldenBM.getPixels(), pictureBM.getPixels(), pixelsSize)) { |
224 numErrors++; | 165 numErrors++; |
225 SkString str; | 166 errors.appendf("For SkXfermode %d %s: SkPictureRecorder bitmap is
wrong\n", |
226 str.printf("For SkXfermode %d %s: Deprecated recorder bitmap is w
rong\n", iMode, SkXfermode::ModeName(mode)); | 167 iMode, SkXfermode::ModeName(mode)); |
227 errors.append(str); | |
228 } | |
229 if ( memcmp( goldenBM.getPixels(), newRecordingBM.getPixels(), pixelsSiz
e ) ) { | |
230 numErrors++; | |
231 SkString str; | |
232 str.printf("For SkXfermode %d %s: SkPictureRecorder bitmap is wro
ng\n", iMode, SkXfermode::ModeName(mode)); | |
233 errors.append(str); | |
234 } | 168 } |
235 #endif | 169 #endif |
236 } | 170 } |
| 171 |
237 #if !FINEGRAIN | 172 #if !FINEGRAIN |
238 REPORTER_ASSERT_MESSAGE( reporter, 0==numErrors, errors.c_str() ); | 173 REPORTER_ASSERT_MESSAGE(reporter, 0 == numErrors, errors.c_str()); |
239 #endif | 174 #endif |
240 } | 175 } |
OLD | NEW |