| #include <cstdio> |
| #include <string> |
| |
| #include "ppapi/cpp/completion_callback.h" |
| #include "ppapi/cpp/graphics_2d.h" |
| #include "ppapi/cpp/image_data.h" |
| #include "ppapi/cpp/instance.h" |
| #include "ppapi/cpp/module.h" |
| #include "ppapi/cpp/var.h" |
| |
| #include "SampleApp.h" |
| #include "SkApplication.h" |
| #include "SkCanvas.h" |
| #include "SkBitmap.h" |
| #include "SkEvent.h" |
| #include "SkWindow.h" |
| |
| class SkiaInstance; |
| |
| namespace { |
| void FlushCallback(void* data, int32_t result); |
| } |
| |
| SkiaInstance* gPluginInstance; |
| extern int main(int, char**); |
| |
| class SkiaInstance : public pp::Instance { |
| public: |
| explicit SkiaInstance(PP_Instance instance) : pp::Instance(instance), |
| fFlushPending(false), |
| fGraphics2dContext(NULL), |
| fPixelBuffer(NULL) |
| { |
| gPluginInstance = this; |
| application_init(); |
| char* commandName = "SampleApp"; |
| fWindow = new SampleWindow(NULL, 0, &commandName, NULL); |
| } |
| |
| virtual ~SkiaInstance() { |
| gPluginInstance = NULL; |
| delete fWindow; |
| application_term(); |
| } |
| |
| virtual void HandleMessage(const pp::Var& var_message) { |
| // Receive a message from javascript. Right now this just signals us to |
| // get started. |
| uint32_t width = 500; |
| uint32_t height = 500; |
| char buffer[2048]; |
| sprintf(buffer, "SetSize:%d,%d", width, height); |
| PostMessage(buffer); |
| } |
| |
| virtual void DidChangeView(const pp::Rect& position, |
| const pp::Rect& clip) { |
| if (position.size().width() == width() && |
| position.size().height() == height()) { |
| return; // Size didn't change, no need to update anything. |
| } |
| // Create a new device context with the new size. |
| DestroyContext(); |
| CreateContext(position.size()); |
| // Delete the old pixel buffer and create a new one. |
| delete fPixelBuffer; |
| fPixelBuffer = NULL; |
| if (fGraphics2dContext != NULL) { |
| fPixelBuffer = new pp::ImageData(this, |
| PP_IMAGEDATAFORMAT_BGRA_PREMUL, |
| fGraphics2dContext->size(), |
| false); |
| fWindow->resize(position.size().width(), position.size().height()); |
| fWindow->update(NULL); |
| paint(); |
| } |
| } |
| |
| // Indicate whether a flush is pending. This can only be called from the |
| // main thread; it is not thread safe. |
| bool flush_pending() const { |
| return fFlushPending; |
| } |
| void set_flush_pending(bool flag) { |
| fFlushPending = flag; |
| } |
| |
| void paint() { |
| if (fPixelBuffer) { |
| // Draw some stuff. TODO(borenet): Actually have SampleApp draw into |
| // the plugin area. |
| uint32_t w = fPixelBuffer->size().width(); |
| uint32_t h = fPixelBuffer->size().height(); |
| uint32_t* data = (uint32_t*) fPixelBuffer->data(); |
| // Create a bitmap using the fPixelBuffer pixels |
| SkBitmap bitmap; |
| bitmap.setConfig(SkBitmap::kARGB_8888_Config, w, h); |
| bitmap.setPixels(data); |
| // Create a canvas with the bitmap as the backend |
| SkCanvas canvas(bitmap); |
| |
| canvas.drawColor(SK_ColorBLUE); |
| SkRect rect = SkRect::MakeXYWH(10, 10, 80, 80); |
| SkPaint rect_paint; |
| rect_paint.setStyle(SkPaint::kFill_Style); |
| rect_paint.setColor(SK_ColorRED); |
| canvas.drawRect(rect, rect_paint); |
| |
| FlushPixelBuffer(); |
| } |
| } |
| |
| private: |
| int width() const { |
| return fPixelBuffer ? fPixelBuffer->size().width() : 0; |
| } |
| |
| int height() const { |
| return fPixelBuffer ? fPixelBuffer->size().height() : 0; |
| } |
| |
| bool IsContextValid() const { |
| return fGraphics2dContext != NULL; |
| } |
| |
| void CreateContext(const pp::Size& size) { |
| if (IsContextValid()) |
| return; |
| fGraphics2dContext = new pp::Graphics2D(this, size, false); |
| if (!BindGraphics(*fGraphics2dContext)) { |
| SkDebugf("Couldn't bind the device context"); |
| } |
| } |
| |
| void DestroyContext() { |
| if (!IsContextValid()) |
| return; |
| delete fGraphics2dContext; |
| fGraphics2dContext = NULL; |
| } |
| |
| void FlushPixelBuffer() { |
| if (!IsContextValid()) |
| return; |
| // Note that the pixel lock is held while the buffer is copied into the |
| // device context and then flushed. |
| fGraphics2dContext->PaintImageData(*fPixelBuffer, pp::Point()); |
| if (flush_pending()) |
| return; |
| set_flush_pending(true); |
| fGraphics2dContext->Flush(pp::CompletionCallback(&FlushCallback, this)); |
| } |
| |
| bool fFlushPending; |
| pp::Graphics2D* fGraphics2dContext; |
| pp::ImageData* fPixelBuffer; |
| SampleWindow* fWindow; |
| }; |
| |
| class SkiaModule : public pp::Module { |
| public: |
| SkiaModule() : pp::Module() {} |
| virtual ~SkiaModule() {} |
| |
| virtual pp::Instance* CreateInstance(PP_Instance instance) { |
| gPluginInstance = new SkiaInstance(instance); |
| return gPluginInstance; |
| } |
| }; |
| |
| namespace { |
| void FlushCallback(void* data, int32_t result) { |
| static_cast<SkiaInstance*>(data)->set_flush_pending(false); |
| } |
| } |
| |
| namespace pp { |
| Module* CreateModule() { |
| return new SkiaModule(); |
| } |
| } // namespace pp |
| |
| |
| /////////////////////////////////////////// |
| ///////////// SkOSWindow impl ///////////// |
| /////////////////////////////////////////// |
| |
| void SkOSWindow::onSetTitle(const char title[]) |
| { |
| char buffer[2048]; |
| sprintf(buffer, "SetTitle:%s", title); |
| gPluginInstance->PostMessage(buffer); |
| } |
| |
| void SkOSWindow::onHandleInval(const SkIRect& rect) |
| { |
| gPluginInstance->paint(); |
| } |
| |
| void SkOSWindow::onPDFSaved(const char title[], const char desc[], |
| const char path[]) { |
| } |
| |
| /////////////////////////////////////////// |
| /////////////// SkEvent impl ////////////// |
| /////////////////////////////////////////// |
| |
| void SkEvent::SignalQueueTimer(SkMSec ms) { |
| } |
| |
| void SkEvent::SignalNonEmptyQueue() { |
| } |