adding first pass of a sample paint plugin based on surface views.
diff --git a/samples/BrowserPlugin/jni/paint/PaintPlugin.cpp b/samples/BrowserPlugin/jni/paint/PaintPlugin.cpp
new file mode 100644
index 0000000..cad0bae
--- /dev/null
+++ b/samples/BrowserPlugin/jni/paint/PaintPlugin.cpp
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "PaintPlugin.h"
+
+#include <fcntl.h>
+#include <math.h>
+#include <string.h>
+
+extern NPNetscapeFuncs* browser;
+extern ANPLogInterfaceV0 gLogI;
+extern ANPCanvasInterfaceV0 gCanvasI;
+extern ANPPaintInterfaceV0 gPaintI;
+extern ANPSurfaceInterfaceV0 gSurfaceI;
+extern ANPTypefaceInterfaceV0 gTypefaceI;
+
+///////////////////////////////////////////////////////////////////////////////
+
+PaintPlugin::PaintPlugin(NPP inst) : SubPlugin(inst) {
+
+ m_isTouchCurrentInput = true;
+ m_isTouchActive = false;
+ m_prevX = m_prevY = 0;
+
+ memset(&m_drawingSurface, 0, sizeof(m_drawingSurface));
+ memset(&m_inputToggle, 0, sizeof(m_inputToggle));
+ memset(&m_colorToggle, 0, sizeof(m_colorToggle));
+ memset(&m_clearSurface, 0, sizeof(m_clearSurface));
+
+ // initialize the drawing surface
+ m_surfaceReady = false;
+ m_surface = gSurfaceI.newSurface(inst, kRGBA_ANPSurfaceType);
+ if(!m_surface)
+ gLogI.log(inst, kError_ANPLogType, "----%p Unable to create RGBA surface", inst);
+
+ m_paintSurface = gPaintI.newPaint();
+ gPaintI.setFlags(m_paintSurface, gPaintI.getFlags(m_paintSurface) | kAntiAlias_ANPPaintFlag);
+ gPaintI.setColor(m_paintSurface, 0xFFC0C0C0);
+ gPaintI.setTextSize(m_paintSurface, 18);
+
+ m_paintButton = gPaintI.newPaint();
+ gPaintI.setFlags(m_paintButton, gPaintI.getFlags(m_paintButton) | kAntiAlias_ANPPaintFlag);
+ gPaintI.setColor(m_paintButton, 0xFFA8A8A8);
+
+ m_paintBlue = gPaintI.newPaint();
+ gPaintI.setFlags(m_paintBlue, gPaintI.getFlags(m_paintBlue) | kAntiAlias_ANPPaintFlag);
+ gPaintI.setColor(m_paintBlue, 0xFF0000FF);
+ gPaintI.setTextSize(m_paintBlue, 18);
+
+ m_paintGreen = gPaintI.newPaint();
+ gPaintI.setFlags(m_paintGreen, gPaintI.getFlags(m_paintGreen) | kAntiAlias_ANPPaintFlag);
+ gPaintI.setColor(m_paintGreen, 0xFF00FF00);
+ gPaintI.setTextSize(m_paintGreen, 18);
+
+ m_paintRed = gPaintI.newPaint();
+ gPaintI.setFlags(m_paintRed, gPaintI.getFlags(m_paintRed) | kAntiAlias_ANPPaintFlag);
+ gPaintI.setColor(m_paintRed, 0xFFFF0000);
+ gPaintI.setTextSize(m_paintRed, 18);
+
+ ANPTypeface* tf = gTypefaceI.createFromName("serif", kItalic_ANPTypefaceStyle);
+ gPaintI.setTypeface(m_paintSurface, tf);
+ gPaintI.setTypeface(m_paintBlue, tf);
+ gPaintI.setTypeface(m_paintGreen, tf);
+ gPaintI.setTypeface(m_paintRed, tf);
+ gTypefaceI.unref(tf);
+
+ // set the default paint color
+ m_activePaint = m_paintRed;
+
+ //register for touch events
+ ANPEventFlags flags = kTouch_ANPEventFlag;
+ NPError err = browser->setvalue(inst, kAcceptEvents_ANPSetValue, &flags);
+ if (err != NPERR_NO_ERROR) {
+ gLogI.log(inst, kError_ANPLogType, "Error selecting input events.");
+ }
+}
+
+PaintPlugin::~PaintPlugin() {
+ gPaintI.deletePaint(m_paintSurface);
+ gPaintI.deletePaint(m_paintButton);
+ gPaintI.deletePaint(m_paintBlue);
+ gPaintI.deletePaint(m_paintGreen);
+ gPaintI.deletePaint(m_paintRed);
+}
+
+bool PaintPlugin::supportsDrawingModel(ANPDrawingModel model) {
+ return (model == kSurface_ANPDrawingModel);
+}
+
+ANPCanvas* PaintPlugin::getCanvas(ANPRectI* dirtyRect) {
+
+ ANPBitmap bitmap;
+ if (!m_surfaceReady || !gSurfaceI.lock(m_surface, &bitmap, dirtyRect))
+ return NULL;
+ return gCanvasI.newCanvas(&bitmap);
+}
+
+ANPCanvas* PaintPlugin::getCanvas(ANPRectF* dirtyRect) {
+
+ ANPRectI newRect;
+ newRect.left = (int) dirtyRect->left;
+ newRect.top = (int) dirtyRect->top;
+ newRect.right = (int) dirtyRect->right;
+ newRect.bottom = (int) dirtyRect->bottom;
+
+ return getCanvas(&newRect);
+}
+
+void PaintPlugin::releaseCanvas(ANPCanvas* canvas) {
+ gSurfaceI.unlock(m_surface);
+ gCanvasI.deleteCanvas(canvas);
+}
+
+void PaintPlugin::drawCleanPlugin(ANPCanvas* canvas) {
+ NPP instance = this->inst();
+ PluginObject *obj = (PluginObject*) instance->pdata;
+
+ // if no canvas get a locked canvas
+ if (!canvas)
+ canvas = getCanvas();
+
+ if (!canvas)
+ return;
+
+ const float buttonWidth = 60;
+ const float buttonHeight = 30;
+ const int W = obj->window->width;
+ const int H = obj->window->height;
+
+ // color the plugin canvas
+ gCanvasI.drawColor(canvas, 0xFFCDCDCD);
+
+ // get font metrics
+ ANPFontMetrics fontMetrics;
+ gPaintI.getFontMetrics(m_paintSurface, &fontMetrics);
+
+ // draw the input toggle button
+ m_inputToggle.left = 5;
+ m_inputToggle.top = H - buttonHeight - 5;
+ m_inputToggle.right = m_inputToggle.left + buttonWidth;
+ m_inputToggle.bottom = m_inputToggle.top + buttonHeight;
+ gCanvasI.drawRect(canvas, &m_inputToggle, m_paintButton);
+ // draw the play box (under track box)
+ const char* inputText = m_isTouchCurrentInput ? "Touch" : "Mouse";
+ gCanvasI.drawText(canvas, inputText, strlen(inputText), m_inputToggle.left + 5,
+ m_inputToggle.top - fontMetrics.fTop, m_paintSurface);
+
+ // draw the color selector button
+ m_colorToggle.left = (W/2) - (buttonWidth/2);
+ m_colorToggle.top = H - buttonHeight - 5;
+ m_colorToggle.right = m_colorToggle.left + buttonWidth;
+ m_colorToggle.bottom = m_colorToggle.top + buttonHeight;
+ gCanvasI.drawRect(canvas, &m_colorToggle, m_paintButton);
+ // draw the play box (under track box)
+ const char* colorText = getColorText();
+ gCanvasI.drawText(canvas, colorText, strlen(colorText), m_colorToggle.left + 5,
+ m_colorToggle.top - fontMetrics.fTop, m_paintSurface);
+
+ // draw the clear canvas button
+ m_clearSurface.left = W - buttonWidth - 5;
+ m_clearSurface.top = H - buttonHeight - 5;
+ m_clearSurface.right = m_clearSurface.left + buttonWidth;
+ m_clearSurface.bottom = m_clearSurface.top + buttonHeight;
+ gCanvasI.drawRect(canvas, &m_clearSurface, m_paintButton);
+ // draw the play box (under track box)
+ const char* clearText = "Clear";
+ gCanvasI.drawText(canvas, clearText, strlen(clearText), m_clearSurface.left + 5,
+ m_clearSurface.top - fontMetrics.fTop, m_paintSurface);
+
+ // draw the drawing surface box (5 px from the edge)
+ m_drawingSurface.left = 5;
+ m_drawingSurface.top = 5;
+ m_drawingSurface.right = W - 5;
+ m_drawingSurface.bottom = m_colorToggle.top - 5;
+ gCanvasI.drawRect(canvas, &m_drawingSurface, m_paintSurface);
+
+ // release the canvas
+ releaseCanvas(canvas);
+}
+
+const char* PaintPlugin::getColorText() {
+
+ if (m_activePaint == m_paintBlue)
+ return "Blue";
+ else if (m_activePaint == m_paintGreen)
+ return "Green";
+ else
+ return "Red";
+}
+
+int16 PaintPlugin::handleEvent(const ANPEvent* evt) {
+ NPP instance = this->inst();
+
+ switch (evt->eventType) {
+ case kSurface_ANPEventType:
+ switch (evt->data.surface.action) {
+ case kCreated_ANPSurfaceAction:
+ m_surfaceReady = true;
+ drawCleanPlugin();
+ return 1;
+ case kDestroyed_ANPSurfaceAction:
+ m_surfaceReady = false;
+ return 1;
+ }
+ break;
+
+ case kTouch_ANPEventType: {
+ int x = evt->data.touch.x;
+ int y = evt->data.touch.y;
+ if (kDown_ANPTouchAction == evt->data.touch.action) {
+
+ ANPRectF* rect = validTouch(x,y);
+ if(rect == &m_drawingSurface) {
+ m_isTouchActive = true;
+ m_prevX = x;
+ m_prevY = y;
+ paint(x, y, true);
+ return 1;
+ }
+
+ } else if (kMove_ANPTouchAction == evt->data.touch.action && m_isTouchActive) {
+ paint(x, y, true);
+ return 1;
+ } else if (kUp_ANPTouchAction == evt->data.touch.action && m_isTouchActive) {
+ paint(x, y, true);
+ m_isTouchActive = false;
+ return 1;
+ } else if (kCancel_ANPTouchAction == evt->data.touch.action) {
+ m_isTouchActive = false;
+ return 1;
+ }
+ break;
+ }
+ case kMouse_ANPEventType: {
+ if (kDown_ANPMouseAction == evt->data.mouse.action) {
+ ANPRectF* rect = validTouch(evt->data.mouse.x, evt->data.mouse.y);
+ if (rect == &m_drawingSurface)
+ paint(evt->data.mouse.x, evt->data.mouse.y, false);
+ else if (rect == &m_inputToggle)
+ toggleInputMethod();
+ else if (rect == &m_colorToggle)
+ togglePaintColor();
+ else if (rect == &m_clearSurface)
+ drawCleanPlugin();
+ }
+ return 1;
+ }
+ default:
+ break;
+ }
+ return 0; // unknown or unhandled event
+}
+
+ANPRectF* PaintPlugin::validTouch(int x, int y) {
+
+ //convert to float
+ float fx = (int) x;
+ float fy = (int) y;
+
+ if (fx > m_drawingSurface.left && fx < m_drawingSurface.right && fy > m_drawingSurface.top && fy < m_drawingSurface.bottom)
+ return &m_drawingSurface;
+ else if (fx > m_inputToggle.left && fx < m_inputToggle.right && fy > m_inputToggle.top && fy < m_inputToggle.bottom)
+ return &m_inputToggle;
+ else if (fx > m_colorToggle.left && fx < m_colorToggle.right && fy > m_colorToggle.top && fy < m_colorToggle.bottom)
+ return &m_colorToggle;
+ else if (fx > m_clearSurface.left && fx < m_clearSurface.right && fy > m_clearSurface.top && fy < m_clearSurface.bottom)
+ return &m_clearSurface;
+ else
+ return NULL;
+}
+
+void PaintPlugin::toggleInputMethod() {
+ m_isTouchCurrentInput = !m_isTouchCurrentInput;
+
+ // lock only the input toggle and redraw the canvas
+ ANPCanvas* lockedCanvas = getCanvas(&m_colorToggle);
+ drawCleanPlugin(lockedCanvas);
+}
+
+void PaintPlugin::togglePaintColor() {
+ if (m_activePaint == m_paintBlue)
+ m_activePaint = m_paintRed;
+ else if (m_activePaint == m_paintGreen)
+ m_activePaint = m_paintBlue;
+ else
+ m_activePaint = m_paintGreen;
+
+ // lock only the color toggle and redraw the canvas
+ ANPCanvas* lockedCanvas = getCanvas(&m_colorToggle);
+ drawCleanPlugin(lockedCanvas);
+}
+
+void PaintPlugin::paint(int x, int y, bool isTouch) {
+ NPP instance = this->inst();
+
+ // check to make sure the input types match
+ if (m_isTouchCurrentInput != isTouch)
+ return;
+
+ //TODO do not paint outside the drawing surface (mouse & touch)
+
+ // handle the simple "mouse" paint (draw a point)
+ if (!isTouch) {
+
+ ANPRectF point;
+ point.left = (float) x-3;
+ point.top = (float) y-3;
+ point.right = (float) x+3;
+ point.bottom = (float) y+3;
+
+ // get a canvas that is only locked around the point
+ ANPCanvas* canvas = getCanvas(&point);
+ gCanvasI.drawOval(canvas, &point, m_activePaint);
+ releaseCanvas(canvas);
+ return;
+ }
+
+ // TODO handle the complex "touch" paint (draw a line)
+}