1327f905d2cb0d37c302d651d8f2b17ea56368467dneto/* 2327f905d2cb0d37c302d651d8f2b17ea56368467dneto * Copyright 2014 Google Inc. 3327f905d2cb0d37c302d651d8f2b17ea56368467dneto * 4327f905d2cb0d37c302d651d8f2b17ea56368467dneto * Use of this source code is governed by a BSD-style license that can be 5327f905d2cb0d37c302d651d8f2b17ea56368467dneto * found in the LICENSE file. 6327f905d2cb0d37c302d651d8f2b17ea56368467dneto */ 7327f905d2cb0d37c302d651d8f2b17ea56368467dneto 8327f905d2cb0d37c302d651d8f2b17ea56368467dneto#include "Test.h" 9327f905d2cb0d37c302d651d8f2b17ea56368467dneto 10327f905d2cb0d37c302d651d8f2b17ea56368467dneto#include "../include/core/SkCanvas.h" 11327f905d2cb0d37c302d651d8f2b17ea56368467dneto#include "../include/core/SkPicture.h" 12327f905d2cb0d37c302d651d8f2b17ea56368467dneto#include "../include/core/SkStream.h" 13327f905d2cb0d37c302d651d8f2b17ea56368467dneto#include "../include/core/SkString.h" 14327f905d2cb0d37c302d651d8f2b17ea56368467dneto#include "../include/core/SkPictureRecorder.h" 15327f905d2cb0d37c302d651d8f2b17ea56368467dneto#include <cstring> 16327f905d2cb0d37c302d651d8f2b17ea56368467dneto 17327f905d2cb0d37c302d651d8f2b17ea56368467dneto// Verify that replay of a recording into a clipped canvas 18327f905d2cb0d37c302d651d8f2b17ea56368467dneto// produces the correct bitmap. 19327f905d2cb0d37c302d651d8f2b17ea56368467dneto// This arose from http://crbug.com/401593 which has 20327f905d2cb0d37c302d651d8f2b17ea56368467dneto// https://code.google.com/p/skia/issues/detail?id=1291 as its root cause. 21327f905d2cb0d37c302d651d8f2b17ea56368467dneto 22327f905d2cb0d37c302d651d8f2b17ea56368467dnetonamespace { 23327f905d2cb0d37c302d651d8f2b17ea56368467dneto 24327f905d2cb0d37c302d651d8f2b17ea56368467dnetoclass Drawer { 25327f905d2cb0d37c302d651d8f2b17ea56368467dneto public: 2646616af01b412ea984a516fda1ed8ec08e689f29mtklein explicit Drawer() : fImageInfo(SkImageInfo::MakeN32Premul(200, 100)) { 2746616af01b412ea984a516fda1ed8ec08e689f29mtklein fCircleBM.allocPixels(SkImageInfo::MakeN32Premul(100, 100)); 28327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkCanvas canvas(fCircleBM); 29327f905d2cb0d37c302d651d8f2b17ea56368467dneto canvas.clear(0xffffffff); 30327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkPaint circlePaint; 31327f905d2cb0d37c302d651d8f2b17ea56368467dneto circlePaint.setColor(0xff000000); 3246616af01b412ea984a516fda1ed8ec08e689f29mtklein canvas.drawCircle(50, 50, 50, circlePaint); 33327f905d2cb0d37c302d651d8f2b17ea56368467dneto } 34327f905d2cb0d37c302d651d8f2b17ea56368467dneto 35327f905d2cb0d37c302d651d8f2b17ea56368467dneto const SkImageInfo& imageInfo() const { return fImageInfo; } 36327f905d2cb0d37c302d651d8f2b17ea56368467dneto 37327f905d2cb0d37c302d651d8f2b17ea56368467dneto void draw(SkCanvas* canvas, const SkRect& clipRect, SkXfermode::Mode mode) const { 38327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkPaint greenPaint; 39327f905d2cb0d37c302d651d8f2b17ea56368467dneto greenPaint.setColor(0xff008000); 40327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkPaint blackPaint; 41327f905d2cb0d37c302d651d8f2b17ea56368467dneto blackPaint.setColor(0xff000000); 42327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkPaint whitePaint; 43327f905d2cb0d37c302d651d8f2b17ea56368467dneto whitePaint.setColor(0xffffffff); 44327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkPaint layerPaint; 45327f905d2cb0d37c302d651d8f2b17ea56368467dneto layerPaint.setColor(0xff000000); 46327f905d2cb0d37c302d651d8f2b17ea56368467dneto layerPaint.setXfermodeMode(mode); 4746616af01b412ea984a516fda1ed8ec08e689f29mtklein SkRect canvasRect(SkRect::MakeWH(SkIntToScalar(fImageInfo.width()), 4846616af01b412ea984a516fda1ed8ec08e689f29mtklein SkIntToScalar(fImageInfo.height()))); 49327f905d2cb0d37c302d651d8f2b17ea56368467dneto 50327f905d2cb0d37c302d651d8f2b17ea56368467dneto canvas->clipRect(clipRect); 51327f905d2cb0d37c302d651d8f2b17ea56368467dneto canvas->clear(0xff000000); 52327f905d2cb0d37c302d651d8f2b17ea56368467dneto 5346616af01b412ea984a516fda1ed8ec08e689f29mtklein canvas->saveLayer(NULL, &blackPaint); 5446616af01b412ea984a516fda1ed8ec08e689f29mtklein canvas->drawRect(canvasRect, greenPaint); 5546616af01b412ea984a516fda1ed8ec08e689f29mtklein canvas->saveLayer(NULL, &layerPaint); 5646616af01b412ea984a516fda1ed8ec08e689f29mtklein canvas->drawBitmapRect(fCircleBM, SkRect::MakeXYWH(20,20,60,60), &blackPaint); 57327f905d2cb0d37c302d651d8f2b17ea56368467dneto canvas->restore(); 58327f905d2cb0d37c302d651d8f2b17ea56368467dneto canvas->restore(); 59327f905d2cb0d37c302d651d8f2b17ea56368467dneto } 60327f905d2cb0d37c302d651d8f2b17ea56368467dneto 61327f905d2cb0d37c302d651d8f2b17ea56368467dneto private: 62327f905d2cb0d37c302d651d8f2b17ea56368467dneto const SkImageInfo fImageInfo; 63327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkBitmap fCircleBM; 64327f905d2cb0d37c302d651d8f2b17ea56368467dneto}; 65327f905d2cb0d37c302d651d8f2b17ea56368467dneto 66327f905d2cb0d37c302d651d8f2b17ea56368467dnetoclass RecordingStrategy { 67327f905d2cb0d37c302d651d8f2b17ea56368467dneto public: 68327f905d2cb0d37c302d651d8f2b17ea56368467dneto virtual ~RecordingStrategy() {} 69327f905d2cb0d37c302d651d8f2b17ea56368467dneto virtual const SkBitmap& recordAndReplay(const Drawer& drawer, 70327f905d2cb0d37c302d651d8f2b17ea56368467dneto const SkRect& intoClip, 71327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkXfermode::Mode) = 0; 72327f905d2cb0d37c302d651d8f2b17ea56368467dneto}; 73327f905d2cb0d37c302d651d8f2b17ea56368467dneto 74327f905d2cb0d37c302d651d8f2b17ea56368467dnetoclass BitmapBackedCanvasStrategy : public RecordingStrategy { 75327f905d2cb0d37c302d651d8f2b17ea56368467dneto // This version just draws into a bitmap-backed canvas. 76327f905d2cb0d37c302d651d8f2b17ea56368467dneto public: 7746616af01b412ea984a516fda1ed8ec08e689f29mtklein BitmapBackedCanvasStrategy(const SkImageInfo& imageInfo) { 78327f905d2cb0d37c302d651d8f2b17ea56368467dneto fBitmap.allocPixels(imageInfo); 79327f905d2cb0d37c302d651d8f2b17ea56368467dneto } 80327f905d2cb0d37c302d651d8f2b17ea56368467dneto 81327f905d2cb0d37c302d651d8f2b17ea56368467dneto virtual const SkBitmap& recordAndReplay(const Drawer& drawer, 82327f905d2cb0d37c302d651d8f2b17ea56368467dneto const SkRect& intoClip, 83327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkXfermode::Mode mode) { 84327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkCanvas canvas(fBitmap); 85327f905d2cb0d37c302d651d8f2b17ea56368467dneto canvas.clear(0xffffffff); 86327f905d2cb0d37c302d651d8f2b17ea56368467dneto // Note that the scene is drawn just into the clipped region! 87327f905d2cb0d37c302d651d8f2b17ea56368467dneto canvas.clipRect(intoClip); 88327f905d2cb0d37c302d651d8f2b17ea56368467dneto drawer.draw(&canvas, intoClip, mode); // Shouild be canvas-wide... 89327f905d2cb0d37c302d651d8f2b17ea56368467dneto return fBitmap; 90327f905d2cb0d37c302d651d8f2b17ea56368467dneto } 91327f905d2cb0d37c302d651d8f2b17ea56368467dneto 92327f905d2cb0d37c302d651d8f2b17ea56368467dneto private: 93327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkBitmap fBitmap; 94327f905d2cb0d37c302d651d8f2b17ea56368467dneto}; 95327f905d2cb0d37c302d651d8f2b17ea56368467dneto 9646616af01b412ea984a516fda1ed8ec08e689f29mtkleinclass PictureStrategy : public RecordingStrategy { 9746616af01b412ea984a516fda1ed8ec08e689f29mtklein // This version draws the entire scene into an SkPictureRecorder. 98327f905d2cb0d37c302d651d8f2b17ea56368467dneto // Then it then replays the scene through a clip rectangle. 99327f905d2cb0d37c302d651d8f2b17ea56368467dneto // This backend proved to be buggy. 100327f905d2cb0d37c302d651d8f2b17ea56368467dneto public: 10146616af01b412ea984a516fda1ed8ec08e689f29mtklein PictureStrategy(const SkImageInfo& imageInfo) { 102327f905d2cb0d37c302d651d8f2b17ea56368467dneto fBitmap.allocPixels(imageInfo); 10346616af01b412ea984a516fda1ed8ec08e689f29mtklein fWidth = imageInfo.width(); 10446616af01b412ea984a516fda1ed8ec08e689f29mtklein fHeight = imageInfo.height(); 105327f905d2cb0d37c302d651d8f2b17ea56368467dneto } 106327f905d2cb0d37c302d651d8f2b17ea56368467dneto 107327f905d2cb0d37c302d651d8f2b17ea56368467dneto virtual const SkBitmap& recordAndReplay(const Drawer& drawer, 108327f905d2cb0d37c302d651d8f2b17ea56368467dneto const SkRect& intoClip, 109327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkXfermode::Mode mode) { 110703dd2ed187b9788c5bb0f2d313f2d07695603d6mtklein SkRTreeFactory factory; 111327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkPictureRecorder recorder; 112327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkRect canvasRect(SkRect::MakeWH(SkIntToScalar(fWidth),SkIntToScalar(fHeight))); 11346616af01b412ea984a516fda1ed8ec08e689f29mtklein SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(fWidth), 11446616af01b412ea984a516fda1ed8ec08e689f29mtklein SkIntToScalar(fHeight), 11546616af01b412ea984a516fda1ed8ec08e689f29mtklein &factory); 116327f905d2cb0d37c302d651d8f2b17ea56368467dneto drawer.draw(canvas, canvasRect, mode); 11790d0ff013bbd8e5295d1517d41cb408e9d9f4d93reed SkAutoTUnref<SkPicture> picture(recorder.endRecording()); 118327f905d2cb0d37c302d651d8f2b17ea56368467dneto 119327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkCanvas replayCanvas(fBitmap); 120327f905d2cb0d37c302d651d8f2b17ea56368467dneto replayCanvas.clear(0xffffffff); 121327f905d2cb0d37c302d651d8f2b17ea56368467dneto replayCanvas.clipRect(intoClip); 122327f905d2cb0d37c302d651d8f2b17ea56368467dneto picture->playback(&replayCanvas); 123327f905d2cb0d37c302d651d8f2b17ea56368467dneto return fBitmap; 124327f905d2cb0d37c302d651d8f2b17ea56368467dneto } 125327f905d2cb0d37c302d651d8f2b17ea56368467dneto 126327f905d2cb0d37c302d651d8f2b17ea56368467dneto private: 127327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkBitmap fBitmap; 128327f905d2cb0d37c302d651d8f2b17ea56368467dneto int fWidth; 129327f905d2cb0d37c302d651d8f2b17ea56368467dneto int fHeight; 130327f905d2cb0d37c302d651d8f2b17ea56368467dneto}; 131327f905d2cb0d37c302d651d8f2b17ea56368467dneto 13246616af01b412ea984a516fda1ed8ec08e689f29mtklein} // namespace 133327f905d2cb0d37c302d651d8f2b17ea56368467dneto 134327f905d2cb0d37c302d651d8f2b17ea56368467dneto 135327f905d2cb0d37c302d651d8f2b17ea56368467dnetoDEF_TEST(SkRecordingAccuracyXfermode, reporter) { 136327f905d2cb0d37c302d651d8f2b17ea56368467dneto#define FINEGRAIN 0 137327f905d2cb0d37c302d651d8f2b17ea56368467dneto const Drawer drawer; 138327f905d2cb0d37c302d651d8f2b17ea56368467dneto 13946616af01b412ea984a516fda1ed8ec08e689f29mtklein BitmapBackedCanvasStrategy golden(drawer.imageInfo()); 14046616af01b412ea984a516fda1ed8ec08e689f29mtklein PictureStrategy picture(drawer.imageInfo()); 141327f905d2cb0d37c302d651d8f2b17ea56368467dneto 142327f905d2cb0d37c302d651d8f2b17ea56368467dneto#if !FINEGRAIN 143327f905d2cb0d37c302d651d8f2b17ea56368467dneto unsigned numErrors = 0; 144327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkString errors; 145327f905d2cb0d37c302d651d8f2b17ea56368467dneto#endif 146327f905d2cb0d37c302d651d8f2b17ea56368467dneto 14746616af01b412ea984a516fda1ed8ec08e689f29mtklein for (int iMode = 0; iMode < int(SkXfermode::kLastMode); iMode++) { 14846616af01b412ea984a516fda1ed8ec08e689f29mtklein const SkRect& clip = SkRect::MakeXYWH(100, 0, 100, 100); 149327f905d2cb0d37c302d651d8f2b17ea56368467dneto SkXfermode::Mode mode = SkXfermode::Mode(iMode); 150327f905d2cb0d37c302d651d8f2b17ea56368467dneto 151327f905d2cb0d37c302d651d8f2b17ea56368467dneto const SkBitmap& goldenBM = golden.recordAndReplay(drawer, clip, mode); 15246616af01b412ea984a516fda1ed8ec08e689f29mtklein const SkBitmap& pictureBM = picture.recordAndReplay(drawer, clip, mode); 153327f905d2cb0d37c302d651d8f2b17ea56368467dneto 154327f905d2cb0d37c302d651d8f2b17ea56368467dneto size_t pixelsSize = goldenBM.getSize(); 15546616af01b412ea984a516fda1ed8ec08e689f29mtklein REPORTER_ASSERT(reporter, pixelsSize == pictureBM.getSize()); 156327f905d2cb0d37c302d651d8f2b17ea56368467dneto 157327f905d2cb0d37c302d651d8f2b17ea56368467dneto // The pixel arrays should match. 158327f905d2cb0d37c302d651d8f2b17ea56368467dneto#if FINEGRAIN 15946616af01b412ea984a516fda1ed8ec08e689f29mtklein REPORTER_ASSERT(reporter, 16046616af01b412ea984a516fda1ed8ec08e689f29mtklein 0 == memcmp(goldenBM.getPixels(), pictureBM.getPixels(), pixelsSize)); 161327f905d2cb0d37c302d651d8f2b17ea56368467dneto#else 16246616af01b412ea984a516fda1ed8ec08e689f29mtklein if (memcmp(goldenBM.getPixels(), pictureBM.getPixels(), pixelsSize)) { 163327f905d2cb0d37c302d651d8f2b17ea56368467dneto numErrors++; 16446616af01b412ea984a516fda1ed8ec08e689f29mtklein errors.appendf("For SkXfermode %d %s: SkPictureRecorder bitmap is wrong\n", 16546616af01b412ea984a516fda1ed8ec08e689f29mtklein iMode, SkXfermode::ModeName(mode)); 166327f905d2cb0d37c302d651d8f2b17ea56368467dneto } 167327f905d2cb0d37c302d651d8f2b17ea56368467dneto#endif 168327f905d2cb0d37c302d651d8f2b17ea56368467dneto } 16946616af01b412ea984a516fda1ed8ec08e689f29mtklein 170327f905d2cb0d37c302d651d8f2b17ea56368467dneto#if !FINEGRAIN 17146616af01b412ea984a516fda1ed8ec08e689f29mtklein REPORTER_ASSERT_MESSAGE(reporter, 0 == numErrors, errors.c_str()); 172327f905d2cb0d37c302d651d8f2b17ea56368467dneto#endif 173327f905d2cb0d37c302d651d8f2b17ea56368467dneto} 174