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