• 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 "SampleCode.h"
9 #include "SkView.h"
10 #include "SkCanvas.h"
11 #include "SkGradientShader.h"
12 #include "SkMakeUnique.h"
13 
make_grad(SkScalar w,SkScalar h)14 static sk_sp<SkShader> make_grad(SkScalar w, SkScalar h) {
15     SkColor colors[] = { 0xFF000000, 0xFF333333 };
16     SkPoint pts[] = { { 0, 0 }, { w, h } };
17     return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode);
18 }
19 
20 class BigGradientView : public SampleView {
21 public:
BigGradientView()22     BigGradientView() {}
23 
24 protected:
onQuery(SkEvent * evt)25     bool onQuery(SkEvent* evt) override {
26         if (SampleCode::TitleQ(*evt)) {
27             SampleCode::TitleR(evt, "BigGradient");
28             return true;
29         }
30         return this->INHERITED::onQuery(evt);
31     }
32 
onDrawContent(SkCanvas * canvas)33     void onDrawContent(SkCanvas* canvas) override {
34         SkRect r;
35         r.set(0, 0, this->width(), this->height());
36         SkPaint p;
37         p.setShader(make_grad(this->width(), this->height()));
38         canvas->drawRect(r, p);
39     }
40 
41 private:
42     typedef SampleView INHERITED;
43 };
44 
45 ///////////////////////////////////////////////////////////////////////////////
46 
MyFactory()47 static SkView* MyFactory() { return new BigGradientView; }
48 static SkViewRegister reg(MyFactory);
49 
50 ///////////////////////////////////////////////////////////////////////////////
51 
52 #include "SkRasterHandleAllocator.h"
53 
54 class GraphicsPort {
55 protected:
56     SkCanvas* fCanvas;
57 
58 public:
GraphicsPort(SkCanvas * canvas)59     GraphicsPort(SkCanvas* canvas) : fCanvas(canvas) {}
~GraphicsPort()60     virtual ~GraphicsPort() {}
61 
save()62     void save() { fCanvas->save(); }
saveLayer(const SkRect & bounds,SkAlpha alpha)63     void saveLayer(const SkRect& bounds, SkAlpha alpha) {
64         fCanvas->saveLayerAlpha(&bounds, alpha);
65     }
restore()66     void restore() { fCanvas->restore(); }
67 
translate(float x,float y)68     void translate(float x, float y) { fCanvas->translate(x, y); }
scale(float s)69     void scale(float s) { fCanvas->scale(s, s); }
clip(const SkRect & r)70     void clip(const SkRect& r) { fCanvas->clipRect(r); }
71 
drawOval(const SkRect & r,SkColor c)72     void drawOval(const SkRect& r, SkColor c) {
73         SkPaint p;
74         p.setColor(c);
75         fCanvas->drawOval(r, p);
76     }
77 
drawRect(const SkRect & r,SkColor c)78     virtual void drawRect(const SkRect& r, SkColor c) {
79         SkPaint p;
80         p.setColor(c);
81         fCanvas->drawRect(r, p);
82     }
83 
peekCanvas() const84     SkCanvas* peekCanvas() const { return fCanvas; }
85 };
86 
87 #ifdef SK_BUILD_FOR_MAC
88 
89 #include "SkCGUtils.h"
90 class CGGraphicsPort : public GraphicsPort {
91 public:
CGGraphicsPort(SkCanvas * canvas)92     CGGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {}
93 
drawRect(const SkRect & r,SkColor c)94     void drawRect(const SkRect& r, SkColor c) override {
95         CGContextRef cg = (CGContextRef)fCanvas->accessTopRasterHandle();
96 
97         CGColorRef color = CGColorCreateGenericRGB(SkColorGetR(c)/255.f,
98                                                    SkColorGetG(c)/255.f,
99                                                    SkColorGetB(c)/255.f,
100                                                    SkColorGetA(c)/255.f);
101 
102         CGContextSetFillColorWithColor(cg, color);
103         CGContextFillRect(cg, CGRectMake(r.x(), r.y(), r.width(), r.height()));
104     }
105 };
106 
matrix_to_transform(CGContextRef cg,const SkMatrix & ctm)107 static CGAffineTransform matrix_to_transform(CGContextRef cg, const SkMatrix& ctm) {
108     SkMatrix matrix;
109     matrix.setScale(1, -1);
110     matrix.postTranslate(0, SkIntToScalar(CGBitmapContextGetHeight(cg)));
111     matrix.preConcat(ctm);
112 
113     return CGAffineTransformMake(matrix[SkMatrix::kMScaleX],
114                                  matrix[SkMatrix::kMSkewY],
115                                  matrix[SkMatrix::kMSkewX],
116                                  matrix[SkMatrix::kMScaleY],
117                                  matrix[SkMatrix::kMTransX],
118                                  matrix[SkMatrix::kMTransY]);
119 }
120 
121 class Allocator_CG : public SkRasterHandleAllocator {
122 public:
Allocator_CG()123     Allocator_CG() {}
124 
allocHandle(const SkImageInfo & info,Rec * rec)125     bool allocHandle(const SkImageInfo& info, Rec* rec) override {
126         // let CG allocate the pixels
127         CGContextRef cg = SkCreateCGContext(SkPixmap(info, nullptr, 0));
128         if (!cg) {
129             return false;
130         }
131         rec->fReleaseProc = [](void* pixels, void* ctx){ CGContextRelease((CGContextRef)ctx); };
132         rec->fReleaseCtx = cg;
133         rec->fPixels = CGBitmapContextGetData(cg);
134         rec->fRowBytes = CGBitmapContextGetBytesPerRow(cg);
135         rec->fHandle = cg;
136         CGContextSaveGState(cg);    // balanced each time updateContext is called
137         return true;
138     }
139 
updateHandle(Handle hndl,const SkMatrix & ctm,const SkIRect & clip)140     void updateHandle(Handle hndl, const SkMatrix& ctm, const SkIRect& clip) override {
141         CGContextRef cg = (CGContextRef)hndl;
142 
143         CGContextRestoreGState(cg);
144         CGContextSaveGState(cg);
145         CGContextClipToRect(cg, CGRectMake(clip.x(), clip.y(), clip.width(), clip.height()));
146         CGContextConcatCTM(cg, matrix_to_transform(cg, ctm));
147     }
148 };
149 
150 #define MyPort CGGraphicsPort
151 #define MyAllocator Allocator_CG
152 
153 #elif defined(WIN32)
154 
toRECT(const SkIRect & r)155 static RECT toRECT(const SkIRect& r) {
156     return { r.left(), r.top(), r.right(), r.bottom() };
157 }
158 
159 class GDIGraphicsPort : public GraphicsPort {
160 public:
GDIGraphicsPort(SkCanvas * canvas)161     GDIGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {}
162 
drawRect(const SkRect & r,SkColor c)163     void drawRect(const SkRect& r, SkColor c) override {
164         HDC hdc = (HDC)fCanvas->accessTopRasterHandle();
165 
166         COLORREF cr = RGB(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));// SkEndian_Swap32(c) >> 8;
167         RECT rounded = toRECT(r.round());
168         FillRect(hdc, &rounded, CreateSolidBrush(cr));
169 
170         // Assuming GDI wrote zeros for alpha, this will or-in 0xFF for alpha
171         SkPaint paint;
172         paint.setBlendMode(SkBlendMode::kDstATop);
173         fCanvas->drawRect(r, paint);
174     }
175 };
176 
DeleteHDCCallback(void *,void * context)177 static void DeleteHDCCallback(void*, void* context) {
178     HDC hdc = static_cast<HDC>(context);
179     HBITMAP hbitmap = static_cast<HBITMAP>(SelectObject(hdc, nullptr));
180     DeleteObject(hbitmap);
181     DeleteDC(hdc);
182 }
183 
184 // We use this static factory function instead of the regular constructor so
185 // that we can create the pixel data before calling the constructor. This is
186 // required so that we can call the base class' constructor with the pixel
187 // data.
Create(int width,int height,bool is_opaque,SkRasterHandleAllocator::Rec * rec)188 static bool Create(int width, int height, bool is_opaque, SkRasterHandleAllocator::Rec* rec) {
189     BITMAPINFOHEADER hdr;
190     memset(&hdr, 0, sizeof(hdr));
191     hdr.biSize = sizeof(BITMAPINFOHEADER);
192     hdr.biWidth = width;
193     hdr.biHeight = -height;  // Minus means top-down bitmap.
194     hdr.biPlanes = 1;
195     hdr.biBitCount = 32;
196     hdr.biCompression = BI_RGB;  // No compression.
197     hdr.biSizeImage = 0;
198     hdr.biXPelsPerMeter = 1;
199     hdr.biYPelsPerMeter = 1;
200     void* pixels;
201     HBITMAP hbitmap = CreateDIBSection(nullptr, (const BITMAPINFO*)&hdr, 0, &pixels, 0, 0);
202     if (!hbitmap) {
203         return false;
204     }
205 
206     size_t row_bytes = width * sizeof(SkPMColor);
207     sk_bzero(pixels, row_bytes * height);
208 
209     HDC hdc = CreateCompatibleDC(nullptr);
210     if (!hdc) {
211         DeleteObject(hbitmap);
212         return false;
213     }
214     SetGraphicsMode(hdc, GM_ADVANCED);
215     SelectObject(hdc, hbitmap);
216 
217     rec->fReleaseProc = DeleteHDCCallback;
218     rec->fReleaseCtx = hdc;
219     rec->fPixels = pixels;
220     rec->fRowBytes = row_bytes;
221     rec->fHandle = hdc;
222     return true;
223 }
224 
225 /**
226 *  Subclass of SkRasterHandleAllocator that returns an HDC as its "handle".
227 */
228 class GDIAllocator : public SkRasterHandleAllocator {
229 public:
GDIAllocator()230     GDIAllocator() {}
231 
allocHandle(const SkImageInfo & info,Rec * rec)232     bool allocHandle(const SkImageInfo& info, Rec* rec) override {
233         SkASSERT(info.colorType() == kN32_SkColorType);
234         return Create(info.width(), info.height(), info.isOpaque(), rec);
235     }
236 
updateHandle(Handle handle,const SkMatrix & ctm,const SkIRect & clip_bounds)237     void updateHandle(Handle handle, const SkMatrix& ctm, const SkIRect& clip_bounds) override {
238         HDC hdc = static_cast<HDC>(handle);
239 
240         XFORM xf;
241         xf.eM11 = ctm[SkMatrix::kMScaleX];
242         xf.eM21 = ctm[SkMatrix::kMSkewX];
243         xf.eDx = ctm[SkMatrix::kMTransX];
244         xf.eM12 = ctm[SkMatrix::kMSkewY];
245         xf.eM22 = ctm[SkMatrix::kMScaleY];
246         xf.eDy = ctm[SkMatrix::kMTransY];
247         SetWorldTransform(hdc, &xf);
248 
249         RECT clip_bounds_RECT = toRECT(clip_bounds);
250         HRGN hrgn = CreateRectRgnIndirect(&clip_bounds_RECT);
251         int result = SelectClipRgn(hdc, hrgn);
252         SkASSERT(result != ERROR);
253         result = DeleteObject(hrgn);
254         SkASSERT(result != 0);
255     }
256 };
257 
258 #define MyPort GDIGraphicsPort
259 #define MyAllocator GDIAllocator
260 
261 #endif
262 
263 #ifdef MyAllocator
264 class RasterAllocatorSample : public SampleView {
265 public:
RasterAllocatorSample()266     RasterAllocatorSample() {}
267 
268 protected:
onQuery(SkEvent * evt)269     bool onQuery(SkEvent* evt) override {
270         if (SampleCode::TitleQ(*evt)) {
271             SampleCode::TitleR(evt, "raster-allocator");
272             return true;
273         }
274         return this->INHERITED::onQuery(evt);
275     }
276 
doDraw(GraphicsPort * port)277     void 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 
onDrawContent(SkCanvas * canvas)295     void onDrawContent(SkCanvas* canvas) override {
296         GraphicsPort skp(canvas);
297         doDraw(&skp);
298 
299         const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
300         std::unique_ptr<SkCanvas> c2 =
301             SkRasterHandleAllocator::MakeCanvas(skstd::make_unique<MyAllocator>(), info);
302         MyPort cgp(c2.get());
303         doDraw(&cgp);
304 
305         SkPixmap pm;
306         c2->peekPixels(&pm);
307         SkBitmap bm;
308         bm.installPixels(pm);
309         canvas->drawBitmap(bm, 280, 0, nullptr);
310     }
311 
312 private:
313     typedef SampleView INHERITED;
314 };
315 DEF_SAMPLE( return new RasterAllocatorSample; )
316 #endif
317