Home | History | Annotate | Download | only in samplecode
      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