1
2/*
3 * Copyright 2013 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "ppapi/cpp/completion_callback.h"
10#include "ppapi/cpp/graphics_2d.h"
11#include "ppapi/cpp/image_data.h"
12#include "ppapi/cpp/instance.h"
13#include "ppapi/cpp/module.h"
14#include "ppapi/cpp/point.h"
15#include "ppapi/cpp/rect.h"
16#include "ppapi/cpp/var.h"
17
18#include "SkBitmap.h"
19#include "SkCanvas.h"
20#include "SkColor.h"
21#include "SkGraphics.h"
22#include "SkStream.h"
23#include "SkString.h"
24
25class SkiaInstance;
26
27// Used by SkDebugf
28SkiaInstance* gPluginInstance;
29
30void FlushCallback(void* data, int32_t result);
31
32static void doDraw(SkCanvas* canvas, const SkPaint& paint, const char text[]) {
33    canvas->drawColor(SK_ColorWHITE);
34    SkPaint red;
35    red.setColor(SK_ColorRED);
36    canvas->drawCircle(150.0, 150.0, 100.0, red);
37    SkRect bounds;
38    canvas->getClipBounds(&bounds);
39    canvas->drawText(text, strlen(text),
40                     bounds.centerX(), bounds.centerY(),
41                     paint);
42}
43
44// Skia's subclass of pp::Instance, our interface with the browser.
45class SkiaInstance : public pp::Instance {
46public:
47    explicit SkiaInstance(PP_Instance instance)
48        : pp::Instance(instance)
49        , fCanvas(NULL)
50        , fFlushLoopRunning(false)
51        , fFlushPending(false)
52    {
53        gPluginInstance = this;
54        SkGraphics::Init();
55    }
56
57    virtual ~SkiaInstance() {
58        SkGraphics::Term();
59        gPluginInstance = NULL;
60    }
61
62    virtual void HandleMessage(const pp::Var& var_message) {
63        // Receive a message from javascript.
64    }
65
66    void Paint() {
67        if (!fImage.is_null()) {
68            SkPaint paint;
69            paint.setAntiAlias(true);
70            paint.setTextSize(SkIntToScalar(30));
71            paint.setTextAlign(SkPaint::kCenter_Align);
72            doDraw(fCanvas, paint, "Hello");
73
74            fDeviceContext.PaintImageData(fImage, pp::Point(0, 0));
75            if (!fFlushPending) {
76                fFlushPending = true;
77                fDeviceContext.Flush(pp::CompletionCallback(&FlushCallback, this));
78            } else {
79                SkDebugf("A flush is pending... Skipping flush.\n");
80            }
81        } else {
82            SkDebugf("No pixels to write to!\n");
83        }
84    }
85
86    virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
87        if (position.size().width() == fWidth &&
88            position.size().height() == fHeight) {
89            return;  // We don't care about the position, only the size.
90        }
91        fWidth = position.size().width();
92        fHeight = position.size().height();
93        fDeviceContext = pp::Graphics2D(this, pp::Size(fWidth, fHeight), false);
94        if (!BindGraphics(fDeviceContext)) {
95            SkDebugf("Couldn't bind the device context\n");
96            return;
97        }
98        fImage = pp::ImageData(this,
99                               PP_IMAGEDATAFORMAT_BGRA_PREMUL,
100                               pp::Size(fWidth, fHeight), false);
101        fBitmap.setConfig(SkBitmap::kARGB_8888_Config, fWidth, fHeight);
102        fBitmap.setPixels(fImage.data());
103        if (fCanvas) {
104            delete fCanvas;
105        }
106        fCanvas = new SkCanvas(fBitmap);
107        fCanvas->clear(SK_ColorWHITE);
108        if (!fFlushLoopRunning) {
109            Paint();
110        }
111    }
112
113    void OnFlush() {
114        fFlushLoopRunning = true;
115        fFlushPending = false;
116        Paint();
117    }
118
119private:
120    pp::Graphics2D fDeviceContext;
121    pp::ImageData fImage;
122    int fWidth;
123    int fHeight;
124
125    SkBitmap fBitmap;
126    SkCanvas* fCanvas;
127
128    bool fFlushLoopRunning;
129    bool fFlushPending;
130};
131
132void FlushCallback(void* data, int32_t result) {
133    static_cast<SkiaInstance*>(data)->OnFlush();
134}
135
136class SkiaModule : public pp::Module {
137public:
138    SkiaModule() : pp::Module() {}
139    virtual ~SkiaModule() {}
140
141    virtual pp::Instance* CreateInstance(PP_Instance instance) {
142        return new SkiaInstance(instance);
143    }
144};
145
146namespace pp {
147Module* CreateModule() {
148    return new SkiaModule();
149}
150}  // namespace pp
151