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 "Sample.h"
9 #include "SkCanvas.h"
10 #include "SkGradientShader.h"
11 #include "SkMakeUnique.h"
12
make_grad(SkScalar w,SkScalar h)13 static sk_sp<SkShader> make_grad(SkScalar w, SkScalar h) {
14 SkColor colors[] = { 0xFF000000, 0xFF333333 };
15 SkPoint pts[] = { { 0, 0 }, { w, h } };
16 return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode);
17 }
18
19 class BigGradientView : public Sample {
20 public:
BigGradientView()21 BigGradientView() {}
22
23 protected:
onQuery(Sample::Event * evt)24 bool onQuery(Sample::Event* evt) override {
25 if (Sample::TitleQ(*evt)) {
26 Sample::TitleR(evt, "BigGradient");
27 return true;
28 }
29 return this->INHERITED::onQuery(evt);
30 }
31
onDrawContent(SkCanvas * canvas)32 void onDrawContent(SkCanvas* canvas) override {
33 SkRect r;
34 r.set(0, 0, this->width(), this->height());
35 SkPaint p;
36 p.setShader(make_grad(this->width(), this->height()));
37 canvas->drawRect(r, p);
38 }
39
40 private:
41 typedef Sample INHERITED;
42 };
43
44 ///////////////////////////////////////////////////////////////////////////////
45
46 DEF_SAMPLE( return new BigGradientView(); )
47
48 ///////////////////////////////////////////////////////////////////////////////
49
50 #include "SkRasterHandleAllocator.h"
51
52 class GraphicsPort {
53 protected:
54 SkCanvas* fCanvas;
55
56 public:
GraphicsPort(SkCanvas * canvas)57 GraphicsPort(SkCanvas* canvas) : fCanvas(canvas) {}
~GraphicsPort()58 virtual ~GraphicsPort() {}
59
save()60 void save() { fCanvas->save(); }
saveLayer(const SkRect & bounds,SkAlpha alpha)61 void saveLayer(const SkRect& bounds, SkAlpha alpha) {
62 fCanvas->saveLayerAlpha(&bounds, alpha);
63 }
restore()64 void restore() { fCanvas->restore(); }
65
translate(float x,float y)66 void translate(float x, float y) { fCanvas->translate(x, y); }
scale(float s)67 void scale(float s) { fCanvas->scale(s, s); }
clip(const SkRect & r)68 void clip(const SkRect& r) { fCanvas->clipRect(r); }
69
drawOval(const SkRect & r,SkColor c)70 void drawOval(const SkRect& r, SkColor c) {
71 SkPaint p;
72 p.setColor(c);
73 fCanvas->drawOval(r, p);
74 }
75
drawRect(const SkRect & r,SkColor c)76 virtual void drawRect(const SkRect& r, SkColor c) {
77 SkPaint p;
78 p.setColor(c);
79 fCanvas->drawRect(r, p);
80 }
81
peekCanvas() const82 SkCanvas* peekCanvas() const { return fCanvas; }
83 };
84
85 #ifdef SK_BUILD_FOR_MAC
86
87 #include "SkCGUtils.h"
88 class CGGraphicsPort : public GraphicsPort {
89 public:
CGGraphicsPort(SkCanvas * canvas)90 CGGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {}
91
drawRect(const SkRect & r,SkColor c)92 void drawRect(const SkRect& r, SkColor c) override {
93 CGContextRef cg = (CGContextRef)fCanvas->accessTopRasterHandle();
94
95 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
matrix_to_transform(CGContextRef cg,const SkMatrix & ctm)105 static 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
119 class Allocator_CG : public SkRasterHandleAllocator {
120 public:
Allocator_CG()121 Allocator_CG() {}
122
allocHandle(const SkImageInfo & info,Rec * rec)123 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
updateHandle(Handle hndl,const SkMatrix & ctm,const SkIRect & clip)138 void updateHandle(Handle hndl, const SkMatrix& ctm, const SkIRect& clip) override {
139 CGContextRef cg = (CGContextRef)hndl;
140
141 CGContextRestoreGState(cg);
142 CGContextSaveGState(cg);
143 CGContextClipToRect(cg, CGRectMake(clip.x(), clip.y(), clip.width(), clip.height()));
144 CGContextConcatCTM(cg, matrix_to_transform(cg, ctm));
145 }
146 };
147
148 #define MyPort CGGraphicsPort
149 #define MyAllocator Allocator_CG
150
151 #elif defined(WIN32)
152
toRECT(const SkIRect & r)153 static RECT toRECT(const SkIRect& r) {
154 return { r.left(), r.top(), r.right(), r.bottom() };
155 }
156
157 class GDIGraphicsPort : public GraphicsPort {
158 public:
GDIGraphicsPort(SkCanvas * canvas)159 GDIGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {}
160
drawRect(const SkRect & r,SkColor c)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;
165 RECT rounded = toRECT(r.round());
166 FillRect(hdc, &rounded, CreateSolidBrush(cr));
167
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
DeleteHDCCallback(void *,void * context)175 static 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.
Create(int width,int height,bool is_opaque,SkRasterHandleAllocator::Rec * rec)186 static bool Create(int width, int height, bool is_opaque, SkRasterHandleAllocator::Rec* rec) {
187 BITMAPINFOHEADER hdr;
188 memset(&hdr, 0, sizeof(hdr));
189 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 */
226 class GDIAllocator : public SkRasterHandleAllocator {
227 public:
GDIAllocator()228 GDIAllocator() {}
229
allocHandle(const SkImageInfo & info,Rec * rec)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
updateHandle(Handle handle,const SkMatrix & ctm,const SkIRect & clip_bounds)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
247 RECT clip_bounds_RECT = toRECT(clip_bounds);
248 HRGN hrgn = CreateRectRgnIndirect(&clip_bounds_RECT);
249 int result = SelectClipRgn(hdc, hrgn);
250 SkASSERT(result != ERROR);
251 result = DeleteObject(hrgn);
252 SkASSERT(result != 0);
253 }
254 };
255
256 #define MyPort GDIGraphicsPort
257 #define MyAllocator GDIAllocator
258
259 #endif
260
261 #ifdef MyAllocator
262 class RasterAllocatorSample : public Sample {
263 public:
RasterAllocatorSample()264 RasterAllocatorSample() {}
265
266 protected:
onQuery(Sample::Event * evt)267 bool onQuery(Sample::Event* evt) override {
268 if (Sample::TitleQ(*evt)) {
269 Sample::TitleR(evt, "raster-allocator");
270 return true;
271 }
272 return this->INHERITED::onQuery(evt);
273 }
274
doDraw(GraphicsPort * port)275 void doDraw(GraphicsPort* port) {
276 SkAutoCanvasRestore acr(port->peekCanvas(), true);
277
278 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();
284
285 port->saveLayer({50, 50, 100, 100}, 0x80);
286 port->drawRect({55, 55, 95, 95}, SK_ColorGREEN);
287 port->restore();
288
289 port->clip({150, 50, 200, 200});
290 port->drawRect({0, 0, 256, 256}, 0xFFCCCCCC);
291 }
292
onDrawContent(SkCanvas * canvas)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 =
299 SkRasterHandleAllocator::MakeCanvas(skstd::make_unique<MyAllocator>(), info);
300 MyPort cgp(c2.get());
301 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
310 private:
311 typedef Sample INHERITED;
312 };
313 DEF_SAMPLE( return new RasterAllocatorSample; )
314 #endif
315