• 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 "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