1/*
2 * Copyright 2009, The Android Open Source Project
3 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *  * Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 *  * Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#define LOG_TAG "WebCore"
28
29#include "config.h"
30#include "PluginView.h"
31
32#include "Document.h"
33#include "Element.h"
34#include "EventNames.h"
35#include "FocusController.h"
36#include "FrameLoader.h"
37#include "FrameLoadRequest.h"
38#include "FrameTree.h"
39#include "Frame.h"
40#include "FrameView.h"
41#include "GraphicsContext.h"
42#include "HTMLNames.h"
43#include "HTMLPlugInElement.h"
44#include "Image.h"
45#include "KeyboardEvent.h"
46#include "MIMETypeRegistry.h"
47#include "MouseEvent.h"
48#include "NetworkStateNotifier.h"
49#include "NotImplemented.h"
50#include "Page.h"
51#include "PlatformGraphicsContext.h"
52#include "PlatformKeyboardEvent.h"
53#include "PluginMainThreadScheduler.h"
54#include "PluginPackage.h"
55#include "Touch.h"
56#include "TouchEvent.h"
57#include "TouchList.h"
58#include "android_graphics.h"
59#include "SkCanvas.h"
60#include "npruntime_impl.h"
61// #include "runtime_root.h"
62#include "utils/SystemClock.h"
63#include "ScriptController.h"
64#include "Settings.h"
65
66#if USE(JSC)
67#include <runtime/JSLock.h>
68#endif
69
70#include <wtf/ASCIICType.h>
71// #include "runtime.h"
72#include "WebViewCore.h"
73
74/* Controls the printing of log messages in this file. This must be defined
75   before PluginDebugAndroid.h is included.
76 */
77// #define PLUGIN_DEBUG_LOCAL
78#define TRACE_KEY_EVENTS 0
79
80#include "PluginDebug.h"
81#include "PluginDebugAndroid.h"
82#include "PluginViewBridgeAndroid.h"
83#include "PluginWidgetAndroid.h"
84
85#include "android_npapi.h"
86#include "ANPSurface_npapi.h"
87#include "ANPSystem_npapi.h"
88#include "SkANP.h"
89#include "SkFlipPixelRef.h"
90
91///////////////////////////////////////////////////////////////////////////////
92
93extern void ANPAudioTrackInterfaceV0_Init(ANPInterface* value);
94extern void ANPBitmapInterfaceV0_Init(ANPInterface* value);
95extern void ANPCanvasInterfaceV0_Init(ANPInterface* value);
96extern void ANPEventInterfaceV0_Init(ANPInterface* value);
97extern void ANPLogInterfaceV0_Init(ANPInterface* value);
98extern void ANPMatrixInterfaceV0_Init(ANPInterface* value);
99extern void ANPOffscreenInterfaceV0_Init(ANPInterface* value);
100extern void ANPPaintInterfaceV0_Init(ANPInterface* value);
101extern void ANPPathInterfaceV0_Init(ANPInterface* value);
102extern void ANPSurfaceInterfaceV0_Init(ANPInterface* value);
103extern void ANPTypefaceInterfaceV0_Init(ANPInterface* value);
104extern void ANPWindowInterfaceV0_Init(ANPInterface* value);
105extern void ANPSystemInterfaceV0_Init(ANPInterface* value);
106
107struct VarProcPair {
108    int         enumValue;
109    size_t      size;
110    void        (*proc)(ANPInterface*);
111};
112
113#define VARPROCLINE(name)   \
114    k##name##_ANPGetValue, sizeof(ANP##name), ANP##name##_Init
115
116static const VarProcPair gVarProcs[] = {
117    { VARPROCLINE(AudioTrackInterfaceV0)    },
118    { VARPROCLINE(BitmapInterfaceV0)        },
119    { VARPROCLINE(CanvasInterfaceV0)        },
120    { VARPROCLINE(EventInterfaceV0)         },
121    { VARPROCLINE(LogInterfaceV0)           },
122    { VARPROCLINE(MatrixInterfaceV0)        },
123    { VARPROCLINE(PaintInterfaceV0)         },
124    { VARPROCLINE(PathInterfaceV0)          },
125    { VARPROCLINE(SurfaceInterfaceV0)       },
126    { VARPROCLINE(TypefaceInterfaceV0)      },
127    { VARPROCLINE(WindowInterfaceV0)        },
128    { VARPROCLINE(SystemInterfaceV0)        },
129};
130
131/*  return true if var was an interface request (error will be set accordingly)
132    return false if var is not a recognized interface (and ignore error param)
133 */
134static bool anp_getInterface(NPNVariable var, void* value, NPError* error) {
135    const VarProcPair* iter = gVarProcs;
136    const VarProcPair* stop = gVarProcs + SK_ARRAY_COUNT(gVarProcs);
137    while (iter < stop) {
138        if (iter->enumValue == var) {
139            ANPInterface* i = reinterpret_cast<ANPInterface*>(value);
140            if (i->inSize < iter->size) {
141                SkDebugf("------- interface %d, expected size %d, allocated %d\n",
142                         var, iter->size, i->inSize);
143                *error = NPERR_INCOMPATIBLE_VERSION_ERROR;
144            } else {
145                iter->proc(i);
146                *error = NPERR_NO_ERROR;
147            }
148            return true;
149        }
150        iter += 1;
151    }
152    SkDebugf("------ unknown NPNVariable %d\n", var);
153    return false;
154}
155
156///////////////////////////////////////////////////////////////////////////////
157
158using std::min;
159
160using namespace WTF;
161
162namespace WebCore {
163
164using namespace HTMLNames;
165
166void PluginView::platformInit()
167{
168    setPlatformWidget(new PluginViewBridgeAndroid());
169
170    m_isWindowed = false;   // we don't support windowed yet
171
172    m_window = new PluginWidgetAndroid(this);
173
174    m_npWindow.type = NPWindowTypeDrawable;
175    m_npWindow.window = 0;
176}
177
178bool PluginView::platformStart()
179{
180    return true;
181}
182
183void PluginView::platformDestroy()
184{
185    delete m_window;
186}
187
188void PluginView::handleTouchEvent(TouchEvent* event)
189{
190    if (!m_window->isAcceptingEvent(kTouch_ANPEventFlag))
191        return;
192
193    if (!m_window->inFullScreen() && m_parentFrame->document()->focusedNode() != m_element)
194        return;
195
196    ANPEvent evt;
197    SkANP::InitEvent(&evt, kTouch_ANPEventType);
198
199    const AtomicString& type = event->type();
200    if (eventNames().touchstartEvent == type)
201        evt.data.touch.action = kDown_ANPTouchAction;
202    else if (eventNames().touchendEvent == type)
203        evt.data.touch.action = kUp_ANPTouchAction;
204    else if (eventNames().touchmoveEvent == type)
205        evt.data.touch.action = kMove_ANPTouchAction;
206    else if (eventNames().touchcancelEvent == type)
207        evt.data.touch.action = kCancel_ANPTouchAction;
208    else if (eventNames().touchlongpressEvent == type)
209        evt.data.touch.action = kLongPress_ANPTouchAction;
210    else if (eventNames().touchdoubletapEvent == type)
211        evt.data.touch.action = kDoubleTap_ANPTouchAction;
212    else
213        return;
214
215    evt.data.touch.modifiers = 0;   // todo
216
217    // In the event of a touchend (up) or touchcancel event, we must ask the changedTouch for the
218    // co-ordinates as there is no touch in touches anymore.
219    TouchList* touches = (evt.data.touch.action == kUp_ANPTouchAction
220        || evt.data.touch.action == kCancel_ANPTouchAction) ? event->changedTouches() : event->touches();
221
222    // Convert to coordinates that are relative to the plugin.
223    // We only support single touch points at the moment, so we want to look at index 0 only.
224    IntPoint localPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(IntPoint(touches->item(0)->pageX(), touches->item(0)->pageY())));
225    evt.data.touch.x = localPos.x();
226    evt.data.touch.y = localPos.y();
227
228    if (m_window->sendEvent(evt))
229        event->preventDefault();
230}
231
232void PluginView::handleMouseEvent(MouseEvent* event)
233{
234    const AtomicString& type = event->type();
235    bool isUp = (eventNames().mouseupEvent == type);
236    bool isDown = (eventNames().mousedownEvent == type);
237
238    ANPEvent    evt;
239
240    if (isUp || isDown) {
241        SkANP::InitEvent(&evt, kMouse_ANPEventType);
242        evt.data.mouse.action = isUp ? kUp_ANPMouseAction : kDown_ANPMouseAction;
243
244        // Convert to coordinates that are relative to the plugin.
245        IntPoint localPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation()));
246        evt.data.mouse.x = localPos.x();
247        evt.data.mouse.y = localPos.y();
248
249        if (isDown) {
250            // The plugin needs focus to receive keyboard and touch events
251            m_element->focus();
252            event->setDefaultHandled();
253        }
254    }
255    else {
256      return;
257    }
258
259    if (m_window->sendEvent(evt)) {
260        event->setDefaultHandled();
261    }
262}
263
264static ANPKeyModifier make_modifiers(bool shift, bool alt) {
265    ANPKeyModifier mod = 0;
266    if (shift) {
267        mod |= kShift_ANPKeyModifier;
268    }
269    if (alt) {
270        mod |= kAlt_ANPKeyModifier;
271    }
272    return mod;
273}
274
275void PluginView::handleFocusEvent(bool hasFocus)
276{
277    ANPEvent evt;
278    SkANP::InitEvent(&evt, kLifecycle_ANPEventType);
279    evt.data.lifecycle.action = hasFocus ? kGainFocus_ANPLifecycleAction :
280                                           kLoseFocus_ANPLifecycleAction;
281    m_window->sendEvent(evt);
282
283    // redraw the plugin which subsequently invalidates the nav cache
284    IntRect rect = IntRect(m_npWindow.x, m_npWindow.y,
285                           m_npWindow.width, m_npWindow.height);
286    m_window->webViewCore()->contentInvalidate(rect);
287}
288
289void PluginView::handleKeyboardEvent(KeyboardEvent* event)
290{
291    if (!m_window->isAcceptingEvent(kKey_ANPEventFlag))
292        return;
293
294    const PlatformKeyboardEvent* pke = event->keyEvent();
295    if (NULL == pke) {
296        return;
297    }
298
299    bool ignoreEvent = false;
300
301    ANPEvent evt;
302    SkANP::InitEvent(&evt, kKey_ANPEventType);
303
304    switch (pke->type()) {
305        case PlatformKeyboardEvent::KeyDown:
306#if TRACE_KEY_EVENTS
307            PLUGIN_LOG("--------- KeyDown, ignore\n");
308#endif
309            ignoreEvent = true;
310            break;
311        case PlatformKeyboardEvent::RawKeyDown:
312            evt.data.key.action = kDown_ANPKeyAction;
313            break;
314        case PlatformKeyboardEvent::Char:
315#if TRACE_KEY_EVENTS
316            PLUGIN_LOG("--------- Char, ignore\n");
317#endif
318            ignoreEvent = true;
319            break;
320        case PlatformKeyboardEvent::KeyUp:
321            evt.data.key.action = kUp_ANPKeyAction;
322            break;
323        default:
324#if TRACE_KEY_EVENTS
325            PLUGIN_LOG("------ unexpected keyevent type %d\n", pke->type());
326#endif
327            ignoreEvent = true;
328            break;
329    }
330
331    /* the plugin should be the only party able to return nav control to the
332     * browser UI. Therefore, if we discard an event on behalf of the plugin
333     * we should mark the event as being handled.
334     */
335    if (ignoreEvent) {
336        int keyCode = pke->nativeVirtualKeyCode();
337        if (keyCode >= kDpadUp_ANPKeyCode && keyCode <= kDpadCenter_ANPKeyCode)
338            event->setDefaultHandled();
339        return;
340    }
341
342    evt.data.key.nativeCode = pke->nativeVirtualKeyCode();
343    evt.data.key.virtualCode = pke->windowsVirtualKeyCode();
344    evt.data.key.repeatCount = pke->repeatCount();
345    evt.data.key.modifiers = make_modifiers(pke->shiftKey(), pke->altKey());
346    evt.data.key.unichar = pke->unichar();
347
348    if (m_window->sendEvent(evt)) {
349        event->setDefaultHandled();
350    } else if (m_window->inFullScreen()){
351        // while in the full screen mode, always consumes the key events and
352        // keeps the document focus
353        event->setDefaultHandled();
354    } else {
355        // remove the plugin from the document's focus
356        m_parentFrame->document()->focusedNodeRemoved();
357    }
358}
359
360NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf)
361{
362    notImplemented();
363    return NPERR_GENERIC_ERROR;
364}
365
366NPError PluginView::getValueStatic(NPNVariable variable, void* value)
367{
368    // our interface query is valid with no NPP instance
369    NPError error = NPERR_GENERIC_ERROR;
370
371    switch (variable) {
372        case NPNVisOfflineBool: {
373            if (value != NULL) {
374                bool* retValue = static_cast<bool*>(value);
375                *retValue = !networkStateNotifier().onLine();
376                return NPERR_NO_ERROR;
377            }
378            break;
379        }
380        case kJavaContext_ANPGetValue: {
381            jobject* retObject = static_cast<jobject*>(value);
382            *retObject = android::WebViewCore::getApplicationContext();
383            return NPERR_NO_ERROR;
384        }
385        default:
386            ; // do nothing
387    }
388
389    (void)anp_getInterface(variable, value, &error);
390    return error;
391}
392
393void PluginView::setParent(ScrollView* parent)
394{
395    PLUGIN_LOG("--%p SetParent old=[%p], new=[%p] \n", instance(), this->parent(), parent);
396
397    Widget::setParent(parent);
398
399    if (parent) {
400        // the widget needs initialized now so that the plugin has access to
401        // WebViewCore when NPP_New is called
402        if (m_window && !m_window->webViewCore()) {
403            android::WebViewCore* c = android::WebViewCore::getWebViewCore(this->parent());
404            m_window->init(c);
405        }
406        init();
407
408        /* Our widget needs to recompute its m_windowRect which then sets
409           the NPWindowRect if necessary.  This ensures that if NPWindowRect
410           is set prior to parent() being set that we still (1) notify the
411           plugin of its current rect and (2) that we execute our logic in
412           PluginWidgetAndroid in response to changes to NPWindowRect.
413         */
414        updatePluginWidget();
415    }
416}
417
418void PluginView::setNPWindowRect(const IntRect&)
419{
420    setNPWindowIfNeeded();
421}
422
423void PluginView::setNPWindowIfNeeded()
424{
425    PLUGIN_LOG("--%p SetWindow isStarted=[%d] \n", instance(), m_isStarted);
426
427    if (!m_isStarted || !parent())
428        return;
429
430    // in Android, plugin always get the setwindow() in the page coordinate.
431
432    // the m_npWindow is relative to the page
433    m_npWindow.x = m_pageRect.x();
434    m_npWindow.y = m_pageRect.y();
435    m_npWindow.width = m_pageRect.width();
436    m_npWindow.height = m_pageRect.height();
437
438    m_npWindow.clipRect.left = m_pageRect.x();
439    m_npWindow.clipRect.top = m_pageRect.y();
440    m_npWindow.clipRect.right = m_pageRect.x() + m_pageRect.width();
441    m_npWindow.clipRect.bottom = m_pageRect.y() + m_pageRect.height();
442
443    if (m_plugin->pluginFuncs()->setwindow) {
444#if USE(JSC)
445        JSC::JSLock::DropAllLocks dropAllLocks(false);
446#endif
447        setCallingPlugin(true);
448        m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
449        setCallingPlugin(false);
450    }
451
452    m_window->setWindow(&m_npWindow, m_isTransparent);
453}
454
455NPError PluginView::getValue(NPNVariable variable, void* value)
456{
457    switch (variable) {
458        case NPNVWindowNPObject: {
459            NPObject* windowScriptObject =
460                    m_parentFrame->script()->windowScriptNPObject();
461
462            // Return value is expected to be retained, as described
463            // here:
464            // <http://www.mozilla.org/projects/plugin/npruntime.html>
465            if (windowScriptObject)
466                _NPN_RetainObject(windowScriptObject);
467
468            void** v = (void**)value;
469            *v = windowScriptObject;
470
471            return NPERR_NO_ERROR;
472        }
473
474        case NPNVPluginElementNPObject: {
475            NPObject* pluginScriptObject = 0;
476
477            if (m_element->hasTagName(appletTag) ||
478                m_element->hasTagName(embedTag) ||
479                m_element->hasTagName(objectTag)) {
480                HTMLPlugInElement* pluginElement =
481                        static_cast<HTMLPlugInElement*>(m_element);
482                pluginScriptObject = pluginElement->getNPObject();
483            }
484
485            // Return value is expected to be retained, as described
486            // here:
487            // <http://www.mozilla.org/projects/plugin/npruntime.html>
488            if (pluginScriptObject)
489                _NPN_RetainObject(pluginScriptObject);
490
491            void** v = (void**)value;
492            *v = pluginScriptObject;
493
494            return NPERR_NO_ERROR;
495        }
496
497        case NPNVnetscapeWindow: {
498            // Return the top level WebView Java object associated
499            // with this instance.
500            jobject *retObject = static_cast<jobject*>(value);
501            *retObject = android::WebViewCore::getWebViewCore(parent())->getWebViewJavaObject();
502            return NPERR_NO_ERROR;
503        }
504
505        case NPNVisOfflineBool: {
506            if (value == NULL) {
507              return NPERR_GENERIC_ERROR;
508            }
509            bool* retValue = static_cast<bool*>(value);
510            *retValue = !networkStateNotifier().onLine();
511            return NPERR_NO_ERROR;
512        }
513
514        case kSupportedDrawingModel_ANPGetValue: {
515            uint32_t* bits = reinterpret_cast<uint32_t*>(value);
516            *bits = kBitmap_ANPDrawingModel & kSurface_ANPDrawingModel;
517            return NPERR_NO_ERROR;
518        }
519
520        case kJavaContext_ANPGetValue: {
521            jobject* retObject = static_cast<jobject*>(value);
522            *retObject = android::WebViewCore::getWebViewCore(parent())->getContext();
523            return NPERR_NO_ERROR;
524        }
525
526        default: {
527            NPError error = NPERR_GENERIC_ERROR;
528            (void)anp_getInterface(variable, value, &error);
529            return error;
530        }
531    }
532}
533
534NPError PluginView::platformSetValue(NPPVariable variable, void* value)
535{
536    NPError error = NPERR_GENERIC_ERROR;
537
538    switch (variable) {
539        case kRequestDrawingModel_ANPSetValue: {
540            ANPDrawingModel model = reinterpret_cast<ANPDrawingModel>(value);
541            if (m_window->setDrawingModel(model))
542                error = NPERR_NO_ERROR;
543            break;
544        }
545        case kAcceptEvents_ANPSetValue : {
546            if(value) {
547                ANPEventFlags flags = *reinterpret_cast<ANPEventFlags*>(value);
548                m_window->updateEventFlags(flags);
549                error = NPERR_NO_ERROR;
550            }
551            break;
552        }
553        default:
554            break;
555    }
556    return error;
557}
558
559void PluginView::invalidateRect(const IntRect& r)
560{
561    m_window->inval(r, true);
562}
563
564void PluginView::invalidateRect(NPRect* rect)
565{
566    IntRect r;
567
568    if (rect) {
569        r = IntRect(rect->left, rect->top,
570                    rect->right - rect->left, rect->bottom - rect->top);
571    } else {
572        r = IntRect(0, 0, m_npWindow.width, m_npWindow.height);
573    }
574
575    m_window->inval(r, true);
576}
577
578void PluginView::invalidateRegion(NPRegion region)
579{
580    // we don't support/define regions (yet), so do nothing
581}
582
583void PluginView::forceRedraw()
584{
585    this->invalidateRect(0);
586}
587
588void PluginView::setFocus()
589{
590    Widget::setFocus();
591//    SkDebugf("------------- setFocus %p\n", this);
592}
593
594void PluginView::show()
595{
596    setSelfVisible(true);
597    Widget::show();
598
599    if (platformPluginWidget())
600        platformPluginWidget()->layoutSurface();
601
602}
603
604void PluginView::hide()
605{
606    setSelfVisible(false);
607    Widget::hide();
608
609   if (platformPluginWidget())
610        platformPluginWidget()->layoutSurface();
611}
612
613void PluginView::setParentVisible(bool visible) {
614
615    if (isParentVisible() == visible)
616        return;
617
618    Widget::setParentVisible(visible);
619
620    if (platformPluginWidget())
621        platformPluginWidget()->layoutSurface();
622
623}
624
625void PluginView::paint(GraphicsContext* context, const IntRect& rect)
626{
627    if (!m_isStarted) {
628        // Draw the "missing plugin" image
629        paintMissingPluginIcon(context, rect);
630        return;
631    }
632
633    IntRect frame = frameRect();
634    if (!frame.width() || !frame.height()) {
635        PLUGIN_LOG("--%p FrameRect Dimensions are (0,0).\n", instance());
636        return;
637    }
638
639    if (m_window->isSurfaceDrawingModel()) {
640        /* the document position of the frame (e.g. iFrame) containing the
641           surface may have changed, which requires us to to update the global
642           coordinates of the surface. This is necessary because the plugin has
643           not moved within its parent frame and therefore will not get any
644           notification of its global position change.
645         */
646        updatePluginWidget();
647        m_window->setSurfaceClip(context->platformContext()->mCanvas->getTotalClip().getBounds());
648    } else {
649        m_window->inval(rect, false);
650        context->save();
651        context->translate(frame.x(), frame.y());
652        m_window->draw(android_gc2canvas(context));
653        context->restore();
654    }
655
656
657}
658
659void PluginView::updatePluginWidget()
660{
661    FrameView* frameView = static_cast<FrameView*>(parent());
662    PLUGIN_LOG("--%p UpdatePluginWidget frame=[%p] \n", instance(), frameView);
663    if (frameView) {
664        m_windowRect = frameView->contentsToWindow(frameRect());
665
666        IntRect oldPageRect = m_pageRect;
667
668        // only the top ScrollView can have the offset
669        m_pageRect = m_windowRect;
670        ScrollView* top = parent();
671        while (top->parent())
672            top = top->parent();
673        m_pageRect.move(top->scrollOffset());
674
675        if (m_pageRect != oldPageRect)
676            setNPWindowIfNeeded();
677    }
678}
679
680void PluginView::halt() {
681    notImplemented();
682}
683
684void PluginView::restart() {
685    notImplemented();
686}
687
688} // namespace WebCore
689