diff --git a/samples/BrowserPlugin/jni/Android.mk b/samples/BrowserPlugin/jni/Android.mk index 329a6fdd1..c3acbd827 100644 --- a/samples/BrowserPlugin/jni/Android.mk +++ b/samples/BrowserPlugin/jni/Android.mk @@ -34,6 +34,7 @@ LOCAL_SRC_FILES := \ audio/AudioPlugin.cpp \ background/BackgroundPlugin.cpp \ form/FormPlugin.cpp \ + paint/PaintPlugin.cpp \ surface/SurfacePlugin.cpp \ LOCAL_C_INCLUDES += \ @@ -42,6 +43,7 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/audio \ $(LOCAL_PATH)/background \ $(LOCAL_PATH)/form \ + $(LOCAL_PATH)/paint \ $(LOCAL_PATH)/surface \ external/webkit/WebCore/bridge \ external/webkit/WebCore/plugins \ diff --git a/samples/BrowserPlugin/jni/main.cpp b/samples/BrowserPlugin/jni/main.cpp index 7e7d04258..a0649cda7 100644 --- a/samples/BrowserPlugin/jni/main.cpp +++ b/samples/BrowserPlugin/jni/main.cpp @@ -32,6 +32,7 @@ #include "AudioPlugin.h" #include "BackgroundPlugin.h" #include "FormPlugin.h" +#include "PaintPlugin.h" #include "SurfacePlugin.h" #include "android_npapi.h" @@ -155,6 +156,31 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, } /* END: STANDARD PLUGIN FRAMEWORK */ + // select the drawing model based on user input + ANPDrawingModel model = kBitmap_ANPDrawingModel; + + for (int i = 0; i < argc; i++) { + if (!strcmp(argn[i], "DrawingModel")) { + if (!strcmp(argv[i], "Bitmap")) { + model = kBitmap_ANPDrawingModel; + } + else if (!strcmp(argv[i], "Surface")) { + model = kSurface_ANPDrawingModel; + } + gLogI.log(instance, kDebug_ANPLogType, "------ %p DrawingModel is %d", instance, model); + break; + } + } + + // notify the plugin API of the drawing model we wish to use. This must be + // done prior to creating certain subPlugin objects (e.g. surfaceViews) + NPError err = browser->setvalue(instance, kRequestDrawingModel_ANPSetValue, + reinterpret_cast(model)); + if (err) { + gLogI.log(instance, kError_ANPLogType, "request model %d err %d", model, err); + return err; + } + // select the pluginType for (int i = 0; i < argc; i++) { if (!strcmp(argn[i], "PluginType")) { @@ -174,6 +200,10 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, obj->pluginType = kForm_PluginType; obj->activePlugin = new FormPlugin(instance); } + else if (!strcmp(argv[i], "Paint")) { + obj->pluginType = kPaint_PluginType; + obj->activePlugin = new PaintPlugin(instance); + } else if (!strcmp(argv[i], "RGBA_Surface")) { obj->pluginType = kSurface_PluginType; obj->activePlugin = new SurfacePlugin(instance, kRGBA_ANPSurfaceType); @@ -185,40 +215,17 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, // if no pluginType is specified then default to Animation if (!obj->pluginType) { + gLogI.log(instance, kError_ANPLogType, "------ %p No PluginType attribute was found", instance); obj->pluginType = kAnimation_PluginType; obj->activePlugin = new BallAnimation(instance); } - // select the drawing model based on user input - ANPDrawingModel model = kBitmap_ANPDrawingModel; - - for (int i = 0; i < argc; i++) { - if (!strcmp(argn[i], "DrawingModel")) { - if (!strcmp(argv[i], "Bitmap")) { - model = kBitmap_ANPDrawingModel; - } - else if (!strcmp(argv[i], "Surface")) { - model = kSurface_ANPDrawingModel; - } - gLogI.log(instance, kDebug_ANPLogType, "------ %p DrawingModel is %d", instance, model); - break; - } - } - // check to ensure the pluginType supports the model if (!obj->activePlugin->supportsDrawingModel(model)) { gLogI.log(instance, kError_ANPLogType, "------ %p Unsupported DrawingModel (%d)", instance, model); return NPERR_GENERIC_ERROR; } - // notify the plugin API of the drawing model we wish to use - NPError err = browser->setvalue(instance, kRequestDrawingModel_ANPSetValue, - reinterpret_cast(model)); - if (err) { - gLogI.log(instance, kError_ANPLogType, "request model %d err %d", model, err); - return err; - } - return NPERR_NO_ERROR; } diff --git a/samples/BrowserPlugin/jni/paint/PaintPlugin.cpp b/samples/BrowserPlugin/jni/paint/PaintPlugin.cpp new file mode 100644 index 000000000..cad0bae5f --- /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 +#include +#include + +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) +} diff --git a/samples/BrowserPlugin/jni/paint/PaintPlugin.h b/samples/BrowserPlugin/jni/paint/PaintPlugin.h new file mode 100644 index 000000000..6671a30cb --- /dev/null +++ b/samples/BrowserPlugin/jni/paint/PaintPlugin.h @@ -0,0 +1,71 @@ +/* + * 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 "PluginObject.h" +#include + +#ifndef paintPlugin__DEFINED +#define paintPlugin__DEFINED + +class PaintPlugin : public SubPlugin { +public: + PaintPlugin(NPP inst); + virtual ~PaintPlugin(); + virtual bool supportsDrawingModel(ANPDrawingModel); + virtual int16 handleEvent(const ANPEvent* evt); +private: + void drawCleanPlugin(ANPCanvas* canvas = NULL); + ANPCanvas* getCanvas(ANPRectI* dirtyRect = NULL); + ANPCanvas* getCanvas(ANPRectF* dirtyRect); + const char* getColorText(); + void paint(int x, int y, bool isTouch); + void releaseCanvas(ANPCanvas*); + void toggleInputMethod(); + void togglePaintColor(); + ANPRectF* validTouch(int x, int y); + + bool m_surfaceReady; + ANPSurface* m_surface; + + ANPRectF m_drawingSurface; + ANPRectF m_inputToggle; + ANPRectF m_colorToggle; + ANPRectF m_clearSurface; + + ANPPaint* m_paintSurface; + ANPPaint* m_paintButton; + ANPPaint* m_paintBlue; + ANPPaint* m_paintGreen; + ANPPaint* m_paintRed; + + ANPPaint* m_activePaint; + + bool m_isTouchCurrentInput; + bool m_isTouchActive; + int m_prevX; + int m_prevY; +}; + +#endif // paintPlugin__DEFINED