WebCore/plugins/mac/PluginViewMac.mm
changeset 0 4f2f89ce4247
child 2 303757a437d3
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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@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 "Bridge.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     show();
       
   231 
       
   232     // TODO: Implement null timer throttling depending on plugin activation
       
   233     m_nullEventTimer.set(new Timer<PluginView>(this, &PluginView::nullEventTimerFired));
       
   234     m_nullEventTimer->startRepeating(0.02);
       
   235 
       
   236     m_lastMousePos.h = m_lastMousePos.v = 0;
       
   237 
       
   238     return true;
       
   239 }
       
   240 
       
   241 void PluginView::platformDestroy()
       
   242 {
       
   243     if (platformPluginWidget())
       
   244         setPlatformPluginWidget(0);
       
   245     else {
       
   246         CGContextRelease(m_contextRef);
       
   247 #ifndef NP_NO_CARBON
       
   248         if (m_fakeWindow)
       
   249             DisposeWindow(m_fakeWindow);
       
   250 #endif
       
   251     }
       
   252 }
       
   253 
       
   254 // Used before the plugin view has been initialized properly, and as a
       
   255 // fallback for variables that do not require a view to resolve.
       
   256 bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result)
       
   257 {
       
   258     switch (variable) {
       
   259     case NPNVToolkit:
       
   260         *static_cast<uint32_t*>(value) = 0;
       
   261         *result = NPERR_NO_ERROR;
       
   262         return true;
       
   263 
       
   264     case NPNVjavascriptEnabledBool:
       
   265         *static_cast<NPBool*>(value) = true;
       
   266         *result = NPERR_NO_ERROR;
       
   267         return true;
       
   268 
       
   269 #ifndef NP_NO_CARBON
       
   270     case NPNVsupportsCarbonBool:
       
   271         *static_cast<NPBool*>(value) = true;
       
   272         *result = NPERR_NO_ERROR;
       
   273         return true;
       
   274 
       
   275 #endif
       
   276     case NPNVsupportsCocoaBool:
       
   277         *static_cast<NPBool*>(value) = false;
       
   278         *result = NPERR_NO_ERROR;
       
   279         return true;
       
   280 
       
   281     // CoreGraphics is the only drawing model we support
       
   282     case NPNVsupportsCoreGraphicsBool:
       
   283         *static_cast<NPBool*>(value) = true;
       
   284         *result = NPERR_NO_ERROR;
       
   285         return true;
       
   286 
       
   287 #ifndef NP_NO_QUICKDRAW
       
   288     // QuickDraw is deprecated in 10.5 and not supported on 64-bit
       
   289     case NPNVsupportsQuickDrawBool:
       
   290 #endif
       
   291     case NPNVsupportsOpenGLBool:
       
   292     case NPNVsupportsCoreAnimationBool:
       
   293         *static_cast<NPBool*>(value) = false;
       
   294         *result = NPERR_NO_ERROR;
       
   295         return true;
       
   296 
       
   297     default:
       
   298         return false;
       
   299     }
       
   300 }
       
   301 
       
   302 // Used only for variables that need a view to resolve
       
   303 bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* error)
       
   304 {
       
   305     return false;
       
   306 }
       
   307 
       
   308 void PluginView::setParent(ScrollView* parent)
       
   309 {
       
   310     LOG(Plugins, "PluginView::setParent(%p)", parent);
       
   311 
       
   312     Widget::setParent(parent);
       
   313 
       
   314     if (parent)
       
   315         init();
       
   316 }
       
   317 
       
   318 // -------------- Geometry and painting ----------------
       
   319 
       
   320 void PluginView::show()
       
   321 {
       
   322     LOG(Plugins, "PluginView::show()");
       
   323 
       
   324     setSelfVisible(true);
       
   325 
       
   326     Widget::show();
       
   327 }
       
   328 
       
   329 void PluginView::hide()
       
   330 {
       
   331     LOG(Plugins, "PluginView::hide()");
       
   332 
       
   333     setSelfVisible(false);
       
   334 
       
   335     Widget::hide();
       
   336 }
       
   337 
       
   338 void PluginView::setFocus(bool focused)
       
   339 {
       
   340     LOG(Plugins, "PluginView::setFocus(%d)", focused);
       
   341     if (!focused) {
       
   342         Widget::setFocus(focused);
       
   343         return;
       
   344     }
       
   345 
       
   346     if (platformPluginWidget())
       
   347 #if PLATFORM(QT)
       
   348        platformPluginWidget()->setFocus(Qt::OtherFocusReason);
       
   349 #else
       
   350         platformPluginWidget()->SetFocus();
       
   351 #endif
       
   352    else
       
   353        Widget::setFocus(focused);
       
   354 
       
   355     // TODO: Also handle and pass on blur events (focus lost)
       
   356 
       
   357 #ifndef NP_NO_CARBON
       
   358     EventRecord record;
       
   359     record.what = getFocusEvent;
       
   360     record.message = 0;
       
   361     record.when = TickCount();
       
   362     record.where = globalMousePosForPlugin();
       
   363     record.modifiers = GetCurrentKeyModifiers();
       
   364 
       
   365     if (!dispatchNPEvent(record))
       
   366         LOG(Events, "PluginView::setFocus(%d): Focus event not accepted", focused);
       
   367 #endif
       
   368 }
       
   369 
       
   370 void PluginView::setParentVisible(bool visible)
       
   371 {
       
   372     if (isParentVisible() == visible)
       
   373         return;
       
   374 
       
   375     Widget::setParentVisible(visible);
       
   376 }
       
   377 
       
   378 void PluginView::setNPWindowRect(const IntRect&)
       
   379 {
       
   380     setNPWindowIfNeeded();
       
   381 }
       
   382 
       
   383 void PluginView::setNPWindowIfNeeded()
       
   384 {
       
   385     if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow)
       
   386         return;
       
   387 
       
   388     CGContextRef newContextRef = 0;
       
   389     WindowRef newWindowRef = 0;
       
   390     if (platformPluginWidget()) {
       
   391         newContextRef = cgHandleFor(platformPluginWidget());
       
   392         newWindowRef = nativeWindowFor(platformPluginWidget());
       
   393         m_npWindow.type = NPWindowTypeWindow;
       
   394     } else {
       
   395         newContextRef = m_contextRef;
       
   396         newWindowRef = m_fakeWindow;
       
   397         m_npWindow.type = NPWindowTypeDrawable;
       
   398     }
       
   399 
       
   400     if (!newContextRef || !newWindowRef)
       
   401         return;
       
   402 
       
   403     m_npWindow.window = (void*)&m_npCgContext;
       
   404 #ifndef NP_NO_CARBON
       
   405     m_npCgContext.window = newWindowRef;
       
   406 #endif
       
   407     m_npCgContext.context = newContextRef;
       
   408 
       
   409     m_npWindow.x = m_windowRect.x();
       
   410     m_npWindow.y = m_windowRect.y();
       
   411     m_npWindow.width = m_windowRect.width();
       
   412     m_npWindow.height = m_windowRect.height();
       
   413 
       
   414     // TODO: (also clip against scrollbars, etc.)
       
   415     m_npWindow.clipRect.left = max(0, m_windowRect.x());
       
   416     m_npWindow.clipRect.top = max(0, m_windowRect.y());
       
   417     m_npWindow.clipRect.right = m_windowRect.x() + m_windowRect.width();
       
   418     m_npWindow.clipRect.bottom = m_windowRect.y() + m_windowRect.height();
       
   419 
       
   420     LOG(Plugins, "PluginView::setNPWindowIfNeeded(): window=%p, context=%p,"
       
   421             " window.x:%d window.y:%d window.width:%d window.height:%d window.clipRect size:%dx%d",
       
   422             newWindowRef, newContextRef, m_npWindow.x, m_npWindow.y, m_npWindow.width, m_npWindow.height,
       
   423             m_npWindow.clipRect.right - m_npWindow.clipRect.left, m_npWindow.clipRect.bottom - m_npWindow.clipRect.top);
       
   424 
       
   425     PluginView::setCurrentPluginView(this);
       
   426     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
       
   427     setCallingPlugin(true);
       
   428     m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
       
   429     setCallingPlugin(false);
       
   430     PluginView::setCurrentPluginView(0);
       
   431 }
       
   432 
       
   433 void PluginView::updatePluginWidget()
       
   434 {
       
   435     if (!parent())
       
   436        return;
       
   437 
       
   438     ASSERT(parent()->isFrameView());
       
   439     FrameView* frameView = static_cast<FrameView*>(parent());
       
   440 
       
   441     IntRect oldWindowRect = m_windowRect;
       
   442     IntRect oldClipRect = m_clipRect;
       
   443 
       
   444     m_windowRect = frameView->contentsToWindow(frameRect());
       
   445     IntPoint offset = topLevelOffsetFor(platformPluginWidget());
       
   446     m_windowRect.move(offset.x(), offset.y());
       
   447 
       
   448     if (!platformPluginWidget()) {
       
   449         if (m_windowRect.size() != oldWindowRect.size()) {
       
   450             CGContextRelease(m_contextRef);
       
   451 #if PLATFORM(QT)
       
   452             m_pixmap = QPixmap(m_windowRect.size());
       
   453             m_pixmap.fill(Qt::transparent);
       
   454             m_contextRef = m_pixmap.isNull() ? 0 : qt_mac_cg_context(&m_pixmap);
       
   455 #endif
       
   456         }
       
   457     }
       
   458 
       
   459     m_clipRect = windowClipRect();
       
   460     m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
       
   461 
       
   462     if (platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect))
       
   463         setNPWindowIfNeeded();
       
   464 }
       
   465 
       
   466 void PluginView::paint(GraphicsContext* context, const IntRect& rect)
       
   467 {
       
   468     if (!m_isStarted || m_status != PluginStatusLoadedSuccessfully) {
       
   469         paintMissingPluginIcon(context, rect);
       
   470         return;
       
   471     }
       
   472 
       
   473     if (context->paintingDisabled())
       
   474         return;
       
   475 
       
   476     setNPWindowIfNeeded();
       
   477 
       
   478     CGContextRef cgContext = m_npCgContext.context;
       
   479     if (!cgContext)
       
   480         return;
       
   481 
       
   482     CGContextSaveGState(cgContext);
       
   483     if (platformPluginWidget()) {
       
   484         IntPoint offset = frameRect().location();
       
   485         CGContextTranslateCTM(cgContext, offset.x(), offset.y());
       
   486     }
       
   487 
       
   488     IntRect targetRect(frameRect());
       
   489     targetRect.intersects(rect);
       
   490 
       
   491     // clip the context so that plugin only updates the interested area.
       
   492     CGRect r;
       
   493     r.origin.x = targetRect.x() - frameRect().x();
       
   494     r.origin.y = targetRect.y() - frameRect().y();
       
   495     r.size.width = targetRect.width();
       
   496     r.size.height = targetRect.height();
       
   497     CGContextClipToRect(cgContext, r);
       
   498 
       
   499     if (!platformPluginWidget() && m_isTransparent) { // clean the pixmap in transparent mode
       
   500 #if PLATFORM(QT)
       
   501         QPainter painter(&m_pixmap);
       
   502         painter.setCompositionMode(QPainter::CompositionMode_Clear);
       
   503         painter.fillRect(QRectF(r.origin.x, r.origin.y, r.size.width, r.size.height), Qt::transparent);
       
   504 #endif
       
   505     }
       
   506 
       
   507 #ifndef NP_NO_CARBON
       
   508     EventRecord event;
       
   509     event.what = updateEvt;
       
   510     event.message = (long unsigned int)m_npCgContext.window;
       
   511     event.when = TickCount();
       
   512     event.where.h = 0;
       
   513     event.where.v = 0;
       
   514     event.modifiers = GetCurrentKeyModifiers();
       
   515 
       
   516     if (!dispatchNPEvent(event))
       
   517         LOG(Events, "PluginView::paint(): Paint event not accepted");
       
   518 #endif
       
   519 
       
   520     CGContextRestoreGState(cgContext);
       
   521 
       
   522     if (!platformPluginWidget()) {
       
   523 #if PLATFORM(QT)
       
   524         QPainter* painter = context->platformContext();
       
   525         painter->drawPixmap(targetRect.x(), targetRect.y(), m_pixmap, 
       
   526                             targetRect.x() - frameRect().x(), targetRect.y() - frameRect().y(), targetRect.width(), targetRect.height());
       
   527 #endif
       
   528     }
       
   529 }
       
   530 
       
   531 void PluginView::invalidateRect(const IntRect& rect)
       
   532 {
       
   533     if (platformPluginWidget())
       
   534 #if PLATFORM(QT)
       
   535         platformPluginWidget()->update(convertToContainingWindow(rect));
       
   536 #else
       
   537         platformPluginWidget()->RefreshRect(convertToContainingWindow(rect));
       
   538 #endif
       
   539     else
       
   540         invalidateWindowlessPluginRect(rect);
       
   541 }
       
   542 
       
   543 void PluginView::invalidateRect(NPRect* rect)
       
   544 {
       
   545     IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
       
   546     invalidateRect(r);
       
   547 }
       
   548 
       
   549 void PluginView::invalidateRegion(NPRegion region)
       
   550 {
       
   551     // TODO: optimize
       
   552     invalidate();
       
   553 }
       
   554 
       
   555 void PluginView::forceRedraw()
       
   556 {
       
   557     notImplemented();
       
   558 }
       
   559 
       
   560 
       
   561 // ----------------- Event handling --------------------
       
   562 
       
   563 void PluginView::handleMouseEvent(MouseEvent* event)
       
   564 {
       
   565     if (!m_isStarted)
       
   566         return;
       
   567 
       
   568 #ifndef NP_NO_CARBON
       
   569     EventRecord record;
       
   570 
       
   571     if (event->type() == eventNames().mousemoveEvent) {
       
   572         // Mouse movement is handled by null timer events
       
   573         m_lastMousePos = mousePosForPlugin(event);
       
   574         return;
       
   575     } else if (event->type() == eventNames().mouseoverEvent) {
       
   576         record.what = adjustCursorEvent;
       
   577     } else if (event->type() == eventNames().mouseoutEvent) {
       
   578         record.what = adjustCursorEvent;
       
   579     } else if (event->type() == eventNames().mousedownEvent) {
       
   580         record.what = mouseDown;
       
   581         // The plugin needs focus to receive keyboard events
       
   582         if (Page* page = m_parentFrame->page())
       
   583             page->focusController()->setFocusedFrame(m_parentFrame);
       
   584         m_parentFrame->document()->setFocusedNode(m_element);
       
   585     } else if (event->type() == eventNames().mouseupEvent) {
       
   586         record.what = mouseUp;
       
   587     } else {
       
   588         return;
       
   589     }
       
   590     record.where = mousePosForPlugin(event);
       
   591     record.modifiers = modifiersForEvent(event);
       
   592 
       
   593     if (!event->buttonDown())
       
   594         record.modifiers |= btnState;
       
   595 
       
   596     if (event->button() == 2)
       
   597         record.modifiers |= controlKey;
       
   598 
       
   599     if (!dispatchNPEvent(record)) {
       
   600         if (record.what == adjustCursorEvent)
       
   601             return; // Signals that the plugin wants a normal cursor
       
   602 
       
   603         LOG(Events, "PluginView::handleMouseEvent(): Mouse event type %d at %d,%d not accepted",
       
   604                 record.what, record.where.h, record.where.v);
       
   605     } else {
       
   606         event->setDefaultHandled();
       
   607     }
       
   608 #endif
       
   609 }
       
   610 
       
   611 void PluginView::handleKeyboardEvent(KeyboardEvent* event)
       
   612 {
       
   613     if (!m_isStarted)
       
   614         return;
       
   615 
       
   616     LOG(Plugins, "PluginView::handleKeyboardEvent() ----------------- ");
       
   617 
       
   618     LOG(Plugins, "PV::hKE(): KE.keyCode: 0x%02X, KE.charCode: %d",
       
   619             event->keyCode(), event->charCode());
       
   620 
       
   621 #ifndef NP_NO_CARBON
       
   622     EventRecord record;
       
   623 
       
   624     if (event->type() == eventNames().keydownEvent) {
       
   625         // This event is the result of a PlatformKeyboardEvent::KeyDown which
       
   626         // was disambiguated into a PlatformKeyboardEvent::RawKeyDown. Since
       
   627         // we don't have access to the text here, we return, and wait for the
       
   628         // corresponding event based on PlatformKeyboardEvent::Char.
       
   629         return;
       
   630     } else if (event->type() == eventNames().keypressEvent) {
       
   631         // Which would be this one. This event was disambiguated from the same
       
   632         // PlatformKeyboardEvent::KeyDown, but to a PlatformKeyboardEvent::Char,
       
   633         // which retains the text from the original event. So, we can safely pass
       
   634         // on the event as a key-down event to the plugin.
       
   635         record.what = keyDown;
       
   636     } else if (event->type() == eventNames().keyupEvent) {
       
   637         // PlatformKeyboardEvent::KeyUp events always have the text, so nothing
       
   638         // fancy here.
       
   639         record.what = keyUp;
       
   640     } else {
       
   641         return;
       
   642     }
       
   643 
       
   644     const PlatformKeyboardEvent* platformEvent = event->keyEvent();
       
   645     int keyCode = platformEvent->nativeVirtualKeyCode();
       
   646 
       
   647     const String text = platformEvent->text();
       
   648     if (text.length() < 1) {
       
   649         event->setDefaultHandled();
       
   650         return;
       
   651     }
       
   652 
       
   653     WTF::RetainPtr<CFStringRef> cfText(WTF::AdoptCF, text.createCFString());
       
   654 
       
   655     LOG(Plugins, "PV::hKE(): PKE.text: %s, PKE.unmodifiedText: %s, PKE.keyIdentifier: %s",
       
   656             text.ascii().data(), platformEvent->unmodifiedText().ascii().data(),
       
   657             platformEvent->keyIdentifier().ascii().data());
       
   658 
       
   659     char charCodes[2] = { 0, 0 };
       
   660     if (!CFStringGetCString(cfText.get(), charCodes, 2, CFStringGetSystemEncoding())) {
       
   661         LOG_ERROR("Could not resolve character code using system encoding.");
       
   662         event->setDefaultHandled();
       
   663         return;
       
   664     }
       
   665 
       
   666     record.where = globalMousePosForPlugin();
       
   667     record.modifiers = modifiersForEvent(event);
       
   668     record.message = ((keyCode & 0xFF) << 8) | (charCodes[0] & 0xFF);
       
   669     record.when = TickCount();
       
   670 
       
   671     LOG(Plugins, "PV::hKE(): record.modifiers: %d", record.modifiers);
       
   672 
       
   673 #if PLATFORM(QT)
       
   674     LOG(Plugins, "PV::hKE(): PKE.qtEvent()->nativeVirtualKey: 0x%02X, charCode: %d",
       
   675                keyCode, int(uchar(charCodes[0])));
       
   676 #endif
       
   677 
       
   678     if (!dispatchNPEvent(record))
       
   679         LOG(Events, "PluginView::handleKeyboardEvent(): Keyboard event type %d not accepted", record.what);
       
   680     else
       
   681         event->setDefaultHandled();
       
   682 #endif
       
   683 }
       
   684 
       
   685 #ifndef NP_NO_CARBON
       
   686 void PluginView::nullEventTimerFired(Timer<PluginView>*)
       
   687 {
       
   688     EventRecord record;
       
   689 
       
   690     record.what = nullEvent;
       
   691     record.message = 0;
       
   692     record.when = TickCount();
       
   693     record.where = m_lastMousePos;
       
   694     record.modifiers = GetCurrentKeyModifiers();
       
   695     if (!Button())
       
   696         record.modifiers |= btnState;
       
   697 
       
   698     if (!dispatchNPEvent(record))
       
   699         LOG(Events, "PluginView::nullEventTimerFired(): Null event not accepted");
       
   700 }
       
   701 #endif
       
   702 
       
   703 #ifndef NP_NO_CARBON
       
   704 static int modifiersForEvent(UIEventWithKeyState* event)
       
   705 {
       
   706     int modifiers = 0;
       
   707 
       
   708     if (event->ctrlKey())
       
   709         modifiers |= controlKey;
       
   710 
       
   711     if (event->altKey())
       
   712         modifiers |= optionKey;
       
   713 
       
   714     if (event->metaKey())
       
   715         modifiers |= cmdKey;
       
   716 
       
   717     if (event->shiftKey())
       
   718         modifiers |= shiftKey;
       
   719 
       
   720      return modifiers;
       
   721 }
       
   722 #endif
       
   723 
       
   724 #ifndef NP_NO_CARBON
       
   725 static bool tigerOrBetter()
       
   726 {
       
   727     static SInt32 systemVersion = 0;
       
   728 
       
   729     if (!systemVersion) {
       
   730         if (Gestalt(gestaltSystemVersion, &systemVersion) != noErr)
       
   731             return false;
       
   732     }
       
   733 
       
   734     return systemVersion >= 0x1040;
       
   735 }
       
   736 #endif
       
   737 
       
   738 #ifndef NP_NO_CARBON
       
   739 Point PluginView::globalMousePosForPlugin() const
       
   740 {
       
   741     Point pos;
       
   742     GetGlobalMouse(&pos);
       
   743 
       
   744     float scaleFactor = tigerOrBetter() ? HIGetScaleFactor() : 1;
       
   745 
       
   746     pos.h = short(pos.h * scaleFactor);
       
   747     pos.v = short(pos.v * scaleFactor);
       
   748 
       
   749 #if PLATFORM(WX)
       
   750     // make sure the titlebar/toolbar size is included
       
   751     WindowRef windowRef = nativeWindowFor(platformPluginWidget());
       
   752     ::Rect content, structure;
       
   753 
       
   754     GetWindowBounds(windowRef, kWindowStructureRgn, &structure);
       
   755     GetWindowBounds(windowRef, kWindowContentRgn, &content);
       
   756 
       
   757     int top = content.top  - structure.top;
       
   758     pos.v -= top;
       
   759 #endif
       
   760 
       
   761     return pos;
       
   762 }
       
   763 #endif
       
   764 
       
   765 #ifndef NP_NO_CARBON
       
   766 Point PluginView::mousePosForPlugin(MouseEvent* event) const
       
   767 {
       
   768     ASSERT(event);
       
   769     if (platformPluginWidget())
       
   770         return globalMousePosForPlugin();
       
   771 
       
   772     if (event->button() == 2) {
       
   773         // always pass the global position for right-click since Flash uses it to position the context menu
       
   774         return globalMousePosForPlugin();
       
   775     }
       
   776 
       
   777     Point pos;
       
   778     IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation()));
       
   779     pos.h = postZoomPos.x() + m_windowRect.x();
       
   780     // The number 22 is the height of the title bar. As to why it figures in the calculation below
       
   781     // is left as an exercise to the reader :-)
       
   782     pos.v = postZoomPos.y() + m_windowRect.y() - 22;
       
   783     return pos;
       
   784 }
       
   785 #endif
       
   786 
       
   787 #ifndef NP_NO_CARBON
       
   788 bool PluginView::dispatchNPEvent(NPEvent& event)
       
   789 {
       
   790     PluginView::setCurrentPluginView(this);
       
   791     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
       
   792     setCallingPlugin(true);
       
   793 
       
   794     bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event);
       
   795 
       
   796     setCallingPlugin(false);
       
   797     PluginView::setCurrentPluginView(0);
       
   798     return accepted;
       
   799 }
       
   800 #endif
       
   801 
       
   802 // ------------------- Miscellaneous  ------------------
       
   803 
       
   804 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf)
       
   805 {
       
   806     String filename(buf, len);
       
   807 
       
   808     if (filename.startsWith("file:///"))
       
   809         filename = filename.substring(8);
       
   810 
       
   811     if (!fileExists(filename))
       
   812         return NPERR_FILE_NOT_FOUND;
       
   813 
       
   814     FILE* fileHandle = fopen((filename.utf8()).data(), "r");
       
   815 
       
   816     if (fileHandle == 0)
       
   817         return NPERR_FILE_NOT_FOUND;
       
   818 
       
   819     int bytesRead = fread(buffer.data(), 1, 0, fileHandle);
       
   820 
       
   821     fclose(fileHandle);
       
   822 
       
   823     if (bytesRead <= 0)
       
   824         return NPERR_FILE_NOT_FOUND;
       
   825 
       
   826     return NPERR_NO_ERROR;
       
   827 }
       
   828 
       
   829 void PluginView::halt()
       
   830 {
       
   831 }
       
   832 
       
   833 void PluginView::restart()
       
   834 {
       
   835 }
       
   836 
       
   837 } // namespace WebCore