1df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger/*
2df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger * Copyright 2009, The Android Open Source Project
3df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger *
4df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger * Redistribution and use in source and binary forms, with or without
5df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger * modification, are permitted provided that the following conditions
6df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger * are met:
7df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger *  * Redistributions of source code must retain the above copyright
8df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger *    notice, this list of conditions and the following disclaimer.
9df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger *  * Redistributions in binary form must reproduce the above copyright
10df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger *    notice, this list of conditions and the following disclaimer in the
11df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger *    documentation and/or other materials provided with the distribution.
12df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger *
13df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger */
25df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
26df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger#include "EventPlugin.h"
27df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger#include "android_npapi.h"
28df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
29df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger#include <stdio.h>
30df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger#include <sys/time.h>
31df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger#include <time.h>
32df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger#include <math.h>
33df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger#include <string.h>
34df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
35df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenbergerextern NPNetscapeFuncs*        browser;
36df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenbergerextern ANPCanvasInterfaceV0    gCanvasI;
37df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenbergerextern ANPLogInterfaceV0       gLogI;
38df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenbergerextern ANPPaintInterfaceV0     gPaintI;
39df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenbergerextern ANPTypefaceInterfaceV0  gTypefaceI;
40df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
41df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger///////////////////////////////////////////////////////////////////////////////
42df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
430b3a5d65247be1fb79d66af534fa78a94743864fDerek SollenbergerEventPlugin::EventPlugin(NPP inst) : SubPlugin(inst) { }
44df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
450b3a5d65247be1fb79d66af534fa78a94743864fDerek SollenbergerEventPlugin::~EventPlugin() { }
46df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
470b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenbergervoid EventPlugin::drawPlugin(const ANPBitmap& bitmap, const ANPRectI& clip) {
48df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
49b16749e2c60dca69f8b71adf900597bad10adf40Derek Sollenberger    gLogI.log(kDebug_ANPLogType, " ------ %p drawing the plugin (%d,%d)",
500b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger              inst(), bitmap.width, bitmap.height);
51df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
52df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    // get the plugin's dimensions according to the DOM
53df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    PluginObject *obj = (PluginObject*) inst()->pdata;
54df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    const int W = obj->window->width;
55df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    const int H = obj->window->height;
56df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
57df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    // compute the current zoom level
580b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger    const float zoomFactorW = static_cast<float>(bitmap.width) / W;
590b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger    const float zoomFactorH = static_cast<float>(bitmap.height) / H;
60df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
61df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    // check to make sure the zoom level is uniform
62df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    if (zoomFactorW + .01 < zoomFactorH && zoomFactorW - .01 > zoomFactorH)
63b16749e2c60dca69f8b71adf900597bad10adf40Derek Sollenberger        gLogI.log(kError_ANPLogType, " ------ %p zoom is out of sync (%f,%f)",
64df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                  inst(), zoomFactorW, zoomFactorH);
65df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
66df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    // scale the variables based on the zoom level
67df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    const int fontSize = (int)(zoomFactorW * 16);
68df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    const int leftMargin = (int)(zoomFactorW * 10);
69df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
700b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger    // create and clip a canvas
71df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    ANPCanvas* canvas = gCanvasI.newCanvas(&bitmap);
720b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger
730b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger    ANPRectF clipR;
740b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger    clipR.left = clip.left;
750b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger    clipR.top = clip.top;
760b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger    clipR.right = clip.right;
770b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger    clipR.bottom = clip.bottom;
780b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger    gCanvasI.clipRect(canvas, &clipR);
790b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger
80df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    gCanvasI.drawColor(canvas, 0xFFFFFFFF);
81df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
82df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    // configure the paint
83df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    ANPPaint* paint = gPaintI.newPaint();
84df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    gPaintI.setFlags(paint, gPaintI.getFlags(paint) | kAntiAlias_ANPPaintFlag);
85df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    gPaintI.setColor(paint, 0xFF0000FF);
86df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    gPaintI.setTextSize(paint, fontSize);
87df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
88df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    // configure the font
89df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    ANPTypeface* tf = gTypefaceI.createFromName("serif", kItalic_ANPTypefaceStyle);
90df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    gPaintI.setTypeface(paint, tf);
91df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    gTypefaceI.unref(tf);
92df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
93df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    // retrieve the font metrics
94df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    ANPFontMetrics fm;
95df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    gPaintI.getFontMetrics(paint, &fm);
96df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
97df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    // write text on the canvas
98df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    const char c[] = "Browser Test Plugin";
99df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    gCanvasI.drawText(canvas, c, sizeof(c)-1, leftMargin, -fm.fTop, paint);
100df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
1010b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger    // clean up variables
102df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    gPaintI.deletePaint(paint);
103df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    gCanvasI.deleteCanvas(canvas);
104df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger}
105df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
106df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenbergervoid EventPlugin::printToDiv(const char* text, int length) {
107df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    // Get the plugin's DOM object
108df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    NPObject* windowObject = NULL;
109df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    browser->getvalue(inst(), NPNVWindowNPObject, &windowObject);
110df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
111df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    if (!windowObject)
112b16749e2c60dca69f8b71adf900597bad10adf40Derek Sollenberger        gLogI.log(kError_ANPLogType, " ------ %p Unable to retrieve DOM Window", inst());
113df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
114df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    // create a string (JS code) that is stored in memory allocated by the browser
115df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    const char* jsBegin = "var outputDiv = document.getElementById('eventOutput'); outputDiv.innerHTML += ' ";
116df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    const char* jsEnd = "';";
117df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
118df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    // allocate memory and configure pointers
119df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    int totalLength = strlen(jsBegin) + length + strlen(jsEnd);
120df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    char* beginMem = (char*)browser->memalloc(totalLength);
121df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    char* middleMem = beginMem + strlen(jsBegin);
122df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    char* endMem = middleMem + length;
123df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
124df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    // copy into the allocated memory
125df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    memcpy(beginMem, jsBegin, strlen(jsBegin));
126df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    memcpy(middleMem, text, length);
127df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    memcpy(endMem, jsEnd, strlen(jsEnd));
128df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
129b16749e2c60dca69f8b71adf900597bad10adf40Derek Sollenberger    gLogI.log(kDebug_ANPLogType, "text: %.*s\n", totalLength, (char*)beginMem);
130df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
131df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    // execute the javascript in the plugin's DOM object
132df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    NPString script = { (char*)beginMem, totalLength };
133df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    NPVariant scriptVariant;
134df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    if (!browser->evaluate(inst(), windowObject, &script, &scriptVariant))
135b16749e2c60dca69f8b71adf900597bad10adf40Derek Sollenberger        gLogI.log(kError_ANPLogType, " ------ %p Unable to eval the JS.", inst());
136df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
137df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    // free the memory allocated within the browser
138df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    browser->memfree(beginMem);
139df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger}
140df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger
141ccee91085913ccb486b063616afae13b53b2e92bBen Murdochint16_t EventPlugin::handleEvent(const ANPEvent* evt) {
142df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    switch (evt->eventType) {
1430b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger
1440b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger        case kDraw_ANPEventType: {
1450b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger            switch (evt->data.draw.model) {
1460b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger                case kBitmap_ANPDrawingModel:
1470b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger                    drawPlugin(evt->data.draw.data.bitmap, evt->data.draw.clip);
148df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                    return 1;
1490b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger                default:
1500b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger                    break;   // unknown drawing model
151df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger            }
1520b3a5d65247be1fb79d66af534fa78a94743864fDerek Sollenberger        }
153df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger        case kLifecycle_ANPEventType:
154df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger            switch (evt->data.lifecycle.action) {
155df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                case kOnLoad_ANPLifecycleAction: {
156df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                    char msg[] = "lifecycle-onLoad";
157df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                    printToDiv(msg, strlen(msg));
158df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                    break;
159df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                }
160df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                case kGainFocus_ANPLifecycleAction: {
161df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                    char msg[] = "lifecycle-gainFocus";
162df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                    printToDiv(msg, strlen(msg));
163df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                    break;
164df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                }
165df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                case kLoseFocus_ANPLifecycleAction: {
166df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                    char msg[] = "lifecycle-loseFocus";
167df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                    printToDiv(msg, strlen(msg));
168df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                    break;
169df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger                }
170df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger            }
171df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger            return 1;
172df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger        case kTouch_ANPEventType:
173b16749e2c60dca69f8b71adf900597bad10adf40Derek Sollenberger            gLogI.log(kError_ANPLogType, " ------ %p the plugin did not request touch events", inst());
174df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger            break;
175df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger        case kKey_ANPEventType:
176b16749e2c60dca69f8b71adf900597bad10adf40Derek Sollenberger            gLogI.log(kError_ANPLogType, " ------ %p the plugin did not request key events", inst());
177df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger            break;
178df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger        default:
179df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger            break;
180df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    }
181df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger    return 0;   // unknown or unhandled event
182df8a3f31d871db25e952972c2eb346a71186e9e3Derek Sollenberger}
183