Title: [136124] trunk/Source/WebCore
Revision
136124
Author
[email protected]
Date
2012-11-29 05:25:53 -0800 (Thu, 29 Nov 2012)

Log Message

[Qt] Implement support for Cocoa based NPAPI plugins on Mac
https://bugs.webkit.org/show_bug.cgi?id=72358

Patch by Andy Shaw <[email protected]> on 2012-11-29
Reviewed by Simon Hausmann.

With later versions of Flash they are only Cocoa based which meant that it was not possible to use Flash in a QtWebKit browser.
This makes it possible to also use 64bit based plugins too.

* plugins/PluginPackage.cpp:
(WebCore::PluginPackage::initializeBrowserFuncs):
(WebCore):
* plugins/PluginQuirkSet.h:
* plugins/PluginView.cpp:
(WebCore::PluginView::handleEvent):
(WebCore::PluginView::PluginView):
(WebCore):
(WebCore::PluginView::userAgent):
* plugins/PluginView.h:
(WebCore):
(PluginView):
* plugins/mac/PluginPackageMac.cpp:
(WebCore::PluginPackage::determineQuirks):
(WebCore::PluginPackage::fetchInfo):
* plugins/mac/PluginViewMac.mm:
(WebCore):
(WebCore::initializeNPCocoaEvent):
(WebCore::getModifiers):
(WebCore::PluginView::platformStart):
* plugins/npapi.cpp:
(NPN_PopUpContextMenu):
* plugins/npapi.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (136123 => 136124)


--- trunk/Source/WebCore/ChangeLog	2012-11-29 13:15:23 UTC (rev 136123)
+++ trunk/Source/WebCore/ChangeLog	2012-11-29 13:25:53 UTC (rev 136124)
@@ -1,3 +1,37 @@
+2012-11-29  Andy Shaw  <[email protected]>
+
+        [Qt] Implement support for Cocoa based NPAPI plugins on Mac
+        https://bugs.webkit.org/show_bug.cgi?id=72358
+
+        Reviewed by Simon Hausmann.
+
+        With later versions of Flash they are only Cocoa based which meant that it was not possible to use Flash in a QtWebKit browser.
+        This makes it possible to also use 64bit based plugins too.  
+
+        * plugins/PluginPackage.cpp:
+        (WebCore::PluginPackage::initializeBrowserFuncs):
+        (WebCore):
+        * plugins/PluginQuirkSet.h:
+        * plugins/PluginView.cpp:
+        (WebCore::PluginView::handleEvent):
+        (WebCore::PluginView::PluginView):
+        (WebCore):
+        (WebCore::PluginView::userAgent):
+        * plugins/PluginView.h:
+        (WebCore):
+        (PluginView):
+        * plugins/mac/PluginPackageMac.cpp:
+        (WebCore::PluginPackage::determineQuirks):
+        (WebCore::PluginPackage::fetchInfo):
+        * plugins/mac/PluginViewMac.mm:
+        (WebCore):
+        (WebCore::initializeNPCocoaEvent):
+        (WebCore::getModifiers):
+        (WebCore::PluginView::platformStart):
+        * plugins/npapi.cpp:
+        (NPN_PopUpContextMenu):
+        * plugins/npapi.h:
+
 2012-11-29  Sheriff Bot  <[email protected]>
 
         Unreviewed, rolling out r136111.

Modified: trunk/Source/WebCore/plugins/PluginPackage.cpp (136123 => 136124)


--- trunk/Source/WebCore/plugins/PluginPackage.cpp	2012-11-29 13:15:23 UTC (rev 136123)
+++ trunk/Source/WebCore/plugins/PluginPackage.cpp	2012-11-29 13:25:53 UTC (rev 136124)
@@ -330,8 +330,10 @@
     m_browserFuncs.getvalueforurl = NPN_GetValueForURL;
     m_browserFuncs.setvalueforurl = NPN_SetValueForURL;
     m_browserFuncs.getauthenticationinfo = NPN_GetAuthenticationInfo;
+
+    m_browserFuncs.popupcontextmenu = NPN_PopUpContextMenu;
 }
-#endif
+#endif // ENABLE(NETSCAPE_PLUGIN_API)
 
 #if ENABLE(PLUGIN_PACKAGE_SIMPLE_HASH)
 unsigned PluginPackage::hash() const

Modified: trunk/Source/WebCore/plugins/PluginQuirkSet.h (136123 => 136124)


--- trunk/Source/WebCore/plugins/PluginQuirkSet.h	2012-11-29 13:15:23 UTC (rev 136123)
+++ trunk/Source/WebCore/plugins/PluginQuirkSet.h	2012-11-29 13:25:53 UTC (rev 136124)
@@ -48,7 +48,8 @@
         PluginQuirkRequiresGtkToolKit = 1 << 12,
         PluginQuirkRequiresDefaultScreenDepth = 1 << 13,
         PluginQuirkDontCallSetWindowMoreThanOnce = 1 << 14,
