skia2/samplecode/SampleFilterFuzz.cpp
senorblanco@chromium.org 97f5fc6519 Allow SkPictureImageFilter to be serialized when not run cross-process.
Picture serialization is not yet hardened, but it turns out we do need
serialization of SkPictureImageFilter for deferred SVG-on-SVG filters,
since the SkPaints (and thus the SkImageFilters) are serialized by
SkPictureRecord. However, deferred filters are always drawn in the
same process, so we can safely serialize them in this case. We do this
by turning the compile-time check for
SK_ALLOW_PICTUREIMAGEFILTER_SERIALIZATION to a runtime check for
isCrossProcess().

The image filter fuzzer sample was also modified to enable fuzzing
of basic picture image filters (the code had rotted a bit, being behind
an #ifdef that no one sets).

BUG=375162
R=sugoi@google.com

Review URL: https://codereview.chromium.org/311443003

git-svn-id: http://skia.googlecode.com/svn/trunk@15008 2bbb7eff-a529-9590-31e7-b0007b416f81
2014-05-30 20:50:56 +00:00

489 lines
17 KiB
C++

/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SampleCode.h"
#include "SkAlphaThresholdFilter.h"
#include "SkBicubicImageFilter.h"
#include "SkBitmapDevice.h"
#include "SkBitmapSource.h"
#include "SkBlurImageFilter.h"
#include "SkCanvas.h"
#include "SkColorFilter.h"
#include "SkColorFilterImageFilter.h"
#include "SkComposeImageFilter.h"
#include "SkData.h"
#include "SkDisplacementMapEffect.h"
#include "SkDropShadowImageFilter.h"
#include "SkFlattenableSerialization.h"
#include "SkLightingImageFilter.h"
#include "SkMagnifierImageFilter.h"
#include "SkMatrixImageFilter.h"
#include "SkMatrixConvolutionImageFilter.h"
#include "SkMergeImageFilter.h"
#include "SkMorphologyImageFilter.h"
#include "SkOffsetImageFilter.h"
#include "SkPerlinNoiseShader.h"
#include "SkPictureImageFilter.h"
#include "SkPictureRecorder.h"
#include "SkRandom.h"
#include "SkRectShaderImageFilter.h"
#include "SkTestImageFilters.h"
#include "SkTileImageFilter.h"
#include "SkView.h"
#include "SkXfermodeImageFilter.h"
#include <stdio.h>
#include <time.h>
//#define SK_ADD_RANDOM_BIT_FLIPS
//#define SK_FUZZER_IS_VERBOSE
static const uint32_t kSeed = (uint32_t)(time(NULL));
static SkRandom gRand(kSeed);
static bool return_large = false;
static bool return_undef = false;
static const int kBitmapSize = 24;
static int R(float x) {
return (int)floor(SkScalarToFloat(gRand.nextUScalar1()) * x);
}
#if defined _WIN32
#pragma warning ( push )
// we are intentionally causing an overflow here
// (warning C4756: overflow in constant arithmetic)
#pragma warning ( disable : 4756 )
#endif
static float huge() {
double d = 1e100;
float f = (float)d;
return f;
}
#if defined _WIN32
#pragma warning ( pop )
#endif
static float make_number(bool positiveOnly) {
float f = positiveOnly ? 1.0f : 0.0f;
float v = f;
int sel;
if (return_large) sel = R(6); else sel = R(4);
if (!return_undef && sel == 0) sel = 1;
if (R(2) == 1) v = (float)(R(100)+f); else
switch (sel) {
case 0: break;
case 1: v = f; break;
case 2: v = 0.000001f; break;
case 3: v = 10000.0f; break;
case 4: v = 2000000000.0f; break;
case 5: v = huge(); break;
}
if (!positiveOnly && (R(4) == 1)) v = -v;
return v;
}
static SkScalar make_scalar(bool positiveOnly = false) {
return make_number(positiveOnly);
}
static SkRect make_rect() {
return SkRect::MakeWH(SkIntToScalar(R(static_cast<float>(kBitmapSize))),
SkIntToScalar(R(static_cast<float>(kBitmapSize))));
}
static SkRegion make_region() {
SkIRect iRegion = SkIRect::MakeXYWH(R(static_cast<float>(kBitmapSize)),
R(static_cast<float>(kBitmapSize)),
R(static_cast<float>(kBitmapSize)),
R(static_cast<float>(kBitmapSize)));
return SkRegion(iRegion);
}
static SkMatrix make_matrix() {
SkMatrix m;
for (int i = 0; i < 9; ++i) {
m[i] = make_scalar();
}
return m;
}
static SkXfermode::Mode make_xfermode() {
return static_cast<SkXfermode::Mode>(R(SkXfermode::kLastMode+1));
}
static SkColor make_color() {
return (R(2) == 1) ? 0xFFC0F0A0 : 0xFF000090;
}
static SkPoint3 make_point() {
return SkPoint3(make_scalar(), make_scalar(), make_scalar(true));
}
static SkDisplacementMapEffect::ChannelSelectorType make_channel_selector_type() {
return static_cast<SkDisplacementMapEffect::ChannelSelectorType>(R(4)+1);
}
static bool valid_for_raster_canvas(const SkImageInfo& info) {
switch (info.colorType()) {
case kAlpha_8_SkColorType:
case kRGB_565_SkColorType:
return true;
case kN32_SkColorType:
return kPremul_SkAlphaType == info.alphaType() ||
kOpaque_SkAlphaType == info.alphaType();
default:
break;
}
return false;
}
static SkColorType rand_colortype() {
return (SkColorType)R(kLastEnum_SkColorType + 1);
}
static void rand_bitmap_for_canvas(SkBitmap* bitmap) {
SkImageInfo info;
do {
info = SkImageInfo::Make(kBitmapSize, kBitmapSize, rand_colortype(),
kPremul_SkAlphaType);
} while (!valid_for_raster_canvas(info) || !bitmap->allocPixels(info));
}
static void make_g_bitmap(SkBitmap& bitmap) {
rand_bitmap_for_canvas(&bitmap);
SkCanvas canvas(bitmap);
canvas.clear(0x00000000);
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(0xFF884422);
paint.setTextSize(SkIntToScalar(kBitmapSize/2));
const char* str = "g";
canvas.drawText(str, strlen(str), SkIntToScalar(kBitmapSize/8),
SkIntToScalar(kBitmapSize/4), paint);
}
static void make_checkerboard_bitmap(SkBitmap& bitmap) {
rand_bitmap_for_canvas(&bitmap);
SkCanvas canvas(bitmap);
canvas.clear(0x00000000);
SkPaint darkPaint;
darkPaint.setColor(0xFF804020);
SkPaint lightPaint;
lightPaint.setColor(0xFF244484);
const int i = kBitmapSize / 8;
const SkScalar f = SkIntToScalar(i);
for (int y = 0; y < kBitmapSize; y += i) {
for (int x = 0; x < kBitmapSize; x += i) {
canvas.save();
canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
canvas.drawRect(SkRect::MakeXYWH(0, 0, f, f), darkPaint);
canvas.drawRect(SkRect::MakeXYWH(f, 0, f, f), lightPaint);
canvas.drawRect(SkRect::MakeXYWH(0, f, f, f), lightPaint);
canvas.drawRect(SkRect::MakeXYWH(f, f, f, f), darkPaint);
canvas.restore();
}
}
}
static const SkBitmap& make_bitmap() {
static SkBitmap bitmap[2];
static bool initialized = false;
if (!initialized) {
make_g_bitmap(bitmap[0]);
make_checkerboard_bitmap(bitmap[1]);
initialized = true;
}
return bitmap[R(2)];
}
static void drawSomething(SkCanvas* canvas) {
SkPaint paint;
canvas->save();
canvas->scale(0.5f, 0.5f);
canvas->drawBitmap(make_bitmap(), 0, 0, NULL);
canvas->restore();
const char beforeStr[] = "before circle";
const char afterStr[] = "after circle";
paint.setAntiAlias(true);
paint.setColor(SK_ColorRED);
canvas->drawData(beforeStr, sizeof(beforeStr));
canvas->drawCircle(SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/3), paint);
canvas->drawData(afterStr, sizeof(afterStr));
paint.setColor(SK_ColorBLACK);
paint.setTextSize(SkIntToScalar(kBitmapSize/3));
canvas->drawText("Picture", 7, SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/4), paint);
}
static SkImageFilter* make_image_filter(bool canBeNull = true) {
SkImageFilter* filter = 0;
// Add a 1 in 3 chance to get a NULL input
if (canBeNull && (R(3) == 1)) { return filter; }
enum { ALPHA_THRESHOLD, BICUBIC, MERGE, COLOR, BLUR, MAGNIFIER,
DOWN_SAMPLE, XFERMODE, OFFSET, MATRIX, MATRIX_CONVOLUTION, COMPOSE,
DISTANT_LIGHT, POINT_LIGHT, SPOT_LIGHT, NOISE, DROP_SHADOW,
MORPHOLOGY, BITMAP, DISPLACE, TILE, PICTURE, NUM_FILTERS };
switch (R(NUM_FILTERS)) {
case ALPHA_THRESHOLD:
filter = SkAlphaThresholdFilter::Create(make_region(), make_scalar(), make_scalar());
break;
case BICUBIC:
// Scale is set to 1 here so that it can fit in the DAG without resizing the output
filter = SkBicubicImageFilter::CreateMitchell(SkSize::Make(1, 1), make_image_filter());
break;
case MERGE:
filter = SkMergeImageFilter::Create(make_image_filter(), make_image_filter(), make_xfermode());
break;
case COLOR:
{
SkAutoTUnref<SkColorFilter> cf((R(2) == 1) ?
SkColorFilter::CreateModeFilter(make_color(), make_xfermode()) :
SkColorFilter::CreateLightingFilter(make_color(), make_color()));
filter = cf.get() ? SkColorFilterImageFilter::Create(cf, make_image_filter()) : 0;
}
break;
case BLUR:
filter = SkBlurImageFilter::Create(make_scalar(true), make_scalar(true), make_image_filter());
break;
case MAGNIFIER:
filter = SkMagnifierImageFilter::Create(make_rect(), make_scalar(true));
break;
case DOWN_SAMPLE:
filter = SkDownSampleImageFilter::Create(make_scalar());
break;
case XFERMODE:
{
SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(make_xfermode()));
filter = SkXfermodeImageFilter::Create(mode, make_image_filter(), make_image_filter());
}
break;
case OFFSET:
filter = SkOffsetImageFilter::Create(make_scalar(), make_scalar(), make_image_filter());
break;
case MATRIX:
filter = SkMatrixImageFilter::Create(make_matrix(),
(SkPaint::FilterLevel)R(4),
make_image_filter());
break;
case MATRIX_CONVOLUTION:
{
SkImageFilter::CropRect cropR(SkRect::MakeWH(SkIntToScalar(kBitmapSize),
SkIntToScalar(kBitmapSize)));
SkISize size = SkISize::Make(R(10)+1, R(10)+1);
int arraySize = size.width() * size.height();
SkTArray<SkScalar> kernel(arraySize);
for (int i = 0; i < arraySize; ++i) {
kernel.push_back() = make_scalar();
}
SkIPoint kernelOffset = SkIPoint::Make(R(SkIntToScalar(size.width())),
R(SkIntToScalar(size.height())));
filter = SkMatrixConvolutionImageFilter::Create(size,
kernel.begin(),
make_scalar(),
make_scalar(),
kernelOffset,
(SkMatrixConvolutionImageFilter::TileMode)R(3),
R(2) == 1,
make_image_filter(),
&cropR);
}
break;
case COMPOSE:
filter = SkComposeImageFilter::Create(make_image_filter(), make_image_filter());
break;
case DISTANT_LIGHT:
filter = (R(2) == 1) ?
SkLightingImageFilter::CreateDistantLitDiffuse(make_point(),
make_color(), make_scalar(), make_scalar(), make_image_filter()) :
SkLightingImageFilter::CreateDistantLitSpecular(make_point(),
make_color(), make_scalar(), make_scalar(), SkIntToScalar(R(10)),
make_image_filter());
break;
case POINT_LIGHT:
filter = (R(2) == 1) ?
SkLightingImageFilter::CreatePointLitDiffuse(make_point(),
make_color(), make_scalar(), make_scalar(), make_image_filter()) :
SkLightingImageFilter::CreatePointLitSpecular(make_point(),
make_color(), make_scalar(), make_scalar(), SkIntToScalar(R(10)),
make_image_filter());
break;
case SPOT_LIGHT:
filter = (R(2) == 1) ?
SkLightingImageFilter::CreateSpotLitDiffuse(SkPoint3(0, 0, 0),
make_point(), make_scalar(), make_scalar(), make_color(),
make_scalar(), make_scalar(), make_image_filter()) :
SkLightingImageFilter::CreateSpotLitSpecular(SkPoint3(0, 0, 0),
make_point(), make_scalar(), make_scalar(), make_color(),
make_scalar(), make_scalar(), SkIntToScalar(R(10)), make_image_filter());
break;
case NOISE:
{
SkAutoTUnref<SkShader> shader((R(2) == 1) ?
SkPerlinNoiseShader::CreateFractalNoise(
make_scalar(true), make_scalar(true), R(10.0f), make_scalar()) :
SkPerlinNoiseShader::CreateTurbulence(
make_scalar(true), make_scalar(true), R(10.0f), make_scalar()));
SkImageFilter::CropRect cropR(SkRect::MakeWH(SkIntToScalar(kBitmapSize),
SkIntToScalar(kBitmapSize)));
filter = SkRectShaderImageFilter::Create(shader, &cropR);
}
break;
case DROP_SHADOW:
filter = SkDropShadowImageFilter::Create(make_scalar(), make_scalar(),
make_scalar(true), make_color(), make_image_filter());
break;
case MORPHOLOGY:
if (R(2) == 1) {
filter = SkDilateImageFilter::Create(R(static_cast<float>(kBitmapSize)),
R(static_cast<float>(kBitmapSize)), make_image_filter());
} else {
filter = SkErodeImageFilter::Create(R(static_cast<float>(kBitmapSize)),
R(static_cast<float>(kBitmapSize)), make_image_filter());
}
break;
case BITMAP:
if (R(2) == 1) {
filter = SkBitmapSource::Create(make_bitmap(), make_rect(), make_rect());
} else {
filter = SkBitmapSource::Create(make_bitmap());
}
break;
case DISPLACE:
filter = SkDisplacementMapEffect::Create(make_channel_selector_type(),
make_channel_selector_type(), make_scalar(),
make_image_filter(false), make_image_filter());
break;
case TILE:
filter = SkTileImageFilter::Create(make_rect(), make_rect(), make_image_filter(false));
break;
case PICTURE:
{
SkRTreeFactory factory;
SkPictureRecorder recorder;
SkCanvas* recordingCanvas = recorder.beginRecording(kBitmapSize, kBitmapSize, &factory, 0);
drawSomething(recordingCanvas);
SkAutoTUnref<SkPicture> pict(recorder.endRecording());
filter = SkPictureImageFilter::Create(pict.get(), make_rect());
}
break;
default:
break;
}
return (filter || canBeNull) ? filter : make_image_filter(canBeNull);
}
static SkImageFilter* make_serialized_image_filter() {
SkAutoTUnref<SkImageFilter> filter(make_image_filter(false));
SkAutoTUnref<SkData> data(SkValidatingSerializeFlattenable(filter));
const unsigned char* ptr = static_cast<const unsigned char*>(data->data());
size_t len = data->size();
#ifdef SK_ADD_RANDOM_BIT_FLIPS
unsigned char* p = const_cast<unsigned char*>(ptr);
for (size_t i = 0; i < len; ++i, ++p) {
if (R(250) == 1) { // 0.4% of the time, flip a bit or byte
if (R(10) == 1) { // Then 10% of the time, change a whole byte
switch(R(3)) {
case 0:
*p ^= 0xFF; // Flip entire byte
break;
case 1:
*p = 0xFF; // Set all bits to 1
break;
case 2:
*p = 0x00; // Set all bits to 0
break;
}
} else {
*p ^= (1 << R(8));
}
}
}
#endif // SK_ADD_RANDOM_BIT_FLIPS
SkFlattenable* flattenable = SkValidatingDeserializeFlattenable(ptr, len,
SkImageFilter::GetFlattenableType());
return static_cast<SkImageFilter*>(flattenable);
}
static void drawClippedBitmap(SkCanvas* canvas, int x, int y, const SkPaint& paint) {
canvas->save();
canvas->clipRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
SkIntToScalar(kBitmapSize), SkIntToScalar(kBitmapSize)));
canvas->drawBitmap(make_bitmap(), SkIntToScalar(x), SkIntToScalar(y), &paint);
canvas->restore();
}
static void do_fuzz(SkCanvas* canvas) {
SkImageFilter* filter = make_serialized_image_filter();
#ifdef SK_FUZZER_IS_VERBOSE
static uint32_t numFilters = 0;
static uint32_t numValidFilters = 0;
if (0 == numFilters) {
printf("Fuzzing with %u\n", kSeed);
}
numFilters++;
if (NULL != filter) {
numValidFilters++;
}
printf("Filter no : %u. Valid filters so far : %u\r", numFilters, numValidFilters);
fflush(stdout);
#endif
SkPaint paint;
SkSafeUnref(paint.setImageFilter(filter));
drawClippedBitmap(canvas, 0, 0, paint);
}
//////////////////////////////////////////////////////////////////////////////
class ImageFilterFuzzView : public SampleView {
public:
ImageFilterFuzzView() {
this->setBGColor(0xFFDDDDDD);
}
protected:
// overrides from SkEventSink
virtual bool onQuery(SkEvent* evt) {
if (SampleCode::TitleQ(*evt)) {
SampleCode::TitleR(evt, "ImageFilterFuzzer");
return true;
}
return this->INHERITED::onQuery(evt);
}
void drawBG(SkCanvas* canvas) {
canvas->drawColor(0xFFDDDDDD);
}
virtual void onDrawContent(SkCanvas* canvas) {
do_fuzz(canvas);
this->inval(0);
}
private:
typedef SkView INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
static SkView* MyFactory() { return new ImageFilterFuzzView; }
static SkViewRegister reg(MyFactory);