Home | History | Annotate | Download | only in src
      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 "SkBase64.h"
     19 #include "SkBitmap.h"
     20 #include "SkCanvas.h"
     21 #include "SkColor.h"
     22 #include "SkDebugger.h"
     23 #include "SkGraphics.h"
     24 #include "SkStream.h"
     25 #include "SkString.h"
     26 
     27 class SkiaInstance;
     28 
     29 // Used by SkDebugf
     30 SkiaInstance* gPluginInstance;
     31 
     32 void FlushCallback(void* data, int32_t result);
     33 
     34 // Skia's subclass of pp::Instance, our interface with the browser.
     35 class SkiaInstance : public pp::Instance {
     36 public:
     37     explicit SkiaInstance(PP_Instance instance)
     38         : pp::Instance(instance)
     39         , fCanvas(NULL)
     40         , fFlushLoopRunning(false)
     41         , fFlushPending(false)
     42 
     43     {
     44         gPluginInstance = this;
     45         SkGraphics::Init();
     46     }
     47 
     48     virtual ~SkiaInstance() {
     49         SkGraphics::Term();
     50         gPluginInstance = NULL;
     51     }
     52 
     53     virtual void HandleMessage(const pp::Var& var_message) {
     54         // Receive a message from javascript.
     55         if (var_message.is_string()) {
     56             SkString msg(var_message.AsString().c_str());
     57             if (msg.startsWith("init")) {
     58             } else if (msg.startsWith("LoadSKP")) {
     59                 size_t startIndex = strlen("LoadSKP");
     60                 size_t dataSize = msg.size()/sizeof(char) - startIndex;
     61                 SkBase64 decodedData;
     62                 decodedData.decode(msg.c_str() + startIndex, dataSize);
     63                 size_t decodedSize = 3 * (dataSize / 4);
     64                 SkDebugf("Got size: %d\n", decodedSize);
     65                 if (!decodedData.getData()) {
     66                     SkDebugf("Failed to decode SKP\n");
     67                     return;
     68                 }
     69                 SkMemoryStream pictureStream(decodedData.getData(), decodedSize);
     70                 SkPicture* picture = SkPicture::CreateFromStream(&pictureStream);
     71                 if (NULL == picture) {
     72                     SkDebugf("Failed to create SKP.\n");
     73                     return;
     74                 }
     75                 fDebugger.loadPicture(picture);
     76                 picture->unref();
     77 
     78                 // Set up the command list.
     79                 SkTArray<SkString>* commands = fDebugger.getDrawCommandsAsStrings();
     80                 PostMessage("ClearCommands");
     81                 for (int i = 0; i < commands->count(); ++i) {
     82                     SkString addCommand("AddCommand:");
     83                     addCommand.append((*commands)[i]);
     84                     PostMessage(addCommand.c_str());
     85                 }
     86                 PostMessage("UpdateCommands");
     87 
     88                 // Set the overview text.
     89                 SkString overviewText;
     90                 fDebugger.getOverviewText(NULL, 0.0, &overviewText, 1);
     91                 overviewText.prepend("SetOverview:");
     92                 PostMessage(overviewText.c_str());
     93 
     94                 // Draw the SKP.
     95                 if (!fFlushLoopRunning) {
     96                     Paint();
     97                 }
     98             } else if (msg.startsWith("CommandSelected:")) {
     99                 size_t startIndex = strlen("CommandSelected:");
    100                 int index = atoi(msg.c_str() + startIndex);
    101                 fDebugger.setIndex(index);
    102                 if (!fFlushLoopRunning) {
    103                     Paint();
    104                 }
    105             } else if (msg.startsWith("Rewind")) {
    106                 fCanvas->clear(SK_ColorWHITE);
    107                 fDebugger.setIndex(0);
    108                 if (!fFlushLoopRunning) {
    109                     Paint();
    110                 }
    111             } else if (msg.startsWith("StepBack")) {
    112                 fCanvas->clear(SK_ColorWHITE);
    113                 int currentIndex = fDebugger.index();
    114                 if (currentIndex > 1) {
    115                     fDebugger.setIndex(currentIndex - 1);
    116                     if (!fFlushLoopRunning) {
    117                         Paint();
    118                     }
    119                 }
    120             } else if (msg.startsWith("Pause")) {
    121                 // TODO(borenet)
    122             } else if (msg.startsWith("StepForward")) {
    123                 int currentIndex = fDebugger.index();
    124                 if (currentIndex < fDebugger.getSize() -1) {
    125                     fDebugger.setIndex(currentIndex + 1);
    126                     if (!fFlushLoopRunning) {
    127                         Paint();
    128                     }
    129                 }
    130             } else if (msg.startsWith("Play")) {
    131                 fDebugger.setIndex(fDebugger.getSize() - 1);
    132                 if (!fFlushLoopRunning) {
    133                     Paint();
    134                 }
    135             }
    136         }
    137     }
    138 
    139     void Paint() {
    140         if (!fImage.is_null()) {
    141             fDebugger.draw(fCanvas);
    142             fDeviceContext.PaintImageData(fImage, pp::Point(0, 0));
    143             if (!fFlushPending) {
    144                 fFlushPending = true;
    145                 fDeviceContext.Flush(pp::CompletionCallback(&FlushCallback, this));
    146             } else {
    147                 SkDebugf("A flush is pending... Skipping flush.\n");
    148             }
    149         } else {
    150             SkDebugf("No pixels to write to!\n");
    151         }
    152     }
    153 
    154     virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
    155         if (position.size().width() == fWidth &&
    156             position.size().height() == fHeight) {
    157             return;  // We don't care about the position, only the size.
    158         }
    159         fWidth = position.size().width();
    160         fHeight = position.size().height();
    161 
    162         fDeviceContext = pp::Graphics2D(this, pp::Size(fWidth, fHeight), false);
    163         if (!BindGraphics(fDeviceContext)) {
    164             SkDebugf("Couldn't bind the device context\n");
    165             return;
    166         }
    167         fImage = pp::ImageData(this,
    168                                PP_IMAGEDATAFORMAT_BGRA_PREMUL,
    169                                pp::Size(fWidth, fHeight), false);
    170         const SkImageInfo info = SkImageInfo::MakeN32Premul(fWidth, fHeight);
    171         fBitmap.installPixels(info, fImage.data(), info.minRowBytes());
    172         if (fCanvas) {
    173             delete fCanvas;
    174         }
    175         fCanvas = new SkCanvas(fBitmap);
    176         fCanvas->clear(SK_ColorWHITE);
    177         if (!fFlushLoopRunning) {
    178             Paint();
    179         }
    180     }
    181 
    182     void OnFlush() {
    183         fFlushLoopRunning = true;
    184         fFlushPending = false;
    185         Paint();
    186     }
    187 
    188 private:
    189     pp::Graphics2D fDeviceContext;
    190     pp::ImageData fImage;
    191     int fWidth;
    192     int fHeight;
    193 
    194     SkBitmap fBitmap;
    195     SkCanvas* fCanvas;
    196     SkDebugger fDebugger;
    197 
    198     bool fFlushLoopRunning;
    199     bool fFlushPending;
    200 };
    201 
    202 void FlushCallback(void* data, int32_t result) {
    203     static_cast<SkiaInstance*>(data)->OnFlush();
    204 }
    205 
    206 class SkiaModule : public pp::Module {
    207 public:
    208     SkiaModule() : pp::Module() {}
    209     virtual ~SkiaModule() {}
    210 
    211     virtual pp::Instance* CreateInstance(PP_Instance instance) {
    212         return new SkiaInstance(instance);
    213     }
    214 };
    215 
    216 namespace pp {
    217 Module* CreateModule() {
    218     return new SkiaModule();
    219 }
    220 }  // namespace pp
    221