-        PluginQuirkIgnoreRightClickInWindowlessMode = 1 << 15
+        PluginQuirkIgnoreRightClickInWindowlessMode = 1 << 15,
+        PluginQuirkWantsChromeUserAgent = 1 << 16
     };
 
     class PluginQuirkSet {

Modified: trunk/Source/WebCore/plugins/PluginView.cpp (136123 => 136124)


--- trunk/Source/WebCore/plugins/PluginView.cpp	2012-11-29 13:15:23 UTC (rev 136123)
+++ trunk/Source/WebCore/plugins/PluginView.cpp	2012-11-29 13:25:53 UTC (rev 136124)
@@ -62,6 +62,7 @@
 #include "ScriptValue.h"
 #include "SecurityOrigin.h"
 #include "Settings.h"
+#include "WheelEvent.h"
 #include "npruntime_impl.h"
 #include <wtf/ASCIICType.h>
 #include <wtf/text/WTFString.h>
@@ -169,6 +170,10 @@
         handleMouseEvent(static_cast<MouseEvent*>(event));
     else if (event->isKeyboardEvent())
         handleKeyboardEvent(static_cast<KeyboardEvent*>(event));
+#if defined(XP_MACOSX)
+    else if (event->type() == eventNames().mousewheelEvent)
+        handleWheelEvent(static_cast<WheelEvent*>(event));
+#endif
     else if (event->type() == eventNames().contextmenuEvent)
         event->setDefaultHandled(); // We don't know if the plug-in has handled mousedown event by displaying a context menu, so we never want WebKit to show a default one.
 #if defined(XP_UNIX) && ENABLE(NETSCAPE_PLUGIN_API)
@@ -832,6 +837,9 @@
     , m_instance(0)
 #if defined(XP_MACOSX)
     , m_isWindowed(false)
+    , m_updatedCocoaTextInputRequested(false)
+    , m_keyDownSent(false)
+    , m_disregardKeyUpCounter(0)
 #else
     , m_isWindowed(true)
 #endif
@@ -1255,11 +1263,27 @@
 #endif
         " en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0";
 
+static const char* const ChromeUserAgent = "Mozilla/5.0 ("
+#if defined(XP_MACOSX)
+    "Macintosh; U; Intel Mac OS X;"
+#elif defined(XP_WIN)
+    "Windows; U; Windows NT 5.1;"
+#elif defined(XP_UNIX)
+    // The Gtk port uses X11 plugins in Mac.
+#if OS(DARWIN) && PLATFORM(GTK)
+    "X11; U; Intel Mac OS X;"
+#else
+    "X11; U; Linux i686;"
+#endif
+#endif
+    " AppleWebKit/534.34 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/534.34";
+
 const char* PluginView::userAgent()
 {
     if (m_plugin->quirks().contains(PluginQuirkWantsMozillaUserAgent))
         return MozillaUserAgent;
-
+    else if (m_plugin->quirks().contains(PluginQuirkWantsChromeUserAgent))
+        return ChromeUserAgent;
     if (m_userAgent.isNull())
         m_userAgent = m_parentFrame->loader()->userAgent(m_url).utf8();
 

Modified: trunk/Source/WebCore/plugins/PluginView.h (136123 => 136124)


--- trunk/Source/WebCore/plugins/PluginView.h	2012-11-29 13:15:23 UTC (rev 136123)
+++ trunk/Source/WebCore/plugins/PluginView.h	2012-11-29 13:25:53 UTC (rev 136124)
@@ -98,6 +98,7 @@
     class PluginStream;
     class ResourceError;
     class ResourceResponse;
+    class WheelEvent;
 
     enum PluginStatus {
         PluginStatusCanNotFindPlugin,
@@ -229,6 +230,10 @@
         const String& mimeType() const { return m_mimeType; }
         const KURL& url() const { return m_url; }
 
+#if defined(XP_MACOSX) && ENABLE(NETSCAPE_PLUGIN_API)
+        bool popUpContextMenu(NPMenu*);
+#endif
+
 #if OS(WINDOWS) && ENABLE(NETSCAPE_PLUGIN_API)
         static LRESULT CALLBACK PluginViewWndProc(HWND, UINT, WPARAM, LPARAM);
         LRESULT wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
@@ -323,6 +328,17 @@
         bool dispatchNPEvent(NPEvent&);
 #endif // ENABLE(NETSCAPE_PLUGIN_API)
 #endif
+#if defined(XP_MACOSX) && ENABLE(NETSCAPE_PLUGIN_API)
+        int16_t dispatchNPCocoaEvent(NPCocoaEvent&);
+        bool m_updatedCocoaTextInputRequested;
+        bool m_keyDownSent;
+        bool m_usePixmap;
+        uint16_t m_disregardKeyUpCounter;
+#endif
+
+#if defined(XP_MACOSX)
+        void handleWheelEvent(WheelEvent*);
+#endif
         void updatePluginWidget();
         void paintMissingPluginIcon(GraphicsContext*, const IntRect&);
 

Modified: trunk/Source/WebCore/plugins/mac/PluginPackageMac.cpp (136123 => 136124)


--- trunk/Source/WebCore/plugins/mac/PluginPackageMac.cpp	2012-11-29 13:15:23 UTC (rev 136123)
+++ trunk/Source/WebCore/plugins/mac/PluginPackageMac.cpp	2012-11-29 13:25:53 UTC (rev 136124)
@@ -57,8 +57,7 @@
     }
 
     if (mimeType == "application/x-shockwave-flash") {
-        // The flash plugin only requests windowless plugins if we return a mozilla user agent
-        m_quirks.add(PluginQuirkWantsMozillaUserAgent);
+        m_quirks.add(PluginQuirkWantsChromeUserAgent);
         m_quirks.add(PluginQuirkThrottleInvalidate);
         m_quirks.add(PluginQuirkThrottleWMUserPlusOneMessages);
         m_quirks.add(PluginQuirkFlashURLNotifyBug);
@@ -196,6 +195,7 @@
 
             String description = (CFStringRef)CFDictionaryGetValue(extensionsDict.get(), CFSTR("WebPluginTypeDescription"));
             m_mimeToDescriptions.set(mimeType, description);
+            determineQuirks(mimeType);
         }
 
         m_name = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(m_module, CFSTR("WebPluginName"));

Modified: trunk/Source/WebCore/plugins/mac/PluginViewMac.mm (136123 => 136124)


--- trunk/Source/WebCore/plugins/mac/PluginViewMac.mm	2012-11-29 13:15:23 UTC (rev 136123)
+++ trunk/Source/WebCore/plugins/mac/PluginViewMac.mm	2012-11-29 13:25:53 UTC (rev 136124)
@@ -58,6 +58,7 @@
 #include "RenderObject.h"
 #include "ScriptController.h"
 #include "Settings.h"
+#include "WheelEvent.h"
 #include "npruntime_impl.h"
 #include "runtime_root.h"
 #include <runtime/JSLock.h>
@@ -75,9 +76,12 @@
 #include <QWidget>
 #include <QKeyEvent>
 #include <QPainter>
+#include <QDateTime>
+#include <QPixmap>
 #include "QWebPageClient.h"
 QT_BEGIN_NAMESPACE
 extern Q_GUI_EXPORT OSWindowRef qt_mac_window_for(const QWidget* w);
+extern Q_GUI_EXPORT CGContextRef qt_mac_cg_context(const QPaintDevice *pdev); //qpaintdevice_mac.cpp
 QT_END_NAMESPACE
 #endif
 
@@ -144,6 +148,25 @@
     return IntPoint();
 }
 
+// --------- Cocoa specific utility functions ----------
+
+static void initializeNPCocoaEvent(NPCocoaEvent* event)
+{
+    memset(event, 0, sizeof(NPCocoaEvent));
+}
+
+static int32_t getModifiers(UIEventWithKeyState *event)
+{
+    int32_t modifiers = 0;
+    if (event->keyCode() == 57) modifiers |= NSAlphaShiftKeyMask;
+    if (event->shiftKey())  modifiers |= NSShiftKeyMask;
+    if (event->ctrlKey())   modifiers |= NSControlKeyMask;
+    if (event->metaKey())   modifiers |= NSCommandKeyMask;
+    if (event->altKey())    modifiers |= NSAlternateKeyMask;
+
+    return modifiers;
+}
+
 // --------------- Lifetime management -----------------
 
 bool PluginView::platformStart()
@@ -179,28 +202,40 @@
     NPBool eventModelSupported;
     if (getValueStatic(NPNVariable(NPNVsupportsCarbonBool + m_eventModel), &eventModelSupported) != NPERR_NO_ERROR
             || !eventModelSupported) {
+#else
+    NPBool eventModelSupported;
+    if (getValueStatic(NPNVariable(NPNVsupportsCocoaBool/* + m_eventModel*/), &eventModelSupported) != NPERR_NO_ERROR
+            || !eventModelSupported) {
 #endif
         m_status = PluginStatusCanNotLoadPlugin;
         LOG(Plugins, "Plug-in '%s' uses unsupported event model %s",
                 m_plugin->name().utf8().data(), prettyNameForEventModel(m_eventModel));
         return false;
-#ifndef NP_NO_CARBON
     }
-#endif
 
 #ifndef NP_NO_QUICKDRAW
     NPBool drawingModelSupported;
     if (getValueStatic(NPNVariable(NPNVsupportsQuickDrawBool + m_drawingModel), &drawingModelSupported) != NPERR_NO_ERROR
             || !drawingModelSupported) {
+        m_status = PluginStatusCanNotLoadPlugin;
+        LOG(Plugins, "Plug-in '%s' uses unsupported drawing model %s",
+                m_plugin->name().utf8().data(), prettyNameForDrawingModel(m_drawingModel));
+        return false;
+    }
 #endif
+
+#ifdef NP_NO_QUICKDRAW
+    NPBool drawingModelSupported;
+    if (getValueStatic(NPNVariable(NPNVsupportsCoreGraphicsBool/* + m_drawingModel*/), &drawingModelSupported) != NPERR_NO_ERROR
+            || !drawingModelSupported) {
         m_status = PluginStatusCanNotLoadPlugin;
         LOG(Plugins, "Plug-in '%s' uses unsupported drawing model %s",
                 m_plugin->name().utf8().data(), prettyNameForDrawingModel(m_drawingModel));
         return false;
-#ifndef NP_NO_QUICKDRAW
     }
 #endif
 
+
 #if PLATFORM(QT)
     // Set the platformPluginWidget only in the case of QWebView so that the context menu appears in the right place.
     // In all other cases, we use off-screen rendering
@@ -215,27 +250,29 @@
 #endif
 
     // Create a fake window relative to which all events will be sent when using offscreen rendering
+#ifndef NP_NO_CARBON
     if (!platformPluginWidget()) {
-#ifndef NP_NO_CARBON
         // Make the default size really big. It is unclear why this is required but with a smaller size, mouse move
         // events don't get processed. Resizing the fake window to flash's size doesn't help.
         ::Rect windowBounds = { 0, 0, 1000, 1000 };
         CreateNewWindow(kDocumentWindowClass, kWindowStandardDocumentAttributes, &windowBounds, &m_fakeWindow);
         // Flash requires the window to be hilited to process mouse move events.
         HiliteWindow(m_fakeWindow, true);
+    }
 #endif
-    }
 
     updatePluginWidget();
 
     if (!m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))
         setNPWindowIfNeeded();
 
