1#include <cstdio>
2#include <string>
3
4#include "ppapi/cpp/completion_callback.h"
5#include "ppapi/cpp/graphics_2d.h"
6#include "ppapi/cpp/image_data.h"
7#include "ppapi/cpp/instance.h"
8#include "ppapi/cpp/module.h"
9#include "ppapi/cpp/var.h"
10
11#include "SampleApp.h"
12#include "SkApplication.h"
13#include "SkCanvas.h"
14#include "SkBitmap.h"
15#include "SkEvent.h"
16#include "SkWindow.h"
17
18class SkiaInstance;
19
20namespace {
21void FlushCallback(void* data, int32_t result);
22}
23
24SkiaInstance* gPluginInstance;
25extern int main(int, char**);
26
27class SkiaInstance : public pp::Instance {
28 public:
29    explicit SkiaInstance(PP_Instance instance) : pp::Instance(instance),
30                                                  fFlushPending(false),
31                                                  fGraphics2dContext(NULL),
32                                                  fPixelBuffer(NULL)
33    {
34        gPluginInstance = this;
35        application_init();
36        char* commandName = "SampleApp";
37        fWindow = new SampleWindow(NULL, 0, &commandName, NULL);
38    }
39
40    virtual ~SkiaInstance() {
41        gPluginInstance = NULL;
42        delete fWindow;
43        application_term();
44    }
45
46    virtual void HandleMessage(const pp::Var& var_message) {
47        // Receive a message from javascript.  Right now this just signals us to
48        // get started.
49        uint32_t width = 500;
50        uint32_t height = 500;
51        char buffer[2048];
52        sprintf(buffer, "SetSize:%d,%d", width, height);
53        PostMessage(buffer);
54    }
55
56    virtual void DidChangeView(const pp::Rect& position,
57                               const pp::Rect& clip) {
58        if (position.size().width() == width() &&
59            position.size().height() == height()) {
60            return;  // Size didn't change, no need to update anything.
61        }
62        // Create a new device context with the new size.
63        DestroyContext();
64        CreateContext(position.size());
65        // Delete the old pixel buffer and create a new one.
66        delete fPixelBuffer;
67        fPixelBuffer = NULL;
68        if (fGraphics2dContext != NULL) {
69            fPixelBuffer = new pp::ImageData(this,
70                                              PP_IMAGEDATAFORMAT_BGRA_PREMUL,
71                                              fGraphics2dContext->size(),
72                                              false);
73            fWindow->resize(position.size().width(), position.size().height());
74            fWindow->update(NULL);
75            paint();
76        }
77    }
78
79    // Indicate whether a flush is pending.  This can only be called from the
80    // main thread; it is not thread safe.
81    bool flush_pending() const {
82        return fFlushPending;
83    }
84    void set_flush_pending(bool flag) {
85        fFlushPending = flag;
86    }
87
88  void paint() {
89    if (fPixelBuffer) {
90      // Draw some stuff.  TODO(borenet): Actually have SampleApp draw into
91      // the plugin area.
92      uint32_t w = fPixelBuffer->size().width();
93      uint32_t h = fPixelBuffer->size().height();
94      uint32_t* data = (uint32_t*) fPixelBuffer->data();
95      // Create a bitmap using the fPixelBuffer pixels
96      SkBitmap bitmap;
97      bitmap.setConfig(SkBitmap::kARGB_8888_Config, w, h);
98      bitmap.setPixels(data);
99      // Create a canvas with the bitmap as the backend
100      SkCanvas canvas(bitmap);
101
102      canvas.drawColor(SK_ColorBLUE);
103      SkRect rect = SkRect::MakeXYWH(10, 10, 80, 80);
104      SkPaint rect_paint;
105      rect_paint.setStyle(SkPaint::kFill_Style);
106      rect_paint.setColor(SK_ColorRED);
107      canvas.drawRect(rect, rect_paint);
108
109      FlushPixelBuffer();
110    }
111  }
112
113private:
114    int width() const {
115        return fPixelBuffer ? fPixelBuffer->size().width() : 0;
116    }
117
118    int height() const {
119        return fPixelBuffer ? fPixelBuffer->size().height() : 0;
120    }
121
122    bool IsContextValid() const {
123        return fGraphics2dContext != NULL;
124    }
125
126    void CreateContext(const pp::Size& size) {
127        if (IsContextValid())
128            return;
129        fGraphics2dContext = new pp::Graphics2D(this, size, false);
130        if (!BindGraphics(*fGraphics2dContext)) {
131            SkDebugf("Couldn't bind the device context");
132        }
133    }
134
135    void DestroyContext() {
136        if (!IsContextValid())
137            return;
138        delete fGraphics2dContext;
139        fGraphics2dContext = NULL;
140    }
141
142    void FlushPixelBuffer() {
143        if (!IsContextValid())
144            return;
145        // Note that the pixel lock is held while the buffer is copied into the
146        // device context and then flushed.
147        fGraphics2dContext->PaintImageData(*fPixelBuffer, pp::Point());
148        if (flush_pending())
149            return;
150        set_flush_pending(true);
151        fGraphics2dContext->Flush(pp::CompletionCallback(&FlushCallback, this));
152    }
153
154    bool fFlushPending;
155    pp::Graphics2D* fGraphics2dContext;
156    pp::ImageData* fPixelBuffer;
157    SampleWindow* fWindow;
158};
159
160class SkiaModule : public pp::Module {
161public:
162    SkiaModule() : pp::Module() {}
163    virtual ~SkiaModule() {}
164
165    virtual pp::Instance* CreateInstance(PP_Instance instance) {
166        gPluginInstance = new SkiaInstance(instance);
167        return gPluginInstance;
168    }
169};
170
171namespace {
172void FlushCallback(void* data, int32_t result) {
173    static_cast<SkiaInstance*>(data)->set_flush_pending(false);
174}
175}
176
177namespace pp {
178Module* CreateModule() {
179    return new SkiaModule();
180}
181}  // namespace pp
182
183
184///////////////////////////////////////////
185///////////// SkOSWindow impl /////////////
186///////////////////////////////////////////
187
188void SkOSWindow::onSetTitle(const char title[])
189{
190    char buffer[2048];
191    sprintf(buffer, "SetTitle:%s", title);
192    gPluginInstance->PostMessage(buffer);
193}
194
195void SkOSWindow::onHandleInval(const SkIRect& rect)
196{
197    gPluginInstance->paint();
198}
199
200void SkOSWindow::onPDFSaved(const char title[], const char desc[],
201                            const char path[]) {
202}
203
204///////////////////////////////////////////
205/////////////// SkEvent impl //////////////
206///////////////////////////////////////////
207
208void SkEvent::SignalQueueTimer(SkMSec ms) {
209}
210
211void SkEvent::SignalNonEmptyQueue() {
212}
213