blob: 1f3f3ea981a2499520501f3974c23db123478198 [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
Ben Wagner2b4dcd32019-06-06 14:39:52 -04008#include "gm/gm.h"
9#include "include/core/SkBitmap.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkCanvas.h"
Ben Wagner2b4dcd32019-06-06 14:39:52 -040011#include "include/core/SkPixmap.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkRasterHandleAllocator.h"
Ben Wagner2b4dcd32019-06-06 14:39:52 -040013#include "src/core/SkMakeUnique.h"
Mike Reed356f7c22017-01-10 11:58:39 -050014
15class GraphicsPort {
16protected:
17 SkCanvas* fCanvas;
18
19public:
20 GraphicsPort(SkCanvas* canvas) : fCanvas(canvas) {}
21 virtual ~GraphicsPort() {}
22
23 void save() { fCanvas->save(); }
24 void saveLayer(const SkRect& bounds, SkAlpha alpha) {
25 fCanvas->saveLayerAlpha(&bounds, alpha);
26 }
27 void restore() { fCanvas->restore(); }
28
29 void translate(float x, float y) { fCanvas->translate(x, y); }
30 void scale(float s) { fCanvas->scale(s, s); }
Mike Reed108f55e2017-01-12 11:28:01 -050031 void clip(const SkRect& r) { fCanvas->clipRect(r); }
Mike Reed356f7c22017-01-10 11:58:39 -050032
33 void drawOval(const SkRect& r, SkColor c) {
34 SkPaint p;
35 p.setColor(c);
36 fCanvas->drawOval(r, p);
37 }
38
39 virtual void drawRect(const SkRect& r, SkColor c) {
40 SkPaint p;
41 p.setColor(c);
42 fCanvas->drawRect(r, p);
43 }
Mike Reed108f55e2017-01-12 11:28:01 -050044
45 SkCanvas* peekCanvas() const { return fCanvas; }
Mike Reed356f7c22017-01-10 11:58:39 -050046};
47
Mike Reede4ca3622017-01-11 21:18:25 -050048#ifdef SK_BUILD_FOR_MAC
49
Mike Kleinc0bd9f92019-04-23 12:05:21 -050050#include "include/utils/mac/SkCGUtils.h"
Mike Reed356f7c22017-01-10 11:58:39 -050051class CGGraphicsPort : public GraphicsPort {
52public:
53 CGGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {}
54
55 void drawRect(const SkRect& r, SkColor c) override {
56 CGContextRef cg = (CGContextRef)fCanvas->accessTopRasterHandle();
Ben Wagner63fd7602017-10-09 15:45:33 -040057
Mike Reed356f7c22017-01-10 11:58:39 -050058 CGColorRef color = CGColorCreateGenericRGB(SkColorGetR(c)/255.f,
59 SkColorGetG(c)/255.f,
60 SkColorGetB(c)/255.f,
61 SkColorGetA(c)/255.f);
62
63 CGContextSetFillColorWithColor(cg, color);
64 CGContextFillRect(cg, CGRectMake(r.x(), r.y(), r.width(), r.height()));
65 }
66};
67
68static CGAffineTransform matrix_to_transform(CGContextRef cg, const SkMatrix& ctm) {
69 SkMatrix matrix;
70 matrix.setScale(1, -1);
71 matrix.postTranslate(0, SkIntToScalar(CGBitmapContextGetHeight(cg)));
72 matrix.preConcat(ctm);
73
74 return CGAffineTransformMake(matrix[SkMatrix::kMScaleX],
75 matrix[SkMatrix::kMSkewY],
76 matrix[SkMatrix::kMSkewX],
77 matrix[SkMatrix::kMScaleY],
78 matrix[SkMatrix::kMTransX],
79 matrix[SkMatrix::kMTransY]);
80}
81
82class Allocator_CG : public SkRasterHandleAllocator {
83public:
84 Allocator_CG() {}
Ben Wagner63fd7602017-10-09 15:45:33 -040085
Mike Reed356f7c22017-01-10 11:58:39 -050086 bool allocHandle(const SkImageInfo& info, Rec* rec) override {
87 // let CG allocate the pixels
88 CGContextRef cg = SkCreateCGContext(SkPixmap(info, nullptr, 0));
89 if (!cg) {
90 return false;
91 }
92 rec->fReleaseProc = [](void* pixels, void* ctx){ CGContextRelease((CGContextRef)ctx); };
93 rec->fReleaseCtx = cg;
94 rec->fPixels = CGBitmapContextGetData(cg);
95 rec->fRowBytes = CGBitmapContextGetBytesPerRow(cg);
96 rec->fHandle = cg;
97 CGContextSaveGState(cg); // balanced each time updateContext is called
98 return true;
99 }
100
101 void updateHandle(Handle hndl, const SkMatrix& ctm, const SkIRect& clip) override {
102 CGContextRef cg = (CGContextRef)hndl;
Ben Wagner63fd7602017-10-09 15:45:33 -0400103
Mike Reed356f7c22017-01-10 11:58:39 -0500104 CGContextRestoreGState(cg);
105 CGContextSaveGState(cg);
Mike Reed108f55e2017-01-12 11:28:01 -0500106 CGContextClipToRect(cg, CGRectMake(clip.x(), clip.y(), clip.width(), clip.height()));
Mike Reed356f7c22017-01-10 11:58:39 -0500107 CGContextConcatCTM(cg, matrix_to_transform(cg, ctm));
108 }
109};
110
Mike Reede4ca3622017-01-11 21:18:25 -0500111#define MyPort CGGraphicsPort
112#define MyAllocator Allocator_CG
113
Ben Wagner2b4dcd32019-06-06 14:39:52 -0400114#elif defined(SK_BUILD_FOR_WIN)
115
116#include "src/core/SkLeanWindows.h"
Mike Reede4ca3622017-01-11 21:18:25 -0500117
Mike Reed9e937af2017-01-12 14:18:39 -0500118static RECT toRECT(const SkIRect& r) {
119 return { r.left(), r.top(), r.right(), r.bottom() };
120}
121
Mike Reede4ca3622017-01-11 21:18:25 -0500122class GDIGraphicsPort : public GraphicsPort {
123public:
124 GDIGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {}
125
126 void drawRect(const SkRect& r, SkColor c) override {
127 HDC hdc = (HDC)fCanvas->accessTopRasterHandle();
128
129 COLORREF cr = RGB(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));// SkEndian_Swap32(c) >> 8;
Mike Kleinc722f792017-07-31 11:57:21 -0400130 RECT rounded = toRECT(r.round());
131 FillRect(hdc, &rounded, CreateSolidBrush(cr));
Mike Reede4ca3622017-01-11 21:18:25 -0500132
133 // Assuming GDI wrote zeros for alpha, this will or-in 0xFF for alpha
134 SkPaint paint;
135 paint.setBlendMode(SkBlendMode::kDstATop);
136 fCanvas->drawRect(r, paint);
137 }
138};
139
Mike Reede4ca3622017-01-11 21:18:25 -0500140// We use this static factory function instead of the regular constructor so
141// that we can create the pixel data before calling the constructor. This is
142// required so that we can call the base class' constructor with the pixel
143// data.
144static bool Create(int width, int height, bool is_opaque, SkRasterHandleAllocator::Rec* rec) {
Chris Dalton1ef80942017-12-04 12:01:30 -0700145 BITMAPINFOHEADER hdr;
146 memset(&hdr, 0, sizeof(hdr));
Mike Reede4ca3622017-01-11 21:18:25 -0500147 hdr.biSize = sizeof(BITMAPINFOHEADER);
148 hdr.biWidth = width;
149 hdr.biHeight = -height; // Minus means top-down bitmap.
150 hdr.biPlanes = 1;
151 hdr.biBitCount = 32;
152 hdr.biCompression = BI_RGB; // No compression.
153 hdr.biSizeImage = 0;
154 hdr.biXPelsPerMeter = 1;
155 hdr.biYPelsPerMeter = 1;
156 void* pixels;
157 HBITMAP hbitmap = CreateDIBSection(nullptr, (const BITMAPINFO*)&hdr, 0, &pixels, 0, 0);
158 if (!hbitmap) {
159 return false;
160 }
161
162 size_t row_bytes = width * sizeof(SkPMColor);
163 sk_bzero(pixels, row_bytes * height);
164
165 HDC hdc = CreateCompatibleDC(nullptr);
166 if (!hdc) {
167 DeleteObject(hbitmap);
168 return false;
169 }
170 SetGraphicsMode(hdc, GM_ADVANCED);
Ben Wagner2b4dcd32019-06-06 14:39:52 -0400171 HGDIOBJ origBitmap = SelectObject(hdc, hbitmap);
Mike Reede4ca3622017-01-11 21:18:25 -0500172
Ben Wagner2b4dcd32019-06-06 14:39:52 -0400173 struct ReleaseContext {
174 HDC hdc;
175 HGDIOBJ hbitmap;
176 };
177 rec->fReleaseProc = [](void*, void* context) {
178 ReleaseContext* ctx = static_cast<ReleaseContext*>(context);
179 HBITMAP hbitmap = static_cast<HBITMAP>(SelectObject(ctx->hdc, ctx->hbitmap));
180 DeleteObject(hbitmap);
181 DeleteDC(ctx->hdc);
182 delete ctx;
183 };
184 rec->fReleaseCtx = new ReleaseContext{hdc, origBitmap};
Mike Reede4ca3622017-01-11 21:18:25 -0500185 rec->fPixels = pixels;
186 rec->fRowBytes = row_bytes;
187 rec->fHandle = hdc;
188 return true;
189}
190
191/**
192* Subclass of SkRasterHandleAllocator that returns an HDC as its "handle".
193*/
194class GDIAllocator : public SkRasterHandleAllocator {
195public:
196 GDIAllocator() {}
197
198 bool allocHandle(const SkImageInfo& info, Rec* rec) override {
199 SkASSERT(info.colorType() == kN32_SkColorType);
200 return Create(info.width(), info.height(), info.isOpaque(), rec);
201 }
202
203 void updateHandle(Handle handle, const SkMatrix& ctm, const SkIRect& clip_bounds) override {
204 HDC hdc = static_cast<HDC>(handle);
205
206 XFORM xf;
207 xf.eM11 = ctm[SkMatrix::kMScaleX];
208 xf.eM21 = ctm[SkMatrix::kMSkewX];
209 xf.eDx = ctm[SkMatrix::kMTransX];
210 xf.eM12 = ctm[SkMatrix::kMSkewY];
211 xf.eM22 = ctm[SkMatrix::kMScaleY];
212 xf.eDy = ctm[SkMatrix::kMTransY];
213 SetWorldTransform(hdc, &xf);
214
Mike Kleinc722f792017-07-31 11:57:21 -0400215 RECT clip_bounds_RECT = toRECT(clip_bounds);
216 HRGN hrgn = CreateRectRgnIndirect(&clip_bounds_RECT);
Mike Reede4ca3622017-01-11 21:18:25 -0500217 int result = SelectClipRgn(hdc, hrgn);
218 SkASSERT(result != ERROR);
219 result = DeleteObject(hrgn);
220 SkASSERT(result != 0);
Mike Reede4ca3622017-01-11 21:18:25 -0500221 }
222};
223
224#define MyPort GDIGraphicsPort
225#define MyAllocator GDIAllocator
226
227#endif
228
Ben Wagner2b4dcd32019-06-06 14:39:52 -0400229DEF_SIMPLE_GM(rasterallocator, canvas, 600, 300) {
230 auto doDraw = [](GraphicsPort* port) {
Mike Reed108f55e2017-01-12 11:28:01 -0500231 SkAutoCanvasRestore acr(port->peekCanvas(), true);
232
Mike Reed356f7c22017-01-10 11:58:39 -0500233 port->drawRect({0, 0, 256, 256}, SK_ColorRED);
234 port->save();
235 port->translate(30, 30);
236 port->drawRect({0, 0, 30, 30}, SK_ColorBLUE);
237 port->drawOval({10, 10, 20, 20}, SK_ColorWHITE);
238 port->restore();
Ben Wagner63fd7602017-10-09 15:45:33 -0400239
Mike Reed356f7c22017-01-10 11:58:39 -0500240 port->saveLayer({50, 50, 100, 100}, 0x80);
241 port->drawRect({55, 55, 95, 95}, SK_ColorGREEN);
242 port->restore();
Mike Reed108f55e2017-01-12 11:28:01 -0500243
244 port->clip({150, 50, 200, 200});
245 port->drawRect({0, 0, 256, 256}, 0xFFCCCCCC);
Ben Wagner2b4dcd32019-06-06 14:39:52 -0400246 };
Mike Reed356f7c22017-01-10 11:58:39 -0500247
Ben Wagner53ae9362019-06-07 14:16:54 -0400248 // TODO: this common code fails pic-8888 and serialize-8888
249 sk_ignore_unused_variable(doDraw);
250 //GraphicsPort skiaPort(canvas);
251 //doDraw(&skiaPort);
Mike Reed356f7c22017-01-10 11:58:39 -0500252
Ben Wagner53ae9362019-06-07 14:16:54 -0400253#ifdef MyAllocator
Ben Wagner2b4dcd32019-06-06 14:39:52 -0400254 const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
Ben Wagner53ae9362019-06-07 14:16:54 -0400255 std::unique_ptr<SkCanvas> nativeCanvas =
Ben Wagner2b4dcd32019-06-06 14:39:52 -0400256 SkRasterHandleAllocator::MakeCanvas(skstd::make_unique<MyAllocator>(), info);
Ben Wagner53ae9362019-06-07 14:16:54 -0400257 MyPort nativePort(nativeCanvas.get());
258 doDraw(&nativePort);
Mike Reed356f7c22017-01-10 11:58:39 -0500259
Ben Wagner2b4dcd32019-06-06 14:39:52 -0400260 SkPixmap pm;
Ben Wagner53ae9362019-06-07 14:16:54 -0400261 nativeCanvas->peekPixels(&pm);
Ben Wagner2b4dcd32019-06-06 14:39:52 -0400262 SkBitmap bm;
263 bm.installPixels(pm);
264 canvas->drawBitmap(bm, 280, 0, nullptr);
Mike Reed356f7c22017-01-10 11:58:39 -0500265#endif
Ben Wagner53ae9362019-06-07 14:16:54 -0400266}