+#ifndef NP_NO_CARBON
     // TODO: Implement null timer throttling depending on plugin activation
     m_nullEventTimer = adoptPtr(new Timer<PluginView>(this, &PluginView::nullEventTimerFired));
     m_nullEventTimer->startRepeating(0.02);
 
     m_lastMousePos.h = m_lastMousePos.v = 0;
+#endif // NP_NO_CARBON
 
     return true;
 }
@@ -276,7 +313,7 @@
 
 #endif
     case NPNVsupportsCocoaBool:
-        *static_cast<NPBool*>(value) = false;
+        *static_cast<NPBool*>(value) = true;
         *result = NPERR_NO_ERROR;
         return true;
 
@@ -286,6 +323,11 @@
         *result = NPERR_NO_ERROR;
         return true;
 
+    case NPNVsupportsAdvancedKeyHandling:
+        *static_cast<NPBool*>(value) = true;
+        *result = NPERR_NO_ERROR;
+        return true;
+
 #ifndef NP_NO_QUICKDRAW
     // QuickDraw is deprecated in 10.5 and not supported on 64-bit
     case NPNVsupportsQuickDrawBool:
@@ -304,6 +346,20 @@
 // Used only for variables that need a view to resolve
 bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* error)
 {
+    // In WebKit2, this is set if the plugin queries it's availiablity and
+    // no key down events have already been sent.
+    if (variable == NPNVsupportsUpdatedCocoaTextInputBool) {
+        if (m_keyDownSent && !m_updatedCocoaTextInputRequested) {
+            *static_cast<NPBool*>(value) = false;
+            *error = NPERR_NO_ERROR;
+        }
+        else {
+            *static_cast<NPBool*>(value) = true;
+            *error = NPERR_NO_ERROR;
+            m_updatedCocoaTextInputRequested = true;
+        }
+        return true;
+    }
     return false;
 }
 
