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 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: 22 BigGradientView() {} 23 24 protected: 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 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 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: 59 GraphicsPort(SkCanvas* canvas) : fCanvas(canvas) {} 60 virtual ~GraphicsPort() {} 61 62 void save() { fCanvas->save(); } 63 void saveLayer(const SkRect& bounds, SkAlpha alpha) { 64 fCanvas->saveLayerAlpha(&bounds, alpha); 65 } 66 void restore() { fCanvas->restore(); } 67 68 void translate(float x, float y) { fCanvas->translate(x, y); } 69 void scale(float s) { fCanvas->scale(s, s); } 70 void clip(const SkRect& r) { fCanvas->clipRect(r); } 71 72 void drawOval(const SkRect& r, SkColor c) { 73 SkPaint p; 74 p.setColor(c); 75 fCanvas->drawOval(r, p); 76 } 77 78 virtual void drawRect(const SkRect& r, SkColor c) { 79 SkPaint p; 80 p.setColor(c); 81 fCanvas->drawRect(r, p); 82 } 83 84 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: 92 CGGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {} 93 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 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: 123 Allocator_CG() {} 124 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 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 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: 161 GDIGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {} 162 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 FillRect(hdc, &toRECT(r.round()), CreateSolidBrush(cr)); 168 169 // Assuming GDI wrote zeros for alpha, this will or-in 0xFF for alpha 170 SkPaint paint; 171 paint.setBlendMode(SkBlendMode::kDstATop); 172 fCanvas->drawRect(r, paint); 173 } 174 }; 175 176 static void DeleteHDCCallback(void*, void* context) { 177 HDC hdc = static_cast<HDC>(context); 178 HBITMAP hbitmap = static_cast<HBITMAP>(SelectObject(hdc, nullptr)); 179 DeleteObject(hbitmap); 180 DeleteDC(hdc); 181 } 182 183 // We use this static factory function instead of the regular constructor so 184 // that we can create the pixel data before calling the constructor. This is 185 // required so that we can call the base class' constructor with the pixel 186 // data. 187 static bool Create(int width, int height, bool is_opaque, SkRasterHandleAllocator::Rec* rec) { 188 BITMAPINFOHEADER hdr = { 0 }; 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: 228 GDIAllocator() {} 229 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 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 HRGN hrgn = CreateRectRgnIndirect(&toRECT(clip_bounds)); 248 int result = SelectClipRgn(hdc, hrgn); 249 SkASSERT(result != ERROR); 250 result = DeleteObject(hrgn); 251 SkASSERT(result != 0); 252 } 253 }; 254 255 #define MyPort GDIGraphicsPort 256 #define MyAllocator GDIAllocator 257 258 #endif 259 260 #ifdef MyAllocator 261 class RasterAllocatorSample : public SampleView { 262 public: 263 RasterAllocatorSample() {} 264 265 protected: 266 bool onQuery(SkEvent* evt) override { 267 if (SampleCode::TitleQ(*evt)) { 268 SampleCode::TitleR(evt, "raster-allocator"); 269 return true; 270 } 271 return this->INHERITED::onQuery(evt); 272 } 273 274 void doDraw(GraphicsPort* port) { 275 SkAutoCanvasRestore acr(port->peekCanvas(), true); 276 277 port->drawRect({0, 0, 256, 256}, SK_ColorRED); 278 port->save(); 279 port->translate(30, 30); 280 port->drawRect({0, 0, 30, 30}, SK_ColorBLUE); 281 port->drawOval({10, 10, 20, 20}, SK_ColorWHITE); 282 port->restore(); 283 284 port->saveLayer({50, 50, 100, 100}, 0x80); 285 port->drawRect({55, 55, 95, 95}, SK_ColorGREEN); 286 port->restore(); 287 288 port->clip({150, 50, 200, 200}); 289 port->drawRect({0, 0, 256, 256}, 0xFFCCCCCC); 290 } 291 292 void onDrawContent(SkCanvas* canvas) override { 293 GraphicsPort skp(canvas); 294 doDraw(&skp); 295 296 const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256); 297 std::unique_ptr<SkCanvas> c2 = 298 SkRasterHandleAllocator::MakeCanvas(skstd::make_unique<MyAllocator>(), info); 299 MyPort cgp(c2.get()); 300 doDraw(&cgp); 301 302 SkPixmap pm; 303 c2->peekPixels(&pm); 304 SkBitmap bm; 305 bm.installPixels(pm); 306 canvas->drawBitmap(bm, 280, 0, nullptr); 307 } 308 309 private: 310 typedef SampleView INHERITED; 311 }; 312 DEF_SAMPLE( return new RasterAllocatorSample; ) 313 #endif 314