2013-08-08 21:13:38 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2013 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
2015-12-25 20:56:03 +00:00
|
|
|
|
2013-08-08 21:13:38 +00:00
|
|
|
#include "gm.h"
|
|
|
|
#include "SkBitmap.h"
|
|
|
|
#include "SkGradientShader.h"
|
2015-12-25 20:56:03 +00:00
|
|
|
#include "SkSurface.h"
|
2016-11-15 21:44:34 +00:00
|
|
|
#include "SkBlendModePriv.h"
|
2013-08-08 21:13:38 +00:00
|
|
|
#include "SkColorPriv.h"
|
|
|
|
|
|
|
|
#if SK_SUPPORT_GPU
|
|
|
|
#include "GrContext.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace skiagm {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This tests drawing device-covering rects with solid colors and bitmap shaders over a
|
|
|
|
* checkerboard background using different xfermodes.
|
|
|
|
*/
|
|
|
|
class Xfermodes3GM : public GM {
|
|
|
|
public:
|
|
|
|
Xfermodes3GM() {}
|
|
|
|
|
|
|
|
protected:
|
2015-03-26 01:17:31 +00:00
|
|
|
SkString onShortName() override {
|
2013-08-08 21:13:38 +00:00
|
|
|
return SkString("xfermodes3");
|
|
|
|
}
|
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
SkISize onISize() override {
|
2014-06-10 06:59:03 +00:00
|
|
|
return SkISize::Make(630, 1215);
|
2013-08-08 21:13:38 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
void onDrawBackground(SkCanvas* canvas) override {
|
2013-08-08 21:13:38 +00:00
|
|
|
SkPaint bgPaint;
|
2015-07-21 14:42:45 +00:00
|
|
|
bgPaint.setColor(sk_tool_utils::color_to_565(0xFF70D0E0));
|
2013-08-08 21:13:38 +00:00
|
|
|
canvas->drawPaint(bgPaint);
|
|
|
|
}
|
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
void onDraw(SkCanvas* canvas) override {
|
2013-08-08 21:13:38 +00:00
|
|
|
canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
|
|
|
|
|
|
|
|
SkPaint labelP;
|
|
|
|
labelP.setAntiAlias(true);
|
2015-07-24 19:09:25 +00:00
|
|
|
sk_tool_utils::set_portable_typeface(&labelP);
|
2013-08-08 21:13:38 +00:00
|
|
|
|
2016-09-01 18:24:54 +00:00
|
|
|
constexpr SkColor kSolidColors[] = {
|
2013-08-08 21:13:38 +00:00
|
|
|
SK_ColorTRANSPARENT,
|
|
|
|
SK_ColorBLUE,
|
|
|
|
0x80808000
|
|
|
|
};
|
|
|
|
|
2016-09-01 18:24:54 +00:00
|
|
|
constexpr SkColor kBmpAlphas[] = {
|
2013-08-08 21:13:38 +00:00
|
|
|
0xff,
|
|
|
|
0x80,
|
|
|
|
};
|
|
|
|
|
2016-03-24 01:59:25 +00:00
|
|
|
auto tempSurface(this->possiblyCreateTempSurface(canvas, kSize, kSize));
|
2013-08-08 21:13:38 +00:00
|
|
|
|
|
|
|
int test = 0;
|
|
|
|
int x = 0, y = 0;
|
2016-09-01 18:24:54 +00:00
|
|
|
constexpr struct { SkPaint::Style fStyle; SkScalar fWidth; } kStrokes[] = {
|
2013-08-14 19:20:45 +00:00
|
|
|
{SkPaint::kFill_Style, 0},
|
|
|
|
{SkPaint::kStroke_Style, SkIntToScalar(kSize) / 2},
|
|
|
|
};
|
|
|
|
for (size_t s = 0; s < SK_ARRAY_COUNT(kStrokes); ++s) {
|
2016-11-15 21:44:34 +00:00
|
|
|
for (size_t m = 0; m <= (size_t)SkBlendMode::kLastMode; ++m) {
|
2016-10-06 00:33:02 +00:00
|
|
|
SkBlendMode mode = static_cast<SkBlendMode>(m);
|
2016-11-15 21:44:34 +00:00
|
|
|
canvas->drawText(SkBlendMode_Name(mode),
|
|
|
|
strlen(SkBlendMode_Name(mode)),
|
2013-08-14 19:20:45 +00:00
|
|
|
SkIntToScalar(x),
|
|
|
|
SkIntToScalar(y + kSize + 3) + labelP.getTextSize(),
|
|
|
|
labelP);
|
|
|
|
for (size_t c = 0; c < SK_ARRAY_COUNT(kSolidColors); ++c) {
|
|
|
|
SkPaint modePaint;
|
2016-10-06 00:33:02 +00:00
|
|
|
modePaint.setBlendMode(mode);
|
2013-08-14 19:20:45 +00:00
|
|
|
modePaint.setColor(kSolidColors[c]);
|
|
|
|
modePaint.setStyle(kStrokes[s].fStyle);
|
|
|
|
modePaint.setStrokeWidth(kStrokes[s].fWidth);
|
|
|
|
|
2016-03-24 01:59:25 +00:00
|
|
|
this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempSurface.get());
|
2013-08-14 19:20:45 +00:00
|
|
|
|
|
|
|
++test;
|
|
|
|
x += kSize + 10;
|
|
|
|
if (!(test % kTestsPerRow)) {
|
|
|
|
x = 0;
|
|
|
|
y += kSize + 30;
|
|
|
|
}
|
2013-08-08 21:13:38 +00:00
|
|
|
}
|
2013-08-14 19:20:45 +00:00
|
|
|
for (size_t a = 0; a < SK_ARRAY_COUNT(kBmpAlphas); ++a) {
|
|
|
|
SkPaint modePaint;
|
2016-10-06 00:33:02 +00:00
|
|
|
modePaint.setBlendMode(mode);
|
2013-08-14 19:20:45 +00:00
|
|
|
modePaint.setAlpha(kBmpAlphas[a]);
|
|
|
|
modePaint.setShader(fBmpShader);
|
|
|
|
modePaint.setStyle(kStrokes[s].fStyle);
|
|
|
|
modePaint.setStrokeWidth(kStrokes[s].fWidth);
|
|
|
|
|
2016-03-24 01:59:25 +00:00
|
|
|
this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempSurface.get());
|
2013-08-14 19:20:45 +00:00
|
|
|
|
|
|
|
++test;
|
|
|
|
x += kSize + 10;
|
|
|
|
if (!(test % kTestsPerRow)) {
|
|
|
|
x = 0;
|
|
|
|
y += kSize + 30;
|
|
|
|
}
|
2013-08-08 21:13:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
/**
|
|
|
|
* GrContext has optimizations around full rendertarget draws that can be replaced with clears.
|
|
|
|
* We are trying to test those. We could use saveLayer() to create small SkGpuDevices but
|
|
|
|
* saveLayer() uses the texture cache. This means that the actual render target may be larger
|
|
|
|
* than the layer. Because the clip will contain the layer's bounds, no draws will be full-RT.
|
|
|
|
* So when running on a GPU canvas we explicitly create a temporary canvas using a texture with
|
|
|
|
* dimensions exactly matching the layer size.
|
|
|
|
*/
|
2016-03-24 01:59:25 +00:00
|
|
|
sk_sp<SkSurface> possiblyCreateTempSurface(SkCanvas* baseCanvas, int w, int h) {
|
2013-08-08 21:13:38 +00:00
|
|
|
#if SK_SUPPORT_GPU
|
2014-06-30 16:05:34 +00:00
|
|
|
GrContext* context = baseCanvas->getGrContext();
|
2015-01-16 15:32:33 +00:00
|
|
|
SkImageInfo baseInfo = baseCanvas->imageInfo();
|
|
|
|
SkImageInfo info = SkImageInfo::Make(w, h, baseInfo.colorType(), baseInfo.alphaType(),
|
2017-01-12 15:13:40 +00:00
|
|
|
baseInfo.refColorSpace());
|
2016-04-06 14:38:23 +00:00
|
|
|
SkSurfaceProps canvasProps(SkSurfaceProps::kLegacyFontHost_InitType);
|
|
|
|
baseCanvas->getProps(&canvasProps);
|
|
|
|
return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0, &canvasProps);
|
2015-12-25 20:56:03 +00:00
|
|
|
#else
|
|
|
|
return nullptr;
|
2013-08-08 21:13:38 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawMode(SkCanvas* canvas,
|
|
|
|
int x, int y, int w, int h,
|
2015-12-25 20:56:03 +00:00
|
|
|
const SkPaint& modePaint, SkSurface* surface) {
|
2013-08-08 21:13:38 +00:00
|
|
|
canvas->save();
|
|
|
|
canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
|
|
|
|
|
|
|
|
SkRect r = SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h));
|
|
|
|
|
|
|
|
SkCanvas* modeCanvas;
|
2015-12-25 20:56:03 +00:00
|
|
|
if (nullptr == surface) {
|
2015-08-27 14:41:13 +00:00
|
|
|
canvas->saveLayer(&r, nullptr);
|
2013-08-08 21:13:38 +00:00
|
|
|
modeCanvas = canvas;
|
|
|
|
} else {
|
2015-12-25 20:56:03 +00:00
|
|
|
modeCanvas = surface->getCanvas();
|
2013-08-08 21:13:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SkPaint bgPaint;
|
|
|
|
bgPaint.setAntiAlias(false);
|
|
|
|
bgPaint.setShader(fBGShader);
|
|
|
|
modeCanvas->drawRect(r, bgPaint);
|
|
|
|
modeCanvas->drawRect(r, modePaint);
|
2015-08-27 14:41:13 +00:00
|
|
|
modeCanvas = nullptr;
|
2013-08-08 21:13:38 +00:00
|
|
|
|
2015-12-25 20:56:03 +00:00
|
|
|
if (nullptr == surface) {
|
2013-08-08 21:13:38 +00:00
|
|
|
canvas->restore();
|
|
|
|
} else {
|
2015-12-25 20:56:03 +00:00
|
|
|
surface->draw(canvas, 0, 0, nullptr);
|
2013-08-08 21:13:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
|
|
|
|
SkPaint borderPaint;
|
|
|
|
borderPaint.setStyle(SkPaint::kStroke_Style);
|
|
|
|
canvas->drawRect(r, borderPaint);
|
|
|
|
|
|
|
|
canvas->restore();
|
|
|
|
}
|
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
void onOnceBeforeDraw() override {
|
2016-09-01 18:24:54 +00:00
|
|
|
const uint32_t kCheckData[] = {
|
2015-07-21 14:42:45 +00:00
|
|
|
SkPackARGB32(0xFF, 0x42, 0x41, 0x42),
|
|
|
|
SkPackARGB32(0xFF, 0xD6, 0xD3, 0xD6),
|
|
|
|
SkPackARGB32(0xFF, 0xD6, 0xD3, 0xD6),
|
|
|
|
SkPackARGB32(0xFF, 0x42, 0x41, 0x42)
|
2013-08-08 21:13:38 +00:00
|
|
|
};
|
|
|
|
SkBitmap bg;
|
2014-01-25 16:46:20 +00:00
|
|
|
bg.allocN32Pixels(2, 2, true);
|
2013-08-08 21:13:38 +00:00
|
|
|
SkAutoLockPixels bgAlp(bg);
|
|
|
|
memcpy(bg.getPixels(), kCheckData, sizeof(kCheckData));
|
|
|
|
|
|
|
|
SkMatrix lm;
|
|
|
|
lm.setScale(SkIntToScalar(kCheckSize), SkIntToScalar(kCheckSize));
|
2016-03-13 21:13:58 +00:00
|
|
|
fBGShader = SkShader::MakeBitmapShader(bg, SkShader::kRepeat_TileMode,
|
|
|
|
SkShader::kRepeat_TileMode, &lm);
|
2013-08-08 21:13:38 +00:00
|
|
|
|
|
|
|
SkPaint bmpPaint;
|
2016-03-13 21:13:58 +00:00
|
|
|
const SkPoint kCenter = { SkIntToScalar(kSize) / 2, SkIntToScalar(kSize) / 2 };
|
|
|
|
const SkColor kColors[] = {
|
|
|
|
SK_ColorTRANSPARENT, 0x80800000, 0xF020F060, SK_ColorWHITE
|
|
|
|
};
|
|
|
|
bmpPaint.setShader(SkGradientShader::MakeRadial(kCenter, 3 * SkIntToScalar(kSize) / 4,
|
|
|
|
kColors, nullptr, SK_ARRAY_COUNT(kColors),
|
|
|
|
SkShader::kRepeat_TileMode));
|
2013-08-08 21:13:38 +00:00
|
|
|
|
|
|
|
SkBitmap bmp;
|
2014-01-25 16:46:20 +00:00
|
|
|
bmp.allocN32Pixels(kSize, kSize);
|
2013-08-08 21:13:38 +00:00
|
|
|
SkCanvas bmpCanvas(bmp);
|
|
|
|
|
|
|
|
bmpCanvas.clear(SK_ColorTRANSPARENT);
|
|
|
|
SkRect rect = { SkIntToScalar(kSize) / 8, SkIntToScalar(kSize) / 8,
|
|
|
|
7 * SkIntToScalar(kSize) / 8, 7 * SkIntToScalar(kSize) / 8};
|
|
|
|
bmpCanvas.drawRect(rect, bmpPaint);
|
|
|
|
|
2016-03-13 21:13:58 +00:00
|
|
|
fBmpShader = SkShader::MakeBitmapShader(bmp, SkShader::kClamp_TileMode,
|
|
|
|
SkShader::kClamp_TileMode);
|
2013-08-08 21:13:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
enum {
|
|
|
|
kCheckSize = 8,
|
|
|
|
kSize = 30,
|
|
|
|
kTestsPerRow = 15,
|
|
|
|
};
|
|
|
|
|
2016-03-13 21:13:58 +00:00
|
|
|
sk_sp<SkShader> fBGShader;
|
|
|
|
sk_sp<SkShader> fBmpShader;
|
2013-08-08 21:13:38 +00:00
|
|
|
|
|
|
|
typedef GM INHERITED;
|
|
|
|
};
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
DEF_GM(return new Xfermodes3GM;)
|
|
|
|
|
|
|
|
}
|