@@ -342,21 +398,22 @@
     LOG(Plugins, "PluginView::setFocus(%d)", focused);
     if (!focused) {
         Widget::setFocus(focused);
-        return;
+        if (m_eventModel != NPEventModelCocoa)
+            return;
     }
 
     if (platformPluginWidget())
 #if PLATFORM(QT)
-       static_cast<QWidget*>(platformPluginWidget())->setFocus(Qt::OtherFocusReason);
+        static_cast<QWidget*>(platformPluginWidget())->setFocus(Qt::OtherFocusReason);
 #else
         platformPluginWidget()->SetFocus();
 #endif
-   else
-       Widget::setFocus(focused);
+    else
+        Widget::setFocus(focused);
 
-    // TODO: Also handle and pass on blur events (focus lost)
 
 #ifndef NP_NO_CARBON
+    // TODO: Also handle and pass on blur events (focus lost)
     EventRecord record;
     record.what = NPEventType_GetFocusEvent;
     record.message = 0;
@@ -367,6 +424,17 @@
     if (!dispatchNPEvent(record))
         LOG(Events, "PluginView::setFocus(%d): Focus event not accepted", focused);
 #endif
+    {
+        NPCocoaEvent cocoaEvent;
+        initializeNPCocoaEvent(&cocoaEvent);
+        cocoaEvent.type = NPCocoaEventFocusChanged;
+        NPBool focus = focused;
+        cocoaEvent.data.focus.hasFocus = focus;
+
+        if(!dispatchNPCocoaEvent(cocoaEvent)) {
+            LOG(Events, "PluginView::setFocus(): Focus event %d not accepted", cocoaEvent.type);
+        }
+    }
 }
 
 void PluginView::setParentVisible(bool visible)
@@ -399,8 +467,10 @@
         m_npWindow.type = NPWindowTypeDrawable;
     }
 
-    if (!newContextRef || !newWindowRef)
-        return;
+    if (!newContextRef || !newWindowRef) {
+        if (!m_usePixmap)
+            return;
+    }
 
     m_npWindow.window = (void*)&m_npCgContext;
 #ifndef NP_NO_CARBON
@@ -474,12 +544,32 @@
 
     if (context->paintingDisabled())
         return;
-
+#if PLATFORM(QT)
+    QPainter* p = context->platformContext();
+    CGContextRef cgContext = qt_mac_cg_context(p->device());
+#else
+    CGContextRef cgContext = m_npCgContext.context;
+#endif
     setNPWindowIfNeeded();
+    if (!cgContext) {
+        cgContext = m_contextRef;
+        if (!cgContext)
+            return;
+        else {
+            m_usePixmap = true;
+            setNPWindowIfNeeded();
+        }
+    } else
+        m_usePixmap = false;
 
