blob: 20a629d8fc60dbf0303b5407fb41b956b6175eec [file] [log] [blame]
Mike Reedfae8fce2019-04-03 10:27:45 -04001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * 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 */
reed8a21c9f2016-03-08 18:50:00 -08007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkCanvas.h"
9#include "include/effects/SkGradientShader.h"
10#include "samplecode/Sample.h"
11#include "src/core/SkMakeUnique.h"
reed@google.com55b8e8c2011-01-13 16:22:35 +000012
reed8a21c9f2016-03-08 18:50:00 -080013static sk_sp<SkShader> make_grad(SkScalar w, SkScalar h) {
reed@google.com55b8e8c2011-01-13 16:22:35 +000014 SkColor colors[] = { 0xFF000000, 0xFF333333 };
15 SkPoint pts[] = { { 0, 0 }, { w, h } };
Mike Reedfae8fce2019-04-03 10:27:45 -040016 return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);
reed@google.com55b8e8c2011-01-13 16:22:35 +000017}
18
Ben Wagnerb2c4ea62018-08-08 11:36:17 -040019class BigGradientView : public Sample {
reed@google.com55b8e8c2011-01-13 16:22:35 +000020public:
rmistry@google.comae933ce2012-08-23 18:19:56 +000021 BigGradientView() {}
reed@google.com55b8e8c2011-01-13 16:22:35 +000022
23protected:
Ben Wagnerb2c4ea62018-08-08 11:36:17 -040024 bool onQuery(Sample::Event* evt) override {
25 if (Sample::TitleQ(*evt)) {
26 Sample::TitleR(evt, "BigGradient");
reed@google.com55b8e8c2011-01-13 16:22:35 +000027 return true;
28 }
29 return this->INHERITED::onQuery(evt);
30 }
31
reed8a21c9f2016-03-08 18:50:00 -080032 void onDrawContent(SkCanvas* canvas) override {
reed@google.com55b8e8c2011-01-13 16:22:35 +000033 SkRect r;
34 r.set(0, 0, this->width(), this->height());
35 SkPaint p;
reed8a21c9f2016-03-08 18:50:00 -080036 p.setShader(make_grad(this->width(), this->height()));
reed@google.com55b8e8c2011-01-13 16:22:35 +000037 canvas->drawRect(r, p);
38 }
39
40private:
Ben Wagnerb2c4ea62018-08-08 11:36:17 -040041 typedef Sample INHERITED;
reed@google.com55b8e8c2011-01-13 16:22:35 +000042};
43
44///////////////////////////////////////////////////////////////////////////////
45
Ben Wagnerb2c4ea62018-08-08 11:36:17 -040046DEF_SAMPLE( return new BigGradientView(); )
Mike Reed356f7c22017-01-10 11:58:39 -050047
48///////////////////////////////////////////////////////////////////////////////
49
Mike Kleinc0bd9f92019-04-23 12:05:21 -050050#include "include/core/SkRasterHandleAllocator.h"
Mike Reed356f7c22017-01-10 11:58:39 -050051
52class GraphicsPort {
53protected:
54 SkCanvas* fCanvas;
55
56public:
57 GraphicsPort(SkCanvas* canvas) : fCanvas(canvas) {}
58 virtual ~GraphicsPort() {}
59
60 void save() { fCanvas->save(); }
61 void saveLayer(const SkRect& bounds, SkAlpha alpha) {
62 fCanvas->saveLayerAlpha(&bounds, alpha);
63 }
64 void restore() { fCanvas->restore(); }
65
66 void translate(float x, float y) { fCanvas->translate(x, y); }
67 void scale(float s) { fCanvas->scale(s, s); }
Mike Reed108f55e2017-01-12 11:28:01 -050068 void clip(const SkRect& r) { fCanvas->clipRect(r); }
Mike Reed356f7c22017-01-10 11:58:39 -050069
70 void drawOval(const SkRect& r, SkColor c) {
71 SkPaint p;
72 p.setColor(c);
73 fCanvas->drawOval(r, p);
74 }
75
76 virtual void drawRect(const SkRect& r, SkColor c) {
77 SkPaint p;
78 p.setColor(c);
79 fCanvas->drawRect(r, p);
80 }
Mike Reed108f55e2017-01-12 11:28:01 -050081
82 SkCanvas* peekCanvas() const { return fCanvas; }
Mike Reed356f7c22017-01-10 11:58:39 -050083};
84
Mike Reede4ca3622017-01-11 21:18:25 -050085#ifdef SK_BUILD_FOR_MAC
86
Mike Kleinc0bd9f92019-04-23 12:05:21 -050087#include "include/utils/mac/SkCGUtils.h"
Mike Reed356f7c22017-01-10 11:58:39 -050088class CGGraphicsPort : public GraphicsPort {
89public:
90 CGGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {}
91
92 void drawRect(const SkRect& r, SkColor c) override {
93 CGContextRef cg = (CGContextRef)fCanvas->accessTopRasterHandle();
Ben Wagner63fd7602017-10-09 15:45:33 -040094
Mike Reed356f7c22017-01-10 11:58:39 -050095 CGColorRef color = CGColorCreateGenericRGB(SkColorGetR(c)/255.f,
96 SkColorGetG(c)/255.f,
97 SkColorGetB(c)/255.f,
98 SkColorGetA(c)/255.f);
99
100 CGContextSetFillColorWithColor(cg, color);
101 CGContextFillRect(cg, CGRectMake(r.x(), r.y(), r.width(), r.height()));
102 }
103};
104
105static CGAffineTransform matrix_to_transform(CGContextRef cg, const SkMatrix& ctm) {
106 SkMatrix matrix;
107 matrix.setScale(1, -1);
108 matrix.postTranslate(0, SkIntToScalar(CGBitmapContextGetHeight(cg)));
109 matrix.preConcat(ctm);
110
111 return CGAffineTransformMake(matrix[SkMatrix::kMScaleX],
112 matrix[SkMatrix::kMSkewY],
113 matrix[SkMatrix::kMSkewX],
114 matrix[SkMatrix::kMScaleY],
115 matrix[SkMatrix::kMTransX],
116 matrix[SkMatrix::kMTransY]);
117}
118
119class Allocator_CG : public SkRasterHandleAllocator {
120public:
121 Allocator_CG() {}
Ben Wagner63fd7602017-10-09 15:45:33 -0400122
Mike Reed356f7c22017-01-10 11:58:39 -0500123 bool allocHandle(const SkImageInfo& info, Rec* rec) override {
124 // let CG allocate the pixels
125 CGContextRef cg = SkCreateCGContext(SkPixmap(info, nullptr, 0));
126 if (!cg) {
127 return false;
128 }
129 rec->fReleaseProc = [](void* pixels, void* ctx){ CGContextRelease((CGContextRef)ctx); };
130 rec->fReleaseCtx = cg;
131 rec->fPixels = CGBitmapContextGetData(cg);
132 rec->fRowBytes = CGBitmapContextGetBytesPerRow(cg);
133 rec->fHandle = cg;
134 CGContextSaveGState(cg); // balanced each time updateContext is called
135 return true;
136 }
137
138 void updateHandle(Handle hndl, const SkMatrix& ctm, const SkIRect& clip) override {
139 CGContextRef cg = (CGContextRef)hndl;
Ben Wagner63fd7602017-10-09 15:45:33 -0400140
Mike Reed356f7c22017-01-10 11:58:39 -0500141 CGContextRestoreGState(cg);
142 CGContextSaveGState(cg);
Mike Reed108f55e2017-01-12 11:28:01 -0500143 CGContextClipToRect(cg, CGRectMake(clip.x(), clip.y(), clip.width(), clip.height()));
Mike Reed356f7c22017-01-10 11:58:39 -0500144 CGContextConcatCTM(cg, matrix_to_transform(cg, ctm));
145 }
146};
147
Mike Reede4ca3622017-01-11 21:18:25 -0500148#define MyPort CGGraphicsPort
149#define MyAllocator Allocator_CG
150
151#elif defined(WIN32)
152
Mike Reed9e937af2017-01-12 14:18:39 -0500153static RECT toRECT(const SkIRect& r) {
154 return { r.left(), r.top(), r.right(), r.bottom() };
155}
156
Mike Reede4ca3622017-01-11 21:18:25 -0500157class GDIGraphicsPort : public GraphicsPort {
158public:
159 GDIGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {}
160
161 void drawRect(const SkRect& r, SkColor c) override {
162 HDC hdc = (HDC)fCanvas->accessTopRasterHandle();
163
164 COLORREF cr = RGB(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));// SkEndian_Swap32(c) >> 8;
Mike Kleinc722f792017-07-31 11:57:21 -0400165 RECT rounded = toRECT(r.round());
166 FillRect(hdc, &rounded, CreateSolidBrush(cr));
Mike Reede4ca3622017-01-11 21:18:25 -0500167
168 // Assuming GDI wrote zeros for alpha, this will or-in 0xFF for alpha
169 SkPaint paint;
170 paint.setBlendMode(SkBlendMode::kDstATop);
171 fCanvas->drawRect(r, paint);
172 }
173};
174
175static void DeleteHDCCallback(void*, void* context) {
176 HDC hdc = static_cast<HDC>(context);
177 HBITMAP hbitmap = static_cast<HBITMAP>(SelectObject(hdc, nullptr));
178 DeleteObject(hbitmap);
179 DeleteDC(hdc);
180}
181
182// We use this static factory function instead of the regular constructor so
183// that we can create the pixel data before calling the constructor. This is
184// required so that we can call the base class' constructor with the pixel
185// data.
186static bool Create(int width, int height, bool is_opaque, SkRasterHandleAllocator::Rec* rec) {
Chris Dalton1ef80942017-12-04 12:01:30 -0700187 BITMAPINFOHEADER hdr;
188 memset(&hdr, 0, sizeof(hdr));
Mike Reede4ca3622017-01-11 21:18:25 -0500189 hdr.biSize = sizeof(BITMAPINFOHEADER);
190 hdr.biWidth = width;
191 hdr.biHeight = -height; // Minus means top-down bitmap.
192 hdr.biPlanes = 1;
193 hdr.biBitCount = 32;
194 hdr.biCompression = BI_RGB; // No compression.
195 hdr.biSizeImage = 0;
196 hdr.biXPelsPerMeter = 1;
197 hdr.biYPelsPerMeter = 1;
198 void* pixels;
199 HBITMAP hbitmap = CreateDIBSection(nullptr, (const BITMAPINFO*)&hdr, 0, &pixels, 0, 0);
200 if (!hbitmap) {
201 return false;
202 }
203
204 size_t row_bytes = width * sizeof(SkPMColor);
205 sk_bzero(pixels, row_bytes * height);
206
207 HDC hdc = CreateCompatibleDC(nullptr);
208 if (!hdc) {
209 DeleteObject(hbitmap);
210 return false;
211 }
212 SetGraphicsMode(hdc, GM_ADVANCED);
213 SelectObject(hdc, hbitmap);
214
215 rec->fReleaseProc = DeleteHDCCallback;
216 rec->fReleaseCtx = hdc;
217 rec->fPixels = pixels;
218 rec->fRowBytes = row_bytes;
219 rec->fHandle = hdc;
220 return true;
221}
222
223/**
224* Subclass of SkRasterHandleAllocator that returns an HDC as its "handle".
225*/
226class GDIAllocator : public SkRasterHandleAllocator {
227public:
228 GDIAllocator() {}
229
230 bool allocHandle(const SkImageInfo& info, Rec* rec) override {
231 SkASSERT(info.colorType() == kN32_SkColorType);
232 return Create(info.width(), info.height(), info.isOpaque(), rec);
233 }
234
235 void updateHandle(Handle handle, const SkMatrix& ctm, const SkIRect& clip_bounds) override {
236 HDC hdc = static_cast<HDC>(handle);
237
238 XFORM xf;
239 xf.eM11 = ctm[SkMatrix::kMScaleX];
240 xf.eM21 = ctm[SkMatrix::kMSkewX];
241 xf.eDx = ctm[SkMatrix::kMTransX];
242 xf.eM12 = ctm[SkMatrix::kMSkewY];
243 xf.eM22 = ctm[SkMatrix::kMScaleY];
244 xf.eDy = ctm[SkMatrix::kMTransY];
245 SetWorldTransform(hdc, &xf);
246
Mike Kleinc722f792017-07-31 11:57:21 -0400247 RECT clip_bounds_RECT = toRECT(clip_bounds);
248 HRGN hrgn = CreateRectRgnIndirect(&clip_bounds_RECT);
Mike Reede4ca3622017-01-11 21:18:25 -0500249 int result = SelectClipRgn(hdc, hrgn);
250 SkASSERT(result != ERROR);
251 result = DeleteObject(hrgn);
252 SkASSERT(result != 0);
Mike Reede4ca3622017-01-11 21:18:25 -0500253 }
254};
255
256#define MyPort GDIGraphicsPort
257#define MyAllocator GDIAllocator
258
259#endif
260
261#ifdef MyAllocator
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400262class RasterAllocatorSample : public Sample {
Mike Reed356f7c22017-01-10 11:58:39 -0500263public:
264 RasterAllocatorSample() {}
265
266protected:
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400267 bool onQuery(Sample::Event* evt) override {
268 if (Sample::TitleQ(*evt)) {
269 Sample::TitleR(evt, "raster-allocator");
Mike Reed356f7c22017-01-10 11:58:39 -0500270 return true;
271 }
272 return this->INHERITED::onQuery(evt);
273 }
274
275 void doDraw(GraphicsPort* port) {
Mike Reed108f55e2017-01-12 11:28:01 -0500276 SkAutoCanvasRestore acr(port->peekCanvas(), true);
277
Mike Reed356f7c22017-01-10 11:58:39 -0500278 port->drawRect({0, 0, 256, 256}, SK_ColorRED);
279 port->save();
280 port->translate(30, 30);
281 port->drawRect({0, 0, 30, 30}, SK_ColorBLUE);
282 port->drawOval({10, 10, 20, 20}, SK_ColorWHITE);
283 port->restore();
Ben Wagner63fd7602017-10-09 15:45:33 -0400284
Mike Reed356f7c22017-01-10 11:58:39 -0500285 port->saveLayer({50, 50, 100, 100}, 0x80);
286 port->drawRect({55, 55, 95, 95}, SK_ColorGREEN);
287 port->restore();
Mike Reed108f55e2017-01-12 11:28:01 -0500288
289 port->clip({150, 50, 200, 200});
290 port->drawRect({0, 0, 256, 256}, 0xFFCCCCCC);
Mike Reed356f7c22017-01-10 11:58:39 -0500291 }
292
293 void onDrawContent(SkCanvas* canvas) override {
294 GraphicsPort skp(canvas);
295 doDraw(&skp);
296
297 const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
298 std::unique_ptr<SkCanvas> c2 =
Mike Reede4ca3622017-01-11 21:18:25 -0500299 SkRasterHandleAllocator::MakeCanvas(skstd::make_unique<MyAllocator>(), info);
300 MyPort cgp(c2.get());
Mike Reed356f7c22017-01-10 11:58:39 -0500301 doDraw(&cgp);
302
303 SkPixmap pm;
304 c2->peekPixels(&pm);
305 SkBitmap bm;
306 bm.installPixels(pm);
307 canvas->drawBitmap(bm, 280, 0, nullptr);
308 }
309
310private:
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400311 typedef Sample INHERITED;
Mike Reed356f7c22017-01-10 11:58:39 -0500312};
313DEF_SAMPLE( return new RasterAllocatorSample; )
314#endif