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 "SkCanvas.h"
59#include "npruntime_impl.h"
60// #include "runtime_root.h"
61#include "utils/SystemClock.h"
62#include "ScriptController.h"
63#include "Settings.h"
64
65#include <wtf/ASCIICType.h>
66// #include "runtime.h"
67#include "WebViewCore.h"
68
69/* Controls the printing of log messages in this file. This must be defined
70   before PluginDebugAndroid.h is included.
71 */
72// #define PLUGIN_DEBUG_LOCAL
73#define TRACE_KEY_EVENTS 0
74
75#include "PluginDebug.h"
76#include "PluginDebugAndroid.h"
77#include "PluginViewBridgeAndroid.h"
78#include "PluginWidgetAndroid.h"
79
80#include "android_npapi.h"
81#include "ANPNativeWindow_npapi.h"
82#include "ANPSurface_npapi.h"
83#include "ANPSystem_npapi.h"
84#include "ANPVideo_npapi.h"
85#include "SkANP.h"
86
87///////////////////////////////////////////////////////////////////////////////
88
89extern void ANPAudioTrackInterfaceV0_Init(ANPInterface* value);
90extern void ANPAudioTrackInterfaceV1_Init(ANPInterface* value);
91extern void ANPBitmapInterfaceV0_Init(ANPInterface* value);
92extern void ANPCanvasInterfaceV0_Init(ANPInterface* value);
93extern void ANPEventInterfaceV0_Init(ANPInterface* value);
94extern void ANPLogInterfaceV0_Init(ANPInterface* value);
95extern void ANPMatrixInterfaceV0_Init(ANPInterface* value);
96extern void ANPOffscreenInterfaceV0_Init(ANPInterface* value);
97extern void ANPPaintInterfaceV0_Init(ANPInterface* value);
98extern void ANPPathInterfaceV0_Init(ANPInterface* value);
99extern void ANPSurfaceInterfaceV0_Init(ANPInterface* value);
100extern void ANPTypefaceInterfaceV0_Init(ANPInterface* value);
101extern void ANPWindowInterfaceV0_Init(ANPInterface* value);
102extern void ANPWindowInterfaceV1_Init(ANPInterface* value);
103extern void ANPWindowInterfaceV2_Init(ANPInterface* value);
104extern void ANPSystemInterfaceV0_Init(ANPInterface* value);
105extern void ANPSystemInterfaceV1_Init(ANPInterface* value);
106extern void ANPSystemInterfaceV2_Init(ANPInterface* value);
107extern void ANPNativeWindowInterfaceV0_Init(ANPInterface* value);
108extern void ANPVideoInterfaceV0_Init(ANPInterface* value);
109extern void ANPVideoInterfaceV1_Init(ANPInterface* value);
110
111struct VarProcPair {
112    int         enumValue;
113    size_t      size;
114    void        (*proc)(ANPInterface*);
115};
116
117#define VARPROCLINE(name)   \
118    k##name##_ANPGetValue, sizeof(ANP##name), ANP##name##_Init
119
120static const VarProcPair gVarProcs[] = {
121    { VARPROCLINE(AudioTrackInterfaceV0)    },
122    { VARPROCLINE(AudioTrackInterfaceV1)    },
123    { VARPROCLINE(BitmapInterfaceV0)        },
124    { VARPROCLINE(CanvasInterfaceV0)        },
125    { VARPROCLINE(EventInterfaceV0)         },
126    { VARPROCLINE(LogInterfaceV0)           },
127    { VARPROCLINE(MatrixInterfaceV0)        },
128    { VARPROCLINE(PaintInterfaceV0)         },
129    { VARPROCLINE(PathInterfaceV0)          },
130    { VARPROCLINE(SurfaceInterfaceV0)       },
131    { VARPROCLINE(TypefaceInterfaceV0)      },
132    { VARPROCLINE(WindowInterfaceV0)        },
133    { VARPROCLINE(WindowInterfaceV1)        },
134    { VARPROCLINE(WindowInterfaceV2)        },
135    { VARPROCLINE(SystemInterfaceV0)        },
136    { VARPROCLINE(SystemInterfaceV1)        },
137    { VARPROCLINE(SystemInterfaceV2)        },
138    { VARPROCLINE(NativeWindowInterfaceV0)  },
139    { VARPROCLINE(VideoInterfaceV0)         },
140    { VARPROCLINE(VideoInterfaceV1)         },
141};
142
143/*  return true if var was an interface request (error will be set accordingly)
144    return false if var is not a recognized interface (and ignore error param)
145 */
146static bool anp_getInterface(NPNVariable var, void* value, NPError* error) {
147    const VarProcPair* iter = gVarProcs;
148    const VarProcPair* stop = gVarProcs + SK_ARRAY_COUNT(gVarProcs);
149    while (iter < stop) {
150        if (iter->enumValue == var) {
151            ANPInterface* i = reinterpret_cast<ANPInterface*>(value);
152            if (i->inSize < iter->size) {
153                SkDebugf("------- interface %d, expected size %d, allocated %d\n",
154                         var, iter->size, i->inSize);
155                *error = NPERR_INCOMPATIBLE_VERSION_ERROR;
156            } else {
157                iter->proc(i);
158                *error = NPERR_NO_ERROR;
159            }
160            return true;
161        }
162        iter += 1;
163    }
164    SkDebugf("------ unknown NPNVariable %d\n", var);
165    return false;
166}
167
168///////////////////////////////////////////////////////////////////////////////
169
170using std::min;
171
172using namespace WTF;
173
174namespace WebCore {
175
176using namespace HTMLNames;
177
178void PluginView::platformInit()
179{
180    setPlatformWidget(new PluginViewBridgeAndroid());
181
182    m_isWindowed = false;   // we don't support windowed yet
183
184    m_window = new PluginWidgetAndroid(this);
185
186    m_npWindow.type = NPWindowTypeDrawable;
187    m_npWindow.window = 0;
188}
189
190bool PluginView::platformStart()
191{
192    return true;
193}
194
195void PluginView::platformDestroy()
196{
197    delete m_window;
198}
199
200PlatformLayer* PluginView::platformLayer() const
201{
202    return (PlatformLayer*) m_window->getLayer();
203}
204
205#if ENABLE(TOUCH_EVENTS)
206void PluginView::handleTouchEvent(TouchEvent* event)
207{
208    if (!m_window->isAcceptingEvent(kTouch_ANPEventFlag))
209        return;
210
211    if (!m_window->inFullScreen() && m_parentFrame->document()->focusedNode() != m_element)
212        return;
213
214    ANPEvent evt;
215    SkANP::InitEvent(&evt, kMultiTouch_ANPEventType);
216
217    const AtomicString& type = event->type();
218    if (eventNames().touchstartEvent == type)
219        evt.data.multiTouch.action = kDown_ANPTouchAction;
220    else if (eventNames().touchendEvent == type)
221        evt.data.multiTouch.action = kUp_ANPTouchAction;
222    else if (eventNames().touchmoveEvent == type)
223        evt.data.multiTouch.action = kMove_ANPTouchAction;
224    else if (eventNames().touchcancelEvent == type)
225        evt.data.multiTouch.action = kCancel_ANPTouchAction;
226    else if (eventNames().touchlongpressEvent == type)
227        evt.data.multiTouch.action = kLongPress_ANPTouchAction;
228    else if (eventNames().touchdoubletapEvent == type)
229        evt.data.multiTouch.action = kDoubleTap_ANPTouchAction;
230    else
231        return;
232
233    // set the id and timestamp
234    evt.data.multiTouch.id = 0; // TODO
235    evt.data.multiTouch.timestamp = 0; // TODO
236
237    // In the event of a touchend (up) or touchcancel event, we must ask the changedTouch for the
238    // co-ordinates as there is no touch in touches anymore.
239    TouchList* touches = (evt.data.multiTouch.action == kUp_ANPTouchAction
240        || evt.data.multiTouch.action == kCancel_ANPTouchAction) ? event->changedTouches() : event->touches();
241
242    // set each touchPoint
243    int pointerCount = touches->length();
244    evt.data.multiTouch.pointerCount = pointerCount;
245    evt.data.multiTouch.touchPoint = new TouchPoint[pointerCount];
246
247    for (int x = 0; x < evt.data.multiTouch.pointerCount; x++) {
248        Touch* touch = touches->item(x);
249        // Convert to coordinates that are relative to the plugin.
250        IntPoint localPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(IntPoint(touch->pageX(), touch->pageY())));
251
252        evt.data.multiTouch.touchPoint[x].id = touch->identifier();
253        evt.data.multiTouch.touchPoint[x].x = localPos.x();
254        evt.data.multiTouch.touchPoint[x].y = localPos.y();
255        evt.data.multiTouch.touchPoint[x].pressure = 1; // TODO
256        evt.data.multiTouch.touchPoint[x].size = 1; // TODO
257    }
258
259    if (m_window->sendEvent(evt))
260        event->preventDefault();
261
262    // cleanup the touch points we allocated
263    delete[] evt.data.multiTouch.touchPoint;
264}
265#endif
266
267void PluginView::handleMouseEvent(MouseEvent* event)
268{
269    const AtomicString& type = event->type();
270    bool isUp = (eventNames().mouseupEvent == type);
271    bool isDown = (eventNames().mousedownEvent == type);
272
273    ANPEvent    evt;
274
275    if (isUp || isDown) {
276        SkANP::InitEvent(&evt, kMouse_ANPEventType);
277        evt.data.mouse.action = isUp ? kUp_ANPMouseAction : kDown_ANPMouseAction;
278
279        // Convert to coordinates that are relative to the plugin.
280        IntPoint localPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation()));
281        evt.data.mouse.x = localPos.x();
282        evt.data.mouse.y = localPos.y();
283
284        if (isDown) {
285            // The plugin needs focus to receive keyboard and touch events
286            m_element->focus();
287            event->setDefaultHandled();
288        }
289    }
290    else {
291      return;
292    }
293
294    if (m_window->sendEvent(evt)) {
295        event->setDefaultHandled();
296    }
297}
298
299static ANPKeyModifier make_modifiers(bool shift, bool alt) {
300    ANPKeyModifier mod = 0;
301    if (shift) {
302        mod |= kShift_ANPKeyModifier;
303    }
304    if (alt) {
305        mod |= kAlt_ANPKeyModifier;
306    }
307    return mod;
308}
309
310void PluginView::handleFocusEvent(bool hasFocus)
311{
312    ANPEvent evt;
313    SkANP::InitEvent(&evt, kLifecycle_ANPEventType);
314    evt.data.lifecycle.action = hasFocus ? kGainFocus_ANPLifecycleAction :
315                                           kLoseFocus_ANPLifecycleAction;
316    m_window->sendEvent(evt);
317
318    // redraw the plugin which subsequently invalidates the nav cache
319    IntRect rect = IntRect(m_npWindow.x, m_npWindow.y,
320                           m_npWindow.width, m_npWindow.height);
321    m_window->webViewCore()->contentInvalidate(rect);
322}
323
324void PluginView::handleKeyboardEvent(KeyboardEvent* event)
325{
326    if (!m_window->isAcceptingEvent(kKey_ANPEventFlag))
327        return;
328
329    const PlatformKeyboardEvent* pke = event->keyEvent();
330    if (NULL == pke) {
331        return;
332    }
333
334    bool ignoreEvent = false;
335
336    ANPEvent evt;
337    SkANP::InitEvent(&evt, kKey_ANPEventType);
338
339    switch (pke->type()) {
340        case PlatformKeyboardEvent::KeyDown:
341#if TRACE_KEY_EVENTS
342            PLUGIN_LOG("--------- KeyDown, ignore\n");
343#endif
344            ignoreEvent = true;
345            break;
346        case PlatformKeyboardEvent::RawKeyDown:
347            evt.data.key.action = kDown_ANPKeyAction;
348            break;
349        case PlatformKeyboardEvent::Char:
350#if TRACE_KEY_EVENTS
351            PLUGIN_LOG("--------- Char, ignore\n");
352#endif
353            ignoreEvent = true;
354            break;
355        case PlatformKeyboardEvent::KeyUp:
356            evt.data.key.action = kUp_ANPKeyAction;
357            break;
358        default:
359#if TRACE_KEY_EVENTS
360            PLUGIN_LOG("------ unexpected keyevent type %d\n", pke->type());
361#endif
362            ignoreEvent = true;
363            break;
364    }
365
366    /* the plugin should be the only party able to return nav control to the
367     * browser UI. Therefore, if we discard an event on behalf of the plugin
368     * we should mark the event as being handled.
369     */
370    if (ignoreEvent) {
371        int keyCode = pke->nativeVirtualKeyCode();
372        if (keyCode >= kDpadUp_ANPKeyCode && keyCode <= kDpadCenter_ANPKeyCode)
373            event->setDefaultHandled();
374        return;
375    }
376
377    evt.data.key.nativeCode = pke->nativeVirtualKeyCode();
378    evt.data.key.virtualCode = pke->windowsVirtualKeyCode();
379    evt.data.key.repeatCount = pke->repeatCount();
380    evt.data.key.modifiers = make_modifiers(pke->shiftKey(), pke->altKey());
381    evt.data.key.unichar = pke->unichar();
382
383    if (m_window->sendEvent(evt)) {
384        event->setDefaultHandled();
385    } else if (m_window->inFullScreen()){
386        // while in the full screen mode, always consumes the key events and
387        // keeps the document focus
388        event->setDefaultHandled();
389    } else {
390        // remove the plugin from the document's focus
391        m_parentFrame->document()->focusedNodeRemoved();
392    }
393}
394
395NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf)
396{
397    notImplemented();
398    return NPERR_GENERIC_ERROR;
399}
400
401bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result)
402{
403    // our interface query is valid with no NPP instance
404    *result = NPERR_GENERIC_ERROR;
405
406    switch ((int)variable) {
407        case NPNVisOfflineBool: {
408            if (value != NULL) {
409                bool* retValue = static_cast<bool*>(value);
410                *retValue = !networkStateNotifier().onLine();
411                *result = NPERR_NO_ERROR;
412                return true;
413            }
414            break;
415        }
416        case kJavaContext_ANPGetValue: {
417            jobject* retObject = static_cast<jobject*>(value);
418            *retObject = android::WebViewCore::getApplicationContext();
419            *result = NPERR_NO_ERROR;
420            return true;
421        }
422        default:
423            break; // do nothing
424    }
425
426    (void)anp_getInterface(variable, value, result);
427    return true;
428}
429
430void PluginView::setParent(ScrollView* parent)
431{
432    PLUGIN_LOG("--%p SetParent old=[%p], new=[%p] \n", instance(), this->parent(), parent);
433
434    Widget::setParent(parent);
435
436    if (parent) {
437        // the widget needs initialized now so that the plugin has access to
438        // WebViewCore when NPP_New is called
439        if (m_window && !m_window->webViewCore()) {
440            android::WebViewCore* c = android::WebViewCore::getWebViewCore(this->parent());
441            m_window->init(c);
442        }
443        init();
444
445        /* Our widget needs to recompute its m_windowRect which then sets
446           the NPWindowRect if necessary.  This ensures that if NPWindowRect
447           is set prior to parent() being set that we still (1) notify the
448           plugin of its current rect and (2) that we execute our logic in
449           PluginWidgetAndroid in response to changes to NPWindowRect.
450         */
451        updatePluginWidget();
452    }
453}
454
455void PluginView::setNPWindowRect(const IntRect&)
456{
457    setNPWindowIfNeeded();
458}
459
460void PluginView::setNPWindowIfNeeded()
461{
462    PLUGIN_LOG("--%p SetWindow isStarted=[%d] \n", instance(), m_isStarted);
463
464    if (!m_isStarted || !parent())
465        return;
466
467    // in Android, plugin always get the setwindow() in the page coordinate.
468
469    // the m_npWindow is relative to the page
470    m_npWindow.x = m_pageRect.x();
471    m_npWindow.y = m_pageRect.y();
472    m_npWindow.width = m_pageRect.width();
473    m_npWindow.height = m_pageRect.height();
474
475    m_npWindow.clipRect.left = m_pageRect.x();
476    m_npWindow.clipRect.top = m_pageRect.y();
477    m_npWindow.clipRect.right = m_pageRect.x() + m_pageRect.width();
478    m_npWindow.clipRect.bottom = m_pageRect.y() + m_pageRect.height();
479
480    if (m_plugin->pluginFuncs()->setwindow) {
481        setCallingPlugin(true);
482        m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
483        setCallingPlugin(false);
484    }
485
486    m_window->setWindow(&m_npWindow, m_isTransparent);
487}
488
489bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result)
490{
491    switch ((int)variable) {
492        case NPNVWindowNPObject: {
493            NPObject* windowScriptObject =
494                    m_parentFrame->script()->windowScriptNPObject();
495
496            // Return value is expected to be retained, as described
497            // here:
498            // <http://www.mozilla.org/projects/plugin/npruntime.html>
499            if (windowScriptObject)
500                _NPN_RetainObject(windowScriptObject);
501
502            void** v = (void**)value;
503            *v = windowScriptObject;
504
505            *result = NPERR_NO_ERROR;
506            return true;
507        }
508
509        case NPNVPluginElementNPObject: {
510            NPObject* pluginScriptObject = 0;
511
512            if (m_element->hasTagName(appletTag) ||
513                m_element->hasTagName(embedTag) ||
514                m_element->hasTagName(objectTag)) {
515                HTMLPlugInElement* pluginElement =
516                        static_cast<HTMLPlugInElement*>(m_element);
517                pluginScriptObject = pluginElement->getNPObject();
518            }
519
520            // Return value is expected to be retained, as described
521            // here:
522            // <http://www.mozilla.org/projects/plugin/npruntime.html>
523            if (pluginScriptObject)
524                _NPN_RetainObject(pluginScriptObject);
525
526            void** v = (void**)value;
527            *v = pluginScriptObject;
528
529           *result = NPERR_NO_ERROR;
530            return true;
531        }
532
533        case NPNVnetscapeWindow: {
534            // Return the top level WebView Java object associated
535            // with this instance.
536            jobject *retObject = static_cast<jobject*>(value);
537            // TODO: Is it safe for this to be NULL? It looks from the NPNVWindowNPObject case that it is.
538            *retObject = android::WebViewCore::getWebViewCore(parent())->getWebViewJavaObject();
539            *result = NPERR_NO_ERROR;
540            return true;
541        }
542
543        case NPNVisOfflineBool: {
544            if (value == NULL) {
545              *result = NPERR_GENERIC_ERROR;
546              return true;
547            }
548            bool* retValue = static_cast<bool*>(value);
549            *retValue = !networkStateNotifier().onLine();
550            *result = NPERR_NO_ERROR;
551            return true;
552        }
553
554        case kSupportedDrawingModel_ANPGetValue: {
555            uint32_t* bits = reinterpret_cast<uint32_t*>(value);
556            *bits = kBitmap_ANPDrawingModel & kSurface_ANPDrawingModel;
557            *result = NPERR_NO_ERROR;
558            return true;
559        }
560
561        case kJavaContext_ANPGetValue: {
562            jobject* retObject = static_cast<jobject*>(value);
563            // TODO: Is it safe for this to be NULL? It looks from the NPNVWindowNPObject case that it is.
564            *retObject = android::WebViewCore::getWebViewCore(parent())->getContext();
565            *result = NPERR_NO_ERROR;
566            return true;
567        }
568
569        default: {
570            NPError error = NPERR_GENERIC_ERROR;
571            (void)anp_getInterface(variable, value, &error);
572            *result = error;
573            return true;
574        }
575    }
576}
577
578NPError PluginView::platformSetValue(NPPVariable variable, void* value)
579{
580    NPError error = NPERR_GENERIC_ERROR;
581
582    switch ((int)variable) {
583        case kRequestDrawingModel_ANPSetValue: {
584            ANPDrawingModel model = reinterpret_cast<ANPDrawingModel>(value);
585            if (m_window->setDrawingModel(model))
586                error = NPERR_NO_ERROR;
587            break;
588        }
589        case kAcceptEvents_ANPSetValue : {
590            if(value) {
591                ANPEventFlags flags = *reinterpret_cast<ANPEventFlags*>(value);
592                m_window->updateEventFlags(flags);
593                error = NPERR_NO_ERROR;
594            }
595            break;
596        }
597        default:
598            break;
599    }
600    return error;
601}
602
603void PluginView::invalidateRect(const IntRect& r)
604{
605    m_window->inval(r, true);
606}
607
608void PluginView::invalidateRect(NPRect* rect)
609{
610    IntRect r;
611
612    if (rect) {
613        r = IntRect(rect->left, rect->top,
614                    rect->right - rect->left, rect->bottom - rect->top);
615    } else {
616        r = IntRect(0, 0, m_npWindow.width, m_npWindow.height);
617    }
618
619    m_window->inval(r, true);
620}
621
622void PluginView::invalidateRegion(NPRegion region)
623{
624    // we don't support/define regions (yet), so do nothing
625}
626
627void PluginView::forceRedraw()
628{
629    this->invalidateRect(0);
630}
631
632void PluginView::setFocus(bool focused)
633{
634    Widget::setFocus(focused);
635//    SkDebugf("------------- setFocus %p\n", this);
636}
637
638void PluginView::show()
639{
640    setSelfVisible(true);
641    Widget::show();
642
643    if (platformPluginWidget())
644        platformPluginWidget()->layoutSurface();
645
646}
647
648void PluginView::hide()
649{
650    setSelfVisible(false);
651    Widget::hide();
652
653   if (platformPluginWidget())
654        platformPluginWidget()->layoutSurface();
655}
656
657void PluginView::setParentVisible(bool visible) {
658
659    if (isParentVisible() == visible)
660        return;
661
662    Widget::setParentVisible(visible);
663
664    if (platformPluginWidget())
665        platformPluginWidget()->layoutSurface();
666
667}
668
669void PluginView::paint(GraphicsContext* context, const IntRect& rect)
670{
671    if (!m_isStarted) {
672        // Draw the "missing plugin" image
673        paintMissingPluginIcon(context, rect);
674        return;
675    }
676
677    IntRect frame = frameRect();
678    if (!frame.width() || !frame.height()) {
679        PLUGIN_LOG("--%p FrameRect Dimensions are (0,0).\n", instance());
680        return;
681    }
682
683    if (m_window->isSurfaceDrawingModel()) {
684        /* the document position of the frame (e.g. iFrame) containing the
685           surface may have changed, which requires us to to update the global
686           coordinates of the surface. This is necessary because the plugin has
687           not moved within its parent frame and therefore will not get any
688           notification of its global position change.
689         */
690        updatePluginWidget();
691        m_window->setSurfaceClip(context->platformContext()->getTotalClipBounds());
692    } else {
693        m_window->inval(rect, false);
694        context->save();
695        context->translate(frame.x(), frame.y());
696        m_window->draw(context->platformContext());
697        context->restore();
698    }
699
700
701}
702
703void PluginView::updatePluginWidget()
704{
705    FrameView* frameView = static_cast<FrameView*>(parent());
706    PLUGIN_LOG("--%p UpdatePluginWidget frame=[%p] \n", instance(), frameView);
707    if (frameView) {
708        m_windowRect = frameView->contentsToWindow(frameRect());
709
710        IntRect oldPageRect = m_pageRect;
711
712        // only the top ScrollView can have the offset
713        m_pageRect = m_windowRect;
714        ScrollView* top = parent();
715        while (top->parent())
716            top = top->parent();
717        m_pageRect.move(top->scrollOffset());
718
719        if (m_pageRect != oldPageRect)
720            setNPWindowIfNeeded();
721    }
722}
723
724void PluginView::halt() {
725    notImplemented();
726}
727
728void PluginView::restart() {
729    notImplemented();
730}
731
732} // namespace WebCore
733