-    CGContextRef cgContext = m_npCgContext.context;
-    if (!cgContext)
-        return;
+    bool oldUsePixmap = m_usePixmap;
+    if (m_isTransparent && !m_usePixmap) {
+        if (m_pixmap.isNull())
+            m_pixmap = QPixmap(frameRect().size());
+        m_usePixmap = true;
+        setNPWindowIfNeeded();
+        cgContext = qt_mac_cg_context(&m_pixmap);
+    }
 
     CGContextSaveGState(cgContext);
     if (platformPluginWidget()) {
@@ -498,7 +588,7 @@
     r.size.height = targetRect.height();
     CGContextClipToRect(cgContext, r);
 
-    if (!platformPluginWidget() && m_isTransparent) { // clean the pixmap in transparent mode
+    if (!platformPluginWidget() || m_isTransparent) { // clean the pixmap in transparent mode
 #if PLATFORM(QT)
         QPainter painter(&m_pixmap);
         painter.setCompositionMode(QPainter::CompositionMode_Clear);
@@ -507,39 +597,70 @@
     }
 
 #ifndef NP_NO_CARBON
-    EventRecord event;
-    event.what = updateEvt;
-    event.message = (long unsigned int)m_npCgContext.window;
-    event.when = TickCount();
-    event.where.h = 0;
-    event.where.v = 0;
-    event.modifiers = GetCurrentKeyModifiers();
+    if (m_eventModel != NPEventModelCocoa) {
+        EventRecord event;
+        event.what = updateEvt;
+        event.message = (long unsigned int)m_npCgContext.window;
+        event.when = TickCount();
+        event.where.h = 0;
+        event.where.v = 0;
+        event.modifiers = GetCurrentKeyModifiers();
 
-    if (!dispatchNPEvent(event))
-        LOG(Events, "PluginView::paint(): Paint event not accepted");
+        if (!dispatchNPEvent(event))
+            LOG(Events, "PluginView::paint(): Paint event not accepted");
+    } else
 #endif
-
-    CGContextRestoreGState(cgContext);
-
-    if (!platformPluginWidget()) {
+    {
+        NPCocoaEvent cocoaEvent;
+        initializeNPCocoaEvent(&cocoaEvent);
+        cocoaEvent.type = NPCocoaEventDrawRect;
+        cocoaEvent.data.draw.x = m_usePixmap ? 0 : r.origin.x;
+        cocoaEvent.data.draw.y = m_usePixmap ? 0 : r.origin.y;
+        cocoaEvent.data.draw.width = m_usePixmap ? m_pixmap.width() : r.size.width;
+        cocoaEvent.data.draw.height = m_usePixmap ? m_pixmap.height() : r.size.height;
+        cocoaEvent.data.draw.context = cgContext;
+        
+        if(!dispatchNPCocoaEvent(cocoaEvent))
+            LOG(Events, "PluginView::paint(): Paint event type %d not accepted", cocoaEvent.type);
+    }
+    
+    if (!platformPluginWidget() || m_isTransparent) {
 #if PLATFORM(QT)
         QPainter* painter = context->platformContext();
-        painter->drawPixmap(targetRect.x(), targetRect.y(), m_pixmap, 
+        painter->drawPixmap(targetRect.x(), targetRect.y(), m_pixmap,
                             targetRect.x() - frameRect().x(), targetRect.y() - frameRect().y(), targetRect.width(), targetRect.height());
 #endif
     }
+    CGContextRestoreGState(cgContext);
+    if (oldUsePixmap != m_usePixmap) {
+        m_usePixmap = oldUsePixmap;
+        m_pixmap = QPixmap();
+    }    
 }
 
+bool PluginView::popUpContextMenu(NPMenu *menu)
+{
+    NSEvent* currentEvent = [NSApp currentEvent];
+    
+    // NPN_PopUpContextMenu must be called from within the plug-in's NPP_HandleEvent.
+    if (!currentEvent)
+        return NPERR_GENERIC_ERROR;
+    
+    NSWindow* window = [currentEvent window];
+    NSView* view = [window contentView];
+    [NSMenu popUpContextMenu:(NSMenu*)menu withEvent:currentEvent forView:view];
+    return true;
+}
+    
 void PluginView::invalidateRect(const IntRect& rect)
 {
-    if (platformPluginWidget())
+    if (platformPluginWidget() && m_isTransparent)
 #if PLATFORM(QT)
         static_cast<QWidget*>(platformPluginWidget())->update(convertToContainingWindow(rect));
 #else
         platformPluginWidget()->RefreshRect(convertToContainingWindow(rect));
 #endif
-    else
-        invalidateWindowlessPluginRect(rect);
+    invalidateWindowlessPluginRect(rect);
 }
 
 void PluginView::invalidateRect(NPRect* rect)
@@ -561,129 +682,297 @@
 
 
 // ----------------- Event handling --------------------
+void PluginView::handleWheelEvent(WheelEvent *event)
+{
+    if (!m_isStarted || m_eventModel != NPEventModelCocoa)
+        return;
+    
+    NPCocoaEvent cocoaEvent;
+    initializeNPCocoaEvent(&cocoaEvent);
+    
+    NSEvent *currentEvent = [NSApp currentEvent];
+    
+    cocoaEvent.type = NPCocoaEventScrollWheel;
+    
+    cocoaEvent.data.mouse.pluginX = event->layerX() - m_npWindow.x + m_windowRect.x() - m_element->offsetLeft();
+    cocoaEvent.data.mouse.pluginY = event->layerY() - m_npWindow.y + m_windowRect.y() - m_element->offsetTop();
+    cocoaEvent.data.mouse.deltaX = [currentEvent deltaX];
+    cocoaEvent.data.mouse.deltaY = [currentEvent deltaY];
+    cocoaEvent.data.mouse.deltaZ = [currentEvent deltaZ];
+    cocoaEvent.data.mouse.modifierFlags = getModifiers(event);
+    
+    if(!dispatchNPCocoaEvent(cocoaEvent)) {
+        LOG(Events, "PluginView::handleMouseEvent(): Wheel event type %d at %d,%d not accepted", cocoaEvent.type
+            cocoaEvent.data.mouse.x, cocoaEvent.data.mouse.y);
+    }
+    event->setDefaultHandled();
+}
 
 void PluginView::handleMouseEvent(MouseEvent* event)
 {
     if (!m_isStarted)
         return;
-
+    
 #ifndef NP_NO_CARBON
-    EventRecord record;
-
-    if (event->type() == eventNames().mousemoveEvent) {
-        // Mouse movement is handled by null timer events
-        m_lastMousePos = mousePosForPlugin(event);
-        return;
-    } else if (event->type() == eventNames().mouseoverEvent) {
-        record.what = NPEventType_AdjustCursorEvent;
-    } else if (event->type() == eventNames().mouseoutEvent) {
-        record.what = NPEventType_AdjustCursorEvent;
-    } else if (event->type() == eventNames().mousedownEvent) {
-        record.what = mouseDown;
-        // The plugin needs focus to receive keyboard events
-        if (Page* page = m_parentFrame->page())
-            page->focusController()->setFocusedFrame(m_parentFrame);
-        m_parentFrame->document()->setFocusedNode(m_element);
-    } else if (event->type() == eventNames().mouseupEvent) {
-        record.what = mouseUp;
-    } else {
-        return;
-    }
-    record.where = mousePosForPlugin(event);
-    record.modifiers = modifiersForEvent(event);
-
-    if (!event->buttonDown())
-        record.modifiers |= btnState;
-
-    if (event->button() == 2)
-        record.modifiers |= controlKey;
-
-    if (!dispatchNPEvent(record)) {
-        if (record.what == NPEventType_AdjustCursorEvent)
-            return; // Signals that the plugin wants a normal cursor
-
-        LOG(Events, "PluginView::handleMouseEvent(): Mouse event type %d at %d,%d not accepted",
+    if (m_eventModel != NPEventModelCocoa) {
+        EventRecord record;
+        
+        if (event->type() == eventNames().mousemoveEvent) {
+            // Mouse movement is handled by null timer events
+            m_lastMousePos = mousePosForPlugin(event);
+            return;
+        } else if (event->type() == eventNames().mouseoverEvent) {
+            record.what = NPEventType_AdjustCursorEvent;
+        } else if (event->type() == eventNames().mouseoutEvent) {
+            record.what = NPEventType_AdjustCursorEvent;
+        } else if (event->type() == eventNames().mousedownEvent) {
+            record.what = mouseDown;
+            // The plugin needs focus to receive keyboard events
+            if (Page* page = m_parentFrame->page())
+                page->focusController()->setFocusedFrame(m_parentFrame);
+            m_parentFrame->document()->setFocusedNode(m_element);
+        } else if (event->type() == eventNames().mouseupEvent) {
+            record.what = mouseUp;
+        } else {
+            return;
+        }
+        record.where = mousePosForPlugin(event);
+        record.modifiers = modifiersForEvent(event);
+        
+        if (!event->buttonDown())
+            record.modifiers |= btnState;
+        
+        if (event->button() == 2)
+            record.modifiers |= controlKey;
+        
+        if (!dispatchNPEvent(record)) {
+            if (record.what == NPEventType_AdjustCursorEvent)
+                return; // Signals that the plugin wants a normal cursor
+            
+            LOG(Events, "PluginView::handleMouseEvent(): Mouse event type %d at %d,%d not accepted",
                 record.what, record.where.h, record.where.v);
-    } else {
+        } else {
+            event->setDefaultHandled();
+        }
+    } else
+#endif
+    {
+        NPCocoaEventType eventType;
+        int32_t buttonNumber = 0;
+        int32_t clickCount = 0;
+        NSEvent *currentEvent = [NSApp currentEvent];
+        
+        NSEventType type = [currentEvent type];
+        
+        switch (type) {
+            case NSLeftMouseDown:
+            case NSRightMouseDown:
+            case NSOtherMouseDown:
+                buttonNumber = [currentEvent buttonNumber];
+                clickCount = [currentEvent clickCount];
+                eventType = NPCocoaEventMouseDown;
+                // The plugin needs focus to receive keyboard events
+                if (Page* page = m_parentFrame->page())
+                    page->focusController()->setFocusedFrame(m_parentFrame);
+                m_parentFrame->document()->setFocusedNode(m_element);
+                break;
+                
+            case NSLeftMouseUp:
+            case NSRightMouseUp:
+            case NSOtherMouseUp:
+                buttonNumber = [currentEvent buttonNumber];
+                clickCount = [currentEvent clickCount];
+                eventType = NPCocoaEventMouseUp;
+                break;
+                
+            case NSMouseMoved:
+                eventType = NPCocoaEventMouseMoved;
+                break;
+                
+            case NSLeftMouseDragged:
+            case NSRightMouseDragged:
+            case NSOtherMouseDragged:
+                buttonNumber = [currentEvent buttonNumber];
+                eventType = NPCocoaEventMouseDragged;
+                break;
+                
+            case NSMouseEntered:
+                eventType = NPCocoaEventMouseEntered;
+                break;
+                
+            case NSMouseExited:
+                eventType = NPCocoaEventMouseExited;
+            default:
+                return;
+        }
+        
+        NPCocoaEvent cocoaEvent;
+        initializeNPCocoaEvent(&cocoaEvent);
+        
+        cocoaEvent.type = eventType;
+        if (!(NPCocoaEventMouseEntered == eventType || NPCocoaEventMouseExited == eventType)) {
+            cocoaEvent.data.mouse.buttonNumber = buttonNumber;
+            cocoaEvent.data.mouse.clickCount = clickCount;
+        }
+        
+        cocoaEvent.data.mouse.pluginX = event->layerX() - m_npWindow.x + m_windowRect.x() - m_element->offsetLeft();
+        cocoaEvent.data.mouse.pluginY = event->layerY() - m_npWindow.y + m_windowRect.y() - m_element->offsetTop();
+        cocoaEvent.data.mouse.deltaX = [currentEvent deltaX];
+        cocoaEvent.data.mouse.deltaY = [currentEvent deltaY];
+        cocoaEvent.data.mouse.deltaZ = [currentEvent deltaZ];
+        cocoaEvent.data.mouse.modifierFlags = getModifiers(event);
+        
+        int16_t response = dispatchNPCocoaEvent(cocoaEvent);
+        if(response = kNPEventNotHandled) {
+            LOG(Events, "PluginView::handleMouseEvent(): Mouse event type %d at %d,%d not accepted", cocoaEvent.type
+                cocoaEvent.data.mouse.x, cocoaEvent.data.mouse.y);
+        }
+        
+        // Safari policy is to return true for all mouse events, because some plugins
+        // return false even if they have handled the event.
         event->setDefaultHandled();
     }
-#endif
 }
-
+    
 void PluginView::handleKeyboardEvent(KeyboardEvent* event)
 {
     if (!m_isStarted)
         return;
-
     LOG(Plugins, "PluginView::handleKeyboardEvent() ----------------- ");
-
+    
     LOG(Plugins, "PV::hKE(): KE.keyCode: 0x%02X, KE.charCode: %d",
-            event->keyCode(), event->charCode());
-
+        event->keyCode(), event->charCode());
+    
 #ifndef NP_NO_CARBON
-    EventRecord record;
-
-    if (event->type() == eventNames().keydownEvent) {
-        // This event is the result of a PlatformEvent::KeyDown which
-        // was disambiguated into a PlatformKeyboardEvent::RawKeyDown. Since
-        // we don't have access to the text here, we return, and wait for the
-        // corresponding event based on PlatformKeyboardEvent::Char.
-        return;
-    } else if (event->type() == eventNames().keypressEvent) {
-        // Which would be this one. This event was disambiguated from the same
-        // PlatformEvent::KeyDown, but to a PlatformEvent::Char,
-        // which retains the text from the original event. So, we can safely pass
-        // on the event as a key-down event to the plugin.
-        record.what = keyDown;
-    } else if (event->type() == eventNames().keyupEvent) {
-        // PlatformEvent::KeyUp events always have the text, so nothing
-        // fancy here.
-        record.what = keyUp;
-    } else {
-        return;
-    }
-
-    const PlatformKeyboardEvent* platformEvent = event->keyEvent();
-    int keyCode = platformEvent->nativeVirtualKeyCode();
-
-    const String text = platformEvent->text();
-    if (text.length() < 1) {
-        event->setDefaultHandled();
-        return;
-    }
-
-    WTF::RetainPtr<CFStringRef> cfText(WTF::AdoptCF, text.createCFString());
-
-    LOG(Plugins, "PV::hKE(): PKE.text: %s, PKE.unmodifiedText: %s, PKE.keyIdentifier: %s",
+    if (m_eventModel != NPEventModelCocoa) {
+        EventRecord record;
+        if (event->type() == eventNames().keydownEvent) {
+            // This event is the result of a PlatformKeyboardEvent::KeyDown which
+            // was disambiguated into a PlatformKeyboardEvent::RawKeyDown. Since
+            // we don't have access to the text here, we return, and wait for the
+            // corresponding event based on PlatformKeyboardEvent::Char.
+            return;
+        } else if (event->type() == eventNames().keypressEvent) {
+            // Which would be this one. This event was disambiguated from the same
+            // PlatformKeyboardEvent::KeyDown, but to a PlatformKeyboardEvent::Char,
+            // which retains the text from the original event. So, we can safely pass
+            // on the event as a key-down event to the plugin.
+            record.what = keyDown;
+        } else if (event->type() == eventNames().keyupEvent) {
+            // PlatformKeyboardEvent::KeyUp events always have the text, so nothing
+            // fancy here.
+            record.what = keyUp;
+        } else {
+            return;
+        }
+        
+        const PlatformKeyboardEvent* platformEvent = event->keyEvent();
+        int keyCode = platformEvent->nativeVirtualKeyCode();
+        
+        const String text = platformEvent->text();
+        if (text.length() < 1) {
+            event->setDefaultHandled();
+            return;
+        }
+        
+        WTF::RetainPtr<CFStringRef> cfText(WTF::AdoptCF, text.createCFString());
+        
+        LOG(Plugins, "PV::hKE(): PKE.text: %s, PKE.unmodifiedText: %s, PKE.keyIdentifier: %s",
             text.ascii().data(), platformEvent->unmodifiedText().ascii().data(),
             platformEvent->keyIdentifier().ascii().data());
-
-    char charCodes[2] = { 0, 0 };
-    if (!CFStringGetCString(cfText.get(), charCodes, 2, CFStringGetSystemEncoding())) {
-        LOG_ERROR("Could not resolve character code using system encoding.");
-        event->setDefaultHandled();
-        return;
-    }
-
-    record.where = globalMousePosForPlugin();
-    record.modifiers = modifiersForEvent(event);
-    record.message = ((keyCode & 0xFF) << 8) | (charCodes[0] & 0xFF);
-    record.when = TickCount();
-
-    LOG(Plugins, "PV::hKE(): record.modifiers: %d", record.modifiers);
-
+        
+        char charCodes[2] = { 0, 0 };
+        if (!CFStringGetCString(cfText.get(), charCodes, 2, CFStringGetSystemEncoding())) {
+            LOG_ERROR("Could not resolve character code using system encoding.");
+            event->setDefaultHandled();
+            return;
+        }
+        
+        record.where = globalMousePosForPlugin();
+        record.modifiers = modifiersForEvent(event);
+        record.message = ((keyCode & 0xFF) << 8) | (charCodes[0] & 0xFF);
+        record.when = TickCount();
+        
+        LOG(Plugins, "PV::hKE(): record.modifiers: %d", record.modifiers);
+        
 #if PLATFORM(QT)
-    LOG(Plugins, "PV::hKE(): PKE.qtEvent()->nativeVirtualKey: 0x%02X, charCode: %d",
-               keyCode, int(uchar(charCodes[0])));
+        LOG(Plugins, "PV::hKE(): PKE.qtEvent()->nativeVirtualKey: 0x%02X, charCode: %d",
+            keyCode, int(uchar(charCodes[0])));
 #endif
-
-    if (!dispatchNPEvent(record))
-        LOG(Events, "PluginView::handleKeyboardEvent(): Keyboard event type %d not accepted", record.what);
-    else
-        event->setDefaultHandled();
+        
+        if (!dispatchNPEvent(record))
+            LOG(Events, "PluginView::handleKeyboardEvent(): Keyboard event type %d not accepted", record.what);
+        else
+            event->setDefaultHandled();
+    } else
 #endif
+    {
+        NSEvent *currentEvent = [NSApp currentEvent];
+        NPCocoaEventType eventType;
+        NSEventType type = [currentEvent type];
+        
+        switch (type) {
+            case NSKeyDown:
+                eventType = NPCocoaEventKeyDown;
+                m_keyDownSent = true;
+                break;
+            case NSKeyUp:
+                if (m_disregardKeyUpCounter > 0) {
+                    m_disregardKeyUpCounter--;
+                    event->setDefaultHandled();
+                    return;
+                }
+                eventType = NPCocoaEventKeyUp;
+                break;
+            case NSFlagsChanged:
+                eventType = NPCocoaEventFlagsChanged;
+                break;
+            default:
+                return;
+        }
+        
+        NPCocoaEvent cocoaEvent;
+        initializeNPCocoaEvent(&cocoaEvent);
+        cocoaEvent.type = eventType;
+        if (eventType != NPCocoaEventFlagsChanged) {
+            NSString *characters = [currentEvent characters];
+            NSString *charactersIgnoringModifiers = [currentEvent charactersIgnoringModifiers];
+            cocoaEvent.data.key.characters = reinterpret_cast<NPNSString*>(characters);
+            cocoaEvent.data.key.charactersIgnoringModifiers = reinterpret_cast<NPNSString*>(charactersIgnoringModifiers);
+            cocoaEvent.data.key.isARepeat = [currentEvent isARepeat];
+            cocoaEvent.data.key.keyCode = [currentEvent keyCode];
+            cocoaEvent.data.key.modifierFlags = getModifiers(event);
+        }
+        
+        int16_t response = dispatchNPCocoaEvent(cocoaEvent);
+        if(response == kNPEventNotHandled) {
+            LOG(Events, "PluginView::handleKeyboardEvent(): Keyboard event type %d not accepted", cocoaEvent.type);
+        } else if (response == kNPEventStartIME) {
+            // increment counter and resend as a text input
+            m_disregardKeyUpCounter++;
+            NPCocoaEvent textEvent;
+            initializeNPCocoaEvent(&textEvent);
+            textEvent.type = NPCocoaEventTextInput;
+            textEvent.data.text.text = reinterpret_cast<NPNSString*>([currentEvent characters]);
+            response = dispatchNPCocoaEvent(textEvent);
+            if(response == kNPEventNotHandled)
+                LOG(Events, "PluginView::handleKeyboardEvent(): Keyboard event type %d not accepted", cocoaEvent.type);
+        }
+        
+        // All keyboard events need to be handled to prevent them falling
+        // through to the page, unless they are Meta key events, in which
+        // case they are, unless they are Cmd+a. From WebKit2, possibly
+        // not the most elegant piece of key handling code.....
+        if (event->metaKey()) {
+            if (cocoaEvent.data.key.keyCode == 0)
+                event->setDefaultHandled();
+        } else {
+            // else ignore, it's a Meta Key event for the browser.
+            event->setDefaultHandled();
+        }
+    }
 }
-
+    
 #ifndef NP_NO_CARBON
 void PluginView::nullEventTimerFired(Timer<PluginView>*)
 {
@@ -782,6 +1071,21 @@
 }
 #endif
 
+
+int16_t PluginView::dispatchNPCocoaEvent(NPCocoaEvent& cocoaEvent)
+{
+    PluginView::setCurrentPluginView(this);
+    JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonJSGlobalData());
+    setCallingPlugin(true);
+
+    int16_t response = m_plugin->pluginFuncs()->event(m_instance, &cocoaEvent);
+
+    setCallingPlugin(false);
+    PluginView::setCurrentPluginView(0);
+
+    return response;
+}
+
 // ------------------- Miscellaneous  ------------------
 
 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf)

Modified: trunk/Source/WebCore/plugins/npapi.cpp (136123 => 136124)


--- trunk/Source/WebCore/plugins/npapi.cpp	2012-11-29 13:15:23 UTC (rev 136123)
+++ trunk/Source/WebCore/plugins/npapi.cpp	2012-11-29 13:25:53 UTC (rev 136124)
@@ -199,3 +199,14 @@
 {
     return pluginViewForInstance(instance)->getAuthenticationInfo(protocol, host, port, scheme, realm, username, ulen, password, plen);
 }
+
+NPError NPN_PopUpContextMenu(NPP instance, NPMenu* menu)
+{
+#if PLATFORM(QT) && defined(XP_MACOSX)
+    PluginView* plugin = pluginViewForInstance(instance);
+    plugin->popUpContextMenu(menu);
+    return NPERR_NO_ERROR;
+#else
+    return NPERR_NO_ERROR;
+#endif // PLATFORM(QT) && defined(XP_MACOSX)
+}

Modified: trunk/Source/WebCore/plugins/npapi.h (136123 => 136124)


--- trunk/Source/WebCore/plugins/npapi.h	2012-11-29 13:15:23 UTC (rev 136123)
+++ trunk/Source/WebCore/plugins/npapi.h	2012-11-29 13:25:53 UTC (rev 136124)
@@ -415,8 +415,10 @@
 
   NPNVSupportsWindowless = 17,
 
-  NPNVprivateModeBool = 18
+  NPNVprivateModeBool = 18,
 
+  NPNVsupportsAdvancedKeyHandling = 21
+
 #if defined(XP_MACOSX)
   /* Used for negotiating drawing models */
   , NPNVpluginDrawingModel = 1000
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to