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)