• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "gm/gm.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkPixmap.h"
12 #include "include/core/SkRasterHandleAllocator.h"
13 #include "include/core/SkSurface.h"
14 #include "src/core/SkMakeUnique.h"
15 
16 class GraphicsPort {
17 protected:
18     SkCanvas* fCanvas;
19 
20 public:
GraphicsPort(SkCanvas * canvas)21     GraphicsPort(SkCanvas* canvas) : fCanvas(canvas) {}
~GraphicsPort()22     virtual ~GraphicsPort() {}
23 
save()24     void save() { fCanvas->save(); }
saveLayer(const SkRect & bounds,SkAlpha alpha)25     void saveLayer(const SkRect& bounds, SkAlpha alpha) {
26         fCanvas->saveLayerAlpha(&bounds, alpha);
27     }
restore()28     void restore() { fCanvas->restore(); }
29 
translate(float x,float y)30     void translate(float x, float y) { fCanvas->translate(x, y); }
scale(float s)31     void scale(float s) { fCanvas->scale(s, s); }
clip(const SkRect & r)32     void clip(const SkRect& r) { fCanvas->clipRect(r); }
33 
drawOval(const SkRect & r,SkColor c)34     void drawOval(const SkRect& r, SkColor c) {
35         SkPaint p;
36         p.setColor(c);
37         fCanvas->drawOval(r, p);
38     }
39 
drawRect(const SkRect & r,SkColor c)40     virtual void drawRect(const SkRect& r, SkColor c) {
41         SkPaint p;
42         p.setColor(c);
43         fCanvas->drawRect(r, p);
44     }
45 
peekCanvas() const46     SkCanvas* peekCanvas() const { return fCanvas; }
47 };
48 
49 class SkiaGraphicsPort : public GraphicsPort {
50 public:
SkiaGraphicsPort(SkCanvas * canvas)51     SkiaGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {}
52 
drawRect(const SkRect & r,SkColor c)53     void drawRect(const SkRect& r, SkColor c) override {
54         SkCanvas* canvas = (SkCanvas*)fCanvas->accessTopRasterHandle();
55         canvas->drawRect(r, SkPaint(SkColor4f::FromColor(c)));
56     }
57 };
58 
59 class SkiaAllocator : public SkRasterHandleAllocator {
60 public:
SkiaAllocator()61     SkiaAllocator() {}
62 
allocHandle(const SkImageInfo & info,Rec * rec)63     bool allocHandle(const SkImageInfo& info, Rec* rec) override {
64         sk_sp<SkSurface> surface = SkSurface::MakeRaster(info);
65         if (!surface) {
66             return false;
67         }
68         SkCanvas* canvas = surface->getCanvas();
69         SkPixmap pixmap;
70         canvas->peekPixels(&pixmap);
71 
72         rec->fReleaseProc = [](void* pixels, void* ctx){ SkSafeUnref((SkSurface*)ctx); };
73         rec->fReleaseCtx = surface.release();
74         rec->fPixels = pixmap.writable_addr();
75         rec->fRowBytes = pixmap.rowBytes();
76         rec->fHandle = canvas;
77         canvas->save();    // balanced each time updateHandle is called
78         return true;
79     }
80 
updateHandle(Handle hndl,const SkMatrix & ctm,const SkIRect & clip)81     void updateHandle(Handle hndl, const SkMatrix& ctm, const SkIRect& clip) override {
82         SkCanvas* canvas = (SkCanvas*)hndl;
83         canvas->restore();
84         canvas->save();
85         canvas->clipRect(SkRect::Make(clip));
86         canvas->concat(ctm);
87     }
88 };
89 
90 #ifdef SK_BUILD_FOR_MAC
91 
92 #include "include/utils/mac/SkCGUtils.h"
93 class CGGraphicsPort : public GraphicsPort {
94 public:
CGGraphicsPort(SkCanvas * canvas)95     CGGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {}
96 
drawRect(const SkRect & r,SkColor c)97     void drawRect(const SkRect& r, SkColor c) override {
98         CGContextRef cg = (CGContextRef)fCanvas->accessTopRasterHandle();
99 
100         CGColorRef color = CGColorCreateGenericRGB(SkColorGetR(c)/255.f,
101                                                    SkColorGetG(c)/255.f,
102                                                    SkColorGetB(c)/255.f,
103                                                    SkColorGetA(c)/255.f);
104 
105         CGContextSetFillColorWithColor(cg, color);
106         CGContextFillRect(cg, CGRectMake(r.x(), r.y(), r.width(), r.height()));
107     }
108 };
109 
matrix_to_transform(CGContextRef cg,const SkMatrix & ctm)110 static CGAffineTransform matrix_to_transform(CGContextRef cg, const SkMatrix& ctm) {
111     SkMatrix matrix;
112     matrix.setScale(1, -1);
113     matrix.postTranslate(0, SkIntToScalar(CGBitmapContextGetHeight(cg)));
114     matrix.preConcat(ctm);
115 
116     return CGAffineTransformMake(matrix[SkMatrix::kMScaleX],
117                                  matrix[SkMatrix::kMSkewY],
118                                  matrix[SkMatrix::kMSkewX],
119                                  matrix[SkMatrix::kMScaleY],
120                                  matrix[SkMatrix::kMTransX],
121                                  matrix[SkMatrix::kMTransY]);
122 }
123 
124 class CGAllocator : public SkRasterHandleAllocator {
125 public:
CGAllocator()126     CGAllocator() {}
127 
allocHandle(const SkImageInfo & info,Rec * rec)128     bool allocHandle(const SkImageInfo& info, Rec* rec) override {
129         // let CG allocate the pixels
130         CGContextRef cg = SkCreateCGContext(SkPixmap(info, nullptr, 0));
131         if (!cg) {
132             return false;
133         }
134         rec->fReleaseProc = [](void* pixels, void* ctx){ CGContextRelease((CGContextRef)ctx); };
135         rec->fReleaseCtx = cg;
136         rec->fPixels = CGBitmapContextGetData(cg);
137         rec->fRowBytes = CGBitmapContextGetBytesPerRow(cg);
138         rec->fHandle = cg;
139         CGContextSaveGState(cg);    // balanced each time updateHandle is called
140         return true;
141     }
142 
updateHandle(Handle hndl,const SkMatrix & ctm,const SkIRect & clip)143     void updateHandle(Handle hndl, const SkMatrix& ctm, const SkIRect& clip) override {
144         CGContextRef cg = (CGContextRef)hndl;
145 
146         CGContextRestoreGState(cg);
147         CGContextSaveGState(cg);
148         CGContextClipToRect(cg, CGRectMake(clip.x(), clip.y(), clip.width(), clip.height()));
149         CGContextConcatCTM(cg, matrix_to_transform(cg, ctm));
150     }
151 };
152 
153 using MyPort = CGGraphicsPort;
154 using MyAllocator = CGAllocator;
155 
156 #elif defined(SK_BUILD_FOR_WIN)
157 
158 #include "src/core/SkLeanWindows.h"
159 
toRECT(const SkIRect & r)160 static RECT toRECT(const SkIRect& r) {
161     return { r.left(), r.top(), r.right(), r.bottom() };
162 }
163 
164 class GDIGraphicsPort : public GraphicsPort {
165 public:
GDIGraphicsPort(SkCanvas * canvas)166     GDIGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {}
167 
drawRect(const SkRect & r,SkColor c)168     void drawRect(const SkRect& r, SkColor c) override {
169         HDC hdc = (HDC)fCanvas->accessTopRasterHandle();
170 
171         COLORREF cr = RGB(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));// SkEndian_Swap32(c) >> 8;
172         RECT rounded = toRECT(r.round());
173         FillRect(hdc, &rounded, CreateSolidBrush(cr));
174 
175         // Assuming GDI wrote zeros for alpha, this will or-in 0xFF for alpha
176         SkPaint paint;
177         paint.setBlendMode(SkBlendMode::kDstATop);
178         fCanvas->drawRect(r, paint);
179     }
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     HGDIOBJ origBitmap = SelectObject(hdc, hbitmap);
214 
215     struct ReleaseContext {
216         HDC hdc;
217         HGDIOBJ hbitmap;
218     };
219     rec->fReleaseProc = [](void*, void* context) {
220         ReleaseContext* ctx = static_cast<ReleaseContext*>(context);
221         HBITMAP hbitmap = static_cast<HBITMAP>(SelectObject(ctx->hdc, ctx->hbitmap));
222         DeleteObject(hbitmap);
223         DeleteDC(ctx->hdc);
224         delete ctx;
225     };
226     rec->fReleaseCtx = new ReleaseContext{hdc, origBitmap};
227     rec->fPixels = pixels;
228     rec->fRowBytes = row_bytes;
229     rec->fHandle = hdc;
230     return true;
231 }
232 
233 /**
234 *  Subclass of SkRasterHandleAllocator that returns an HDC as its "handle".
235 */
236 class GDIAllocator : public SkRasterHandleAllocator {
237 public:
GDIAllocator()238     GDIAllocator() {}
239 
allocHandle(const SkImageInfo & info,Rec * rec)240     bool allocHandle(const SkImageInfo& info, Rec* rec) override {
241         SkASSERT(info.colorType() == kN32_SkColorType);
242         return Create(info.width(), info.height(), info.isOpaque(), rec);
243     }
244 
updateHandle(Handle handle,const SkMatrix & ctm,const SkIRect & clip_bounds)245     void updateHandle(Handle handle, const SkMatrix& ctm, const SkIRect& clip_bounds) override {
246         HDC hdc = static_cast<HDC>(handle);
247 
248         XFORM xf;
249         xf.eM11 = ctm[SkMatrix::kMScaleX];
250         xf.eM21 = ctm[SkMatrix::kMSkewX];
251         xf.eDx = ctm[SkMatrix::kMTransX];
252         xf.eM12 = ctm[SkMatrix::kMSkewY];
253         xf.eM22 = ctm[SkMatrix::kMScaleY];
254         xf.eDy = ctm[SkMatrix::kMTransY];
255         SetWorldTransform(hdc, &xf);
256 
257         RECT clip_bounds_RECT = toRECT(clip_bounds);
258         HRGN hrgn = CreateRectRgnIndirect(&clip_bounds_RECT);
259         int result = SelectClipRgn(hdc, hrgn);
260         SkASSERT(result != ERROR);
261         result = DeleteObject(hrgn);
262         SkASSERT(result != 0);
263     }
264 };
265 
266 using MyPort = GDIGraphicsPort;
267 using MyAllocator = GDIAllocator;
268 
269 #else
270 
271 using MyPort = SkiaGraphicsPort;
272 using MyAllocator = SkiaAllocator;
273 
274 #endif
275 
276 DEF_SIMPLE_GM(rasterallocator, canvas, 600, 300) {
__anon652ecda10402(GraphicsPort* port) 277     auto doDraw = [](GraphicsPort* port) {
278         SkAutoCanvasRestore acr(port->peekCanvas(), true);
279 
280         port->drawRect({0, 0, 256, 256}, SK_ColorRED);
281         port->save();
282         port->translate(30, 30);
283         port->drawRect({0, 0, 30, 30}, SK_ColorBLUE);
284         port->drawOval({10, 10, 20, 20}, SK_ColorWHITE);
285         port->restore();
286 
287         port->saveLayer({50, 50, 100, 100}, 0x80);
288         port->drawRect({55, 55, 95, 95}, SK_ColorGREEN);
289         port->restore();
290 
291         port->clip({150, 50, 200, 200});
292         port->drawRect({0, 0, 256, 256}, 0xFFCCCCCC);
293     };
294 
295     // TODO: this common code fails pic-8888 and serialize-8888
296     //GraphicsPort skiaPort(canvas);
297     //doDraw(&skiaPort);
298 
299     const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
300     std::unique_ptr<SkCanvas> nativeCanvas =
301         SkRasterHandleAllocator::MakeCanvas(skstd::make_unique<MyAllocator>(), info);
302     MyPort nativePort(nativeCanvas.get());
303     doDraw(&nativePort);
304 
305     SkPixmap pm;
306     nativeCanvas->peekPixels(&pm);
307     SkBitmap bm;
308     bm.installPixels(pm);
309     canvas->drawBitmap(bm, 280, 0, nullptr);
310 }
311