| 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 |