/* * 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) }