Home | History | Annotate | Download | only in src
      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 
     18 class SkiaInstance;
     19 
     20 namespace {
     21 void FlushCallback(void* data, int32_t result);
     22 }
     23 
     24 SkiaInstance* gPluginInstance;
     25 extern int main(int, char**);
     26 
     27 class 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 
    113 private:
    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 
    160 class SkiaModule : public pp::Module {
    161 public:
    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 
    171 namespace {
    172 void FlushCallback(void* data, int32_t result) {
    173     static_cast<SkiaInstance*>(data)->set_flush_pending(false);
    174 }
    175 }
    176 
    177 namespace pp {
    178 Module* CreateModule() {
    179     return new SkiaModule();
    180 }
    181 }  // namespace pp
    182 
    183 
    184 ///////////////////////////////////////////
    185 ///////////// SkOSWindow impl /////////////
    186 ///////////////////////////////////////////
    187 
    188 void SkOSWindow::onSetTitle(const char title[])
    189 {
    190     char buffer[2048];
    191     sprintf(buffer, "SetTitle:%s", title);
    192     gPluginInstance->PostMessage(buffer);
    193 }
    194 
    195 void SkOSWindow::onHandleInval(const SkIRect& rect)
    196 {
    197     gPluginInstance->paint();
    198 }
    199 
    200 void SkOSWindow::onPDFSaved(const char title[], const char desc[],
    201                             const char path[]) {
    202 }
    203 
    204 ///////////////////////////////////////////
    205 /////////////// SkEvent impl //////////////
    206 ///////////////////////////////////////////
    207 
    208 void SkEvent::SignalQueueTimer(SkMSec ms) {
    209 }
    210 
    211 void SkEvent::SignalNonEmptyQueue() {
    212 }
    213