Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2011 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 "SkBlurMask.h"
      9 #include "SkBlurMaskFilter.h"
     10 #include "SkBlurDrawLooper.h"
     11 #include "SkLayerDrawLooper.h"
     12 #include "SkEmbossMaskFilter.h"
     13 #include "SkCanvas.h"
     14 #include "SkMath.h"
     15 #include "SkPaint.h"
     16 #include "Test.h"
     17 
     18 #if SK_SUPPORT_GPU
     19 #include "GrContextFactory.h"
     20 #include "SkGpuDevice.h"
     21 #endif
     22 
     23 #define WRITE_CSV 0
     24 
     25 ///////////////////////////////////////////////////////////////////////////////
     26 
     27 #define ILLEGAL_MODE    ((SkXfermode::Mode)-1)
     28 
     29 static const int outset = 100;
     30 static const SkColor bgColor = SK_ColorWHITE;
     31 static const int strokeWidth = 4;
     32 
     33 static void create(SkBitmap* bm, const SkIRect& bound) {
     34     bm->allocN32Pixels(bound.width(), bound.height());
     35 }
     36 
     37 static void drawBG(SkCanvas* canvas) {
     38     canvas->drawColor(bgColor);
     39 }
     40 
     41 
     42 struct BlurTest {
     43     void (*addPath)(SkPath*);
     44     int viewLen;
     45     SkIRect views[9];
     46 };
     47 
     48 //Path Draw Procs
     49 //Beware that paths themselves my draw differently depending on the clip.
     50 static void draw50x50Rect(SkPath* path) {
     51     path->addRect(0, 0, SkIntToScalar(50), SkIntToScalar(50));
     52 }
     53 
     54 //Tests
     55 static BlurTest tests[] = {
     56     { draw50x50Rect, 3, {
     57         //inner half of blur
     58         { 0, 0, 50, 50 },
     59         //blur, but no path.
     60         { 50 + strokeWidth/2, 50 + strokeWidth/2, 100, 100 },
     61         //just an edge
     62         { 40, strokeWidth, 60, 50 - strokeWidth },
     63     }},
     64 };
     65 
     66 /** Assumes that the ref draw was completely inside ref canvas --
     67     implies that everything outside is "bgColor".
     68     Checks that all overlap is the same and that all non-overlap on the
     69     ref is "bgColor".
     70  */
     71 static bool compare(const SkBitmap& ref, const SkIRect& iref,
     72                     const SkBitmap& test, const SkIRect& itest)
     73 {
     74     const int xOff = itest.fLeft - iref.fLeft;
     75     const int yOff = itest.fTop - iref.fTop;
     76 
     77     SkAutoLockPixels alpRef(ref);
     78     SkAutoLockPixels alpTest(test);
     79 
     80     for (int y = 0; y < test.height(); ++y) {
     81         for (int x = 0; x < test.width(); ++x) {
     82             SkColor testColor = test.getColor(x, y);
     83             int refX = x + xOff;
     84             int refY = y + yOff;
     85             SkColor refColor;
     86             if (refX >= 0 && refX < ref.width() &&
     87                 refY >= 0 && refY < ref.height())
     88             {
     89                 refColor = ref.getColor(refX, refY);
     90             } else {
     91                 refColor = bgColor;
     92             }
     93             if (refColor != testColor) {
     94                 return false;
     95             }
     96         }
     97     }
     98     return true;
     99 }
    100 
    101 static void test_blur_drawing(skiatest::Reporter* reporter) {
    102 
    103     SkPaint paint;
    104     paint.setColor(SK_ColorGRAY);
    105     paint.setStyle(SkPaint::kStroke_Style);
    106     paint.setStrokeWidth(SkIntToScalar(strokeWidth));
    107 
    108     SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(5));
    109     for (int style = 0; style <= kLastEnum_SkBlurStyle; ++style) {
    110         SkBlurStyle blurStyle = static_cast<SkBlurStyle>(style);
    111 
    112         const uint32_t flagPermutations = SkBlurMaskFilter::kAll_BlurFlag;
    113         for (uint32_t flags = 0; flags < flagPermutations; ++flags) {
    114             SkMaskFilter* filter;
    115             filter = SkBlurMaskFilter::Create(blurStyle, sigma, flags);
    116 
    117             paint.setMaskFilter(filter);
    118             filter->unref();
    119 
    120             for (size_t test = 0; test < SK_ARRAY_COUNT(tests); ++test) {
    121                 SkPath path;
    122                 tests[test].addPath(&path);
    123                 SkPath strokedPath;
    124                 paint.getFillPath(path, &strokedPath);
    125                 SkRect refBound = strokedPath.getBounds();
    126                 SkIRect iref;
    127                 refBound.roundOut(&iref);
    128                 iref.inset(-outset, -outset);
    129                 SkBitmap refBitmap;
    130                 create(&refBitmap, iref);
    131 
    132                 SkCanvas refCanvas(refBitmap);
    133                 refCanvas.translate(SkIntToScalar(-iref.fLeft),
    134                                     SkIntToScalar(-iref.fTop));
    135                 drawBG(&refCanvas);
    136                 refCanvas.drawPath(path, paint);
    137 
    138                 for (int view = 0; view < tests[test].viewLen; ++view) {
    139                     SkIRect itest = tests[test].views[view];
    140                     SkBitmap testBitmap;
    141                     create(&testBitmap, itest);
    142 
    143                     SkCanvas testCanvas(testBitmap);
    144                     testCanvas.translate(SkIntToScalar(-itest.fLeft),
    145                                          SkIntToScalar(-itest.fTop));
    146                     drawBG(&testCanvas);
    147                     testCanvas.drawPath(path, paint);
    148 
    149                     REPORTER_ASSERT(reporter,
    150                         compare(refBitmap, iref, testBitmap, itest));
    151                 }
    152             }
    153         }
    154     }
    155 }
    156 
    157 ///////////////////////////////////////////////////////////////////////////////
    158 
    159 // Use SkBlurMask::BlurGroundTruth to blur a 'width' x 'height' solid
    160 // white rect. Return the right half of the middle row in 'result'.
    161 static void ground_truth_2d(int width, int height,
    162                             SkScalar sigma,
    163                             int* result, int resultCount) {
    164     SkMask src, dst;
    165 
    166     src.fBounds.set(0, 0, width, height);
    167     src.fFormat = SkMask::kA8_Format;
    168     src.fRowBytes = src.fBounds.width();
    169     src.fImage = SkMask::AllocImage(src.computeTotalImageSize());
    170 
    171     memset(src.fImage, 0xff, src.computeTotalImageSize());
    172 
    173     dst.fImage = NULL;
    174     SkBlurMask::BlurGroundTruth(sigma, &dst, src, kNormal_SkBlurStyle);
    175 
    176     int midX = dst.fBounds.centerX();
    177     int midY = dst.fBounds.centerY();
    178     uint8_t* bytes = dst.getAddr8(midX, midY);
    179     int i;
    180     for (i = 0; i < dst.fBounds.width()-(midX-dst.fBounds.fLeft); ++i) {
    181         if (i < resultCount) {
    182             result[i] = bytes[i];
    183         }
    184     }
    185     for ( ; i < resultCount; ++i) {
    186         result[i] = 0;
    187     }
    188 
    189     SkMask::FreeImage(src.fImage);
    190     SkMask::FreeImage(dst.fImage);
    191 }
    192 
    193 // Implement a step function that is 255 between min and max; 0 elsewhere.
    194 static int step(int x, SkScalar min, SkScalar max) {
    195     if (min < x && x < max) {
    196         return 255;
    197     }
    198     return 0;
    199 }
    200 
    201 // Implement a Gaussian function with 0 mean and std.dev. of 'sigma'.
    202 static float gaussian(int x, SkScalar sigma) {
    203     float k = SK_Scalar1/(sigma * sqrtf(2.0f*SK_ScalarPI));
    204     float exponent = -(x * x) / (2 * sigma * sigma);
    205     return k * expf(exponent);
    206 }
    207 
    208 // Perform a brute force convolution of a step function with a Gaussian.
    209 // Return the right half in 'result'
    210 static void brute_force_1d(SkScalar stepMin, SkScalar stepMax,
    211                            SkScalar gaussianSigma,
    212                            int* result, int resultCount) {
    213 
    214     int gaussianRange = SkScalarCeilToInt(10 * gaussianSigma);
    215 
    216     for (int i = 0; i < resultCount; ++i) {
    217         SkScalar sum = 0.0f;
    218         for (int j = -gaussianRange; j < gaussianRange; ++j) {
    219             sum += gaussian(j, gaussianSigma) * step(i-j, stepMin, stepMax);
    220         }
    221 
    222         result[i] = SkClampMax(SkClampPos(int(sum + 0.5f)), 255);
    223     }
    224 }
    225 
    226 static void blur_path(SkCanvas* canvas, const SkPath& path,
    227                       SkScalar gaussianSigma) {
    228 
    229     SkScalar midX = path.getBounds().centerX();
    230     SkScalar midY = path.getBounds().centerY();
    231 
    232     canvas->translate(-midX, -midY);
    233 
    234     SkPaint blurPaint;
    235     blurPaint.setColor(SK_ColorWHITE);
    236     SkMaskFilter* filter = SkBlurMaskFilter::Create(kNormal_SkBlurStyle,
    237                                                     gaussianSigma,
    238                                                     SkBlurMaskFilter::kHighQuality_BlurFlag);
    239     blurPaint.setMaskFilter(filter)->unref();
    240 
    241     canvas->drawColor(SK_ColorBLACK);
    242     canvas->drawPath(path, blurPaint);
    243 }
    244 
    245 // Readback the blurred draw results from the canvas
    246 static void readback(SkCanvas* canvas, int* result, int resultCount) {
    247     SkBitmap readback;
    248     readback.allocN32Pixels(resultCount, 30);
    249 
    250     SkIRect readBackRect = { 0, 0, resultCount, 30 };
    251 
    252     canvas->readPixels(readBackRect, &readback);
    253 
    254     readback.lockPixels();
    255     SkPMColor* pixels = (SkPMColor*) readback.getAddr32(0, 15);
    256 
    257     for (int i = 0; i < resultCount; ++i) {
    258         result[i] = SkColorGetR(pixels[i]);
    259     }
    260 }
    261 
    262 // Draw a blurred version of the provided path.
    263 // Return the right half of the middle row in 'result'.
    264 static void cpu_blur_path(const SkPath& path, SkScalar gaussianSigma,
    265                           int* result, int resultCount) {
    266 
    267     SkBitmap bitmap;
    268     bitmap.allocN32Pixels(resultCount, 30);
    269     SkCanvas canvas(bitmap);
    270 
    271     blur_path(&canvas, path, gaussianSigma);
    272     readback(&canvas, result, resultCount);
    273 }
    274 
    275 #if SK_SUPPORT_GPU
    276 #if 0
    277 // temporary disable; see below for explanation
    278 static bool gpu_blur_path(GrContextFactory* factory, const SkPath& path,
    279                           SkScalar gaussianSigma,
    280                           int* result, int resultCount) {
    281 
    282     GrContext* grContext = factory->get(GrContextFactory::kNative_GLContextType);
    283     if (NULL == grContext) {
    284         return false;
    285     }
    286 
    287     GrTextureDesc desc;
    288     desc.fConfig = kSkia8888_GrPixelConfig;
    289     desc.fFlags = kRenderTarget_GrTextureFlagBit;
    290     desc.fWidth = resultCount;
    291     desc.fHeight = 30;
    292     desc.fSampleCnt = 0;
    293 
    294     SkAutoTUnref<GrTexture> texture(grContext->createUncachedTexture(desc, NULL, 0));
    295     SkAutoTUnref<SkGpuDevice> device(SkNEW_ARGS(SkGpuDevice, (grContext, texture.get())));
    296     SkCanvas canvas(device.get());
    297 
    298     blur_path(&canvas, path, gaussianSigma);
    299     readback(&canvas, result, resultCount);
    300     return true;
    301 }
    302 #endif
    303 #endif
    304 
    305 #if WRITE_CSV
    306 static void write_as_csv(const char* label, SkScalar scale, int* data, int count) {
    307     SkDebugf("%s_%.2f,", label, scale);
    308     for (int i = 0; i < count-1; ++i) {
    309         SkDebugf("%d,", data[i]);
    310     }
    311     SkDebugf("%d\n", data[count-1]);
    312 }
    313 #endif
    314 
    315 static bool match(int* first, int* second, int count, int tol) {
    316     int delta;
    317     for (int i = 0; i < count; ++i) {
    318         delta = first[i] - second[i];
    319         if (delta > tol || delta < -tol) {
    320             return false;
    321         }
    322     }
    323 
    324     return true;
    325 }
    326 
    327 // Test out the normal blur style with a wide range of sigmas
    328 static void test_sigma_range(skiatest::Reporter* reporter, GrContextFactory* factory) {
    329 
    330     static const int kSize = 100;
    331 
    332     // The geometry is offset a smidge to trigger:
    333     // https://code.google.com/p/chromium/issues/detail?id=282418
    334     SkPath rectPath;
    335     rectPath.addRect(0.3f, 0.3f, 100.3f, 100.3f);
    336 
    337     SkPoint polyPts[] = {
    338         { 0.3f, 0.3f },
    339         { 100.3f, 0.3f },
    340         { 100.3f, 100.3f },
    341         { 0.3f, 100.3f },
    342         { 2.3f, 50.3f }     // a little divet to throw off the rect special case
    343     };
    344     SkPath polyPath;
    345     polyPath.addPoly(polyPts, SK_ARRAY_COUNT(polyPts), true);
    346 
    347     int rectSpecialCaseResult[kSize];
    348     int generalCaseResult[kSize];
    349     int groundTruthResult[kSize];
    350     int bruteForce1DResult[kSize];
    351 
    352     SkScalar sigma = 10.0f;
    353 
    354     for (int i = 0; i < 4; ++i, sigma /= 10) {
    355 
    356         cpu_blur_path(rectPath, sigma, rectSpecialCaseResult, kSize);
    357         cpu_blur_path(polyPath, sigma, generalCaseResult, kSize);
    358 
    359         ground_truth_2d(100, 100, sigma, groundTruthResult, kSize);
    360         brute_force_1d(-50.0f, 50.0f, sigma, bruteForce1DResult, kSize);
    361 
    362         REPORTER_ASSERT(reporter, match(rectSpecialCaseResult, bruteForce1DResult, kSize, 5));
    363         REPORTER_ASSERT(reporter, match(generalCaseResult, bruteForce1DResult, kSize, 15));
    364 #if SK_SUPPORT_GPU
    365 #if 0
    366         int gpuResult[kSize];
    367         bool haveGPUResult = gpu_blur_path(factory, rectPath, sigma, gpuResult, kSize);
    368         // Disabling this test for now -- I don't think it's a legit comparison.
    369         // Will continue to investigate this.
    370         if (haveGPUResult) {
    371             // 1 works everywhere but: Ubuntu13 & Nexus4
    372             REPORTER_ASSERT(reporter, match(gpuResult, bruteForce1DResult, kSize, 10));
    373         }
    374 #endif
    375 #endif
    376         REPORTER_ASSERT(reporter, match(groundTruthResult, bruteForce1DResult, kSize, 1));
    377 
    378 #if WRITE_CSV
    379         write_as_csv("RectSpecialCase", sigma, rectSpecialCaseResult, kSize);
    380         write_as_csv("GeneralCase", sigma, generalCaseResult, kSize);
    381 #if SK_SUPPORT_GPU
    382         write_as_csv("GPU", sigma, gpuResult, kSize);
    383 #endif
    384         write_as_csv("GroundTruth2D", sigma, groundTruthResult, kSize);
    385         write_as_csv("BruteForce1D", sigma, bruteForce1DResult, kSize);
    386 #endif
    387     }
    388 }
    389 
    390 ///////////////////////////////////////////////////////////////////////////////////////////
    391 
    392 static SkBlurQuality blurMaskFilterFlags_as_quality(uint32_t blurMaskFilterFlags) {
    393     return (blurMaskFilterFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
    394             kHigh_SkBlurQuality : kLow_SkBlurQuality;
    395 }
    396 
    397 static uint32_t blurMaskFilterFlags_to_blurDrawLooperFlags(uint32_t bmf) {
    398     const struct {
    399         uint32_t fBlurMaskFilterFlag;
    400         uint32_t fBlurDrawLooperFlag;
    401     } pairs[] = {
    402         { SkBlurMaskFilter::kIgnoreTransform_BlurFlag, SkBlurDrawLooper::kIgnoreTransform_BlurFlag },
    403         { SkBlurMaskFilter::kHighQuality_BlurFlag,     SkBlurDrawLooper::kHighQuality_BlurFlag },
    404     };
    405 
    406     uint32_t bdl = 0;
    407     for (size_t i = 0; i < SK_ARRAY_COUNT(pairs); ++i) {
    408         if (bmf & pairs[i].fBlurMaskFilterFlag) {
    409             bdl |= pairs[i].fBlurDrawLooperFlag;
    410         }
    411     }
    412     return bdl;
    413 }
    414 
    415 static void test_blurDrawLooper(skiatest::Reporter* reporter, SkScalar sigma,
    416                                 SkBlurStyle style, uint32_t blurMaskFilterFlags) {
    417     if (kNormal_SkBlurStyle != style) {
    418         return; // blurdrawlooper only supports normal
    419     }
    420 
    421     const SkColor color = 0xFF335577;
    422     const SkScalar dx = 10;
    423     const SkScalar dy = -5;
    424     const SkBlurQuality quality = blurMaskFilterFlags_as_quality(blurMaskFilterFlags);
    425     uint32_t flags = blurMaskFilterFlags_to_blurDrawLooperFlags(blurMaskFilterFlags);
    426 
    427     SkAutoTUnref<SkDrawLooper> lp(SkBlurDrawLooper::Create(color, sigma, dx, dy, flags));
    428 
    429     const bool expectSuccess = sigma > 0 &&
    430                                0 == (flags & SkBlurDrawLooper::kIgnoreTransform_BlurFlag);
    431 
    432     if (NULL == lp.get()) {
    433         REPORTER_ASSERT(reporter, sigma <= 0);
    434     } else {
    435         SkDrawLooper::BlurShadowRec rec;
    436         bool success = lp->asABlurShadow(&rec);
    437         REPORTER_ASSERT(reporter, success == expectSuccess);
    438         if (success) {
    439             REPORTER_ASSERT(reporter, rec.fSigma == sigma);
    440             REPORTER_ASSERT(reporter, rec.fOffset.x() == dx);
    441             REPORTER_ASSERT(reporter, rec.fOffset.y() == dy);
    442             REPORTER_ASSERT(reporter, rec.fColor == color);
    443             REPORTER_ASSERT(reporter, rec.fStyle == style);
    444             REPORTER_ASSERT(reporter, rec.fQuality == quality);
    445         }
    446     }
    447 }
    448 
    449 static void test_delete_looper(skiatest::Reporter* reporter, SkDrawLooper* lp, SkScalar sigma,
    450                                SkBlurStyle style, SkBlurQuality quality, bool expectSuccess) {
    451     SkDrawLooper::BlurShadowRec rec;
    452     bool success = lp->asABlurShadow(&rec);
    453     REPORTER_ASSERT(reporter, success == expectSuccess);
    454     if (success != expectSuccess) {
    455         lp->asABlurShadow(&rec);
    456     }
    457     if (success) {
    458         REPORTER_ASSERT(reporter, rec.fSigma == sigma);
    459         REPORTER_ASSERT(reporter, rec.fStyle == style);
    460         REPORTER_ASSERT(reporter, rec.fQuality == quality);
    461     }
    462     lp->unref();
    463 }
    464 
    465 static void make_noop_layer(SkLayerDrawLooper::Builder* builder) {
    466     SkLayerDrawLooper::LayerInfo info;
    467 
    468     info.fPaintBits = 0;
    469     info.fColorMode = SkXfermode::kDst_Mode;
    470     builder->addLayer(info);
    471 }
    472 
    473 static void make_blur_layer(SkLayerDrawLooper::Builder* builder, SkMaskFilter* mf) {
    474     SkLayerDrawLooper::LayerInfo info;
    475 
    476     info.fPaintBits = SkLayerDrawLooper::kMaskFilter_Bit;
    477     info.fColorMode = SkXfermode::kSrc_Mode;
    478     SkPaint* paint = builder->addLayer(info);
    479     paint->setMaskFilter(mf);
    480 }
    481 
    482 static void test_layerDrawLooper(skiatest::Reporter* reporter, SkMaskFilter* mf, SkScalar sigma,
    483                                  SkBlurStyle style, SkBlurQuality quality, bool expectSuccess) {
    484 
    485     SkLayerDrawLooper::LayerInfo info;
    486     SkLayerDrawLooper::Builder builder;
    487 
    488     // 1 layer is too few
    489     make_noop_layer(&builder);
    490     test_delete_looper(reporter, builder.detachLooper(), sigma, style, quality, false);
    491 
    492     // 2 layers is good, but need blur
    493     make_noop_layer(&builder);
    494     make_noop_layer(&builder);
    495     test_delete_looper(reporter, builder.detachLooper(), sigma, style, quality, false);
    496 
    497     // 2 layers is just right
    498     make_noop_layer(&builder);
    499     make_blur_layer(&builder, mf);
    500     test_delete_looper(reporter, builder.detachLooper(), sigma, style, quality, expectSuccess);
    501 
    502     // 3 layers is too many
    503     make_noop_layer(&builder);
    504     make_blur_layer(&builder, mf);
    505     make_noop_layer(&builder);
    506     test_delete_looper(reporter, builder.detachLooper(), sigma, style, quality, false);
    507 }
    508 
    509 static void test_asABlur(skiatest::Reporter* reporter) {
    510     const SkBlurStyle styles[] = {
    511         kNormal_SkBlurStyle, kSolid_SkBlurStyle, kOuter_SkBlurStyle, kInner_SkBlurStyle
    512     };
    513     const SkScalar sigmas[] = {
    514         // values <= 0 should not success for a blur
    515         -1, 0, 0.5f, 2
    516     };
    517 
    518     // Test asABlur for SkBlurMaskFilter
    519     //
    520     for (size_t i = 0; i < SK_ARRAY_COUNT(styles); ++i) {
    521         const SkBlurStyle style = (SkBlurStyle)styles[i];
    522         for (size_t j = 0; j < SK_ARRAY_COUNT(sigmas); ++j) {
    523             const SkScalar sigma = sigmas[j];
    524             for (int flags = 0; flags <= SkBlurMaskFilter::kAll_BlurFlag; ++flags) {
    525                 const SkBlurQuality quality = blurMaskFilterFlags_as_quality(flags);
    526 
    527                 SkAutoTUnref<SkMaskFilter> mf(SkBlurMaskFilter::Create(style, sigma, flags));
    528                 if (NULL == mf.get()) {
    529                     REPORTER_ASSERT(reporter, sigma <= 0);
    530                 } else {
    531                     REPORTER_ASSERT(reporter, sigma > 0);
    532                     SkMaskFilter::BlurRec rec;
    533                     bool success = mf->asABlur(&rec);
    534                     if (flags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
    535                         REPORTER_ASSERT(reporter, !success);
    536                     } else {
    537                         REPORTER_ASSERT(reporter, success);
    538                         REPORTER_ASSERT(reporter, rec.fSigma == sigma);
    539                         REPORTER_ASSERT(reporter, rec.fStyle == style);
    540                         REPORTER_ASSERT(reporter, rec.fQuality == quality);
    541                     }
    542                     test_layerDrawLooper(reporter, mf, sigma, style, quality, success);
    543                 }
    544                 test_blurDrawLooper(reporter, sigma, style, flags);
    545             }
    546         }
    547     }
    548 
    549     // Test asABlur for SkEmbossMaskFilter -- should never succeed
    550     //
    551     {
    552         SkEmbossMaskFilter::Light light = {
    553             { 1, 1, 1 }, 0, 127, 127
    554         };
    555         for (size_t j = 0; j < SK_ARRAY_COUNT(sigmas); ++j) {
    556             const SkScalar sigma = sigmas[j];
    557             SkAutoTUnref<SkMaskFilter> mf(SkEmbossMaskFilter::Create(sigma, light));
    558             if (mf.get()) {
    559                 SkMaskFilter::BlurRec rec;
    560                 bool success = mf->asABlur(&rec);
    561                 REPORTER_ASSERT(reporter, !success);
    562             }
    563         }
    564     }
    565 }
    566 
    567 ///////////////////////////////////////////////////////////////////////////////////////////
    568 
    569 DEF_GPUTEST(Blur, reporter, factory) {
    570     test_blur_drawing(reporter);
    571     test_sigma_range(reporter, factory);
    572     test_asABlur(reporter);
    573 }
    574