Home | History | Annotate | Download | only in mac
      1 /*
      2  * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
      3  * Copyright (C) 2008 Collabora Ltd. All rights reserved.
      4  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
      5  * Copyright (C) 2009 Girish Ramakrishnan <girish (at) forwardbias.in>
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include "config.h"
     30 #include "PluginView.h"
     31 
     32 #include "BridgeJSC.h"
     33 #include "Document.h"
     34 #include "DocumentLoader.h"
     35 #include "Element.h"
     36 #include "EventNames.h"
     37 #include "FocusController.h"
     38 #include "FrameLoader.h"
     39 #include "FrameLoadRequest.h"
     40 #include "FrameTree.h"
     41 #include "Frame.h"
     42 #include "FrameView.h"
     43 #include "GraphicsContext.h"
     44 #include "HostWindow.h"
     45 #include "HTMLNames.h"
     46 #include "HTMLPlugInElement.h"
     47 #include "Image.h"
     48 #include "JSDOMBinding.h"
     49 #include "KeyboardEvent.h"
     50 #include "MouseEvent.h"
     51 #include "NotImplemented.h"
     52 #include "Page.h"
     53 #include "PlatformMouseEvent.h"
     54 #include "PlatformKeyboardEvent.h"
     55 #include "PluginDebug.h"
     56 #include "PluginPackage.h"
     57 #include "PluginMainThreadScheduler.h"
     58 #include "RenderLayer.h"
     59 #include "ScriptController.h"
     60 #include "Settings.h"
     61 #include "npruntime_impl.h"
     62 #include "runtime_root.h"
     63 #include <runtime/JSLock.h>
     64 #include <runtime/JSValue.h>
     65 #include <wtf/RetainPtr.h>
     66 
     67 
     68 using JSC::ExecState;
     69 using JSC::Interpreter;
     70 using JSC::JSLock;
     71 using JSC::JSObject;
     72 using JSC::JSValue;
     73 using JSC::UString;
     74 
     75 #if PLATFORM(QT)
     76 #include <QWidget>
     77 #include <QKeyEvent>
     78 #include <QPainter>
     79 #include "QWebPageClient.h"
     80 QT_BEGIN_NAMESPACE
     81 extern Q_GUI_EXPORT OSWindowRef qt_mac_window_for(const QWidget* w);
     82 QT_END_NAMESPACE
     83 #endif
     84 
     85 #if PLATFORM(WX)
     86 #include <wx/defs.h>
     87 #include <wx/wx.h>
     88 #endif
     89 
     90 using std::min;
     91 
     92 using namespace WTF;
     93 
     94 namespace WebCore {
     95 
     96 using namespace HTMLNames;
     97 
     98 #ifndef NP_NO_CARBON
     99 static int modifiersForEvent(UIEventWithKeyState *event);
    100 #endif
    101 
    102 static inline WindowRef nativeWindowFor(PlatformWidget widget)
    103 {
    104 #if PLATFORM(QT)
    105     if (widget)
    106 #if QT_MAC_USE_COCOA
    107         return static_cast<WindowRef>([qt_mac_window_for(widget) windowRef]);
    108 #else
    109         return static_cast<WindowRef>(qt_mac_window_for(widget));
    110 #endif
    111 #elif PLATFORM(WX)
    112     if (widget)
    113         return (WindowRef)widget->MacGetTopLevelWindowRef();
    114 #endif
    115     return 0;
    116 }
    117 
    118 static inline CGContextRef cgHandleFor(PlatformWidget widget)
    119 {
    120 #if PLATFORM(QT)
    121     if (widget)
    122         return (CGContextRef)widget->macCGHandle();
    123 #endif
    124 #if PLATFORM(WX)
    125     if (widget)
    126         return (CGContextRef)widget->MacGetCGContextRef();
    127 #endif
    128     return 0;
    129 }
    130 
    131 static inline IntPoint topLevelOffsetFor(PlatformWidget widget)
    132 {
    133 #if PLATFORM(QT)
    134     if (widget) {
    135         PlatformWidget topLevel = widget->window();
    136         return widget->mapTo(topLevel, QPoint(0, 0)) + topLevel->geometry().topLeft() - topLevel->pos();
    137     }
    138 #endif
    139 #if PLATFORM(WX)
    140     if (widget) {
    141         PlatformWidget toplevel = wxGetTopLevelParent(widget);
    142         return toplevel->ScreenToClient(widget->GetScreenPosition());
    143     }
    144 #endif
    145     return IntPoint();
    146 }
    147 
    148 // --------------- Lifetime management -----------------
    149 
    150 bool PluginView::platformStart()
    151 {
    152     ASSERT(m_isStarted);
    153     ASSERT(m_status == PluginStatusLoadedSuccessfully);
    154 
    155     if (m_drawingModel == NPDrawingModel(-1)) {
    156         // We default to QuickDraw, even though we don't support it,
    157         // since that's what Safari does, and some plugins expect this
    158         // behavior and never set the drawing model explicitly.
    159 #ifndef NP_NO_QUICKDRAW
    160         m_drawingModel = NPDrawingModelQuickDraw;
    161 #else
    162         // QuickDraw not available, so we have to default to CoreGraphics
    163         m_drawingModel = NPDrawingModelCoreGraphics;
    164 #endif
    165     }
    166 
    167     if (m_eventModel == NPEventModel(-1)) {
    168         // If the plug-in did not specify an event model
    169         // we default to Carbon, when it is available.
    170 #ifndef NP_NO_CARBON
    171         m_eventModel = NPEventModelCarbon;
    172 #else
    173         m_eventModel = NPEventModelCocoa;
    174 #endif
    175     }
    176 
    177     // Gracefully handle unsupported drawing or event models. We can do this
    178     // now since the drawing and event model can only be set during NPP_New.
    179 #ifndef NP_NO_CARBON
    180     NPBool eventModelSupported;
    181     if (getValueStatic(NPNVariable(NPNVsupportsCarbonBool + m_eventModel), &eventModelSupported) != NPERR_NO_ERROR
    182             || !eventModelSupported) {
    183 #endif
    184         m_status = PluginStatusCanNotLoadPlugin;
    185         LOG(Plugins, "Plug-in '%s' uses unsupported event model %s",
    186                 m_plugin->name().utf8().data(), prettyNameForEventModel(m_eventModel));
    187         return false;
    188 #ifndef NP_NO_CARBON
    189     }
    190 #endif
    191 
    192 #ifndef NP_NO_QUICKDRAW
    193     NPBool drawingModelSupported;
    194     if (getValueStatic(NPNVariable(NPNVsupportsQuickDrawBool + m_drawingModel), &drawingModelSupported) != NPERR_NO_ERROR
    195             || !drawingModelSupported) {
    196 #endif
    197         m_status = PluginStatusCanNotLoadPlugin;
    198         LOG(Plugins, "Plug-in '%s' uses unsupported drawing model %s",
    199                 m_plugin->name().utf8().data(), prettyNameForDrawingModel(m_drawingModel));
    200         return false;
    201 #ifndef NP_NO_QUICKDRAW
    202     }
    203 #endif
    204 
    205 #if PLATFORM(QT)
    206     // Set the platformPluginWidget only in the case of QWebView so that the context menu appears in the right place.
    207     // In all other cases, we use off-screen rendering
    208     if (QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient()) {
    209         if (QWidget* widget = qobject_cast<QWidget*>(client->pluginParent()))
    210             setPlatformPluginWidget(widget);
    211     }
    212 #endif
    213 #if PLATFORM(WX)
    214     if (wxWindow* widget = m_parentFrame->view()->hostWindow()->platformPageClient())
    215         setPlatformPluginWidget(widget);
    216 #endif
    217 
    218     // Create a fake window relative to which all events will be sent when using offscreen rendering
    219     if (!platformPluginWidget()) {
    220 #ifndef NP_NO_CARBON
    221         // Make the default size really big. It is unclear why this is required but with a smaller size, mouse move
    222         // events don't get processed. Resizing the fake window to flash's size doesn't help.
    223         ::Rect windowBounds = { 0, 0, 1000, 1000 };
    224         CreateNewWindow(kDocumentWindowClass, kWindowStandardDocumentAttributes, &windowBounds, &m_fakeWindow);
    225         // Flash requires the window to be hilited to process mouse move events.
    226         HiliteWindow(m_fakeWindow, true);
    227 #endif
    228     }
    229 
    230     updatePluginWidget();
    231 
    232     if (!m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))
    233         setNPWindowIfNeeded();
    234 
    235     // TODO: Implement null timer throttling depending on plugin activation
    236     m_nullEventTimer.set(new Timer<PluginView>(this, &PluginView::nullEventTimerFired));
    237     m_nullEventTimer->startRepeating(0.02);
    238 
    239     m_lastMousePos.h = m_lastMousePos.v = 0;
    240 
    241     return true;
    242 }
    243 
    244 void PluginView::platformDestroy()
    245 {
    246     if (platformPluginWidget())
    247         setPlatformPluginWidget(0);
    248     else {
    249         CGContextRelease(m_contextRef);
    250 #ifndef NP_NO_CARBON
    251         if (m_fakeWindow)
    252             DisposeWindow(m_fakeWindow);
    253 #endif
    254     }
    255 }
    256 
    257 // Used before the plugin view has been initialized properly, and as a
    258 // fallback for variables that do not require a view to resolve.
    259 bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result)
    260 {
    261     switch (variable) {
    262     case NPNVToolkit:
    263         *static_cast<uint32_t*>(value) = 0;
    264         *result = NPERR_NO_ERROR;
    265         return true;
    266 
    267     case NPNVjavascriptEnabledBool:
    268         *static_cast<NPBool*>(value) = true;
    269         *result = NPERR_NO_ERROR;
    270         return true;
    271 
    272 #ifndef NP_NO_CARBON
    273     case NPNVsupportsCarbonBool:
    274         *static_cast<NPBool*>(value) = true;
    275         *result = NPERR_NO_ERROR;
    276         return true;
    277 
    278 #endif
    279     case NPNVsupportsCocoaBool:
    280         *static_cast<NPBool*>(value) = false;
    281         *result = NPERR_NO_ERROR;
    282         return true;
    283 
    284     // CoreGraphics is the only drawing model we support
    285     case NPNVsupportsCoreGraphicsBool:
    286         *static_cast<NPBool*>(value) = true;
    287         *result = NPERR_NO_ERROR;
    288         return true;
    289 
    290 #ifndef NP_NO_QUICKDRAW
    291     // QuickDraw is deprecated in 10.5 and not supported on 64-bit
    292     case NPNVsupportsQuickDrawBool:
    293 #endif
    294     case NPNVsupportsOpenGLBool:
    295     case NPNVsupportsCoreAnimationBool:
    296         *static_cast<NPBool*>(value) = false;
    297         *result = NPERR_NO_ERROR;
    298         return true;
    299 
    300     default:
    301         return false;
    302     }
    303 }
    304 
    305 // Used only for variables that need a view to resolve
    306 bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* error)
    307 {
    308     return false;
    309 }
    310 
    311 void PluginView::setParent(ScrollView* parent)
    312 {
    313     LOG(Plugins, "PluginView::setParent(%p)", parent);
    314 
    315     Widget::setParent(parent);
    316 
    317     if (parent)
    318         init();
    319 }
    320 
    321 // -------------- Geometry and painting ----------------
    322 
    323 void PluginView::show()
    324 {
    325     LOG(Plugins, "PluginView::show()");
    326 
    327     setSelfVisible(true);
    328 
    329     Widget::show();
    330 }
    331 
    332 void PluginView::hide()
    333 {
    334     LOG(Plugins, "PluginView::hide()");
    335 
    336     setSelfVisible(false);
    337 
    338     Widget::hide();
    339 }
    340 
    341 void PluginView::setFocus(bool focused)
    342 {
    343     LOG(Plugins, "PluginView::setFocus(%d)", focused);
    344     if (!focused) {
    345         Widget::setFocus(focused);
    346         return;
    347     }
    348 
    349     if (platformPluginWidget())
    350 #if PLATFORM(QT)
    351        platformPluginWidget()->setFocus(Qt::OtherFocusReason);
    352 #else
    353         platformPluginWidget()->SetFocus();
    354 #endif
    355    else
    356        Widget::setFocus(focused);
    357 
    358     // TODO: Also handle and pass on blur events (focus lost)
    359 
    360 #ifndef NP_NO_CARBON
    361     EventRecord record;
    362     record.what = NPEventType_GetFocusEvent;
    363     record.message = 0;
    364     record.when = TickCount();
    365     record.where = globalMousePosForPlugin();
    366     record.modifiers = GetCurrentKeyModifiers();
    367 
    368     if (!dispatchNPEvent(record))
    369         LOG(Events, "PluginView::setFocus(%d): Focus event not accepted", focused);
    370 #endif
    371 }
    372 
    373 void PluginView::setParentVisible(bool visible)
    374 {
    375     if (isParentVisible() == visible)
    376         return;
    377 
    378     Widget::setParentVisible(visible);
    379 }
    380 
    381 void PluginView::setNPWindowRect(const IntRect&)
    382 {
    383     setNPWindowIfNeeded();
    384 }
    385 
    386 void PluginView::setNPWindowIfNeeded()
    387 {
    388     if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow)
    389         return;
    390 
    391     CGContextRef newContextRef = 0;
    392     WindowRef newWindowRef = 0;
    393     if (platformPluginWidget()) {
    394         newContextRef = cgHandleFor(platformPluginWidget());
    395         newWindowRef = nativeWindowFor(platformPluginWidget());
    396         m_npWindow.type = NPWindowTypeWindow;
    397     } else {
    398         newContextRef = m_contextRef;
    399         newWindowRef = m_fakeWindow;
    400         m_npWindow.type = NPWindowTypeDrawable;
    401     }
    402 
    403     if (!newContextRef || !newWindowRef)
    404         return;
    405 
    406     m_npWindow.window = (void*)&m_npCgContext;
    407 #ifndef NP_NO_CARBON
    408     m_npCgContext.window = newWindowRef;
    409 #endif
    410     m_npCgContext.context = newContextRef;
    411 
    412     m_npWindow.x = m_windowRect.x();
    413     m_npWindow.y = m_windowRect.y();
    414     m_npWindow.width = m_windowRect.width();
    415     m_npWindow.height = m_windowRect.height();
    416 
    417     // TODO: (also clip against scrollbars, etc.)
    418     m_npWindow.clipRect.left = max(0, m_windowRect.x());
    419     m_npWindow.clipRect.top = max(0, m_windowRect.y());
    420     m_npWindow.clipRect.right = m_windowRect.x() + m_windowRect.width();
    421     m_npWindow.clipRect.bottom = m_windowRect.y() + m_windowRect.height();
    422 
    423     LOG(Plugins, "PluginView::setNPWindowIfNeeded(): window=%p, context=%p,"
    424             " window.x:%d window.y:%d window.width:%d window.height:%d window.clipRect size:%dx%d",
    425             newWindowRef, newContextRef, m_npWindow.x, m_npWindow.y, m_npWindow.width, m_npWindow.height,
    426             m_npWindow.clipRect.right - m_npWindow.clipRect.left, m_npWindow.clipRect.bottom - m_npWindow.clipRect.top);
    427 
    428     PluginView::setCurrentPluginView(this);
    429     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
    430     setCallingPlugin(true);
    431     m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
    432     setCallingPlugin(false);
    433     PluginView::setCurrentPluginView(0);
    434 }
    435 
    436 void PluginView::updatePluginWidget()
    437 {
    438     if (!parent())
    439        return;
    440 
    441     ASSERT(parent()->isFrameView());
    442     FrameView* frameView = static_cast<FrameView*>(parent());
    443 
    444     IntRect oldWindowRect = m_windowRect;
    445     IntRect oldClipRect = m_clipRect;
    446 
    447     m_windowRect = frameView->contentsToWindow(frameRect());
    448     IntPoint offset = topLevelOffsetFor(platformPluginWidget());
    449     m_windowRect.move(offset.x(), offset.y());
    450 
    451     if (!platformPluginWidget()) {
    452         if (m_windowRect.size() != oldWindowRect.size()) {
    453             CGContextRelease(m_contextRef);
    454 #if PLATFORM(QT)
    455             m_pixmap = QPixmap(m_windowRect.size());
    456             m_pixmap.fill(Qt::transparent);
    457             m_contextRef = m_pixmap.isNull() ? 0 : qt_mac_cg_context(&m_pixmap);
    458 #endif
    459         }
    460     }
    461 
    462     m_clipRect = windowClipRect();
    463     m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
    464 
    465     if (platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect))
    466         setNPWindowIfNeeded();
    467 }
    468 
    469 void PluginView::paint(GraphicsContext* context, const IntRect& rect)
    470 {
    471     if (!m_isStarted || m_status != PluginStatusLoadedSuccessfully) {
    472         paintMissingPluginIcon(context, rect);
    473         return;
    474     }
    475 
    476     if (context->paintingDisabled())
    477         return;
    478 
    479     setNPWindowIfNeeded();
    480 
    481     CGContextRef cgContext = m_npCgContext.context;
    482     if (!cgContext)
    483         return;
    484 
    485     CGContextSaveGState(cgContext);
    486     if (platformPluginWidget()) {
    487         IntPoint offset = frameRect().location();
    488         CGContextTranslateCTM(cgContext, offset.x(), offset.y());
    489     }
    490 
    491     IntRect targetRect(frameRect());
    492     targetRect.intersects(rect);
    493 
    494     // clip the context so that plugin only updates the interested area.
    495     CGRect r;
    496     r.origin.x = targetRect.x() - frameRect().x();
    497     r.origin.y = targetRect.y() - frameRect().y();
    498     r.size.width = targetRect.width();
    499     r.size.height = targetRect.height();
    500     CGContextClipToRect(cgContext, r);
    501 
    502     if (!platformPluginWidget() && m_isTransparent) { // clean the pixmap in transparent mode
    503 #if PLATFORM(QT)
    504         QPainter painter(&m_pixmap);
    505         painter.setCompositionMode(QPainter::CompositionMode_Clear);
    506         painter.fillRect(QRectF(r.origin.x, r.origin.y, r.size.width, r.size.height), Qt::transparent);
    507 #endif
    508     }
    509 
    510 #ifndef NP_NO_CARBON
    511     EventRecord event;
    512     event.what = updateEvt;
    513     event.message = (long unsigned int)m_npCgContext.window;
    514     event.when = TickCount();
    515     event.where.h = 0;
    516     event.where.v = 0;
    517     event.modifiers = GetCurrentKeyModifiers();
    518 
    519     if (!dispatchNPEvent(event))
    520         LOG(Events, "PluginView::paint(): Paint event not accepted");
    521 #endif
    522 
    523     CGContextRestoreGState(cgContext);
    524 
    525     if (!platformPluginWidget()) {
    526 #if PLATFORM(QT)
    527         QPainter* painter = context->platformContext();
    528         painter->drawPixmap(targetRect.x(), targetRect.y(), m_pixmap,
    529                             targetRect.x() - frameRect().x(), targetRect.y() - frameRect().y(), targetRect.width(), targetRect.height());
    530 #endif
    531     }
    532 }
    533 
    534 void PluginView::invalidateRect(const IntRect& rect)
    535 {
    536     if (platformPluginWidget())
    537 #if PLATFORM(QT)
    538         platformPluginWidget()->update(convertToContainingWindow(rect));
    539 #else
    540         platformPluginWidget()->RefreshRect(convertToContainingWindow(rect));
    541 #endif
    542     else
    543         invalidateWindowlessPluginRect(rect);
    544 }
    545 
    546 void PluginView::invalidateRect(NPRect* rect)
    547 {
    548     IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
    549     invalidateRect(r);
    550 }
    551 
    552 void PluginView::invalidateRegion(NPRegion region)
    553 {
    554     // TODO: optimize
    555     invalidate();
    556 }
    557 
    558 void PluginView::forceRedraw()
    559 {
    560     notImplemented();
    561 }
    562 
    563 
    564 // ----------------- Event handling --------------------
    565 
    566 void PluginView::handleMouseEvent(MouseEvent* event)
    567 {
    568     if (!m_isStarted)
    569         return;
    570 
    571 #ifndef NP_NO_CARBON
    572     EventRecord record;
    573 
    574     if (event->type() == eventNames().mousemoveEvent) {
    575         // Mouse movement is handled by null timer events
    576         m_lastMousePos = mousePosForPlugin(event);
    577         return;
    578     } else if (event->type() == eventNames().mouseoverEvent) {
    579         record.what = NPEventType_AdjustCursorEvent;
    580     } else if (event->type() == eventNames().mouseoutEvent) {
    581         record.what = NPEventType_AdjustCursorEvent;
    582     } else if (event->type() == eventNames().mousedownEvent) {
    583         record.what = mouseDown;
    584         // The plugin needs focus to receive keyboard events
    585         if (Page* page = m_parentFrame->page())
    586             page->focusController()->setFocusedFrame(m_parentFrame);
    587         m_parentFrame->document()->setFocusedNode(m_element);
    588     } else if (event->type() == eventNames().mouseupEvent) {
    589         record.what = mouseUp;
    590     } else {
    591         return;
    592     }
    593     record.where = mousePosForPlugin(event);
    594     record.modifiers = modifiersForEvent(event);
    595 
    596     if (!event->buttonDown())
    597         record.modifiers |= btnState;
    598 
    599     if (event->button() == 2)
    600         record.modifiers |= controlKey;
    601 
    602     if (!dispatchNPEvent(record)) {
    603         if (record.what == NPEventType_AdjustCursorEvent)
    604             return; // Signals that the plugin wants a normal cursor
    605 
    606         LOG(Events, "PluginView::handleMouseEvent(): Mouse event type %d at %d,%d not accepted",
    607                 record.what, record.where.h, record.where.v);
    608     } else {
    609         event->setDefaultHandled();
    610     }
    611 #endif
    612 }
    613 
    614 void PluginView::handleKeyboardEvent(KeyboardEvent* event)
    615 {
    616     if (!m_isStarted)
    617         return;
    618 
    619     LOG(Plugins, "PluginView::handleKeyboardEvent() ----------------- ");
    620 
    621     LOG(Plugins, "PV::hKE(): KE.keyCode: 0x%02X, KE.charCode: %d",
    622             event->keyCode(), event->charCode());
    623 
    624 #ifndef NP_NO_CARBON
    625     EventRecord record;
    626 
    627     if (event->type() == eventNames().keydownEvent) {
    628         // This event is the result of a PlatformKeyboardEvent::KeyDown which
    629         // was disambiguated into a PlatformKeyboardEvent::RawKeyDown. Since
    630         // we don't have access to the text here, we return, and wait for the
    631         // corresponding event based on PlatformKeyboardEvent::Char.
    632         return;
    633     } else if (event->type() == eventNames().keypressEvent) {
    634         // Which would be this one. This event was disambiguated from the same
    635         // PlatformKeyboardEvent::KeyDown, but to a PlatformKeyboardEvent::Char,
    636         // which retains the text from the original event. So, we can safely pass
    637         // on the event as a key-down event to the plugin.
    638         record.what = keyDown;
    639     } else if (event->type() == eventNames().keyupEvent) {
    640         // PlatformKeyboardEvent::KeyUp events always have the text, so nothing
    641         // fancy here.
    642         record.what = keyUp;
    643     } else {
    644         return;
    645     }
    646 
    647     const PlatformKeyboardEvent* platformEvent = event->keyEvent();
    648     int keyCode = platformEvent->nativeVirtualKeyCode();
    649 
    650     const String text = platformEvent->text();
    651     if (text.length() < 1) {
    652         event->setDefaultHandled();
    653         return;
    654     }
    655 
    656     WTF::RetainPtr<CFStringRef> cfText(WTF::AdoptCF, text.createCFString());
    657 
    658     LOG(Plugins, "PV::hKE(): PKE.text: %s, PKE.unmodifiedText: %s, PKE.keyIdentifier: %s",
    659             text.ascii().data(), platformEvent->unmodifiedText().ascii().data(),
    660             platformEvent->keyIdentifier().ascii().data());
    661 
    662     char charCodes[2] = { 0, 0 };
    663     if (!CFStringGetCString(cfText.get(), charCodes, 2, CFStringGetSystemEncoding())) {
    664         LOG_ERROR("Could not resolve character code using system encoding.");
    665         event->setDefaultHandled();
    666         return;
    667     }
    668 
    669     record.where = globalMousePosForPlugin();
    670     record.modifiers = modifiersForEvent(event);
    671     record.message = ((keyCode & 0xFF) << 8) | (charCodes[0] & 0xFF);
    672     record.when = TickCount();
    673 
    674     LOG(Plugins, "PV::hKE(): record.modifiers: %d", record.modifiers);
    675 
    676 #if PLATFORM(QT)
    677     LOG(Plugins, "PV::hKE(): PKE.qtEvent()->nativeVirtualKey: 0x%02X, charCode: %d",
    678                keyCode, int(uchar(charCodes[0])));
    679 #endif
    680 
    681     if (!dispatchNPEvent(record))
    682         LOG(Events, "PluginView::handleKeyboardEvent(): Keyboard event type %d not accepted", record.what);
    683     else
    684         event->setDefaultHandled();
    685 #endif
    686 }
    687 
    688 #ifndef NP_NO_CARBON
    689 void PluginView::nullEventTimerFired(Timer<PluginView>*)
    690 {
    691     EventRecord record;
    692 
    693     record.what = nullEvent;
    694     record.message = 0;
    695     record.when = TickCount();
    696     record.where = m_lastMousePos;
    697     record.modifiers = GetCurrentKeyModifiers();
    698     if (!Button())
    699         record.modifiers |= btnState;
    700 
    701     if (!dispatchNPEvent(record))
    702         LOG(Events, "PluginView::nullEventTimerFired(): Null event not accepted");
    703 }
    704 #endif
    705 
    706 #ifndef NP_NO_CARBON
    707 static int modifiersForEvent(UIEventWithKeyState* event)
    708 {
    709     int modifiers = 0;
    710 
    711     if (event->ctrlKey())
    712         modifiers |= controlKey;
    713 
    714     if (event->altKey())
    715         modifiers |= optionKey;
    716 
    717     if (event->metaKey())
    718         modifiers |= cmdKey;
    719 
    720     if (event->shiftKey())
    721         modifiers |= shiftKey;
    722 
    723      return modifiers;
    724 }
    725 #endif
    726 
    727 #ifndef NP_NO_CARBON
    728 Point PluginView::globalMousePosForPlugin() const
    729 {
    730     Point pos;
    731     GetGlobalMouse(&pos);
    732 
    733 #if PLATFORM(WX)
    734     // make sure the titlebar/toolbar size is included
    735     WindowRef windowRef = nativeWindowFor(platformPluginWidget());
    736     ::Rect content, structure;
    737 
    738     GetWindowBounds(windowRef, kWindowStructureRgn, &structure);
    739     GetWindowBounds(windowRef, kWindowContentRgn, &content);
    740 
    741     int top = content.top  - structure.top;
    742     pos.v -= top;
    743 #endif
    744 
    745     return pos;
    746 }
    747 #endif
    748 
    749 #ifndef NP_NO_CARBON
    750 Point PluginView::mousePosForPlugin(MouseEvent* event) const
    751 {
    752     ASSERT(event);
    753     if (platformPluginWidget())
    754         return globalMousePosForPlugin();
    755 
    756     if (event->button() == 2) {
    757         // always pass the global position for right-click since Flash uses it to position the context menu
    758         return globalMousePosForPlugin();
    759     }
    760 
    761     Point pos;
    762     IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation()));
    763     pos.h = postZoomPos.x() + m_windowRect.x();
    764     // The number 22 is the height of the title bar. As to why it figures in the calculation below
    765     // is left as an exercise to the reader :-)
    766     pos.v = postZoomPos.y() + m_windowRect.y() - 22;
    767     return pos;
    768 }
    769 #endif
    770 
    771 #ifndef NP_NO_CARBON
    772 bool PluginView::dispatchNPEvent(NPEvent& event)
    773 {
    774     PluginView::setCurrentPluginView(this);
    775     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
    776     setCallingPlugin(true);
    777 
    778     bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event);
    779 
    780     setCallingPlugin(false);
    781     PluginView::setCurrentPluginView(0);
    782     return accepted;
    783 }
    784 #endif
    785 
    786 // ------------------- Miscellaneous  ------------------
    787 
    788 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf)
    789 {
    790     String filename(buf, len);
    791 
    792     if (filename.startsWith("file:///"))
    793         filename = filename.substring(8);
    794 
    795     if (!fileExists(filename))
    796         return NPERR_FILE_NOT_FOUND;
    797 
    798     FILE* fileHandle = fopen((filename.utf8()).data(), "r");
    799 
    800     if (fileHandle == 0)
    801         return NPERR_FILE_NOT_FOUND;
    802 
    803     int bytesRead = fread(buffer.data(), 1, 0, fileHandle);
    804 
    805     fclose(fileHandle);
    806 
    807     if (bytesRead <= 0)
    808         return NPERR_FILE_NOT_FOUND;
    809 
    810     return NPERR_NO_ERROR;
    811 }
    812 
    813 void PluginView::halt()
    814 {
    815 }
    816 
    817 void PluginView::restart()
    818 {
    819 }
    820 
    821 } // namespace WebCore
    822