1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2011 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "gm/gm.h" 9cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h" 10cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 11cb93a386Sopenharmony_ci#include "include/core/SkPixmap.h" 12cb93a386Sopenharmony_ci#include "include/core/SkRasterHandleAllocator.h" 13cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ciclass GraphicsPort { 16cb93a386Sopenharmony_ciprotected: 17cb93a386Sopenharmony_ci SkCanvas* fCanvas; 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_cipublic: 20cb93a386Sopenharmony_ci GraphicsPort(SkCanvas* canvas) : fCanvas(canvas) {} 21cb93a386Sopenharmony_ci virtual ~GraphicsPort() {} 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci void save() { fCanvas->save(); } 24cb93a386Sopenharmony_ci void saveLayer(const SkRect& bounds, SkAlpha alpha) { 25cb93a386Sopenharmony_ci fCanvas->saveLayerAlpha(&bounds, alpha); 26cb93a386Sopenharmony_ci } 27cb93a386Sopenharmony_ci void restore() { fCanvas->restore(); } 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ci void translate(float x, float y) { fCanvas->translate(x, y); } 30cb93a386Sopenharmony_ci void scale(float s) { fCanvas->scale(s, s); } 31cb93a386Sopenharmony_ci void clip(const SkRect& r) { fCanvas->clipRect(r); } 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_ci void drawOval(const SkRect& r, SkColor c) { 34cb93a386Sopenharmony_ci SkPaint p; 35cb93a386Sopenharmony_ci p.setColor(c); 36cb93a386Sopenharmony_ci fCanvas->drawOval(r, p); 37cb93a386Sopenharmony_ci } 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci virtual void drawRect(const SkRect& r, SkColor c) { 40cb93a386Sopenharmony_ci SkPaint p; 41cb93a386Sopenharmony_ci p.setColor(c); 42cb93a386Sopenharmony_ci fCanvas->drawRect(r, p); 43cb93a386Sopenharmony_ci } 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci SkCanvas* peekCanvas() const { return fCanvas; } 46cb93a386Sopenharmony_ci}; 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ciclass SkiaGraphicsPort : public GraphicsPort { 49cb93a386Sopenharmony_cipublic: 50cb93a386Sopenharmony_ci SkiaGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {} 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci void drawRect(const SkRect& r, SkColor c) override { 53cb93a386Sopenharmony_ci SkCanvas* canvas = (SkCanvas*)fCanvas->accessTopRasterHandle(); 54cb93a386Sopenharmony_ci canvas->drawRect(r, SkPaint(SkColor4f::FromColor(c))); 55cb93a386Sopenharmony_ci } 56cb93a386Sopenharmony_ci}; 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ciclass SkiaAllocator : public SkRasterHandleAllocator { 59cb93a386Sopenharmony_cipublic: 60cb93a386Sopenharmony_ci SkiaAllocator() {} 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_ci bool allocHandle(const SkImageInfo& info, Rec* rec) override { 63cb93a386Sopenharmony_ci sk_sp<SkSurface> surface = SkSurface::MakeRaster(info); 64cb93a386Sopenharmony_ci if (!surface) { 65cb93a386Sopenharmony_ci return false; 66cb93a386Sopenharmony_ci } 67cb93a386Sopenharmony_ci SkCanvas* canvas = surface->getCanvas(); 68cb93a386Sopenharmony_ci SkPixmap pixmap; 69cb93a386Sopenharmony_ci canvas->peekPixels(&pixmap); 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci rec->fReleaseProc = [](void* pixels, void* ctx){ SkSafeUnref((SkSurface*)ctx); }; 72cb93a386Sopenharmony_ci rec->fReleaseCtx = surface.release(); 73cb93a386Sopenharmony_ci rec->fPixels = pixmap.writable_addr(); 74cb93a386Sopenharmony_ci rec->fRowBytes = pixmap.rowBytes(); 75cb93a386Sopenharmony_ci rec->fHandle = canvas; 76cb93a386Sopenharmony_ci canvas->save(); // balanced each time updateHandle is called 77cb93a386Sopenharmony_ci return true; 78cb93a386Sopenharmony_ci } 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ci void updateHandle(Handle hndl, const SkMatrix& ctm, const SkIRect& clip) override { 81cb93a386Sopenharmony_ci SkCanvas* canvas = (SkCanvas*)hndl; 82cb93a386Sopenharmony_ci canvas->restore(); 83cb93a386Sopenharmony_ci canvas->save(); 84cb93a386Sopenharmony_ci canvas->clipRect(SkRect::Make(clip)); 85cb93a386Sopenharmony_ci canvas->concat(ctm); 86cb93a386Sopenharmony_ci } 87cb93a386Sopenharmony_ci}; 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_MAC 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_ci#include "include/utils/mac/SkCGUtils.h" 92cb93a386Sopenharmony_ciclass CGGraphicsPort : public GraphicsPort { 93cb93a386Sopenharmony_cipublic: 94cb93a386Sopenharmony_ci CGGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {} 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci void drawRect(const SkRect& r, SkColor c) override { 97cb93a386Sopenharmony_ci CGContextRef cg = (CGContextRef)fCanvas->accessTopRasterHandle(); 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci CGColorRef color = CGColorCreateGenericRGB(SkColorGetR(c)/255.f, 100cb93a386Sopenharmony_ci SkColorGetG(c)/255.f, 101cb93a386Sopenharmony_ci SkColorGetB(c)/255.f, 102cb93a386Sopenharmony_ci SkColorGetA(c)/255.f); 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ci CGContextSetFillColorWithColor(cg, color); 105cb93a386Sopenharmony_ci CGContextFillRect(cg, CGRectMake(r.x(), r.y(), r.width(), r.height())); 106cb93a386Sopenharmony_ci } 107cb93a386Sopenharmony_ci}; 108cb93a386Sopenharmony_ci 109cb93a386Sopenharmony_cistatic CGAffineTransform matrix_to_transform(CGContextRef cg, const SkMatrix& ctm) { 110cb93a386Sopenharmony_ci SkMatrix matrix; 111cb93a386Sopenharmony_ci matrix.setScale(1, -1); 112cb93a386Sopenharmony_ci matrix.postTranslate(0, SkIntToScalar(CGBitmapContextGetHeight(cg))); 113cb93a386Sopenharmony_ci matrix.preConcat(ctm); 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_ci return CGAffineTransformMake(matrix[SkMatrix::kMScaleX], 116cb93a386Sopenharmony_ci matrix[SkMatrix::kMSkewY], 117cb93a386Sopenharmony_ci matrix[SkMatrix::kMSkewX], 118cb93a386Sopenharmony_ci matrix[SkMatrix::kMScaleY], 119cb93a386Sopenharmony_ci matrix[SkMatrix::kMTransX], 120cb93a386Sopenharmony_ci matrix[SkMatrix::kMTransY]); 121cb93a386Sopenharmony_ci} 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ciclass CGAllocator : public SkRasterHandleAllocator { 124cb93a386Sopenharmony_cipublic: 125cb93a386Sopenharmony_ci CGAllocator() {} 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_ci bool allocHandle(const SkImageInfo& info, Rec* rec) override { 128cb93a386Sopenharmony_ci // let CG allocate the pixels 129cb93a386Sopenharmony_ci CGContextRef cg = SkCreateCGContext(SkPixmap(info, nullptr, 0)); 130cb93a386Sopenharmony_ci if (!cg) { 131cb93a386Sopenharmony_ci return false; 132cb93a386Sopenharmony_ci } 133cb93a386Sopenharmony_ci rec->fReleaseProc = [](void* pixels, void* ctx){ CGContextRelease((CGContextRef)ctx); }; 134cb93a386Sopenharmony_ci rec->fReleaseCtx = cg; 135cb93a386Sopenharmony_ci rec->fPixels = CGBitmapContextGetData(cg); 136cb93a386Sopenharmony_ci rec->fRowBytes = CGBitmapContextGetBytesPerRow(cg); 137cb93a386Sopenharmony_ci rec->fHandle = cg; 138cb93a386Sopenharmony_ci CGContextSaveGState(cg); // balanced each time updateHandle is called 139cb93a386Sopenharmony_ci return true; 140cb93a386Sopenharmony_ci } 141cb93a386Sopenharmony_ci 142cb93a386Sopenharmony_ci void updateHandle(Handle hndl, const SkMatrix& ctm, const SkIRect& clip) override { 143cb93a386Sopenharmony_ci CGContextRef cg = (CGContextRef)hndl; 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci CGContextRestoreGState(cg); 146cb93a386Sopenharmony_ci CGContextSaveGState(cg); 147cb93a386Sopenharmony_ci CGContextClipToRect(cg, CGRectMake(clip.x(), clip.y(), clip.width(), clip.height())); 148cb93a386Sopenharmony_ci CGContextConcatCTM(cg, matrix_to_transform(cg, ctm)); 149cb93a386Sopenharmony_ci } 150cb93a386Sopenharmony_ci}; 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ciusing MyPort = CGGraphicsPort; 153cb93a386Sopenharmony_ciusing MyAllocator = CGAllocator; 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci#elif defined(SK_BUILD_FOR_WIN) 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci#include "src/core/SkLeanWindows.h" 158cb93a386Sopenharmony_ci 159cb93a386Sopenharmony_cistatic RECT toRECT(const SkIRect& r) { 160cb93a386Sopenharmony_ci return { r.left(), r.top(), r.right(), r.bottom() }; 161cb93a386Sopenharmony_ci} 162cb93a386Sopenharmony_ci 163cb93a386Sopenharmony_ciclass GDIGraphicsPort : public GraphicsPort { 164cb93a386Sopenharmony_cipublic: 165cb93a386Sopenharmony_ci GDIGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {} 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_ci void drawRect(const SkRect& r, SkColor c) override { 168cb93a386Sopenharmony_ci HDC hdc = (HDC)fCanvas->accessTopRasterHandle(); 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci COLORREF cr = RGB(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));// SkEndian_Swap32(c) >> 8; 171cb93a386Sopenharmony_ci RECT rounded = toRECT(r.round()); 172cb93a386Sopenharmony_ci FillRect(hdc, &rounded, CreateSolidBrush(cr)); 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ci // Assuming GDI wrote zeros for alpha, this will or-in 0xFF for alpha 175cb93a386Sopenharmony_ci SkPaint paint; 176cb93a386Sopenharmony_ci paint.setBlendMode(SkBlendMode::kDstATop); 177cb93a386Sopenharmony_ci fCanvas->drawRect(r, paint); 178cb93a386Sopenharmony_ci } 179cb93a386Sopenharmony_ci}; 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ci// We use this static factory function instead of the regular constructor so 182cb93a386Sopenharmony_ci// that we can create the pixel data before calling the constructor. This is 183cb93a386Sopenharmony_ci// required so that we can call the base class' constructor with the pixel 184cb93a386Sopenharmony_ci// data. 185cb93a386Sopenharmony_cistatic bool Create(int width, int height, bool is_opaque, SkRasterHandleAllocator::Rec* rec) { 186cb93a386Sopenharmony_ci BITMAPINFOHEADER hdr; 187cb93a386Sopenharmony_ci memset(&hdr, 0, sizeof(hdr)); 188cb93a386Sopenharmony_ci hdr.biSize = sizeof(BITMAPINFOHEADER); 189cb93a386Sopenharmony_ci hdr.biWidth = width; 190cb93a386Sopenharmony_ci hdr.biHeight = -height; // Minus means top-down bitmap. 191cb93a386Sopenharmony_ci hdr.biPlanes = 1; 192cb93a386Sopenharmony_ci hdr.biBitCount = 32; 193cb93a386Sopenharmony_ci hdr.biCompression = BI_RGB; // No compression. 194cb93a386Sopenharmony_ci hdr.biSizeImage = 0; 195cb93a386Sopenharmony_ci hdr.biXPelsPerMeter = 1; 196cb93a386Sopenharmony_ci hdr.biYPelsPerMeter = 1; 197cb93a386Sopenharmony_ci void* pixels; 198cb93a386Sopenharmony_ci HBITMAP hbitmap = CreateDIBSection(nullptr, (const BITMAPINFO*)&hdr, 0, &pixels, 0, 0); 199cb93a386Sopenharmony_ci if (!hbitmap) { 200cb93a386Sopenharmony_ci return false; 201cb93a386Sopenharmony_ci } 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ci size_t row_bytes = width * sizeof(SkPMColor); 204cb93a386Sopenharmony_ci sk_bzero(pixels, row_bytes * height); 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci HDC hdc = CreateCompatibleDC(nullptr); 207cb93a386Sopenharmony_ci if (!hdc) { 208cb93a386Sopenharmony_ci DeleteObject(hbitmap); 209cb93a386Sopenharmony_ci return false; 210cb93a386Sopenharmony_ci } 211cb93a386Sopenharmony_ci SetGraphicsMode(hdc, GM_ADVANCED); 212cb93a386Sopenharmony_ci HGDIOBJ origBitmap = SelectObject(hdc, hbitmap); 213cb93a386Sopenharmony_ci 214cb93a386Sopenharmony_ci struct ReleaseContext { 215cb93a386Sopenharmony_ci HDC hdc; 216cb93a386Sopenharmony_ci HGDIOBJ hbitmap; 217cb93a386Sopenharmony_ci }; 218cb93a386Sopenharmony_ci rec->fReleaseProc = [](void*, void* context) { 219cb93a386Sopenharmony_ci ReleaseContext* ctx = static_cast<ReleaseContext*>(context); 220cb93a386Sopenharmony_ci HBITMAP hbitmap = static_cast<HBITMAP>(SelectObject(ctx->hdc, ctx->hbitmap)); 221cb93a386Sopenharmony_ci DeleteObject(hbitmap); 222cb93a386Sopenharmony_ci DeleteDC(ctx->hdc); 223cb93a386Sopenharmony_ci delete ctx; 224cb93a386Sopenharmony_ci }; 225cb93a386Sopenharmony_ci rec->fReleaseCtx = new ReleaseContext{hdc, origBitmap}; 226cb93a386Sopenharmony_ci rec->fPixels = pixels; 227cb93a386Sopenharmony_ci rec->fRowBytes = row_bytes; 228cb93a386Sopenharmony_ci rec->fHandle = hdc; 229cb93a386Sopenharmony_ci return true; 230cb93a386Sopenharmony_ci} 231cb93a386Sopenharmony_ci 232cb93a386Sopenharmony_ci/** 233cb93a386Sopenharmony_ci* Subclass of SkRasterHandleAllocator that returns an HDC as its "handle". 234cb93a386Sopenharmony_ci*/ 235cb93a386Sopenharmony_ciclass GDIAllocator : public SkRasterHandleAllocator { 236cb93a386Sopenharmony_cipublic: 237cb93a386Sopenharmony_ci GDIAllocator() {} 238cb93a386Sopenharmony_ci 239cb93a386Sopenharmony_ci bool allocHandle(const SkImageInfo& info, Rec* rec) override { 240cb93a386Sopenharmony_ci SkASSERT(info.colorType() == kN32_SkColorType); 241cb93a386Sopenharmony_ci return Create(info.width(), info.height(), info.isOpaque(), rec); 242cb93a386Sopenharmony_ci } 243cb93a386Sopenharmony_ci 244cb93a386Sopenharmony_ci void updateHandle(Handle handle, const SkMatrix& ctm, const SkIRect& clip_bounds) override { 245cb93a386Sopenharmony_ci HDC hdc = static_cast<HDC>(handle); 246cb93a386Sopenharmony_ci 247cb93a386Sopenharmony_ci XFORM xf; 248cb93a386Sopenharmony_ci xf.eM11 = ctm[SkMatrix::kMScaleX]; 249cb93a386Sopenharmony_ci xf.eM21 = ctm[SkMatrix::kMSkewX]; 250cb93a386Sopenharmony_ci xf.eDx = ctm[SkMatrix::kMTransX]; 251cb93a386Sopenharmony_ci xf.eM12 = ctm[SkMatrix::kMSkewY]; 252cb93a386Sopenharmony_ci xf.eM22 = ctm[SkMatrix::kMScaleY]; 253cb93a386Sopenharmony_ci xf.eDy = ctm[SkMatrix::kMTransY]; 254cb93a386Sopenharmony_ci SetWorldTransform(hdc, &xf); 255cb93a386Sopenharmony_ci 256cb93a386Sopenharmony_ci RECT clip_bounds_RECT = toRECT(clip_bounds); 257cb93a386Sopenharmony_ci HRGN hrgn = CreateRectRgnIndirect(&clip_bounds_RECT); 258cb93a386Sopenharmony_ci SK_MAYBE_UNUSED int result = SelectClipRgn(hdc, hrgn); 259cb93a386Sopenharmony_ci SkASSERT(result != ERROR); 260cb93a386Sopenharmony_ci result = DeleteObject(hrgn); 261cb93a386Sopenharmony_ci SkASSERT(result != 0); 262cb93a386Sopenharmony_ci } 263cb93a386Sopenharmony_ci}; 264cb93a386Sopenharmony_ci 265cb93a386Sopenharmony_ciusing MyPort = GDIGraphicsPort; 266cb93a386Sopenharmony_ciusing MyAllocator = GDIAllocator; 267cb93a386Sopenharmony_ci 268cb93a386Sopenharmony_ci#else 269cb93a386Sopenharmony_ci 270cb93a386Sopenharmony_ciusing MyPort = SkiaGraphicsPort; 271cb93a386Sopenharmony_ciusing MyAllocator = SkiaAllocator; 272cb93a386Sopenharmony_ci 273cb93a386Sopenharmony_ci#endif 274cb93a386Sopenharmony_ci 275cb93a386Sopenharmony_ciDEF_SIMPLE_GM(rasterallocator, canvas, 600, 300) { 276cb93a386Sopenharmony_ci auto doDraw = [](GraphicsPort* port) { 277cb93a386Sopenharmony_ci SkAutoCanvasRestore acr(port->peekCanvas(), true); 278cb93a386Sopenharmony_ci 279cb93a386Sopenharmony_ci port->drawRect({0, 0, 256, 256}, SK_ColorRED); 280cb93a386Sopenharmony_ci port->save(); 281cb93a386Sopenharmony_ci port->translate(30, 30); 282cb93a386Sopenharmony_ci port->drawRect({0, 0, 30, 30}, SK_ColorBLUE); 283cb93a386Sopenharmony_ci port->drawOval({10, 10, 20, 20}, SK_ColorWHITE); 284cb93a386Sopenharmony_ci port->restore(); 285cb93a386Sopenharmony_ci 286cb93a386Sopenharmony_ci port->saveLayer({50, 50, 100, 100}, 0x80); 287cb93a386Sopenharmony_ci port->drawRect({55, 55, 95, 95}, SK_ColorGREEN); 288cb93a386Sopenharmony_ci port->restore(); 289cb93a386Sopenharmony_ci 290cb93a386Sopenharmony_ci port->clip({150, 50, 200, 200}); 291cb93a386Sopenharmony_ci port->drawRect({0, 0, 256, 256}, 0xFFCCCCCC); 292cb93a386Sopenharmony_ci }; 293cb93a386Sopenharmony_ci 294cb93a386Sopenharmony_ci // TODO: this common code fails pic-8888 and serialize-8888 295cb93a386Sopenharmony_ci //GraphicsPort skiaPort(canvas); 296cb93a386Sopenharmony_ci //doDraw(&skiaPort); 297cb93a386Sopenharmony_ci 298cb93a386Sopenharmony_ci const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256); 299cb93a386Sopenharmony_ci std::unique_ptr<SkCanvas> nativeCanvas = 300cb93a386Sopenharmony_ci SkRasterHandleAllocator::MakeCanvas(std::make_unique<MyAllocator>(), info); 301cb93a386Sopenharmony_ci MyPort nativePort(nativeCanvas.get()); 302cb93a386Sopenharmony_ci doDraw(&nativePort); 303cb93a386Sopenharmony_ci 304cb93a386Sopenharmony_ci SkPixmap pm; 305cb93a386Sopenharmony_ci nativeCanvas->peekPixels(&pm); 306cb93a386Sopenharmony_ci canvas->drawImage(SkImage::MakeRasterCopy(pm), 280, 0); 307cb93a386Sopenharmony_ci} 308