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