dom/plugins/base/nsPluginInstanceOwner.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 // vim:set ts=2 sts=2 sw=2 et cin:
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifdef MOZ_X11
michael@0 8 #include <cairo-xlib.h>
michael@0 9 #include "gfxXlibSurface.h"
michael@0 10 /* X headers suck */
michael@0 11 enum { XKeyPress = KeyPress };
michael@0 12 #include "mozilla/X11Util.h"
michael@0 13 using mozilla::DefaultXDisplay;
michael@0 14 #endif
michael@0 15
michael@0 16 #include "nsPluginInstanceOwner.h"
michael@0 17 #include "nsIRunnable.h"
michael@0 18 #include "nsContentUtils.h"
michael@0 19 #include "nsRect.h"
michael@0 20 #include "nsSize.h"
michael@0 21 #include "nsDisplayList.h"
michael@0 22 #include "ImageLayers.h"
michael@0 23 #include "SharedTextureImage.h"
michael@0 24 #include "nsObjectFrame.h"
michael@0 25 #include "nsIPluginDocument.h"
michael@0 26 #include "nsIStringStream.h"
michael@0 27 #include "nsNetUtil.h"
michael@0 28 #include "mozilla/Preferences.h"
michael@0 29 #include "nsILinkHandler.h"
michael@0 30 #include "nsIDocShellTreeItem.h"
michael@0 31 #include "nsIWebBrowserChrome.h"
michael@0 32 #include "nsLayoutUtils.h"
michael@0 33 #include "nsIPluginWidget.h"
michael@0 34 #include "nsViewManager.h"
michael@0 35 #include "nsIDocShellTreeOwner.h"
michael@0 36 #include "nsIDOMHTMLObjectElement.h"
michael@0 37 #include "nsIAppShell.h"
michael@0 38 #include "nsIDOMHTMLAppletElement.h"
michael@0 39 #include "nsIObjectLoadingContent.h"
michael@0 40 #include "nsAttrName.h"
michael@0 41 #include "nsIFocusManager.h"
michael@0 42 #include "nsFocusManager.h"
michael@0 43 #include "nsIDOMDragEvent.h"
michael@0 44 #include "nsIScrollableFrame.h"
michael@0 45 #include "nsIDocShell.h"
michael@0 46 #include "ImageContainer.h"
michael@0 47 #include "nsIDOMHTMLCollection.h"
michael@0 48 #include "GLContext.h"
michael@0 49 #include "GLSharedHandleHelpers.h"
michael@0 50 #include "nsIContentInlines.h"
michael@0 51 #include "mozilla/MiscEvents.h"
michael@0 52 #include "mozilla/MouseEvents.h"
michael@0 53 #include "mozilla/TextEvents.h"
michael@0 54
michael@0 55 #include "nsContentCID.h"
michael@0 56 #include "nsWidgetsCID.h"
michael@0 57 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
michael@0 58 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
michael@0 59
michael@0 60 #ifdef XP_WIN
michael@0 61 #include <wtypes.h>
michael@0 62 #include <winuser.h>
michael@0 63 #endif
michael@0 64
michael@0 65 #ifdef XP_MACOSX
michael@0 66 #include <Carbon/Carbon.h>
michael@0 67 #include "nsPluginUtilsOSX.h"
michael@0 68 #endif
michael@0 69
michael@0 70 #if (MOZ_WIDGET_GTK == 2)
michael@0 71 #include <gdk/gdk.h>
michael@0 72 #include <gdk/gdkx.h>
michael@0 73 #include <gtk/gtk.h>
michael@0 74 #endif
michael@0 75
michael@0 76 #ifdef MOZ_WIDGET_ANDROID
michael@0 77 #include "ANPBase.h"
michael@0 78 #include "AndroidBridge.h"
michael@0 79 #include "nsWindow.h"
michael@0 80
michael@0 81 static nsPluginInstanceOwner* sFullScreenInstance = nullptr;
michael@0 82
michael@0 83 using namespace mozilla::dom;
michael@0 84
michael@0 85 #include <android/log.h>
michael@0 86 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
michael@0 87 #endif
michael@0 88
michael@0 89 using namespace mozilla;
michael@0 90 using namespace mozilla::layers;
michael@0 91
michael@0 92 // special class for handeling DOM context menu events because for
michael@0 93 // some reason it starves other mouse events if implemented on the
michael@0 94 // same class
michael@0 95 class nsPluginDOMContextMenuListener : public nsIDOMEventListener
michael@0 96 {
michael@0 97 public:
michael@0 98 nsPluginDOMContextMenuListener(nsIContent* aContent);
michael@0 99 virtual ~nsPluginDOMContextMenuListener();
michael@0 100
michael@0 101 NS_DECL_ISUPPORTS
michael@0 102 NS_DECL_NSIDOMEVENTLISTENER
michael@0 103
michael@0 104 void Destroy(nsIContent* aContent);
michael@0 105
michael@0 106 nsEventStatus ProcessEvent(const WidgetGUIEvent& anEvent)
michael@0 107 {
michael@0 108 return nsEventStatus_eConsumeNoDefault;
michael@0 109 }
michael@0 110 };
michael@0 111
michael@0 112 class AsyncPaintWaitEvent : public nsRunnable
michael@0 113 {
michael@0 114 public:
michael@0 115 AsyncPaintWaitEvent(nsIContent* aContent, bool aFinished) :
michael@0 116 mContent(aContent), mFinished(aFinished)
michael@0 117 {
michael@0 118 }
michael@0 119
michael@0 120 NS_IMETHOD Run()
michael@0 121 {
michael@0 122 nsContentUtils::DispatchTrustedEvent(mContent->OwnerDoc(), mContent,
michael@0 123 mFinished ? NS_LITERAL_STRING("MozPaintWaitFinished") : NS_LITERAL_STRING("MozPaintWait"),
michael@0 124 true, true);
michael@0 125 return NS_OK;
michael@0 126 }
michael@0 127
michael@0 128 private:
michael@0 129 nsCOMPtr<nsIContent> mContent;
michael@0 130 bool mFinished;
michael@0 131 };
michael@0 132
michael@0 133 void
michael@0 134 nsPluginInstanceOwner::NotifyPaintWaiter(nsDisplayListBuilder* aBuilder)
michael@0 135 {
michael@0 136 // This is notification for reftests about async plugin paint start
michael@0 137 if (!mWaitingForPaint && !IsUpToDate() && aBuilder->ShouldSyncDecodeImages()) {
michael@0 138 nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(mContent, false);
michael@0 139 // Run this event as soon as it's safe to do so, since listeners need to
michael@0 140 // receive it immediately
michael@0 141 mWaitingForPaint = nsContentUtils::AddScriptRunner(event);
michael@0 142 }
michael@0 143 }
michael@0 144
michael@0 145 already_AddRefed<ImageContainer>
michael@0 146 nsPluginInstanceOwner::GetImageContainer()
michael@0 147 {
michael@0 148 if (!mInstance)
michael@0 149 return nullptr;
michael@0 150
michael@0 151 nsRefPtr<ImageContainer> container;
michael@0 152
michael@0 153 #if MOZ_WIDGET_ANDROID
michael@0 154 // Right now we only draw with Gecko layers on Honeycomb and higher. See Paint()
michael@0 155 // for what we do on other versions.
michael@0 156 if (AndroidBridge::Bridge()->GetAPIVersion() < 11)
michael@0 157 return nullptr;
michael@0 158
michael@0 159 LayoutDeviceRect r = GetPluginRect();
michael@0 160
michael@0 161 // NotifySize() causes Flash to do a bunch of stuff like ask for surfaces to render
michael@0 162 // into, set y-flip flags, etc, so we do this at the beginning.
michael@0 163 gfxSize resolution = mObjectFrame->PresContext()->PresShell()->GetCumulativeResolution();
michael@0 164 ScreenSize screenSize = (r * LayoutDeviceToScreenScale(resolution.width, resolution.height)).Size();
michael@0 165 mInstance->NotifySize(nsIntSize(screenSize.width, screenSize.height));
michael@0 166
michael@0 167 container = LayerManager::CreateImageContainer();
michael@0 168
michael@0 169 nsRefPtr<Image> img = container->CreateImage(ImageFormat::SHARED_TEXTURE);
michael@0 170
michael@0 171 SharedTextureImage::Data data;
michael@0 172 data.mSize = gfx::IntSize(r.width, r.height);
michael@0 173 data.mHandle = mInstance->CreateSharedHandle();
michael@0 174 data.mShareType = mozilla::gl::SharedTextureShareType::SameProcess;
michael@0 175 data.mInverted = mInstance->Inverted();
michael@0 176
michael@0 177 SharedTextureImage* pluginImage = static_cast<SharedTextureImage*>(img.get());
michael@0 178 pluginImage->SetData(data);
michael@0 179
michael@0 180 container->SetCurrentImageInTransaction(img);
michael@0 181
michael@0 182 return container.forget();
michael@0 183 #endif
michael@0 184
michael@0 185 mInstance->GetImageContainer(getter_AddRefs(container));
michael@0 186 return container.forget();
michael@0 187 }
michael@0 188
michael@0 189 void
michael@0 190 nsPluginInstanceOwner::SetBackgroundUnknown()
michael@0 191 {
michael@0 192 if (mInstance) {
michael@0 193 mInstance->SetBackgroundUnknown();
michael@0 194 }
michael@0 195 }
michael@0 196
michael@0 197 already_AddRefed<gfxContext>
michael@0 198 nsPluginInstanceOwner::BeginUpdateBackground(const nsIntRect& aRect)
michael@0 199 {
michael@0 200 nsIntRect rect = aRect;
michael@0 201 nsRefPtr<gfxContext> ctx;
michael@0 202 if (mInstance &&
michael@0 203 NS_SUCCEEDED(mInstance->BeginUpdateBackground(&rect, getter_AddRefs(ctx)))) {
michael@0 204 return ctx.forget();
michael@0 205 }
michael@0 206 return nullptr;
michael@0 207 }
michael@0 208
michael@0 209 void
michael@0 210 nsPluginInstanceOwner::EndUpdateBackground(gfxContext* aContext,
michael@0 211 const nsIntRect& aRect)
michael@0 212 {
michael@0 213 nsIntRect rect = aRect;
michael@0 214 if (mInstance) {
michael@0 215 mInstance->EndUpdateBackground(aContext, &rect);
michael@0 216 }
michael@0 217 }
michael@0 218
michael@0 219 bool
michael@0 220 nsPluginInstanceOwner::UseAsyncRendering()
michael@0 221 {
michael@0 222 #ifdef XP_MACOSX
michael@0 223 if (mUseAsyncRendering) {
michael@0 224 return true;
michael@0 225 }
michael@0 226 #endif
michael@0 227
michael@0 228 bool isOOP;
michael@0 229 bool result = (mInstance &&
michael@0 230 NS_SUCCEEDED(mInstance->GetIsOOP(&isOOP)) && isOOP
michael@0 231 #ifndef XP_MACOSX
michael@0 232 && (!mPluginWindow ||
michael@0 233 mPluginWindow->type == NPWindowTypeDrawable)
michael@0 234 #endif
michael@0 235 );
michael@0 236
michael@0 237 #ifdef XP_MACOSX
michael@0 238 if (result) {
michael@0 239 mUseAsyncRendering = true;
michael@0 240 }
michael@0 241 #endif
michael@0 242
michael@0 243 return result;
michael@0 244 }
michael@0 245
michael@0 246 nsIntSize
michael@0 247 nsPluginInstanceOwner::GetCurrentImageSize()
michael@0 248 {
michael@0 249 nsIntSize size(0,0);
michael@0 250 if (mInstance) {
michael@0 251 mInstance->GetImageSize(&size);
michael@0 252 }
michael@0 253 return size;
michael@0 254 }
michael@0 255
michael@0 256 nsPluginInstanceOwner::nsPluginInstanceOwner()
michael@0 257 {
michael@0 258 // create nsPluginNativeWindow object, it is derived from NPWindow
michael@0 259 // struct and allows to manipulate native window procedure
michael@0 260 nsCOMPtr<nsIPluginHost> pluginHostCOM = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
michael@0 261 mPluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
michael@0 262 if (mPluginHost)
michael@0 263 mPluginHost->NewPluginNativeWindow(&mPluginWindow);
michael@0 264 else
michael@0 265 mPluginWindow = nullptr;
michael@0 266
michael@0 267 mObjectFrame = nullptr;
michael@0 268 mContent = nullptr;
michael@0 269 mWidgetCreationComplete = false;
michael@0 270 #ifdef XP_MACOSX
michael@0 271 memset(&mCGPluginPortCopy, 0, sizeof(NP_CGContext));
michael@0 272 mInCGPaintLevel = 0;
michael@0 273 mSentInitialTopLevelWindowEvent = false;
michael@0 274 mColorProfile = nullptr;
michael@0 275 mPluginPortChanged = false;
michael@0 276 #endif
michael@0 277 mContentFocused = false;
michael@0 278 mWidgetVisible = true;
michael@0 279 mPluginWindowVisible = false;
michael@0 280 mPluginDocumentActiveState = true;
michael@0 281 mNumCachedAttrs = 0;
michael@0 282 mNumCachedParams = 0;
michael@0 283 mCachedAttrParamNames = nullptr;
michael@0 284 mCachedAttrParamValues = nullptr;
michael@0 285 mLastMouseDownButtonType = -1;
michael@0 286
michael@0 287 #ifdef XP_MACOSX
michael@0 288 #ifndef NP_NO_CARBON
michael@0 289 // We don't support Carbon, but it is still the default model for i386 NPAPI.
michael@0 290 mEventModel = NPEventModelCarbon;
michael@0 291 #else
michael@0 292 mEventModel = NPEventModelCocoa;
michael@0 293 #endif
michael@0 294 mUseAsyncRendering = false;
michael@0 295 #endif
michael@0 296
michael@0 297 mWaitingForPaint = false;
michael@0 298
michael@0 299 #ifdef MOZ_WIDGET_ANDROID
michael@0 300 mFullScreen = false;
michael@0 301 mJavaView = nullptr;
michael@0 302 #endif
michael@0 303 }
michael@0 304
michael@0 305 nsPluginInstanceOwner::~nsPluginInstanceOwner()
michael@0 306 {
michael@0 307 int32_t cnt;
michael@0 308
michael@0 309 if (mWaitingForPaint) {
michael@0 310 // We don't care when the event is dispatched as long as it's "soon",
michael@0 311 // since whoever needs it will be waiting for it.
michael@0 312 nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(mContent, true);
michael@0 313 NS_DispatchToMainThread(event);
michael@0 314 }
michael@0 315
michael@0 316 mObjectFrame = nullptr;
michael@0 317
michael@0 318 for (cnt = 0; cnt < (mNumCachedAttrs + 1 + mNumCachedParams); cnt++) {
michael@0 319 if (mCachedAttrParamNames && mCachedAttrParamNames[cnt]) {
michael@0 320 NS_Free(mCachedAttrParamNames[cnt]);
michael@0 321 mCachedAttrParamNames[cnt] = nullptr;
michael@0 322 }
michael@0 323
michael@0 324 if (mCachedAttrParamValues && mCachedAttrParamValues[cnt]) {
michael@0 325 NS_Free(mCachedAttrParamValues[cnt]);
michael@0 326 mCachedAttrParamValues[cnt] = nullptr;
michael@0 327 }
michael@0 328 }
michael@0 329
michael@0 330 if (mCachedAttrParamNames) {
michael@0 331 NS_Free(mCachedAttrParamNames);
michael@0 332 mCachedAttrParamNames = nullptr;
michael@0 333 }
michael@0 334
michael@0 335 if (mCachedAttrParamValues) {
michael@0 336 NS_Free(mCachedAttrParamValues);
michael@0 337 mCachedAttrParamValues = nullptr;
michael@0 338 }
michael@0 339
michael@0 340 PLUG_DeletePluginNativeWindow(mPluginWindow);
michael@0 341 mPluginWindow = nullptr;
michael@0 342
michael@0 343 #ifdef MOZ_WIDGET_ANDROID
michael@0 344 RemovePluginView();
michael@0 345 #endif
michael@0 346
michael@0 347 if (mInstance) {
michael@0 348 mInstance->SetOwner(nullptr);
michael@0 349 }
michael@0 350 }
michael@0 351
michael@0 352 NS_IMPL_ISUPPORTS(nsPluginInstanceOwner,
michael@0 353 nsIPluginInstanceOwner,
michael@0 354 nsIDOMEventListener,
michael@0 355 nsIPrivacyTransitionObserver,
michael@0 356 nsISupportsWeakReference)
michael@0 357
michael@0 358 nsresult
michael@0 359 nsPluginInstanceOwner::SetInstance(nsNPAPIPluginInstance *aInstance)
michael@0 360 {
michael@0 361 NS_ASSERTION(!mInstance || !aInstance, "mInstance should only be set or unset!");
michael@0 362
michael@0 363 // If we're going to null out mInstance after use, be sure to call
michael@0 364 // mInstance->SetOwner(nullptr) here, since it now won't be called
michael@0 365 // from our destructor. This fixes bug 613376.
michael@0 366 if (mInstance && !aInstance) {
michael@0 367 mInstance->SetOwner(nullptr);
michael@0 368
michael@0 369 #ifdef MOZ_WIDGET_ANDROID
michael@0 370 RemovePluginView();
michael@0 371 #endif
michael@0 372 }
michael@0 373
michael@0 374 mInstance = aInstance;
michael@0 375
michael@0 376 nsCOMPtr<nsIDocument> doc;
michael@0 377 GetDocument(getter_AddRefs(doc));
michael@0 378 if (doc) {
michael@0 379 nsCOMPtr<nsPIDOMWindow> domWindow = doc->GetWindow();
michael@0 380 if (domWindow) {
michael@0 381 nsCOMPtr<nsIDocShell> docShell = domWindow->GetDocShell();
michael@0 382 if (docShell)
michael@0 383 docShell->AddWeakPrivacyTransitionObserver(this);
michael@0 384 }
michael@0 385 }
michael@0 386
michael@0 387 return NS_OK;
michael@0 388 }
michael@0 389
michael@0 390 NS_IMETHODIMP nsPluginInstanceOwner::GetWindow(NPWindow *&aWindow)
michael@0 391 {
michael@0 392 NS_ASSERTION(mPluginWindow, "the plugin window object being returned is null");
michael@0 393 aWindow = mPluginWindow;
michael@0 394 return NS_OK;
michael@0 395 }
michael@0 396
michael@0 397 NS_IMETHODIMP nsPluginInstanceOwner::GetMode(int32_t *aMode)
michael@0 398 {
michael@0 399 nsCOMPtr<nsIDocument> doc;
michael@0 400 nsresult rv = GetDocument(getter_AddRefs(doc));
michael@0 401 nsCOMPtr<nsIPluginDocument> pDoc (do_QueryInterface(doc));
michael@0 402
michael@0 403 if (pDoc) {
michael@0 404 *aMode = NP_FULL;
michael@0 405 } else {
michael@0 406 *aMode = NP_EMBED;
michael@0 407 }
michael@0 408
michael@0 409 return rv;
michael@0 410 }
michael@0 411
michael@0 412 NS_IMETHODIMP nsPluginInstanceOwner::GetAttributes(uint16_t& n,
michael@0 413 const char*const*& names,
michael@0 414 const char*const*& values)
michael@0 415 {
michael@0 416 nsresult rv = EnsureCachedAttrParamArrays();
michael@0 417 NS_ENSURE_SUCCESS(rv, rv);
michael@0 418
michael@0 419 n = mNumCachedAttrs;
michael@0 420 names = (const char **)mCachedAttrParamNames;
michael@0 421 values = (const char **)mCachedAttrParamValues;
michael@0 422
michael@0 423 return rv;
michael@0 424 }
michael@0 425
michael@0 426 NS_IMETHODIMP nsPluginInstanceOwner::GetAttribute(const char* name, const char* *result)
michael@0 427 {
michael@0 428 NS_ENSURE_ARG_POINTER(name);
michael@0 429 NS_ENSURE_ARG_POINTER(result);
michael@0 430
michael@0 431 nsresult rv = EnsureCachedAttrParamArrays();
michael@0 432 NS_ENSURE_SUCCESS(rv, rv);
michael@0 433
michael@0 434 *result = nullptr;
michael@0 435
michael@0 436 for (int i = 0; i < mNumCachedAttrs; i++) {
michael@0 437 if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) {
michael@0 438 *result = mCachedAttrParamValues[i];
michael@0 439 return NS_OK;
michael@0 440 }
michael@0 441 }
michael@0 442
michael@0 443 return NS_ERROR_FAILURE;
michael@0 444 }
michael@0 445
michael@0 446 NS_IMETHODIMP nsPluginInstanceOwner::GetDOMElement(nsIDOMElement* *result)
michael@0 447 {
michael@0 448 return CallQueryInterface(mContent, result);
michael@0 449 }
michael@0 450
michael@0 451 nsresult nsPluginInstanceOwner::GetInstance(nsNPAPIPluginInstance **aInstance)
michael@0 452 {
michael@0 453 NS_ENSURE_ARG_POINTER(aInstance);
michael@0 454
michael@0 455 *aInstance = mInstance;
michael@0 456 NS_IF_ADDREF(*aInstance);
michael@0 457 return NS_OK;
michael@0 458 }
michael@0 459
michael@0 460 NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL,
michael@0 461 const char *aTarget,
michael@0 462 nsIInputStream *aPostStream,
michael@0 463 void *aHeadersData,
michael@0 464 uint32_t aHeadersDataLen)
michael@0 465 {
michael@0 466 NS_ENSURE_TRUE(mContent, NS_ERROR_NULL_POINTER);
michael@0 467
michael@0 468 if (mContent->IsEditable()) {
michael@0 469 return NS_OK;
michael@0 470 }
michael@0 471
michael@0 472 nsIDocument *doc = mContent->GetCurrentDoc();
michael@0 473 if (!doc) {
michael@0 474 return NS_ERROR_FAILURE;
michael@0 475 }
michael@0 476
michael@0 477 nsIPresShell *presShell = doc->GetShell();
michael@0 478 if (!presShell) {
michael@0 479 return NS_ERROR_FAILURE;
michael@0 480 }
michael@0 481
michael@0 482 nsPresContext *presContext = presShell->GetPresContext();
michael@0 483 if (!presContext) {
michael@0 484 return NS_ERROR_FAILURE;
michael@0 485 }
michael@0 486
michael@0 487 // the container of the pres context will give us the link handler
michael@0 488 nsCOMPtr<nsISupports> container = presContext->GetContainerWeak();
michael@0 489 NS_ENSURE_TRUE(container,NS_ERROR_FAILURE);
michael@0 490 nsCOMPtr<nsILinkHandler> lh = do_QueryInterface(container);
michael@0 491 NS_ENSURE_TRUE(lh, NS_ERROR_FAILURE);
michael@0 492
michael@0 493 nsAutoString unitarget;
michael@0 494 unitarget.AssignASCII(aTarget); // XXX could this be nonascii?
michael@0 495
michael@0 496 nsCOMPtr<nsIURI> baseURI = GetBaseURI();
michael@0 497
michael@0 498 // Create an absolute URL
michael@0 499 nsCOMPtr<nsIURI> uri;
michael@0 500 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, baseURI);
michael@0 501
michael@0 502 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
michael@0 503
michael@0 504 nsCOMPtr<nsIInputStream> headersDataStream;
michael@0 505 if (aPostStream && aHeadersData) {
michael@0 506 if (!aHeadersDataLen)
michael@0 507 return NS_ERROR_UNEXPECTED;
michael@0 508
michael@0 509 nsCOMPtr<nsIStringInputStream> sis = do_CreateInstance("@mozilla.org/io/string-input-stream;1");
michael@0 510 if (!sis)
michael@0 511 return NS_ERROR_OUT_OF_MEMORY;
michael@0 512
michael@0 513 rv = sis->SetData((char *)aHeadersData, aHeadersDataLen);
michael@0 514 NS_ENSURE_SUCCESS(rv, rv);
michael@0 515 headersDataStream = do_QueryInterface(sis);
michael@0 516 }
michael@0 517
michael@0 518 int32_t blockPopups =
michael@0 519 Preferences::GetInt("privacy.popups.disable_from_plugins");
michael@0 520 nsAutoPopupStatePusher popupStatePusher((PopupControlState)blockPopups);
michael@0 521
michael@0 522 rv = lh->OnLinkClick(mContent, uri, unitarget.get(), NullString(),
michael@0 523 aPostStream, headersDataStream, true);
michael@0 524
michael@0 525 return rv;
michael@0 526 }
michael@0 527
michael@0 528 NS_IMETHODIMP nsPluginInstanceOwner::ShowStatus(const char *aStatusMsg)
michael@0 529 {
michael@0 530 nsresult rv = NS_ERROR_FAILURE;
michael@0 531
michael@0 532 rv = this->ShowStatus(NS_ConvertUTF8toUTF16(aStatusMsg).get());
michael@0 533
michael@0 534 return rv;
michael@0 535 }
michael@0 536
michael@0 537 NS_IMETHODIMP nsPluginInstanceOwner::ShowStatus(const char16_t *aStatusMsg)
michael@0 538 {
michael@0 539 nsresult rv = NS_ERROR_FAILURE;
michael@0 540
michael@0 541 if (!mObjectFrame) {
michael@0 542 return rv;
michael@0 543 }
michael@0 544 nsCOMPtr<nsIDocShellTreeItem> docShellItem = mObjectFrame->PresContext()->GetDocShell();
michael@0 545 if (NS_FAILED(rv) || !docShellItem) {
michael@0 546 return rv;
michael@0 547 }
michael@0 548
michael@0 549 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
michael@0 550 rv = docShellItem->GetTreeOwner(getter_AddRefs(treeOwner));
michael@0 551 if (NS_FAILED(rv) || !treeOwner) {
michael@0 552 return rv;
michael@0 553 }
michael@0 554
michael@0 555 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(treeOwner, &rv));
michael@0 556 if (NS_FAILED(rv) || !browserChrome) {
michael@0 557 return rv;
michael@0 558 }
michael@0 559 rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
michael@0 560 aStatusMsg);
michael@0 561
michael@0 562 return rv;
michael@0 563 }
michael@0 564
michael@0 565 NS_IMETHODIMP nsPluginInstanceOwner::GetDocument(nsIDocument* *aDocument)
michael@0 566 {
michael@0 567 if (!aDocument)
michael@0 568 return NS_ERROR_NULL_POINTER;
michael@0 569
michael@0 570 // XXX sXBL/XBL2 issue: current doc or owner doc?
michael@0 571 // But keep in mind bug 322414 comment 33
michael@0 572 NS_IF_ADDREF(*aDocument = mContent->OwnerDoc());
michael@0 573 return NS_OK;
michael@0 574 }
michael@0 575
michael@0 576 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(NPRect *invalidRect)
michael@0 577 {
michael@0 578 // If our object frame has gone away, we won't be able to determine
michael@0 579 // up-to-date-ness, so just fire off the event.
michael@0 580 if (mWaitingForPaint && (!mObjectFrame || IsUpToDate())) {
michael@0 581 // We don't care when the event is dispatched as long as it's "soon",
michael@0 582 // since whoever needs it will be waiting for it.
michael@0 583 nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(mContent, true);
michael@0 584 NS_DispatchToMainThread(event);
michael@0 585 mWaitingForPaint = false;
michael@0 586 }
michael@0 587
michael@0 588 if (!mObjectFrame || !invalidRect || !mWidgetVisible)
michael@0 589 return NS_ERROR_FAILURE;
michael@0 590
michael@0 591 #if defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID)
michael@0 592 // Each time an asynchronously-drawing plugin sends a new surface to display,
michael@0 593 // the image in the ImageContainer is updated and InvalidateRect is called.
michael@0 594 // There are different side effects for (sync) Android plugins.
michael@0 595 nsRefPtr<ImageContainer> container;
michael@0 596 mInstance->GetImageContainer(getter_AddRefs(container));
michael@0 597 #endif
michael@0 598
michael@0 599 #ifndef XP_MACOSX
michael@0 600 // Windowed plugins should not be calling NPN_InvalidateRect, but
michael@0 601 // Silverlight does and expects it to "work"
michael@0 602 if (mWidget) {
michael@0 603 mWidget->Invalidate(nsIntRect(invalidRect->left, invalidRect->top,
michael@0 604 invalidRect->right - invalidRect->left,
michael@0 605 invalidRect->bottom - invalidRect->top));
michael@0 606 return NS_OK;
michael@0 607 }
michael@0 608 #endif
michael@0 609 nsIntRect rect(invalidRect->left,
michael@0 610 invalidRect->top,
michael@0 611 invalidRect->right - invalidRect->left,
michael@0 612 invalidRect->bottom - invalidRect->top);
michael@0 613 // invalidRect is in "display pixels". In non-HiDPI modes "display pixels"
michael@0 614 // are device pixels. But in HiDPI modes each display pixel corresponds
michael@0 615 // to more than one device pixel.
michael@0 616 double scaleFactor = 1.0;
michael@0 617 GetContentsScaleFactor(&scaleFactor);
michael@0 618 rect.ScaleRoundOut(scaleFactor);
michael@0 619 mObjectFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN, &rect);
michael@0 620 return NS_OK;
michael@0 621 }
michael@0 622
michael@0 623 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(NPRegion invalidRegion)
michael@0 624 {
michael@0 625 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 626 }
michael@0 627
michael@0 628 NS_IMETHODIMP
michael@0 629 nsPluginInstanceOwner::RedrawPlugin()
michael@0 630 {
michael@0 631 if (mObjectFrame) {
michael@0 632 mObjectFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN);
michael@0 633 }
michael@0 634 return NS_OK;
michael@0 635 }
michael@0 636
michael@0 637 NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value)
michael@0 638 {
michael@0 639 if (!mObjectFrame) {
michael@0 640 NS_WARNING("plugin owner has no owner in getting doc's window handle");
michael@0 641 return NS_ERROR_FAILURE;
michael@0 642 }
michael@0 643
michael@0 644 #if defined(XP_WIN)
michael@0 645 void** pvalue = (void**)value;
michael@0 646 nsViewManager* vm = mObjectFrame->PresContext()->GetPresShell()->GetViewManager();
michael@0 647 if (!vm)
michael@0 648 return NS_ERROR_FAILURE;
michael@0 649 #if defined(XP_WIN)
michael@0 650 // This property is provided to allow a "windowless" plugin to determine the window it is drawing
michael@0 651 // in, so it can translate mouse coordinates it receives directly from the operating system
michael@0 652 // to coordinates relative to itself.
michael@0 653
michael@0 654 // The original code (outside this #if) returns the document's window, which is OK if the window the "windowless" plugin
michael@0 655 // is drawing into has the same origin as the document's window, but this is not the case for "windowless" plugins inside of scrolling DIVs etc
michael@0 656
michael@0 657 // To make sure "windowless" plugins always get the right origin for translating mouse coordinates, this code
michael@0 658 // determines the window handle of the mozilla window containing the "windowless" plugin.
michael@0 659
michael@0 660 // Given that this HWND may not be that of the document's window, there is a slight risk
michael@0 661 // of confusing a plugin that is using this HWND for illicit purposes, but since the documentation
michael@0 662 // does not suggest this HWND IS that of the document window, rather that of the window
michael@0 663 // the plugin is drawn in, this seems like a safe fix.
michael@0 664
michael@0 665 // we only attempt to get the nearest window if this really is a "windowless" plugin so as not
michael@0 666 // to change any behaviour for the much more common windowed plugins,
michael@0 667 // though why this method would even be being called for a windowed plugin escapes me.
michael@0 668 if (mPluginWindow && mPluginWindow->type == NPWindowTypeDrawable) {
michael@0 669 // it turns out that flash also uses this window for determining focus, and is currently
michael@0 670 // unable to show a caret correctly if we return the enclosing window. Therefore for
michael@0 671 // now we only return the enclosing window when there is an actual offset which
michael@0 672 // would otherwise cause coordinates to be offset incorrectly. (i.e.
michael@0 673 // if the enclosing window if offset from the document window)
michael@0 674 //
michael@0 675 // fixing both the caret and ability to interact issues for a windowless control in a non document aligned windw
michael@0 676 // does not seem to be possible without a change to the flash plugin
michael@0 677
michael@0 678 nsIWidget* win = mObjectFrame->GetNearestWidget();
michael@0 679 if (win) {
michael@0 680 nsView *view = nsView::GetViewFor(win);
michael@0 681 NS_ASSERTION(view, "No view for widget");
michael@0 682 nsPoint offset = view->GetOffsetTo(nullptr);
michael@0 683
michael@0 684 if (offset.x || offset.y) {
michael@0 685 // in the case the two windows are offset from eachother, we do go ahead and return the correct enclosing window
michael@0 686 // so that mouse co-ordinates are not messed up.
michael@0 687 *pvalue = (void*)win->GetNativeData(NS_NATIVE_WINDOW);
michael@0 688 if (*pvalue)
michael@0 689 return NS_OK;
michael@0 690 }
michael@0 691 }
michael@0 692 }
michael@0 693 #endif
michael@0 694 // simply return the topmost document window
michael@0 695 nsCOMPtr<nsIWidget> widget;
michael@0 696 vm->GetRootWidget(getter_AddRefs(widget));
michael@0 697 if (widget) {
michael@0 698 *pvalue = (void*)widget->GetNativeData(NS_NATIVE_WINDOW);
michael@0 699 } else {
michael@0 700 NS_ASSERTION(widget, "couldn't get doc's widget in getting doc's window handle");
michael@0 701 }
michael@0 702
michael@0 703 return NS_OK;
michael@0 704 #elif (defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)) && defined(MOZ_X11)
michael@0 705 // X11 window managers want the toplevel window for WM_TRANSIENT_FOR.
michael@0 706 nsIWidget* win = mObjectFrame->GetNearestWidget();
michael@0 707 if (!win)
michael@0 708 return NS_ERROR_FAILURE;
michael@0 709 *static_cast<Window*>(value) = (long unsigned int)win->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW);
michael@0 710 return NS_OK;
michael@0 711 #else
michael@0 712 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 713 #endif
michael@0 714 }
michael@0 715
michael@0 716 NS_IMETHODIMP nsPluginInstanceOwner::SetEventModel(int32_t eventModel)
michael@0 717 {
michael@0 718 #ifdef XP_MACOSX
michael@0 719 mEventModel = static_cast<NPEventModel>(eventModel);
michael@0 720 return NS_OK;
michael@0 721 #else
michael@0 722 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 723 #endif
michael@0 724 }
michael@0 725
michael@0 726 NPError nsPluginInstanceOwner::ShowNativeContextMenu(NPMenu* menu, void* event)
michael@0 727 {
michael@0 728 if (!menu || !event)
michael@0 729 return NPERR_GENERIC_ERROR;
michael@0 730
michael@0 731 #ifdef XP_MACOSX
michael@0 732 if (GetEventModel() != NPEventModelCocoa)
michael@0 733 return NPERR_INCOMPATIBLE_VERSION_ERROR;
michael@0 734
michael@0 735 return NS_NPAPI_ShowCocoaContextMenu(static_cast<void*>(menu), mWidget,
michael@0 736 static_cast<NPCocoaEvent*>(event));
michael@0 737 #else
michael@0 738 return NPERR_INCOMPATIBLE_VERSION_ERROR;
michael@0 739 #endif
michael@0 740 }
michael@0 741
michael@0 742 NPBool nsPluginInstanceOwner::ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
michael@0 743 double *destX, double *destY, NPCoordinateSpace destSpace)
michael@0 744 {
michael@0 745 #ifdef XP_MACOSX
michael@0 746 if (!mWidget)
michael@0 747 return false;
michael@0 748
michael@0 749 return NS_NPAPI_ConvertPointCocoa(mWidget->GetNativeData(NS_NATIVE_WIDGET),
michael@0 750 sourceX, sourceY, sourceSpace, destX, destY, destSpace);
michael@0 751 #else
michael@0 752 // we should implement this for all platforms
michael@0 753 return false;
michael@0 754 #endif
michael@0 755 }
michael@0 756
michael@0 757 NPError nsPluginInstanceOwner::InitAsyncSurface(NPSize *size, NPImageFormat format,
michael@0 758 void *initData, NPAsyncSurface *surface)
michael@0 759 {
michael@0 760 return NPERR_INCOMPATIBLE_VERSION_ERROR;
michael@0 761 }
michael@0 762
michael@0 763 NPError nsPluginInstanceOwner::FinalizeAsyncSurface(NPAsyncSurface *)
michael@0 764 {
michael@0 765 return NPERR_INCOMPATIBLE_VERSION_ERROR;
michael@0 766 }
michael@0 767
michael@0 768 void nsPluginInstanceOwner::SetCurrentAsyncSurface(NPAsyncSurface *, NPRect*)
michael@0 769 {
michael@0 770 }
michael@0 771
michael@0 772 NS_IMETHODIMP nsPluginInstanceOwner::GetTagType(nsPluginTagType *result)
michael@0 773 {
michael@0 774 NS_ENSURE_ARG_POINTER(result);
michael@0 775
michael@0 776 *result = nsPluginTagType_Unknown;
michael@0 777
michael@0 778 nsIAtom *atom = mContent->Tag();
michael@0 779
michael@0 780 if (atom == nsGkAtoms::applet)
michael@0 781 *result = nsPluginTagType_Applet;
michael@0 782 else if (atom == nsGkAtoms::embed)
michael@0 783 *result = nsPluginTagType_Embed;
michael@0 784 else if (atom == nsGkAtoms::object)
michael@0 785 *result = nsPluginTagType_Object;
michael@0 786
michael@0 787 return NS_OK;
michael@0 788 }
michael@0 789
michael@0 790 NS_IMETHODIMP nsPluginInstanceOwner::GetParameters(uint16_t& n, const char*const*& names, const char*const*& values)
michael@0 791 {
michael@0 792 nsresult rv = EnsureCachedAttrParamArrays();
michael@0 793 NS_ENSURE_SUCCESS(rv, rv);
michael@0 794
michael@0 795 n = mNumCachedParams;
michael@0 796 if (n) {
michael@0 797 names = (const char **)(mCachedAttrParamNames + mNumCachedAttrs + 1);
michael@0 798 values = (const char **)(mCachedAttrParamValues + mNumCachedAttrs + 1);
michael@0 799 } else
michael@0 800 names = values = nullptr;
michael@0 801
michael@0 802 return rv;
michael@0 803 }
michael@0 804
michael@0 805 NS_IMETHODIMP nsPluginInstanceOwner::GetParameter(const char* name, const char* *result)
michael@0 806 {
michael@0 807 NS_ENSURE_ARG_POINTER(name);
michael@0 808 NS_ENSURE_ARG_POINTER(result);
michael@0 809
michael@0 810 nsresult rv = EnsureCachedAttrParamArrays();
michael@0 811 NS_ENSURE_SUCCESS(rv, rv);
michael@0 812
michael@0 813 *result = nullptr;
michael@0 814
michael@0 815 for (int i = mNumCachedAttrs + 1; i < (mNumCachedParams + 1 + mNumCachedAttrs); i++) {
michael@0 816 if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) {
michael@0 817 *result = mCachedAttrParamValues[i];
michael@0 818 return NS_OK;
michael@0 819 }
michael@0 820 }
michael@0 821
michael@0 822 return NS_ERROR_FAILURE;
michael@0 823 }
michael@0 824
michael@0 825
michael@0 826 // Cache the attributes and/or parameters of our tag into a single set
michael@0 827 // of arrays to be compatible with Netscape 4.x. The attributes go first,
michael@0 828 // followed by a PARAM/null and then any PARAM tags. Also, hold the
michael@0 829 // cached array around for the duration of the life of the instance
michael@0 830 // because Netscape 4.x did. See bug 111008.
michael@0 831 nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays()
michael@0 832 {
michael@0 833 if (mCachedAttrParamValues)
michael@0 834 return NS_OK;
michael@0 835
michael@0 836 NS_PRECONDITION(((mNumCachedAttrs + mNumCachedParams) == 0) &&
michael@0 837 !mCachedAttrParamNames,
michael@0 838 "re-cache of attrs/params not implemented! use the DOM "
michael@0 839 "node directy instead");
michael@0 840
michael@0 841 // Convert to a 16-bit count. Subtract 3 in case we add an extra
michael@0 842 // "src", "wmode", or "codebase" entry below.
michael@0 843 uint32_t cattrs = mContent->GetAttrCount();
michael@0 844 if (cattrs < 0x0000FFFC) {
michael@0 845 mNumCachedAttrs = static_cast<uint16_t>(cattrs);
michael@0 846 } else {
michael@0 847 mNumCachedAttrs = 0xFFFC;
michael@0 848 }
michael@0 849
michael@0 850 // Check if we are java for special codebase handling
michael@0 851 const char* mime = nullptr;
michael@0 852 bool isJava = NS_SUCCEEDED(mInstance->GetMIMEType(&mime)) && mime &&
michael@0 853 nsPluginHost::IsJavaMIMEType(mime);
michael@0 854
michael@0 855 // now, we need to find all the PARAM tags that are children of us
michael@0 856 // however, be careful not to include any PARAMs that don't have us
michael@0 857 // as a direct parent. For nested object (or applet) tags, be sure
michael@0 858 // to only round up the param tags that coorespond with THIS
michael@0 859 // instance. And also, weed out any bogus tags that may get in the
michael@0 860 // way, see bug 39609. Then, with any param tag that meet our
michael@0 861 // qualification, temporarly cache them in an nsCOMArray until
michael@0 862 // we can figure out what size to make our fixed char* array.
michael@0 863 nsCOMArray<nsIDOMElement> ourParams;
michael@0 864
michael@0 865 // Get all dependent PARAM tags, even if they are not direct children.
michael@0 866 nsCOMPtr<nsIDOMElement> mydomElement = do_QueryInterface(mContent);
michael@0 867 NS_ENSURE_TRUE(mydomElement, NS_ERROR_NO_INTERFACE);
michael@0 868
michael@0 869 // Making DOM method calls can cause our frame to go away.
michael@0 870 nsCOMPtr<nsIPluginInstanceOwner> kungFuDeathGrip(this);
michael@0 871
michael@0 872 nsCOMPtr<nsIDOMHTMLCollection> allParams;
michael@0 873 NS_NAMED_LITERAL_STRING(xhtml_ns, "http://www.w3.org/1999/xhtml");
michael@0 874 mydomElement->GetElementsByTagNameNS(xhtml_ns, NS_LITERAL_STRING("param"),
michael@0 875 getter_AddRefs(allParams));
michael@0 876 if (allParams) {
michael@0 877 uint32_t numAllParams;
michael@0 878 allParams->GetLength(&numAllParams);
michael@0 879 for (uint32_t i = 0; i < numAllParams; i++) {
michael@0 880 nsCOMPtr<nsIDOMNode> pnode;
michael@0 881 allParams->Item(i, getter_AddRefs(pnode));
michael@0 882 nsCOMPtr<nsIDOMElement> domelement = do_QueryInterface(pnode);
michael@0 883 if (domelement) {
michael@0 884 // Ignore params without a name attribute.
michael@0 885 nsAutoString name;
michael@0 886 domelement->GetAttribute(NS_LITERAL_STRING("name"), name);
michael@0 887 if (!name.IsEmpty()) {
michael@0 888 // Find the first object or applet parent.
michael@0 889 nsCOMPtr<nsIDOMNode> parent;
michael@0 890 nsCOMPtr<nsIDOMHTMLObjectElement> domobject;
michael@0 891 nsCOMPtr<nsIDOMHTMLAppletElement> domapplet;
michael@0 892 pnode->GetParentNode(getter_AddRefs(parent));
michael@0 893 while (!(domobject || domapplet) && parent) {
michael@0 894 domobject = do_QueryInterface(parent);
michael@0 895 domapplet = do_QueryInterface(parent);
michael@0 896 nsCOMPtr<nsIDOMNode> temp;
michael@0 897 parent->GetParentNode(getter_AddRefs(temp));
michael@0 898 parent = temp;
michael@0 899 }
michael@0 900 if (domapplet || domobject) {
michael@0 901 if (domapplet) {
michael@0 902 parent = do_QueryInterface(domapplet);
michael@0 903 }
michael@0 904 else {
michael@0 905 parent = do_QueryInterface(domobject);
michael@0 906 }
michael@0 907 nsCOMPtr<nsIDOMNode> mydomNode = do_QueryInterface(mydomElement);
michael@0 908 if (parent == mydomNode) {
michael@0 909 ourParams.AppendObject(domelement);
michael@0 910 }
michael@0 911 }
michael@0 912 }
michael@0 913 }
michael@0 914 }
michael@0 915 }
michael@0 916
michael@0 917 // Convert to a 16-bit count.
michael@0 918 uint32_t cparams = ourParams.Count();
michael@0 919 if (cparams < 0x0000FFFF) {
michael@0 920 mNumCachedParams = static_cast<uint16_t>(cparams);
michael@0 921 } else {
michael@0 922 mNumCachedParams = 0xFFFF;
michael@0 923 }
michael@0 924
michael@0 925 uint16_t numRealAttrs = mNumCachedAttrs;
michael@0 926
michael@0 927 // Some plugins were never written to understand the "data" attribute of the OBJECT tag.
michael@0 928 // Real and WMP will not play unless they find a "src" attribute, see bug 152334.
michael@0 929 // Nav 4.x would simply replace the "data" with "src". Because some plugins correctly
michael@0 930 // look for "data", lets instead copy the "data" attribute and add another entry
michael@0 931 // to the bottom of the array if there isn't already a "src" specified.
michael@0 932 nsAutoString data;
michael@0 933 if (mContent->Tag() == nsGkAtoms::object &&
michael@0 934 !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::src) &&
michael@0 935 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, data) &&
michael@0 936 !data.IsEmpty()) {
michael@0 937 mNumCachedAttrs++;
michael@0 938 }
michael@0 939
michael@0 940 // "plugins.force.wmode" forces us to send a specific "wmode" parameter,
michael@0 941 // used by flash to select a rendering mode. Common values include
michael@0 942 // "opaque", "transparent", "windowed", "direct"
michael@0 943 nsCString wmodeType;
michael@0 944 nsAdoptingCString wmodePref = Preferences::GetCString("plugins.force.wmode");
michael@0 945 if (!wmodePref.IsEmpty()) {
michael@0 946 mNumCachedAttrs++;
michael@0 947 wmodeType = wmodePref;
michael@0 948 }
michael@0 949 #if defined(XP_WIN) || defined(XP_LINUX)
michael@0 950 // Bug 923745 - Until we support windowed mode plugins in content processes,
michael@0 951 // force flash to use a windowless rendering mode. This hack should go away
michael@0 952 // when bug 923746 lands. (OS X plugins always use some native widgets, so
michael@0 953 // unfortunately this does not help there)
michael@0 954 else if (XRE_GetProcessType() == GeckoProcessType_Content) {
michael@0 955 mNumCachedAttrs++;
michael@0 956 wmodeType.AssignLiteral("transparent");
michael@0 957 }
michael@0 958 #endif
michael@0 959
michael@0 960 // (Bug 738396) java has quirks in its codebase parsing, pass the
michael@0 961 // absolute codebase URI as content sees it.
michael@0 962 bool addCodebase = false;
michael@0 963 nsAutoCString codebaseStr;
michael@0 964 if (isJava) {
michael@0 965 nsCOMPtr<nsIObjectLoadingContent> objlc = do_QueryInterface(mContent);
michael@0 966 NS_ENSURE_TRUE(objlc, NS_ERROR_UNEXPECTED);
michael@0 967 nsCOMPtr<nsIURI> codebaseURI;
michael@0 968 nsresult rv = objlc->GetBaseURI(getter_AddRefs(codebaseURI));
michael@0 969 NS_ENSURE_SUCCESS(rv, rv);
michael@0 970 codebaseURI->GetSpec(codebaseStr);
michael@0 971 if (!mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::codebase)) {
michael@0 972 mNumCachedAttrs++;
michael@0 973 addCodebase = true;
michael@0 974 }
michael@0 975 }
michael@0 976
michael@0 977 mCachedAttrParamNames = (char**)NS_Alloc(sizeof(char*) * (mNumCachedAttrs + 1 + mNumCachedParams));
michael@0 978 NS_ENSURE_TRUE(mCachedAttrParamNames, NS_ERROR_OUT_OF_MEMORY);
michael@0 979 mCachedAttrParamValues = (char**)NS_Alloc(sizeof(char*) * (mNumCachedAttrs + 1 + mNumCachedParams));
michael@0 980 NS_ENSURE_TRUE(mCachedAttrParamValues, NS_ERROR_OUT_OF_MEMORY);
michael@0 981
michael@0 982 // Some plugins (eg Flash, see bug 234675.) are actually sensitive to the
michael@0 983 // attribute order. So we want to make sure we give the plugin the
michael@0 984 // attributes in the order they came in in the source, to be compatible with
michael@0 985 // other browsers. Now in HTML, the storage order is the reverse of the
michael@0 986 // source order, while in XML and XHTML it's the same as the source order
michael@0 987 // (see the AddAttributes functions in the HTML and XML content sinks).
michael@0 988 int32_t start, end, increment;
michael@0 989 if (mContent->IsHTML() &&
michael@0 990 mContent->IsInHTMLDocument()) {
michael@0 991 // HTML. Walk attributes in reverse order.
michael@0 992 start = numRealAttrs - 1;
michael@0 993 end = -1;
michael@0 994 increment = -1;
michael@0 995 } else {
michael@0 996 // XHTML or XML. Walk attributes in forward order.
michael@0 997 start = 0;
michael@0 998 end = numRealAttrs;
michael@0 999 increment = 1;
michael@0 1000 }
michael@0 1001
michael@0 1002 // Set to the next slot to fill in name and value cache arrays.
michael@0 1003 uint32_t nextAttrParamIndex = 0;
michael@0 1004
michael@0 1005 // Whether or not we force the wmode below while traversing
michael@0 1006 // the name/value pairs.
michael@0 1007 bool wmodeSet = false;
michael@0 1008
michael@0 1009 // Add attribute name/value pairs.
michael@0 1010 for (int32_t index = start; index != end; index += increment) {
michael@0 1011 const nsAttrName* attrName = mContent->GetAttrNameAt(index);
michael@0 1012 nsIAtom* atom = attrName->LocalName();
michael@0 1013 nsAutoString value;
michael@0 1014 mContent->GetAttr(attrName->NamespaceID(), atom, value);
michael@0 1015 nsAutoString name;
michael@0 1016 atom->ToString(name);
michael@0 1017
michael@0 1018 FixUpURLS(name, value);
michael@0 1019
michael@0 1020 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(name);
michael@0 1021 if (!wmodeType.IsEmpty() &&
michael@0 1022 0 == PL_strcasecmp(mCachedAttrParamNames[nextAttrParamIndex], "wmode")) {
michael@0 1023 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(wmodeType));
michael@0 1024
michael@0 1025 if (!wmodeSet) {
michael@0 1026 // We allocated space to add a wmode attr, but we don't need it now.
michael@0 1027 mNumCachedAttrs--;
michael@0 1028 wmodeSet = true;
michael@0 1029 }
michael@0 1030 } else if (isJava && 0 == PL_strcasecmp(mCachedAttrParamNames[nextAttrParamIndex], "codebase")) {
michael@0 1031 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(codebaseStr));
michael@0 1032 } else {
michael@0 1033 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(value);
michael@0 1034 }
michael@0 1035 nextAttrParamIndex++;
michael@0 1036 }
michael@0 1037
michael@0 1038 // Potentially add CODEBASE attribute
michael@0 1039 if (addCodebase) {
michael@0 1040 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("codebase"));
michael@0 1041 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(codebaseStr));
michael@0 1042 nextAttrParamIndex++;
michael@0 1043 }
michael@0 1044
michael@0 1045 // Potentially add WMODE attribute.
michael@0 1046 if (!wmodeType.IsEmpty() && !wmodeSet) {
michael@0 1047 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("wmode"));
michael@0 1048 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(wmodeType));
michael@0 1049 nextAttrParamIndex++;
michael@0 1050 }
michael@0 1051
michael@0 1052 // Potentially add SRC attribute.
michael@0 1053 if (!data.IsEmpty()) {
michael@0 1054 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("SRC"));
michael@0 1055 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(data);
michael@0 1056 nextAttrParamIndex++;
michael@0 1057 }
michael@0 1058
michael@0 1059 // Add PARAM and null separator.
michael@0 1060 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("PARAM"));
michael@0 1061 #ifdef MOZ_WIDGET_ANDROID
michael@0 1062 // Flash expects an empty string on android
michael@0 1063 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING(""));
michael@0 1064 #else
michael@0 1065 mCachedAttrParamValues[nextAttrParamIndex] = nullptr;
michael@0 1066 #endif
michael@0 1067 nextAttrParamIndex++;
michael@0 1068
michael@0 1069 // Add PARAM name/value pairs.
michael@0 1070
michael@0 1071 // We may decrement mNumCachedParams below
michael@0 1072 uint16_t totalParams = mNumCachedParams;
michael@0 1073 for (uint16_t i = 0; i < totalParams; i++) {
michael@0 1074 nsIDOMElement* param = ourParams.ObjectAt(i);
michael@0 1075 if (!param) {
michael@0 1076 continue;
michael@0 1077 }
michael@0 1078
michael@0 1079 nsAutoString name;
michael@0 1080 nsAutoString value;
michael@0 1081 param->GetAttribute(NS_LITERAL_STRING("name"), name); // check for empty done above
michael@0 1082 param->GetAttribute(NS_LITERAL_STRING("value"), value);
michael@0 1083
michael@0 1084 FixUpURLS(name, value);
michael@0 1085
michael@0 1086 /*
michael@0 1087 * According to the HTML 4.01 spec, at
michael@0 1088 * http://www.w3.org/TR/html4/types.html#type-cdata
michael@0 1089 * ''User agents may ignore leading and trailing
michael@0 1090 * white space in CDATA attribute values (e.g., "
michael@0 1091 * myval " may be interpreted as "myval"). Authors
michael@0 1092 * should not declare attribute values with
michael@0 1093 * leading or trailing white space.''
michael@0 1094 * However, do not trim consecutive spaces as in bug 122119
michael@0 1095 */
michael@0 1096 name.Trim(" \n\r\t\b", true, true, false);
michael@0 1097 value.Trim(" \n\r\t\b", true, true, false);
michael@0 1098 if (isJava && name.EqualsIgnoreCase("codebase")) {
michael@0 1099 // We inserted normalized codebase above, don't include other versions in
michael@0 1100 // params
michael@0 1101 mNumCachedParams--;
michael@0 1102 continue;
michael@0 1103 }
michael@0 1104 mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(name);
michael@0 1105 mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(value);
michael@0 1106 nextAttrParamIndex++;
michael@0 1107 }
michael@0 1108
michael@0 1109 return NS_OK;
michael@0 1110 }
michael@0 1111
michael@0 1112 #ifdef XP_MACOSX
michael@0 1113
michael@0 1114 static void InitializeNPCocoaEvent(NPCocoaEvent* event)
michael@0 1115 {
michael@0 1116 memset(event, 0, sizeof(NPCocoaEvent));
michael@0 1117 }
michael@0 1118
michael@0 1119 NPDrawingModel nsPluginInstanceOwner::GetDrawingModel()
michael@0 1120 {
michael@0 1121 #ifndef NP_NO_QUICKDRAW
michael@0 1122 // We don't support the Quickdraw drawing model any more but it's still
michael@0 1123 // the default model for i386 per NPAPI.
michael@0 1124 NPDrawingModel drawingModel = NPDrawingModelQuickDraw;
michael@0 1125 #else
michael@0 1126 NPDrawingModel drawingModel = NPDrawingModelCoreGraphics;
michael@0 1127 #endif
michael@0 1128
michael@0 1129 if (!mInstance)
michael@0 1130 return drawingModel;
michael@0 1131
michael@0 1132 mInstance->GetDrawingModel((int32_t*)&drawingModel);
michael@0 1133 return drawingModel;
michael@0 1134 }
michael@0 1135
michael@0 1136 bool nsPluginInstanceOwner::IsRemoteDrawingCoreAnimation()
michael@0 1137 {
michael@0 1138 if (!mInstance)
michael@0 1139 return false;
michael@0 1140
michael@0 1141 bool coreAnimation;
michael@0 1142 if (!NS_SUCCEEDED(mInstance->IsRemoteDrawingCoreAnimation(&coreAnimation)))
michael@0 1143 return false;
michael@0 1144
michael@0 1145 return coreAnimation;
michael@0 1146 }
michael@0 1147
michael@0 1148 nsresult nsPluginInstanceOwner::ContentsScaleFactorChanged(double aContentsScaleFactor)
michael@0 1149 {
michael@0 1150 if (!mInstance) {
michael@0 1151 return NS_ERROR_NULL_POINTER;
michael@0 1152 }
michael@0 1153 return mInstance->ContentsScaleFactorChanged(aContentsScaleFactor);
michael@0 1154 }
michael@0 1155
michael@0 1156 NPEventModel nsPluginInstanceOwner::GetEventModel()
michael@0 1157 {
michael@0 1158 return mEventModel;
michael@0 1159 }
michael@0 1160
michael@0 1161 #define DEFAULT_REFRESH_RATE 20 // 50 FPS
michael@0 1162
michael@0 1163 nsCOMPtr<nsITimer> *nsPluginInstanceOwner::sCATimer = nullptr;
michael@0 1164 nsTArray<nsPluginInstanceOwner*> *nsPluginInstanceOwner::sCARefreshListeners = nullptr;
michael@0 1165
michael@0 1166 void nsPluginInstanceOwner::CARefresh(nsITimer *aTimer, void *aClosure) {
michael@0 1167 if (!sCARefreshListeners) {
michael@0 1168 return;
michael@0 1169 }
michael@0 1170 for (size_t i = 0; i < sCARefreshListeners->Length(); i++) {
michael@0 1171 nsPluginInstanceOwner* instanceOwner = (*sCARefreshListeners)[i];
michael@0 1172 NPWindow *window;
michael@0 1173 instanceOwner->GetWindow(window);
michael@0 1174 if (!window) {
michael@0 1175 continue;
michael@0 1176 }
michael@0 1177 NPRect r;
michael@0 1178 r.left = 0;
michael@0 1179 r.top = 0;
michael@0 1180 r.right = window->width;
michael@0 1181 r.bottom = window->height;
michael@0 1182 instanceOwner->InvalidateRect(&r);
michael@0 1183 }
michael@0 1184 }
michael@0 1185
michael@0 1186 void nsPluginInstanceOwner::AddToCARefreshTimer() {
michael@0 1187 if (!mInstance) {
michael@0 1188 return;
michael@0 1189 }
michael@0 1190
michael@0 1191 // Flash invokes InvalidateRect for us.
michael@0 1192 const char* mime = nullptr;
michael@0 1193 if (NS_SUCCEEDED(mInstance->GetMIMEType(&mime)) && mime) {
michael@0 1194 if (strcmp(mime, "application/x-shockwave-flash") == 0) {
michael@0 1195 return;
michael@0 1196 }
michael@0 1197 }
michael@0 1198
michael@0 1199 if (!sCARefreshListeners) {
michael@0 1200 sCARefreshListeners = new nsTArray<nsPluginInstanceOwner*>();
michael@0 1201 if (!sCARefreshListeners) {
michael@0 1202 return;
michael@0 1203 }
michael@0 1204 }
michael@0 1205
michael@0 1206 if (sCARefreshListeners->Contains(this)) {
michael@0 1207 return;
michael@0 1208 }
michael@0 1209
michael@0 1210 sCARefreshListeners->AppendElement(this);
michael@0 1211
michael@0 1212 if (!sCATimer) {
michael@0 1213 sCATimer = new nsCOMPtr<nsITimer>();
michael@0 1214 if (!sCATimer) {
michael@0 1215 return;
michael@0 1216 }
michael@0 1217 }
michael@0 1218
michael@0 1219 if (sCARefreshListeners->Length() == 1) {
michael@0 1220 *sCATimer = do_CreateInstance("@mozilla.org/timer;1");
michael@0 1221 (*sCATimer)->InitWithFuncCallback(CARefresh, nullptr,
michael@0 1222 DEFAULT_REFRESH_RATE, nsITimer::TYPE_REPEATING_SLACK);
michael@0 1223 }
michael@0 1224 }
michael@0 1225
michael@0 1226 void nsPluginInstanceOwner::RemoveFromCARefreshTimer() {
michael@0 1227 if (!sCARefreshListeners || sCARefreshListeners->Contains(this) == false) {
michael@0 1228 return;
michael@0 1229 }
michael@0 1230
michael@0 1231 sCARefreshListeners->RemoveElement(this);
michael@0 1232
michael@0 1233 if (sCARefreshListeners->Length() == 0) {
michael@0 1234 if (sCATimer) {
michael@0 1235 (*sCATimer)->Cancel();
michael@0 1236 delete sCATimer;
michael@0 1237 sCATimer = nullptr;
michael@0 1238 }
michael@0 1239 delete sCARefreshListeners;
michael@0 1240 sCARefreshListeners = nullptr;
michael@0 1241 }
michael@0 1242 }
michael@0 1243
michael@0 1244 void nsPluginInstanceOwner::RenderCoreAnimation(CGContextRef aCGContext,
michael@0 1245 int aWidth, int aHeight)
michael@0 1246 {
michael@0 1247 if (aWidth == 0 || aHeight == 0)
michael@0 1248 return;
michael@0 1249
michael@0 1250 if (!mCARenderer) {
michael@0 1251 mCARenderer = new nsCARenderer();
michael@0 1252 }
michael@0 1253
michael@0 1254 // aWidth and aHeight are in "display pixels". In non-HiDPI modes
michael@0 1255 // "display pixels" are device pixels. But in HiDPI modes each
michael@0 1256 // display pixel corresponds to more than one device pixel.
michael@0 1257 double scaleFactor = 1.0;
michael@0 1258 GetContentsScaleFactor(&scaleFactor);
michael@0 1259
michael@0 1260 if (!mIOSurface ||
michael@0 1261 (mIOSurface->GetWidth() != (size_t)aWidth ||
michael@0 1262 mIOSurface->GetHeight() != (size_t)aHeight ||
michael@0 1263 mIOSurface->GetContentsScaleFactor() != scaleFactor)) {
michael@0 1264 mIOSurface = nullptr;
michael@0 1265
michael@0 1266 // If the renderer is backed by an IOSurface, resize it as required.
michael@0 1267 mIOSurface = MacIOSurface::CreateIOSurface(aWidth, aHeight, scaleFactor);
michael@0 1268 if (mIOSurface) {
michael@0 1269 RefPtr<MacIOSurface> attachSurface = MacIOSurface::LookupSurface(
michael@0 1270 mIOSurface->GetIOSurfaceID(),
michael@0 1271 scaleFactor);
michael@0 1272 if (attachSurface) {
michael@0 1273 mCARenderer->AttachIOSurface(attachSurface);
michael@0 1274 } else {
michael@0 1275 NS_ERROR("IOSurface attachment failed");
michael@0 1276 mIOSurface = nullptr;
michael@0 1277 }
michael@0 1278 }
michael@0 1279 }
michael@0 1280
michael@0 1281 if (!mColorProfile) {
michael@0 1282 mColorProfile = CreateSystemColorSpace();
michael@0 1283 }
michael@0 1284
michael@0 1285 if (mCARenderer->isInit() == false) {
michael@0 1286 void *caLayer = nullptr;
michael@0 1287 nsresult rv = mInstance->GetValueFromPlugin(NPPVpluginCoreAnimationLayer, &caLayer);
michael@0 1288 if (NS_FAILED(rv) || !caLayer) {
michael@0 1289 return;
michael@0 1290 }
michael@0 1291
michael@0 1292 // We don't run Flash in-process so we can unconditionally disallow
michael@0 1293 // the offliner renderer.
michael@0 1294 mCARenderer->SetupRenderer(caLayer, aWidth, aHeight, scaleFactor,
michael@0 1295 DISALLOW_OFFLINE_RENDERER);
michael@0 1296
michael@0 1297 // Setting up the CALayer requires resetting the painting otherwise we
michael@0 1298 // get garbage for the first few frames.
michael@0 1299 FixUpPluginWindow(ePluginPaintDisable);
michael@0 1300 FixUpPluginWindow(ePluginPaintEnable);
michael@0 1301 }
michael@0 1302
michael@0 1303 CGImageRef caImage = nullptr;
michael@0 1304 nsresult rt = mCARenderer->Render(aWidth, aHeight, scaleFactor, &caImage);
michael@0 1305 if (rt == NS_OK && mIOSurface && mColorProfile) {
michael@0 1306 nsCARenderer::DrawSurfaceToCGContext(aCGContext, mIOSurface, mColorProfile,
michael@0 1307 0, 0, aWidth, aHeight);
michael@0 1308 } else if (rt == NS_OK && caImage != nullptr) {
michael@0 1309 // Significant speed up by resetting the scaling
michael@0 1310 ::CGContextSetInterpolationQuality(aCGContext, kCGInterpolationNone );
michael@0 1311 ::CGContextTranslateCTM(aCGContext, 0, (double) aHeight * scaleFactor);
michael@0 1312 ::CGContextScaleCTM(aCGContext, scaleFactor, -scaleFactor);
michael@0 1313
michael@0 1314 ::CGContextDrawImage(aCGContext, CGRectMake(0,0,aWidth,aHeight), caImage);
michael@0 1315 } else {
michael@0 1316 NS_NOTREACHED("nsCARenderer::Render failure");
michael@0 1317 }
michael@0 1318 }
michael@0 1319
michael@0 1320 void* nsPluginInstanceOwner::GetPluginPortCopy()
michael@0 1321 {
michael@0 1322 if (GetDrawingModel() == NPDrawingModelCoreGraphics ||
michael@0 1323 GetDrawingModel() == NPDrawingModelCoreAnimation ||
michael@0 1324 GetDrawingModel() == NPDrawingModelInvalidatingCoreAnimation)
michael@0 1325 return &mCGPluginPortCopy;
michael@0 1326 return nullptr;
michael@0 1327 }
michael@0 1328
michael@0 1329 // Currently (on OS X in Cocoa widgets) any changes made as a result of
michael@0 1330 // calling GetPluginPortFromWidget() are immediately reflected in the NPWindow
michael@0 1331 // structure that has been passed to the plugin via SetWindow(). This is
michael@0 1332 // because calls to nsChildView::GetNativeData(NS_NATIVE_PLUGIN_PORT_CG)
michael@0 1333 // always return a pointer to the same internal (private) object, but may
michael@0 1334 // make changes inside that object. All calls to GetPluginPortFromWidget() made while
michael@0 1335 // the plugin is active (i.e. excluding those made at our initialization)
michael@0 1336 // need to take this into account. The easiest way to do so is to replace
michael@0 1337 // them with calls to SetPluginPortAndDetectChange(). This method keeps track
michael@0 1338 // of when calls to GetPluginPortFromWidget() result in changes, and sets a flag to make
michael@0 1339 // sure SetWindow() gets called the next time through FixUpPluginWindow(), so
michael@0 1340 // that the plugin is notified of these changes.
michael@0 1341 void* nsPluginInstanceOwner::SetPluginPortAndDetectChange()
michael@0 1342 {
michael@0 1343 if (!mPluginWindow)
michael@0 1344 return nullptr;
michael@0 1345 void* pluginPort = GetPluginPortFromWidget();
michael@0 1346 if (!pluginPort)
michael@0 1347 return nullptr;
michael@0 1348 mPluginWindow->window = pluginPort;
michael@0 1349
michael@0 1350 return mPluginWindow->window;
michael@0 1351 }
michael@0 1352
michael@0 1353 void nsPluginInstanceOwner::BeginCGPaint()
michael@0 1354 {
michael@0 1355 ++mInCGPaintLevel;
michael@0 1356 }
michael@0 1357
michael@0 1358 void nsPluginInstanceOwner::EndCGPaint()
michael@0 1359 {
michael@0 1360 --mInCGPaintLevel;
michael@0 1361 NS_ASSERTION(mInCGPaintLevel >= 0, "Mismatched call to nsPluginInstanceOwner::EndCGPaint()!");
michael@0 1362 }
michael@0 1363
michael@0 1364 #endif
michael@0 1365
michael@0 1366 // static
michael@0 1367 uint32_t
michael@0 1368 nsPluginInstanceOwner::GetEventloopNestingLevel()
michael@0 1369 {
michael@0 1370 nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
michael@0 1371 uint32_t currentLevel = 0;
michael@0 1372 if (appShell) {
michael@0 1373 appShell->GetEventloopNestingLevel(&currentLevel);
michael@0 1374 #ifdef XP_MACOSX
michael@0 1375 // Cocoa widget code doesn't process UI events through the normal
michael@0 1376 // appshell event loop, so it needs an additional count here.
michael@0 1377 currentLevel++;
michael@0 1378 #endif
michael@0 1379 }
michael@0 1380
michael@0 1381 // No idea how this happens... but Linux doesn't consistently
michael@0 1382 // process UI events through the appshell event loop. If we get a 0
michael@0 1383 // here on any platform we increment the level just in case so that
michael@0 1384 // we make sure we always tear the plugin down eventually.
michael@0 1385 if (!currentLevel) {
michael@0 1386 currentLevel++;
michael@0 1387 }
michael@0 1388
michael@0 1389 return currentLevel;
michael@0 1390 }
michael@0 1391
michael@0 1392 #ifdef MOZ_WIDGET_ANDROID
michael@0 1393
michael@0 1394 // Modified version of nsFrame::GetOffsetToCrossDoc that stops when it
michael@0 1395 // hits an element with a displayport (or runs out of frames). This is
michael@0 1396 // not really the right thing to do, but it's better than what was here before.
michael@0 1397 static nsPoint
michael@0 1398 GetOffsetRootContent(nsIFrame* aFrame)
michael@0 1399 {
michael@0 1400 // offset will hold the final offset
michael@0 1401 // docOffset holds the currently accumulated offset at the current APD, it
michael@0 1402 // will be converted and added to offset when the current APD changes.
michael@0 1403 nsPoint offset(0, 0), docOffset(0, 0);
michael@0 1404 const nsIFrame* f = aFrame;
michael@0 1405 int32_t currAPD = aFrame->PresContext()->AppUnitsPerDevPixel();
michael@0 1406 int32_t apd = currAPD;
michael@0 1407 nsRect displayPort;
michael@0 1408 while (f) {
michael@0 1409 if (f->GetContent() && nsLayoutUtils::GetDisplayPort(f->GetContent(), &displayPort))
michael@0 1410 break;
michael@0 1411
michael@0 1412 docOffset += f->GetPosition();
michael@0 1413 nsIFrame* parent = f->GetParent();
michael@0 1414 if (parent) {
michael@0 1415 f = parent;
michael@0 1416 } else {
michael@0 1417 nsPoint newOffset(0, 0);
michael@0 1418 f = nsLayoutUtils::GetCrossDocParentFrame(f, &newOffset);
michael@0 1419 int32_t newAPD = f ? f->PresContext()->AppUnitsPerDevPixel() : 0;
michael@0 1420 if (!f || newAPD != currAPD) {
michael@0 1421 // Convert docOffset to the right APD and add it to offset.
michael@0 1422 offset += docOffset.ConvertAppUnits(currAPD, apd);
michael@0 1423 docOffset.x = docOffset.y = 0;
michael@0 1424 }
michael@0 1425 currAPD = newAPD;
michael@0 1426 docOffset += newOffset;
michael@0 1427 }
michael@0 1428 }
michael@0 1429
michael@0 1430 offset += docOffset.ConvertAppUnits(currAPD, apd);
michael@0 1431
michael@0 1432 return offset;
michael@0 1433 }
michael@0 1434
michael@0 1435 LayoutDeviceRect nsPluginInstanceOwner::GetPluginRect()
michael@0 1436 {
michael@0 1437 // Get the offset of the content relative to the page
michael@0 1438 nsRect bounds = mObjectFrame->GetContentRectRelativeToSelf() + GetOffsetRootContent(mObjectFrame);
michael@0 1439 LayoutDeviceIntRect rect = LayoutDeviceIntRect::FromAppUnitsToNearest(bounds, mObjectFrame->PresContext()->AppUnitsPerDevPixel());
michael@0 1440 return LayoutDeviceRect(rect);
michael@0 1441 }
michael@0 1442
michael@0 1443 bool nsPluginInstanceOwner::AddPluginView(const LayoutDeviceRect& aRect /* = LayoutDeviceRect(0, 0, 0, 0) */)
michael@0 1444 {
michael@0 1445 if (!mJavaView) {
michael@0 1446 mJavaView = mInstance->GetJavaSurface();
michael@0 1447
michael@0 1448 if (!mJavaView)
michael@0 1449 return false;
michael@0 1450
michael@0 1451 mJavaView = (void*)AndroidBridge::GetJNIEnv()->NewGlobalRef((jobject)mJavaView);
michael@0 1452 }
michael@0 1453
michael@0 1454 if (AndroidBridge::Bridge())
michael@0 1455 AndroidBridge::Bridge()->AddPluginView((jobject)mJavaView, aRect, mFullScreen);
michael@0 1456
michael@0 1457 if (mFullScreen)
michael@0 1458 sFullScreenInstance = this;
michael@0 1459
michael@0 1460 return true;
michael@0 1461 }
michael@0 1462
michael@0 1463 void nsPluginInstanceOwner::RemovePluginView()
michael@0 1464 {
michael@0 1465 if (!mInstance || !mJavaView)
michael@0 1466 return;
michael@0 1467
michael@0 1468 mozilla::widget::android::GeckoAppShell::RemovePluginView((jobject)mJavaView, mFullScreen);
michael@0 1469 AndroidBridge::GetJNIEnv()->DeleteGlobalRef((jobject)mJavaView);
michael@0 1470 mJavaView = nullptr;
michael@0 1471
michael@0 1472 if (mFullScreen)
michael@0 1473 sFullScreenInstance = nullptr;
michael@0 1474 }
michael@0 1475
michael@0 1476 void nsPluginInstanceOwner::GetVideos(nsTArray<nsNPAPIPluginInstance::VideoInfo*>& aVideos)
michael@0 1477 {
michael@0 1478 if (!mInstance)
michael@0 1479 return;
michael@0 1480
michael@0 1481 mInstance->GetVideos(aVideos);
michael@0 1482 }
michael@0 1483
michael@0 1484 already_AddRefed<ImageContainer> nsPluginInstanceOwner::GetImageContainerForVideo(nsNPAPIPluginInstance::VideoInfo* aVideoInfo)
michael@0 1485 {
michael@0 1486 nsRefPtr<ImageContainer> container = LayerManager::CreateImageContainer();
michael@0 1487
michael@0 1488 nsRefPtr<Image> img = container->CreateImage(ImageFormat::SHARED_TEXTURE);
michael@0 1489
michael@0 1490 SharedTextureImage::Data data;
michael@0 1491
michael@0 1492 data.mShareType = gl::SharedTextureShareType::SameProcess;
michael@0 1493 data.mHandle = gl::CreateSharedHandle(mInstance->GLContext(),
michael@0 1494 data.mShareType,
michael@0 1495 aVideoInfo->mSurfaceTexture,
michael@0 1496 gl::SharedTextureBufferType::SurfaceTexture);
michael@0 1497
michael@0 1498 // The logic below for Honeycomb is just a guess, but seems to work. We don't have a separate
michael@0 1499 // inverted flag for video.
michael@0 1500 data.mInverted = AndroidBridge::Bridge()->IsHoneycomb() ? true : mInstance->Inverted();
michael@0 1501 data.mSize = gfx::IntSize(aVideoInfo->mDimensions.width, aVideoInfo->mDimensions.height);
michael@0 1502
michael@0 1503 SharedTextureImage* pluginImage = static_cast<SharedTextureImage*>(img.get());
michael@0 1504 pluginImage->SetData(data);
michael@0 1505 container->SetCurrentImageInTransaction(img);
michael@0 1506
michael@0 1507 return container.forget();
michael@0 1508 }
michael@0 1509
michael@0 1510 void nsPluginInstanceOwner::Invalidate() {
michael@0 1511 NPRect rect;
michael@0 1512 rect.left = rect.top = 0;
michael@0 1513 rect.right = mPluginWindow->width;
michael@0 1514 rect.bottom = mPluginWindow->height;
michael@0 1515 InvalidateRect(&rect);
michael@0 1516 }
michael@0 1517
michael@0 1518 void nsPluginInstanceOwner::RequestFullScreen() {
michael@0 1519 if (mFullScreen)
michael@0 1520 return;
michael@0 1521
michael@0 1522 // Remove whatever view we currently have (if any, fullscreen or otherwise)
michael@0 1523 RemovePluginView();
michael@0 1524
michael@0 1525 mFullScreen = true;
michael@0 1526 AddPluginView();
michael@0 1527
michael@0 1528 mInstance->NotifyFullScreen(mFullScreen);
michael@0 1529 }
michael@0 1530
michael@0 1531 void nsPluginInstanceOwner::ExitFullScreen() {
michael@0 1532 if (!mFullScreen)
michael@0 1533 return;
michael@0 1534
michael@0 1535 RemovePluginView();
michael@0 1536
michael@0 1537 mFullScreen = false;
michael@0 1538
michael@0 1539 int32_t model = mInstance->GetANPDrawingModel();
michael@0 1540
michael@0 1541 if (model == kSurface_ANPDrawingModel) {
michael@0 1542 // We need to do this immediately, otherwise Flash
michael@0 1543 // sometimes causes a deadlock (bug 762407)
michael@0 1544 AddPluginView(GetPluginRect());
michael@0 1545 }
michael@0 1546
michael@0 1547 mInstance->NotifyFullScreen(mFullScreen);
michael@0 1548
michael@0 1549 // This will cause Paint() to be called, which is where
michael@0 1550 // we normally add/update views and layers
michael@0 1551 Invalidate();
michael@0 1552 }
michael@0 1553
michael@0 1554 void nsPluginInstanceOwner::ExitFullScreen(jobject view) {
michael@0 1555 JNIEnv* env = AndroidBridge::GetJNIEnv();
michael@0 1556
michael@0 1557 if (sFullScreenInstance && sFullScreenInstance->mInstance &&
michael@0 1558 env->IsSameObject(view, (jobject)sFullScreenInstance->mInstance->GetJavaSurface())) {
michael@0 1559 sFullScreenInstance->ExitFullScreen();
michael@0 1560 }
michael@0 1561 }
michael@0 1562
michael@0 1563 #endif
michael@0 1564
michael@0 1565 nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
michael@0 1566 {
michael@0 1567 #ifdef MOZ_WIDGET_ANDROID
michael@0 1568 if (mInstance) {
michael@0 1569 ANPEvent event;
michael@0 1570 event.inSize = sizeof(ANPEvent);
michael@0 1571 event.eventType = kLifecycle_ANPEventType;
michael@0 1572
michael@0 1573 nsAutoString eventType;
michael@0 1574 aFocusEvent->GetType(eventType);
michael@0 1575 if (eventType.EqualsLiteral("focus")) {
michael@0 1576 event.data.lifecycle.action = kGainFocus_ANPLifecycleAction;
michael@0 1577 }
michael@0 1578 else if (eventType.EqualsLiteral("blur")) {
michael@0 1579 event.data.lifecycle.action = kLoseFocus_ANPLifecycleAction;
michael@0 1580 }
michael@0 1581 else {
michael@0 1582 NS_ASSERTION(false, "nsPluginInstanceOwner::DispatchFocusToPlugin, wierd eventType");
michael@0 1583 }
michael@0 1584 mInstance->HandleEvent(&event, nullptr);
michael@0 1585 }
michael@0 1586 #endif
michael@0 1587
michael@0 1588 #ifndef XP_MACOSX
michael@0 1589 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow)) {
michael@0 1590 // continue only for cases without child window
michael@0 1591 return aFocusEvent->PreventDefault(); // consume event
michael@0 1592 }
michael@0 1593 #endif
michael@0 1594
michael@0 1595 WidgetEvent* theEvent = aFocusEvent->GetInternalNSEvent();
michael@0 1596 if (theEvent) {
michael@0 1597 // we only care about the message in ProcessEvent
michael@0 1598 WidgetGUIEvent focusEvent(theEvent->mFlags.mIsTrusted, theEvent->message,
michael@0 1599 nullptr);
michael@0 1600 nsEventStatus rv = ProcessEvent(focusEvent);
michael@0 1601 if (nsEventStatus_eConsumeNoDefault == rv) {
michael@0 1602 aFocusEvent->PreventDefault();
michael@0 1603 aFocusEvent->StopPropagation();
michael@0 1604 }
michael@0 1605 }
michael@0 1606
michael@0 1607 return NS_OK;
michael@0 1608 }
michael@0 1609
michael@0 1610 nsresult nsPluginInstanceOwner::ProcessKeyPress(nsIDOMEvent* aKeyEvent)
michael@0 1611 {
michael@0 1612 #ifdef XP_MACOSX
michael@0 1613 return DispatchKeyToPlugin(aKeyEvent);
michael@0 1614 #else
michael@0 1615 if (SendNativeEvents())
michael@0 1616 DispatchKeyToPlugin(aKeyEvent);
michael@0 1617
michael@0 1618 if (mInstance) {
michael@0 1619 // If this event is going to the plugin, we want to kill it.
michael@0 1620 // Not actually sending keypress to the plugin, since we didn't before.
michael@0 1621 aKeyEvent->PreventDefault();
michael@0 1622 aKeyEvent->StopPropagation();
michael@0 1623 }
michael@0 1624 return NS_OK;
michael@0 1625 #endif
michael@0 1626 }
michael@0 1627
michael@0 1628 nsresult nsPluginInstanceOwner::DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent)
michael@0 1629 {
michael@0 1630 #if !defined(XP_MACOSX)
michael@0 1631 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
michael@0 1632 return aKeyEvent->PreventDefault(); // consume event
michael@0 1633 // continue only for cases without child window
michael@0 1634 #endif
michael@0 1635
michael@0 1636 if (mInstance) {
michael@0 1637 WidgetKeyboardEvent* keyEvent =
michael@0 1638 aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
michael@0 1639 if (keyEvent && keyEvent->eventStructType == NS_KEY_EVENT) {
michael@0 1640 nsEventStatus rv = ProcessEvent(*keyEvent);
michael@0 1641 if (nsEventStatus_eConsumeNoDefault == rv) {
michael@0 1642 aKeyEvent->PreventDefault();
michael@0 1643 aKeyEvent->StopPropagation();
michael@0 1644 }
michael@0 1645 }
michael@0 1646 }
michael@0 1647
michael@0 1648 return NS_OK;
michael@0 1649 }
michael@0 1650
michael@0 1651 nsresult
michael@0 1652 nsPluginInstanceOwner::ProcessMouseDown(nsIDOMEvent* aMouseEvent)
michael@0 1653 {
michael@0 1654 #if !defined(XP_MACOSX)
michael@0 1655 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
michael@0 1656 return aMouseEvent->PreventDefault(); // consume event
michael@0 1657 // continue only for cases without child window
michael@0 1658 #endif
michael@0 1659
michael@0 1660 // if the plugin is windowless, we need to set focus ourselves
michael@0 1661 // otherwise, we might not get key events
michael@0 1662 if (mObjectFrame && mPluginWindow &&
michael@0 1663 mPluginWindow->type == NPWindowTypeDrawable) {
michael@0 1664
michael@0 1665 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
michael@0 1666 if (fm) {
michael@0 1667 nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(mContent);
michael@0 1668 fm->SetFocus(elem, 0);
michael@0 1669 }
michael@0 1670 }
michael@0 1671
michael@0 1672 WidgetMouseEvent* mouseEvent =
michael@0 1673 aMouseEvent->GetInternalNSEvent()->AsMouseEvent();
michael@0 1674 if (mouseEvent && mouseEvent->eventStructType == NS_MOUSE_EVENT) {
michael@0 1675 mLastMouseDownButtonType = mouseEvent->button;
michael@0 1676 nsEventStatus rv = ProcessEvent(*mouseEvent);
michael@0 1677 if (nsEventStatus_eConsumeNoDefault == rv) {
michael@0 1678 return aMouseEvent->PreventDefault(); // consume event
michael@0 1679 }
michael@0 1680 }
michael@0 1681
michael@0 1682 return NS_OK;
michael@0 1683 }
michael@0 1684
michael@0 1685 nsresult nsPluginInstanceOwner::DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent,
michael@0 1686 bool aAllowPropagate)
michael@0 1687 {
michael@0 1688 #if !defined(XP_MACOSX)
michael@0 1689 if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
michael@0 1690 return aMouseEvent->PreventDefault(); // consume event
michael@0 1691 // continue only for cases without child window
michael@0 1692 #endif
michael@0 1693 // don't send mouse events if we are hidden
michael@0 1694 if (!mWidgetVisible)
michael@0 1695 return NS_OK;
michael@0 1696
michael@0 1697 WidgetMouseEvent* mouseEvent =
michael@0 1698 aMouseEvent->GetInternalNSEvent()->AsMouseEvent();
michael@0 1699 if (mouseEvent && mouseEvent->eventStructType == NS_MOUSE_EVENT) {
michael@0 1700 nsEventStatus rv = ProcessEvent(*mouseEvent);
michael@0 1701 if (nsEventStatus_eConsumeNoDefault == rv) {
michael@0 1702 aMouseEvent->PreventDefault();
michael@0 1703 if (!aAllowPropagate) {
michael@0 1704 aMouseEvent->StopPropagation();
michael@0 1705 }
michael@0 1706 }
michael@0 1707 if (mouseEvent->message == NS_MOUSE_BUTTON_UP) {
michael@0 1708 mLastMouseDownButtonType = -1;
michael@0 1709 }
michael@0 1710 }
michael@0 1711 return NS_OK;
michael@0 1712 }
michael@0 1713
michael@0 1714 nsresult
michael@0 1715 nsPluginInstanceOwner::HandleEvent(nsIDOMEvent* aEvent)
michael@0 1716 {
michael@0 1717 NS_ASSERTION(mInstance, "Should have a valid plugin instance or not receive events.");
michael@0 1718
michael@0 1719 nsAutoString eventType;
michael@0 1720 aEvent->GetType(eventType);
michael@0 1721 if (eventType.EqualsLiteral("focus")) {
michael@0 1722 mContentFocused = true;
michael@0 1723 return DispatchFocusToPlugin(aEvent);
michael@0 1724 }
michael@0 1725 if (eventType.EqualsLiteral("blur")) {
michael@0 1726 mContentFocused = false;
michael@0 1727 return DispatchFocusToPlugin(aEvent);
michael@0 1728 }
michael@0 1729 if (eventType.EqualsLiteral("mousedown")) {
michael@0 1730 return ProcessMouseDown(aEvent);
michael@0 1731 }
michael@0 1732 if (eventType.EqualsLiteral("mouseup")) {
michael@0 1733 // Don't send a mouse-up event to the plugin if its button type doesn't
michael@0 1734 // match that of the preceding mouse-down event (if any). This kind of
michael@0 1735 // mismatch can happen if the previous mouse-down event was sent to a DOM
michael@0 1736 // element above the plugin, the mouse is still above the plugin, and the
michael@0 1737 // mouse-down event caused the element to disappear. See bug 627649 and
michael@0 1738 // bug 909678.
michael@0 1739 WidgetMouseEvent* mouseEvent = aEvent->GetInternalNSEvent()->AsMouseEvent();
michael@0 1740 if (mouseEvent &&
michael@0 1741 static_cast<int>(mouseEvent->button) != mLastMouseDownButtonType) {
michael@0 1742 aEvent->PreventDefault();
michael@0 1743 return NS_OK;
michael@0 1744 }
michael@0 1745 return DispatchMouseToPlugin(aEvent);
michael@0 1746 }
michael@0 1747 if (eventType.EqualsLiteral("mousemove")) {
michael@0 1748 return DispatchMouseToPlugin(aEvent, true);
michael@0 1749 }
michael@0 1750 if (eventType.EqualsLiteral("click") ||
michael@0 1751 eventType.EqualsLiteral("dblclick") ||
michael@0 1752 eventType.EqualsLiteral("mouseover") ||
michael@0 1753 eventType.EqualsLiteral("mouseout")) {
michael@0 1754 return DispatchMouseToPlugin(aEvent);
michael@0 1755 }
michael@0 1756 if (eventType.EqualsLiteral("keydown") ||
michael@0 1757 eventType.EqualsLiteral("keyup")) {
michael@0 1758 return DispatchKeyToPlugin(aEvent);
michael@0 1759 }
michael@0 1760 if (eventType.EqualsLiteral("keypress")) {
michael@0 1761 return ProcessKeyPress(aEvent);
michael@0 1762 }
michael@0 1763
michael@0 1764 nsCOMPtr<nsIDOMDragEvent> dragEvent(do_QueryInterface(aEvent));
michael@0 1765 if (dragEvent && mInstance) {
michael@0 1766 WidgetEvent* ievent = aEvent->GetInternalNSEvent();
michael@0 1767 if ((ievent && ievent->mFlags.mIsTrusted) &&
michael@0 1768 ievent->message != NS_DRAGDROP_ENTER && ievent->message != NS_DRAGDROP_OVER) {
michael@0 1769 aEvent->PreventDefault();
michael@0 1770 }
michael@0 1771
michael@0 1772 // Let the plugin handle drag events.
michael@0 1773 aEvent->StopPropagation();
michael@0 1774 }
michael@0 1775 return NS_OK;
michael@0 1776 }
michael@0 1777
michael@0 1778 #ifdef MOZ_X11
michael@0 1779 static unsigned int XInputEventState(const WidgetInputEvent& anEvent)
michael@0 1780 {
michael@0 1781 unsigned int state = 0;
michael@0 1782 if (anEvent.IsShift()) state |= ShiftMask;
michael@0 1783 if (anEvent.IsControl()) state |= ControlMask;
michael@0 1784 if (anEvent.IsAlt()) state |= Mod1Mask;
michael@0 1785 if (anEvent.IsMeta()) state |= Mod4Mask;
michael@0 1786 return state;
michael@0 1787 }
michael@0 1788 #endif
michael@0 1789
michael@0 1790 nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
michael@0 1791 {
michael@0 1792 nsEventStatus rv = nsEventStatus_eIgnore;
michael@0 1793
michael@0 1794 if (!mInstance || !mObjectFrame) // if mInstance is null, we shouldn't be here
michael@0 1795 return nsEventStatus_eIgnore;
michael@0 1796
michael@0 1797 #ifdef XP_MACOSX
michael@0 1798 if (!mWidget)
michael@0 1799 return nsEventStatus_eIgnore;
michael@0 1800
michael@0 1801 // we never care about synthesized mouse enter
michael@0 1802 if (anEvent.message == NS_MOUSE_ENTER_SYNTH)
michael@0 1803 return nsEventStatus_eIgnore;
michael@0 1804
michael@0 1805 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
michael@0 1806 if (!pluginWidget || NS_FAILED(pluginWidget->StartDrawPlugin()))
michael@0 1807 return nsEventStatus_eIgnore;
michael@0 1808
michael@0 1809 NPEventModel eventModel = GetEventModel();
michael@0 1810
michael@0 1811 // If we have to synthesize an event we'll use one of these.
michael@0 1812 NPCocoaEvent synthCocoaEvent;
michael@0 1813 void* event = anEvent.pluginEvent;
michael@0 1814 nsPoint pt =
michael@0 1815 nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
michael@0 1816 mObjectFrame->GetContentRectRelativeToSelf().TopLeft();
michael@0 1817 nsPresContext* presContext = mObjectFrame->PresContext();
michael@0 1818 // Plugin event coordinates need to be translated from device pixels
michael@0 1819 // into "display pixels" in HiDPI modes.
michael@0 1820 double scaleFactor = 1.0;
michael@0 1821 GetContentsScaleFactor(&scaleFactor);
michael@0 1822 size_t intScaleFactor = ceil(scaleFactor);
michael@0 1823 nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x) / intScaleFactor,
michael@0 1824 presContext->AppUnitsToDevPixels(pt.y) / intScaleFactor);
michael@0 1825
michael@0 1826 if (!event) {
michael@0 1827 InitializeNPCocoaEvent(&synthCocoaEvent);
michael@0 1828 switch (anEvent.message) {
michael@0 1829 case NS_MOUSE_MOVE:
michael@0 1830 {
michael@0 1831 // Ignore mouse-moved events that happen as part of a dragging
michael@0 1832 // operation that started over another frame. See bug 525078.
michael@0 1833 nsRefPtr<nsFrameSelection> frameselection = mObjectFrame->GetFrameSelection();
michael@0 1834 if (!frameselection->GetMouseDownState() ||
michael@0 1835 (nsIPresShell::GetCapturingContent() == mObjectFrame->GetContent())) {
michael@0 1836 synthCocoaEvent.type = NPCocoaEventMouseMoved;
michael@0 1837 synthCocoaEvent.data.mouse.pluginX = static_cast<double>(ptPx.x);
michael@0 1838 synthCocoaEvent.data.mouse.pluginY = static_cast<double>(ptPx.y);
michael@0 1839 event = &synthCocoaEvent;
michael@0 1840 }
michael@0 1841 }
michael@0 1842 break;
michael@0 1843 case NS_MOUSE_BUTTON_DOWN:
michael@0 1844 synthCocoaEvent.type = NPCocoaEventMouseDown;
michael@0 1845 synthCocoaEvent.data.mouse.pluginX = static_cast<double>(ptPx.x);
michael@0 1846 synthCocoaEvent.data.mouse.pluginY = static_cast<double>(ptPx.y);
michael@0 1847 event = &synthCocoaEvent;
michael@0 1848 break;
michael@0 1849 case NS_MOUSE_BUTTON_UP:
michael@0 1850 // If we're in a dragging operation that started over another frame,
michael@0 1851 // convert it into a mouse-entered event (in the Cocoa Event Model).
michael@0 1852 // See bug 525078.
michael@0 1853 if (anEvent.AsMouseEvent()->button == WidgetMouseEvent::eLeftButton &&
michael@0 1854 (nsIPresShell::GetCapturingContent() != mObjectFrame->GetContent())) {
michael@0 1855 synthCocoaEvent.type = NPCocoaEventMouseEntered;
michael@0 1856 synthCocoaEvent.data.mouse.pluginX = static_cast<double>(ptPx.x);
michael@0 1857 synthCocoaEvent.data.mouse.pluginY = static_cast<double>(ptPx.y);
michael@0 1858 event = &synthCocoaEvent;
michael@0 1859 } else {
michael@0 1860 synthCocoaEvent.type = NPCocoaEventMouseUp;
michael@0 1861 synthCocoaEvent.data.mouse.pluginX = static_cast<double>(ptPx.x);
michael@0 1862 synthCocoaEvent.data.mouse.pluginY = static_cast<double>(ptPx.y);
michael@0 1863 event = &synthCocoaEvent;
michael@0 1864 }
michael@0 1865 break;
michael@0 1866 default:
michael@0 1867 break;
michael@0 1868 }
michael@0 1869
michael@0 1870 // If we still don't have an event, bail.
michael@0 1871 if (!event) {
michael@0 1872 pluginWidget->EndDrawPlugin();
michael@0 1873 return nsEventStatus_eIgnore;
michael@0 1874 }
michael@0 1875 }
michael@0 1876
michael@0 1877 int16_t response = kNPEventNotHandled;
michael@0 1878 void* window = FixUpPluginWindow(ePluginPaintEnable);
michael@0 1879 if (window || (eventModel == NPEventModelCocoa)) {
michael@0 1880 mInstance->HandleEvent(event, &response, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
michael@0 1881 }
michael@0 1882
michael@0 1883 if (eventModel == NPEventModelCocoa && response == kNPEventStartIME) {
michael@0 1884 pluginWidget->StartComplexTextInputForCurrentEvent();
michael@0 1885 }
michael@0 1886
michael@0 1887 if ((response == kNPEventHandled || response == kNPEventStartIME) &&
michael@0 1888 !(anEvent.message == NS_MOUSE_BUTTON_DOWN &&
michael@0 1889 anEvent.AsMouseEvent()->button == WidgetMouseEvent::eLeftButton &&
michael@0 1890 !mContentFocused)) {
michael@0 1891 rv = nsEventStatus_eConsumeNoDefault;
michael@0 1892 }
michael@0 1893
michael@0 1894 pluginWidget->EndDrawPlugin();
michael@0 1895 #endif
michael@0 1896
michael@0 1897 #ifdef XP_WIN
michael@0 1898 // this code supports windowless plugins
michael@0 1899 NPEvent *pPluginEvent = (NPEvent*)anEvent.pluginEvent;
michael@0 1900 // we can get synthetic events from the EventStateManager... these
michael@0 1901 // have no pluginEvent
michael@0 1902 NPEvent pluginEvent;
michael@0 1903 if (anEvent.eventStructType == NS_MOUSE_EVENT) {
michael@0 1904 if (!pPluginEvent) {
michael@0 1905 // XXX Should extend this list to synthesize events for more event
michael@0 1906 // types
michael@0 1907 pluginEvent.event = 0;
michael@0 1908 const WidgetMouseEvent* mouseEvent = anEvent.AsMouseEvent();
michael@0 1909 switch (anEvent.message) {
michael@0 1910 case NS_MOUSE_MOVE:
michael@0 1911 pluginEvent.event = WM_MOUSEMOVE;
michael@0 1912 break;
michael@0 1913 case NS_MOUSE_BUTTON_DOWN: {
michael@0 1914 static const int downMsgs[] =
michael@0 1915 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
michael@0 1916 static const int dblClickMsgs[] =
michael@0 1917 { WM_LBUTTONDBLCLK, WM_MBUTTONDBLCLK, WM_RBUTTONDBLCLK };
michael@0 1918 if (mouseEvent->clickCount == 2) {
michael@0 1919 pluginEvent.event = dblClickMsgs[mouseEvent->button];
michael@0 1920 } else {
michael@0 1921 pluginEvent.event = downMsgs[mouseEvent->button];
michael@0 1922 }
michael@0 1923 break;
michael@0 1924 }
michael@0 1925 case NS_MOUSE_BUTTON_UP: {
michael@0 1926 static const int upMsgs[] =
michael@0 1927 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
michael@0 1928 pluginEvent.event = upMsgs[mouseEvent->button];
michael@0 1929 break;
michael@0 1930 }
michael@0 1931 // don't synthesize anything for NS_MOUSE_DOUBLECLICK, since that
michael@0 1932 // is a synthetic event generated on mouse-up, and Windows WM_*DBLCLK
michael@0 1933 // messages are sent on mouse-down
michael@0 1934 default:
michael@0 1935 break;
michael@0 1936 }
michael@0 1937 if (pluginEvent.event) {
michael@0 1938 pPluginEvent = &pluginEvent;
michael@0 1939 pluginEvent.wParam =
michael@0 1940 (::GetKeyState(VK_CONTROL) ? MK_CONTROL : 0) |
michael@0 1941 (::GetKeyState(VK_SHIFT) ? MK_SHIFT : 0) |
michael@0 1942 (::GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0) |
michael@0 1943 (::GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0) |
michael@0 1944 (::GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0) |
michael@0 1945 (::GetKeyState(VK_XBUTTON1) ? MK_XBUTTON1 : 0) |
michael@0 1946 (::GetKeyState(VK_XBUTTON2) ? MK_XBUTTON2 : 0);
michael@0 1947 }
michael@0 1948 }
michael@0 1949 if (pPluginEvent) {
michael@0 1950 // Make event coordinates relative to our enclosing widget,
michael@0 1951 // not the widget they were received on.
michael@0 1952 // See use of NPEvent in widget/windows/nsWindow.cpp
michael@0 1953 // for why this assert should be safe
michael@0 1954 NS_ASSERTION(anEvent.message == NS_MOUSE_BUTTON_DOWN ||
michael@0 1955 anEvent.message == NS_MOUSE_BUTTON_UP ||
michael@0 1956 anEvent.message == NS_MOUSE_DOUBLECLICK ||
michael@0 1957 anEvent.message == NS_MOUSE_ENTER_SYNTH ||
michael@0 1958 anEvent.message == NS_MOUSE_EXIT_SYNTH ||
michael@0 1959 anEvent.message == NS_MOUSE_MOVE,
michael@0 1960 "Incorrect event type for coordinate translation");
michael@0 1961 nsPoint pt =
michael@0 1962 nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
michael@0 1963 mObjectFrame->GetContentRectRelativeToSelf().TopLeft();
michael@0 1964 nsPresContext* presContext = mObjectFrame->PresContext();
michael@0 1965 nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x),
michael@0 1966 presContext->AppUnitsToDevPixels(pt.y));
michael@0 1967 nsIntPoint widgetPtPx = ptPx + mObjectFrame->GetWindowOriginInPixels(true);
michael@0 1968 pPluginEvent->lParam = MAKELPARAM(widgetPtPx.x, widgetPtPx.y);
michael@0 1969 }
michael@0 1970 }
michael@0 1971 else if (!pPluginEvent) {
michael@0 1972 switch (anEvent.message) {
michael@0 1973 case NS_FOCUS_CONTENT:
michael@0 1974 pluginEvent.event = WM_SETFOCUS;
michael@0 1975 pluginEvent.wParam = 0;
michael@0 1976 pluginEvent.lParam = 0;
michael@0 1977 pPluginEvent = &pluginEvent;
michael@0 1978 break;
michael@0 1979 case NS_BLUR_CONTENT:
michael@0 1980 pluginEvent.event = WM_KILLFOCUS;
michael@0 1981 pluginEvent.wParam = 0;
michael@0 1982 pluginEvent.lParam = 0;
michael@0 1983 pPluginEvent = &pluginEvent;
michael@0 1984 break;
michael@0 1985 }
michael@0 1986 }
michael@0 1987
michael@0 1988 if (pPluginEvent && !pPluginEvent->event) {
michael@0 1989 // Don't send null events to plugins.
michael@0 1990 NS_WARNING("nsObjectFrame ProcessEvent: trying to send null event to plugin.");
michael@0 1991 return rv;
michael@0 1992 }
michael@0 1993
michael@0 1994 if (pPluginEvent) {
michael@0 1995 int16_t response = kNPEventNotHandled;
michael@0 1996 mInstance->HandleEvent(pPluginEvent, &response, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
michael@0 1997 if (response == kNPEventHandled)
michael@0 1998 rv = nsEventStatus_eConsumeNoDefault;
michael@0 1999 }
michael@0 2000 #endif
michael@0 2001
michael@0 2002 #ifdef MOZ_X11
michael@0 2003 // this code supports windowless plugins
michael@0 2004 nsIWidget* widget = anEvent.widget;
michael@0 2005 XEvent pluginEvent = XEvent();
michael@0 2006 pluginEvent.type = 0;
michael@0 2007
michael@0 2008 switch(anEvent.eventStructType)
michael@0 2009 {
michael@0 2010 case NS_MOUSE_EVENT:
michael@0 2011 {
michael@0 2012 switch (anEvent.message)
michael@0 2013 {
michael@0 2014 case NS_MOUSE_CLICK:
michael@0 2015 case NS_MOUSE_DOUBLECLICK:
michael@0 2016 // Button up/down events sent instead.
michael@0 2017 return rv;
michael@0 2018 }
michael@0 2019
michael@0 2020 // Get reference point relative to plugin origin.
michael@0 2021 const nsPresContext* presContext = mObjectFrame->PresContext();
michael@0 2022 nsPoint appPoint =
michael@0 2023 nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
michael@0 2024 mObjectFrame->GetContentRectRelativeToSelf().TopLeft();
michael@0 2025 nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x),
michael@0 2026 presContext->AppUnitsToDevPixels(appPoint.y));
michael@0 2027 const WidgetMouseEvent& mouseEvent = *anEvent.AsMouseEvent();
michael@0 2028 // Get reference point relative to screen:
michael@0 2029 LayoutDeviceIntPoint rootPoint(-1, -1);
michael@0 2030 if (widget)
michael@0 2031 rootPoint = anEvent.refPoint +
michael@0 2032 LayoutDeviceIntPoint::FromUntyped(widget->WidgetToScreenOffset());
michael@0 2033 #ifdef MOZ_WIDGET_GTK
michael@0 2034 Window root = GDK_ROOT_WINDOW();
michael@0 2035 #elif defined(MOZ_WIDGET_QT)
michael@0 2036 Window root = RootWindowOfScreen(DefaultScreenOfDisplay(mozilla::DefaultXDisplay()));
michael@0 2037 #else
michael@0 2038 Window root = None; // Could XQueryTree, but this is not important.
michael@0 2039 #endif
michael@0 2040
michael@0 2041 switch (anEvent.message)
michael@0 2042 {
michael@0 2043 case NS_MOUSE_ENTER_SYNTH:
michael@0 2044 case NS_MOUSE_EXIT_SYNTH:
michael@0 2045 {
michael@0 2046 XCrossingEvent& event = pluginEvent.xcrossing;
michael@0 2047 event.type = anEvent.message == NS_MOUSE_ENTER_SYNTH ?
michael@0 2048 EnterNotify : LeaveNotify;
michael@0 2049 event.root = root;
michael@0 2050 event.time = anEvent.time;
michael@0 2051 event.x = pluginPoint.x;
michael@0 2052 event.y = pluginPoint.y;
michael@0 2053 event.x_root = rootPoint.x;
michael@0 2054 event.y_root = rootPoint.y;
michael@0 2055 event.state = XInputEventState(mouseEvent);
michael@0 2056 // information lost
michael@0 2057 event.subwindow = None;
michael@0 2058 event.mode = -1;
michael@0 2059 event.detail = NotifyDetailNone;
michael@0 2060 event.same_screen = True;
michael@0 2061 event.focus = mContentFocused;
michael@0 2062 }
michael@0 2063 break;
michael@0 2064 case NS_MOUSE_MOVE:
michael@0 2065 {
michael@0 2066 XMotionEvent& event = pluginEvent.xmotion;
michael@0 2067 event.type = MotionNotify;
michael@0 2068 event.root = root;
michael@0 2069 event.time = anEvent.time;
michael@0 2070 event.x = pluginPoint.x;
michael@0 2071 event.y = pluginPoint.y;
michael@0 2072 event.x_root = rootPoint.x;
michael@0 2073 event.y_root = rootPoint.y;
michael@0 2074 event.state = XInputEventState(mouseEvent);
michael@0 2075 // information lost
michael@0 2076 event.subwindow = None;
michael@0 2077 event.is_hint = NotifyNormal;
michael@0 2078 event.same_screen = True;
michael@0 2079 }
michael@0 2080 break;
michael@0 2081 case NS_MOUSE_BUTTON_DOWN:
michael@0 2082 case NS_MOUSE_BUTTON_UP:
michael@0 2083 {
michael@0 2084 XButtonEvent& event = pluginEvent.xbutton;
michael@0 2085 event.type = anEvent.message == NS_MOUSE_BUTTON_DOWN ?
michael@0 2086 ButtonPress : ButtonRelease;
michael@0 2087 event.root = root;
michael@0 2088 event.time = anEvent.time;
michael@0 2089 event.x = pluginPoint.x;
michael@0 2090 event.y = pluginPoint.y;
michael@0 2091 event.x_root = rootPoint.x;
michael@0 2092 event.y_root = rootPoint.y;
michael@0 2093 event.state = XInputEventState(mouseEvent);
michael@0 2094 switch (mouseEvent.button)
michael@0 2095 {
michael@0 2096 case WidgetMouseEvent::eMiddleButton:
michael@0 2097 event.button = 2;
michael@0 2098 break;
michael@0 2099 case WidgetMouseEvent::eRightButton:
michael@0 2100 event.button = 3;
michael@0 2101 break;
michael@0 2102 default: // WidgetMouseEvent::eLeftButton;
michael@0 2103 event.button = 1;
michael@0 2104 break;
michael@0 2105 }
michael@0 2106 // information lost:
michael@0 2107 event.subwindow = None;
michael@0 2108 event.same_screen = True;
michael@0 2109 }
michael@0 2110 break;
michael@0 2111 }
michael@0 2112 }
michael@0 2113 break;
michael@0 2114
michael@0 2115 //XXX case NS_MOUSE_SCROLL_EVENT: not received.
michael@0 2116
michael@0 2117 case NS_KEY_EVENT:
michael@0 2118 if (anEvent.pluginEvent)
michael@0 2119 {
michael@0 2120 XKeyEvent &event = pluginEvent.xkey;
michael@0 2121 #ifdef MOZ_WIDGET_GTK
michael@0 2122 event.root = GDK_ROOT_WINDOW();
michael@0 2123 event.time = anEvent.time;
michael@0 2124 const GdkEventKey* gdkEvent =
michael@0 2125 static_cast<const GdkEventKey*>(anEvent.pluginEvent);
michael@0 2126 event.keycode = gdkEvent->hardware_keycode;
michael@0 2127 event.state = gdkEvent->state;
michael@0 2128 switch (anEvent.message)
michael@0 2129 {
michael@0 2130 case NS_KEY_DOWN:
michael@0 2131 // Handle NS_KEY_DOWN for modifier key presses
michael@0 2132 // For non-modifiers we get NS_KEY_PRESS
michael@0 2133 if (gdkEvent->is_modifier)
michael@0 2134 event.type = XKeyPress;
michael@0 2135 break;
michael@0 2136 case NS_KEY_PRESS:
michael@0 2137 event.type = XKeyPress;
michael@0 2138 break;
michael@0 2139 case NS_KEY_UP:
michael@0 2140 event.type = KeyRelease;
michael@0 2141 break;
michael@0 2142 }
michael@0 2143 #endif
michael@0 2144
michael@0 2145 // Information that could be obtained from pluginEvent but we may not
michael@0 2146 // want to promise to provide:
michael@0 2147 event.subwindow = None;
michael@0 2148 event.x = 0;
michael@0 2149 event.y = 0;
michael@0 2150 event.x_root = -1;
michael@0 2151 event.y_root = -1;
michael@0 2152 event.same_screen = False;
michael@0 2153 }
michael@0 2154 else
michael@0 2155 {
michael@0 2156 // If we need to send synthesized key events, then
michael@0 2157 // DOMKeyCodeToGdkKeyCode(keyEvent.keyCode) and
michael@0 2158 // gdk_keymap_get_entries_for_keyval will be useful, but the
michael@0 2159 // mappings will not be unique.
michael@0 2160 NS_WARNING("Synthesized key event not sent to plugin");
michael@0 2161 }
michael@0 2162 break;
michael@0 2163
michael@0 2164 default:
michael@0 2165 switch (anEvent.message)
michael@0 2166 {
michael@0 2167 case NS_FOCUS_CONTENT:
michael@0 2168 case NS_BLUR_CONTENT:
michael@0 2169 {
michael@0 2170 XFocusChangeEvent &event = pluginEvent.xfocus;
michael@0 2171 event.type =
michael@0 2172 anEvent.message == NS_FOCUS_CONTENT ? FocusIn : FocusOut;
michael@0 2173 // information lost:
michael@0 2174 event.mode = -1;
michael@0 2175 event.detail = NotifyDetailNone;
michael@0 2176 }
michael@0 2177 break;
michael@0 2178 }
michael@0 2179 }
michael@0 2180
michael@0 2181 if (!pluginEvent.type) {
michael@0 2182 return rv;
michael@0 2183 }
michael@0 2184
michael@0 2185 // Fill in (useless) generic event information.
michael@0 2186 XAnyEvent& event = pluginEvent.xany;
michael@0 2187 event.display = widget ?
michael@0 2188 static_cast<Display*>(widget->GetNativeData(NS_NATIVE_DISPLAY)) : nullptr;
michael@0 2189 event.window = None; // not a real window
michael@0 2190 // information lost:
michael@0 2191 event.serial = 0;
michael@0 2192 event.send_event = False;
michael@0 2193
michael@0 2194 int16_t response = kNPEventNotHandled;
michael@0 2195 mInstance->HandleEvent(&pluginEvent, &response, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
michael@0 2196 if (response == kNPEventHandled)
michael@0 2197 rv = nsEventStatus_eConsumeNoDefault;
michael@0 2198 #endif
michael@0 2199
michael@0 2200 #ifdef MOZ_WIDGET_ANDROID
michael@0 2201 // this code supports windowless plugins
michael@0 2202 {
michael@0 2203 // The plugin needs focus to receive keyboard and touch events
michael@0 2204 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
michael@0 2205 if (fm) {
michael@0 2206 nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(mContent);
michael@0 2207 fm->SetFocus(elem, 0);
michael@0 2208 }
michael@0 2209 }
michael@0 2210 switch(anEvent.eventStructType)
michael@0 2211 {
michael@0 2212 case NS_MOUSE_EVENT:
michael@0 2213 {
michael@0 2214 switch (anEvent.message)
michael@0 2215 {
michael@0 2216 case NS_MOUSE_CLICK:
michael@0 2217 case NS_MOUSE_DOUBLECLICK:
michael@0 2218 // Button up/down events sent instead.
michael@0 2219 return rv;
michael@0 2220 }
michael@0 2221
michael@0 2222 // Get reference point relative to plugin origin.
michael@0 2223 const nsPresContext* presContext = mObjectFrame->PresContext();
michael@0 2224 nsPoint appPoint =
michael@0 2225 nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mObjectFrame) -
michael@0 2226 mObjectFrame->GetContentRectRelativeToSelf().TopLeft();
michael@0 2227 nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x),
michael@0 2228 presContext->AppUnitsToDevPixels(appPoint.y));
michael@0 2229
michael@0 2230 switch (anEvent.message)
michael@0 2231 {
michael@0 2232 case NS_MOUSE_MOVE:
michael@0 2233 {
michael@0 2234 // are these going to be touch events?
michael@0 2235 // pluginPoint.x;
michael@0 2236 // pluginPoint.y;
michael@0 2237 }
michael@0 2238 break;
michael@0 2239 case NS_MOUSE_BUTTON_DOWN:
michael@0 2240 {
michael@0 2241 ANPEvent event;
michael@0 2242 event.inSize = sizeof(ANPEvent);
michael@0 2243 event.eventType = kMouse_ANPEventType;
michael@0 2244 event.data.mouse.action = kDown_ANPMouseAction;
michael@0 2245 event.data.mouse.x = pluginPoint.x;
michael@0 2246 event.data.mouse.y = pluginPoint.y;
michael@0 2247 mInstance->HandleEvent(&event, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
michael@0 2248 }
michael@0 2249 break;
michael@0 2250 case NS_MOUSE_BUTTON_UP:
michael@0 2251 {
michael@0 2252 ANPEvent event;
michael@0 2253 event.inSize = sizeof(ANPEvent);
michael@0 2254 event.eventType = kMouse_ANPEventType;
michael@0 2255 event.data.mouse.action = kUp_ANPMouseAction;
michael@0 2256 event.data.mouse.x = pluginPoint.x;
michael@0 2257 event.data.mouse.y = pluginPoint.y;
michael@0 2258 mInstance->HandleEvent(&event, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
michael@0 2259 }
michael@0 2260 break;
michael@0 2261 }
michael@0 2262 }
michael@0 2263 break;
michael@0 2264
michael@0 2265 case NS_KEY_EVENT:
michael@0 2266 {
michael@0 2267 const WidgetKeyboardEvent& keyEvent = *anEvent.AsKeyboardEvent();
michael@0 2268 LOG("Firing NS_KEY_EVENT %d %d\n", keyEvent.keyCode, keyEvent.charCode);
michael@0 2269 // pluginEvent is initialized by nsWindow::InitKeyEvent().
michael@0 2270 ANPEvent* pluginEvent = reinterpret_cast<ANPEvent*>(keyEvent.pluginEvent);
michael@0 2271 if (pluginEvent) {
michael@0 2272 MOZ_ASSERT(pluginEvent->inSize == sizeof(ANPEvent));
michael@0 2273 MOZ_ASSERT(pluginEvent->eventType == kKey_ANPEventType);
michael@0 2274 mInstance->HandleEvent(pluginEvent, nullptr, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
michael@0 2275 }
michael@0 2276 }
michael@0 2277 break;
michael@0 2278
michael@0 2279 default:
michael@0 2280 break;
michael@0 2281 }
michael@0 2282 rv = nsEventStatus_eConsumeNoDefault;
michael@0 2283 #endif
michael@0 2284
michael@0 2285 return rv;
michael@0 2286 }
michael@0 2287
michael@0 2288 nsresult
michael@0 2289 nsPluginInstanceOwner::Destroy()
michael@0 2290 {
michael@0 2291 SetFrame(nullptr);
michael@0 2292
michael@0 2293 #ifdef XP_MACOSX
michael@0 2294 RemoveFromCARefreshTimer();
michael@0 2295 if (mColorProfile)
michael@0 2296 ::CGColorSpaceRelease(mColorProfile);
michael@0 2297 #endif
michael@0 2298
michael@0 2299 // unregister context menu listener
michael@0 2300 if (mCXMenuListener) {
michael@0 2301 mCXMenuListener->Destroy(mContent);
michael@0 2302 mCXMenuListener = nullptr;
michael@0 2303 }
michael@0 2304
michael@0 2305 mContent->RemoveEventListener(NS_LITERAL_STRING("focus"), this, false);
michael@0 2306 mContent->RemoveEventListener(NS_LITERAL_STRING("blur"), this, false);
michael@0 2307 mContent->RemoveEventListener(NS_LITERAL_STRING("mouseup"), this, false);
michael@0 2308 mContent->RemoveEventListener(NS_LITERAL_STRING("mousedown"), this, false);
michael@0 2309 mContent->RemoveEventListener(NS_LITERAL_STRING("mousemove"), this, false);
michael@0 2310 mContent->RemoveEventListener(NS_LITERAL_STRING("click"), this, false);
michael@0 2311 mContent->RemoveEventListener(NS_LITERAL_STRING("dblclick"), this, false);
michael@0 2312 mContent->RemoveEventListener(NS_LITERAL_STRING("mouseover"), this, false);
michael@0 2313 mContent->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this, false);
michael@0 2314 mContent->RemoveEventListener(NS_LITERAL_STRING("keypress"), this, true);
michael@0 2315 mContent->RemoveEventListener(NS_LITERAL_STRING("keydown"), this, true);
michael@0 2316 mContent->RemoveEventListener(NS_LITERAL_STRING("keyup"), this, true);
michael@0 2317 mContent->RemoveEventListener(NS_LITERAL_STRING("drop"), this, true);
michael@0 2318 mContent->RemoveEventListener(NS_LITERAL_STRING("dragdrop"), this, true);
michael@0 2319 mContent->RemoveEventListener(NS_LITERAL_STRING("drag"), this, true);
michael@0 2320 mContent->RemoveEventListener(NS_LITERAL_STRING("dragenter"), this, true);
michael@0 2321 mContent->RemoveEventListener(NS_LITERAL_STRING("dragover"), this, true);
michael@0 2322 mContent->RemoveEventListener(NS_LITERAL_STRING("dragleave"), this, true);
michael@0 2323 mContent->RemoveEventListener(NS_LITERAL_STRING("dragexit"), this, true);
michael@0 2324 mContent->RemoveEventListener(NS_LITERAL_STRING("dragstart"), this, true);
michael@0 2325 mContent->RemoveEventListener(NS_LITERAL_STRING("draggesture"), this, true);
michael@0 2326 mContent->RemoveEventListener(NS_LITERAL_STRING("dragend"), this, true);
michael@0 2327
michael@0 2328 #if MOZ_WIDGET_ANDROID
michael@0 2329 RemovePluginView();
michael@0 2330 #endif
michael@0 2331
michael@0 2332 if (mWidget) {
michael@0 2333 if (mPluginWindow) {
michael@0 2334 mPluginWindow->SetPluginWidget(nullptr);
michael@0 2335 }
michael@0 2336
michael@0 2337 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
michael@0 2338 if (pluginWidget) {
michael@0 2339 pluginWidget->SetPluginInstanceOwner(nullptr);
michael@0 2340 }
michael@0 2341 mWidget->Destroy();
michael@0 2342 }
michael@0 2343
michael@0 2344 return NS_OK;
michael@0 2345 }
michael@0 2346
michael@0 2347 // Paints are handled differently, so we just simulate an update event.
michael@0 2348
michael@0 2349 #ifdef XP_MACOSX
michael@0 2350 void nsPluginInstanceOwner::Paint(const gfxRect& aDirtyRect, CGContextRef cgContext)
michael@0 2351 {
michael@0 2352 if (!mInstance || !mObjectFrame)
michael@0 2353 return;
michael@0 2354
michael@0 2355 gfxRect dirtyRectCopy = aDirtyRect;
michael@0 2356 double scaleFactor = 1.0;
michael@0 2357 GetContentsScaleFactor(&scaleFactor);
michael@0 2358 if (scaleFactor != 1.0) {
michael@0 2359 ::CGContextScaleCTM(cgContext, scaleFactor, scaleFactor);
michael@0 2360 // Convert aDirtyRect from device pixels to "display pixels"
michael@0 2361 // for HiDPI modes
michael@0 2362 dirtyRectCopy.ScaleRoundOut(1.0 / scaleFactor);
michael@0 2363 }
michael@0 2364
michael@0 2365 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
michael@0 2366 if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) {
michael@0 2367 DoCocoaEventDrawRect(dirtyRectCopy, cgContext);
michael@0 2368 pluginWidget->EndDrawPlugin();
michael@0 2369 }
michael@0 2370 }
michael@0 2371
michael@0 2372 void nsPluginInstanceOwner::DoCocoaEventDrawRect(const gfxRect& aDrawRect, CGContextRef cgContext)
michael@0 2373 {
michael@0 2374 if (!mInstance || !mObjectFrame)
michael@0 2375 return;
michael@0 2376
michael@0 2377 // The context given here is only valid during the HandleEvent call.
michael@0 2378 NPCocoaEvent updateEvent;
michael@0 2379 InitializeNPCocoaEvent(&updateEvent);
michael@0 2380 updateEvent.type = NPCocoaEventDrawRect;
michael@0 2381 updateEvent.data.draw.context = cgContext;
michael@0 2382 updateEvent.data.draw.x = aDrawRect.X();
michael@0 2383 updateEvent.data.draw.y = aDrawRect.Y();
michael@0 2384 updateEvent.data.draw.width = aDrawRect.Width();
michael@0 2385 updateEvent.data.draw.height = aDrawRect.Height();
michael@0 2386
michael@0 2387 mInstance->HandleEvent(&updateEvent, nullptr);
michael@0 2388 }
michael@0 2389 #endif
michael@0 2390
michael@0 2391 #ifdef XP_WIN
michael@0 2392 void nsPluginInstanceOwner::Paint(const RECT& aDirty, HDC aDC)
michael@0 2393 {
michael@0 2394 if (!mInstance || !mObjectFrame)
michael@0 2395 return;
michael@0 2396
michael@0 2397 NPEvent pluginEvent;
michael@0 2398 pluginEvent.event = WM_PAINT;
michael@0 2399 pluginEvent.wParam = WPARAM(aDC);
michael@0 2400 pluginEvent.lParam = LPARAM(&aDirty);
michael@0 2401 mInstance->HandleEvent(&pluginEvent, nullptr);
michael@0 2402 }
michael@0 2403 #endif
michael@0 2404
michael@0 2405 #ifdef MOZ_WIDGET_ANDROID
michael@0 2406
michael@0 2407 void nsPluginInstanceOwner::Paint(gfxContext* aContext,
michael@0 2408 const gfxRect& aFrameRect,
michael@0 2409 const gfxRect& aDirtyRect)
michael@0 2410 {
michael@0 2411 if (!mInstance || !mObjectFrame || !mPluginDocumentActiveState || mFullScreen)
michael@0 2412 return;
michael@0 2413
michael@0 2414 int32_t model = mInstance->GetANPDrawingModel();
michael@0 2415
michael@0 2416 if (model == kSurface_ANPDrawingModel) {
michael@0 2417 if (!AddPluginView(GetPluginRect())) {
michael@0 2418 Invalidate();
michael@0 2419 }
michael@0 2420 return;
michael@0 2421 }
michael@0 2422
michael@0 2423 if (model != kBitmap_ANPDrawingModel)
michael@0 2424 return;
michael@0 2425
michael@0 2426 #ifdef ANP_BITMAP_DRAWING_MODEL
michael@0 2427 static nsRefPtr<gfxImageSurface> pluginSurface;
michael@0 2428
michael@0 2429 if (pluginSurface == nullptr ||
michael@0 2430 aFrameRect.width != pluginSurface->Width() ||
michael@0 2431 aFrameRect.height != pluginSurface->Height()) {
michael@0 2432
michael@0 2433 pluginSurface = new gfxImageSurface(gfxIntSize(aFrameRect.width, aFrameRect.height),
michael@0 2434 gfxImageFormat::ARGB32);
michael@0 2435 if (!pluginSurface)
michael@0 2436 return;
michael@0 2437 }
michael@0 2438
michael@0 2439 // Clears buffer. I think this is needed.
michael@0 2440 nsRefPtr<gfxContext> ctx = new gfxContext(pluginSurface);
michael@0 2441 ctx->SetOperator(gfxContext::OPERATOR_CLEAR);
michael@0 2442 ctx->Paint();
michael@0 2443
michael@0 2444 ANPEvent event;
michael@0 2445 event.inSize = sizeof(ANPEvent);
michael@0 2446 event.eventType = 4;
michael@0 2447 event.data.draw.model = 1;
michael@0 2448
michael@0 2449 event.data.draw.clip.top = 0;
michael@0 2450 event.data.draw.clip.left = 0;
michael@0 2451 event.data.draw.clip.bottom = aFrameRect.width;
michael@0 2452 event.data.draw.clip.right = aFrameRect.height;
michael@0 2453
michael@0 2454 event.data.draw.data.bitmap.format = kRGBA_8888_ANPBitmapFormat;
michael@0 2455 event.data.draw.data.bitmap.width = aFrameRect.width;
michael@0 2456 event.data.draw.data.bitmap.height = aFrameRect.height;
michael@0 2457 event.data.draw.data.bitmap.baseAddr = pluginSurface->Data();
michael@0 2458 event.data.draw.data.bitmap.rowBytes = aFrameRect.width * 4;
michael@0 2459
michael@0 2460 if (!mInstance)
michael@0 2461 return;
michael@0 2462
michael@0 2463 mInstance->HandleEvent(&event, nullptr);
michael@0 2464
michael@0 2465 aContext->SetOperator(gfxContext::OPERATOR_SOURCE);
michael@0 2466 aContext->SetSource(pluginSurface, gfxPoint(aFrameRect.x, aFrameRect.y));
michael@0 2467 aContext->Clip(aFrameRect);
michael@0 2468 aContext->Paint();
michael@0 2469 #endif
michael@0 2470 }
michael@0 2471 #endif
michael@0 2472
michael@0 2473 #if defined(MOZ_X11)
michael@0 2474 void nsPluginInstanceOwner::Paint(gfxContext* aContext,
michael@0 2475 const gfxRect& aFrameRect,
michael@0 2476 const gfxRect& aDirtyRect)
michael@0 2477 {
michael@0 2478 if (!mInstance || !mObjectFrame)
michael@0 2479 return;
michael@0 2480
michael@0 2481 // to provide crisper and faster drawing.
michael@0 2482 gfxRect pluginRect = aFrameRect;
michael@0 2483 if (aContext->UserToDevicePixelSnapped(pluginRect)) {
michael@0 2484 pluginRect = aContext->DeviceToUser(pluginRect);
michael@0 2485 }
michael@0 2486
michael@0 2487 // Round out the dirty rect to plugin pixels to ensure the plugin draws
michael@0 2488 // enough pixels for interpolation to device pixels.
michael@0 2489 gfxRect dirtyRect = aDirtyRect - pluginRect.TopLeft();
michael@0 2490 dirtyRect.RoundOut();
michael@0 2491
michael@0 2492 // Plugins can only draw an integer number of pixels.
michael@0 2493 //
michael@0 2494 // With translation-only transformation matrices, pluginRect is already
michael@0 2495 // pixel-aligned.
michael@0 2496 //
michael@0 2497 // With more complex transformations, modifying the scales in the
michael@0 2498 // transformation matrix could retain subpixel accuracy and let the plugin
michael@0 2499 // draw a suitable number of pixels for interpolation to device pixels in
michael@0 2500 // Renderer::Draw, but such cases are not common enough to warrant the
michael@0 2501 // effort now.
michael@0 2502 nsIntSize pluginSize(NS_lround(pluginRect.width),
michael@0 2503 NS_lround(pluginRect.height));
michael@0 2504
michael@0 2505 // Determine what the plugin needs to draw.
michael@0 2506 nsIntRect pluginDirtyRect(int32_t(dirtyRect.x),
michael@0 2507 int32_t(dirtyRect.y),
michael@0 2508 int32_t(dirtyRect.width),
michael@0 2509 int32_t(dirtyRect.height));
michael@0 2510 if (!pluginDirtyRect.
michael@0 2511 IntersectRect(nsIntRect(0, 0, pluginSize.width, pluginSize.height),
michael@0 2512 pluginDirtyRect))
michael@0 2513 return;
michael@0 2514
michael@0 2515 NPWindow* window;
michael@0 2516 GetWindow(window);
michael@0 2517
michael@0 2518 uint32_t rendererFlags = 0;
michael@0 2519 if (!mFlash10Quirks) {
michael@0 2520 rendererFlags |=
michael@0 2521 Renderer::DRAW_SUPPORTS_CLIP_RECT |
michael@0 2522 Renderer::DRAW_SUPPORTS_ALTERNATE_VISUAL;
michael@0 2523 }
michael@0 2524
michael@0 2525 bool transparent;
michael@0 2526 mInstance->IsTransparent(&transparent);
michael@0 2527 if (!transparent)
michael@0 2528 rendererFlags |= Renderer::DRAW_IS_OPAQUE;
michael@0 2529
michael@0 2530 // Renderer::Draw() draws a rectangle with top-left at the aContext origin.
michael@0 2531 gfxContextAutoSaveRestore autoSR(aContext);
michael@0 2532 aContext->Translate(pluginRect.TopLeft());
michael@0 2533
michael@0 2534 Renderer renderer(window, this, pluginSize, pluginDirtyRect);
michael@0 2535
michael@0 2536 Display* dpy = mozilla::DefaultXDisplay();
michael@0 2537 Screen* screen = DefaultScreenOfDisplay(dpy);
michael@0 2538 Visual* visual = DefaultVisualOfScreen(screen);
michael@0 2539
michael@0 2540 renderer.Draw(aContext, nsIntSize(window->width, window->height),
michael@0 2541 rendererFlags, screen, visual);
michael@0 2542 }
michael@0 2543 nsresult
michael@0 2544 nsPluginInstanceOwner::Renderer::DrawWithXlib(cairo_surface_t* xsurface,
michael@0 2545 nsIntPoint offset,
michael@0 2546 nsIntRect *clipRects,
michael@0 2547 uint32_t numClipRects)
michael@0 2548 {
michael@0 2549 Screen *screen = cairo_xlib_surface_get_screen(xsurface);
michael@0 2550 Colormap colormap;
michael@0 2551 Visual* visual;
michael@0 2552 if (!gfxXlibSurface::GetColormapAndVisual(xsurface, &colormap, &visual)) {
michael@0 2553 NS_ERROR("Failed to get visual and colormap");
michael@0 2554 return NS_ERROR_UNEXPECTED;
michael@0 2555 }
michael@0 2556
michael@0 2557 nsNPAPIPluginInstance *instance = mInstanceOwner->mInstance;
michael@0 2558 if (!instance)
michael@0 2559 return NS_ERROR_FAILURE;
michael@0 2560
michael@0 2561 // See if the plugin must be notified of new window parameters.
michael@0 2562 bool doupdatewindow = false;
michael@0 2563
michael@0 2564 if (mWindow->x != offset.x || mWindow->y != offset.y) {
michael@0 2565 mWindow->x = offset.x;
michael@0 2566 mWindow->y = offset.y;
michael@0 2567 doupdatewindow = true;
michael@0 2568 }
michael@0 2569
michael@0 2570 if (nsIntSize(mWindow->width, mWindow->height) != mPluginSize) {
michael@0 2571 mWindow->width = mPluginSize.width;
michael@0 2572 mWindow->height = mPluginSize.height;
michael@0 2573 doupdatewindow = true;
michael@0 2574 }
michael@0 2575
michael@0 2576 // The clip rect is relative to drawable top-left.
michael@0 2577 NS_ASSERTION(numClipRects <= 1, "We don't support multiple clip rectangles!");
michael@0 2578 nsIntRect clipRect;
michael@0 2579 if (numClipRects) {
michael@0 2580 clipRect.x = clipRects[0].x;
michael@0 2581 clipRect.y = clipRects[0].y;
michael@0 2582 clipRect.width = clipRects[0].width;
michael@0 2583 clipRect.height = clipRects[0].height;
michael@0 2584 // NPRect members are unsigned, but clip rectangles should be contained by
michael@0 2585 // the surface.
michael@0 2586 NS_ASSERTION(clipRect.x >= 0 && clipRect.y >= 0,
michael@0 2587 "Clip rectangle offsets are negative!");
michael@0 2588 }
michael@0 2589 else {
michael@0 2590 clipRect.x = offset.x;
michael@0 2591 clipRect.y = offset.y;
michael@0 2592 clipRect.width = mWindow->width;
michael@0 2593 clipRect.height = mWindow->height;
michael@0 2594 // Don't ask the plugin to draw outside the drawable.
michael@0 2595 // This also ensures that the unsigned clip rectangle offsets won't be -ve.
michael@0 2596 clipRect.IntersectRect(clipRect,
michael@0 2597 nsIntRect(0, 0,
michael@0 2598 cairo_xlib_surface_get_width(xsurface),
michael@0 2599 cairo_xlib_surface_get_height(xsurface)));
michael@0 2600 }
michael@0 2601
michael@0 2602 NPRect newClipRect;
michael@0 2603 newClipRect.left = clipRect.x;
michael@0 2604 newClipRect.top = clipRect.y;
michael@0 2605 newClipRect.right = clipRect.XMost();
michael@0 2606 newClipRect.bottom = clipRect.YMost();
michael@0 2607 if (mWindow->clipRect.left != newClipRect.left ||
michael@0 2608 mWindow->clipRect.top != newClipRect.top ||
michael@0 2609 mWindow->clipRect.right != newClipRect.right ||
michael@0 2610 mWindow->clipRect.bottom != newClipRect.bottom) {
michael@0 2611 mWindow->clipRect = newClipRect;
michael@0 2612 doupdatewindow = true;
michael@0 2613 }
michael@0 2614
michael@0 2615 NPSetWindowCallbackStruct* ws_info =
michael@0 2616 static_cast<NPSetWindowCallbackStruct*>(mWindow->ws_info);
michael@0 2617 #ifdef MOZ_X11
michael@0 2618 if (ws_info->visual != visual || ws_info->colormap != colormap) {
michael@0 2619 ws_info->visual = visual;
michael@0 2620 ws_info->colormap = colormap;
michael@0 2621 ws_info->depth = gfxXlibSurface::DepthOfVisual(screen, visual);
michael@0 2622 doupdatewindow = true;
michael@0 2623 }
michael@0 2624 #endif
michael@0 2625
michael@0 2626 {
michael@0 2627 if (doupdatewindow)
michael@0 2628 instance->SetWindow(mWindow);
michael@0 2629 }
michael@0 2630
michael@0 2631 // Translate the dirty rect to drawable coordinates.
michael@0 2632 nsIntRect dirtyRect = mDirtyRect + offset;
michael@0 2633 if (mInstanceOwner->mFlash10Quirks) {
michael@0 2634 // Work around a bug in Flash up to 10.1 d51 at least, where expose event
michael@0 2635 // top left coordinates within the plugin-rect and not at the drawable
michael@0 2636 // origin are misinterpreted. (We can move the top left coordinate
michael@0 2637 // provided it is within the clipRect.)
michael@0 2638 dirtyRect.SetRect(offset.x, offset.y,
michael@0 2639 mDirtyRect.XMost(), mDirtyRect.YMost());
michael@0 2640 }
michael@0 2641 // Intersect the dirty rect with the clip rect to ensure that it lies within
michael@0 2642 // the drawable.
michael@0 2643 if (!dirtyRect.IntersectRect(dirtyRect, clipRect))
michael@0 2644 return NS_OK;
michael@0 2645
michael@0 2646 {
michael@0 2647 XEvent pluginEvent = XEvent();
michael@0 2648 XGraphicsExposeEvent& exposeEvent = pluginEvent.xgraphicsexpose;
michael@0 2649 // set the drawing info
michael@0 2650 exposeEvent.type = GraphicsExpose;
michael@0 2651 exposeEvent.display = DisplayOfScreen(screen);
michael@0 2652 exposeEvent.drawable = cairo_xlib_surface_get_drawable(xsurface);
michael@0 2653 exposeEvent.x = dirtyRect.x;
michael@0 2654 exposeEvent.y = dirtyRect.y;
michael@0 2655 exposeEvent.width = dirtyRect.width;
michael@0 2656 exposeEvent.height = dirtyRect.height;
michael@0 2657 exposeEvent.count = 0;
michael@0 2658 // information not set:
michael@0 2659 exposeEvent.serial = 0;
michael@0 2660 exposeEvent.send_event = False;
michael@0 2661 exposeEvent.major_code = 0;
michael@0 2662 exposeEvent.minor_code = 0;
michael@0 2663
michael@0 2664 instance->HandleEvent(&pluginEvent, nullptr);
michael@0 2665 }
michael@0 2666 return NS_OK;
michael@0 2667 }
michael@0 2668 #endif
michael@0 2669
michael@0 2670 nsresult nsPluginInstanceOwner::Init(nsIContent* aContent)
michael@0 2671 {
michael@0 2672 mLastEventloopNestingLevel = GetEventloopNestingLevel();
michael@0 2673
michael@0 2674 mContent = aContent;
michael@0 2675
michael@0 2676 // Get a frame, don't reflow. If a reflow was necessary it should have been
michael@0 2677 // done at a higher level than this (content).
michael@0 2678 nsIFrame* frame = aContent->GetPrimaryFrame();
michael@0 2679 nsIObjectFrame* iObjFrame = do_QueryFrame(frame);
michael@0 2680 nsObjectFrame* objFrame = static_cast<nsObjectFrame*>(iObjFrame);
michael@0 2681 if (objFrame) {
michael@0 2682 SetFrame(objFrame);
michael@0 2683 // Some plugins require a specific sequence of shutdown and startup when
michael@0 2684 // a page is reloaded. Shutdown happens usually when the last instance
michael@0 2685 // is destroyed. Here we make sure the plugin instance in the old
michael@0 2686 // document is destroyed before we try to create the new one.
michael@0 2687 objFrame->PresContext()->EnsureVisible();
michael@0 2688 } else {
michael@0 2689 NS_NOTREACHED("Should not be initializing plugin without a frame");
michael@0 2690 return NS_ERROR_FAILURE;
michael@0 2691 }
michael@0 2692
michael@0 2693 // register context menu listener
michael@0 2694 mCXMenuListener = new nsPluginDOMContextMenuListener(aContent);
michael@0 2695
michael@0 2696 mContent->AddEventListener(NS_LITERAL_STRING("focus"), this, false,
michael@0 2697 false);
michael@0 2698 mContent->AddEventListener(NS_LITERAL_STRING("blur"), this, false,
michael@0 2699 false);
michael@0 2700 mContent->AddEventListener(NS_LITERAL_STRING("mouseup"), this, false,
michael@0 2701 false);
michael@0 2702 mContent->AddEventListener(NS_LITERAL_STRING("mousedown"), this, false,
michael@0 2703 false);
michael@0 2704 mContent->AddEventListener(NS_LITERAL_STRING("mousemove"), this, false,
michael@0 2705 false);
michael@0 2706 mContent->AddEventListener(NS_LITERAL_STRING("click"), this, false,
michael@0 2707 false);
michael@0 2708 mContent->AddEventListener(NS_LITERAL_STRING("dblclick"), this, false,
michael@0 2709 false);
michael@0 2710 mContent->AddEventListener(NS_LITERAL_STRING("mouseover"), this, false,
michael@0 2711 false);
michael@0 2712 mContent->AddEventListener(NS_LITERAL_STRING("mouseout"), this, false,
michael@0 2713 false);
michael@0 2714 mContent->AddEventListener(NS_LITERAL_STRING("keypress"), this, true);
michael@0 2715 mContent->AddEventListener(NS_LITERAL_STRING("keydown"), this, true);
michael@0 2716 mContent->AddEventListener(NS_LITERAL_STRING("keyup"), this, true);
michael@0 2717 mContent->AddEventListener(NS_LITERAL_STRING("drop"), this, true);
michael@0 2718 mContent->AddEventListener(NS_LITERAL_STRING("dragdrop"), this, true);
michael@0 2719 mContent->AddEventListener(NS_LITERAL_STRING("drag"), this, true);
michael@0 2720 mContent->AddEventListener(NS_LITERAL_STRING("dragenter"), this, true);
michael@0 2721 mContent->AddEventListener(NS_LITERAL_STRING("dragover"), this, true);
michael@0 2722 mContent->AddEventListener(NS_LITERAL_STRING("dragleave"), this, true);
michael@0 2723 mContent->AddEventListener(NS_LITERAL_STRING("dragexit"), this, true);
michael@0 2724 mContent->AddEventListener(NS_LITERAL_STRING("dragstart"), this, true);
michael@0 2725 mContent->AddEventListener(NS_LITERAL_STRING("draggesture"), this, true);
michael@0 2726 mContent->AddEventListener(NS_LITERAL_STRING("dragend"), this, true);
michael@0 2727
michael@0 2728 return NS_OK;
michael@0 2729 }
michael@0 2730
michael@0 2731 void* nsPluginInstanceOwner::GetPluginPortFromWidget()
michael@0 2732 {
michael@0 2733 //!!! Port must be released for windowless plugins on Windows, because it is HDC !!!
michael@0 2734
michael@0 2735 void* result = nullptr;
michael@0 2736 if (mWidget) {
michael@0 2737 #ifdef XP_WIN
michael@0 2738 if (mPluginWindow && (mPluginWindow->type == NPWindowTypeDrawable))
michael@0 2739 result = mWidget->GetNativeData(NS_NATIVE_GRAPHIC);
michael@0 2740 else
michael@0 2741 #endif
michael@0 2742 #ifdef XP_MACOSX
michael@0 2743 if (GetDrawingModel() == NPDrawingModelCoreGraphics ||
michael@0 2744 GetDrawingModel() == NPDrawingModelCoreAnimation ||
michael@0 2745 GetDrawingModel() == NPDrawingModelInvalidatingCoreAnimation)
michael@0 2746 result = mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT_CG);
michael@0 2747 else
michael@0 2748 #endif
michael@0 2749 result = mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
michael@0 2750 }
michael@0 2751 return result;
michael@0 2752 }
michael@0 2753
michael@0 2754 void nsPluginInstanceOwner::ReleasePluginPort(void * pluginPort)
michael@0 2755 {
michael@0 2756 #ifdef XP_WIN
michael@0 2757 if (mWidget && mPluginWindow &&
michael@0 2758 mPluginWindow->type == NPWindowTypeDrawable) {
michael@0 2759 mWidget->FreeNativeData((HDC)pluginPort, NS_NATIVE_GRAPHIC);
michael@0 2760 }
michael@0 2761 #endif
michael@0 2762 }
michael@0 2763
michael@0 2764 NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void)
michael@0 2765 {
michael@0 2766 NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER);
michael@0 2767
michael@0 2768 nsresult rv = NS_ERROR_FAILURE;
michael@0 2769
michael@0 2770 // Can't call this twice!
michael@0 2771 if (mWidget) {
michael@0 2772 NS_WARNING("Trying to create a plugin widget twice!");
michael@0 2773 return NS_ERROR_FAILURE;
michael@0 2774 }
michael@0 2775
michael@0 2776 bool windowless = false;
michael@0 2777 mInstance->IsWindowless(&windowless);
michael@0 2778 if (!windowless && !nsIWidget::UsePuppetWidgets()) {
michael@0 2779 // Try to get a parent widget, on some platforms widget creation will fail without
michael@0 2780 // a parent.
michael@0 2781 nsCOMPtr<nsIWidget> parentWidget;
michael@0 2782 nsIDocument *doc = nullptr;
michael@0 2783 if (mContent) {
michael@0 2784 doc = mContent->OwnerDoc();
michael@0 2785 parentWidget = nsContentUtils::WidgetForDocument(doc);
michael@0 2786 }
michael@0 2787
michael@0 2788 mWidget = do_CreateInstance(kWidgetCID, &rv);
michael@0 2789 if (NS_FAILED(rv)) {
michael@0 2790 return rv;
michael@0 2791 }
michael@0 2792
michael@0 2793 nsWidgetInitData initData;
michael@0 2794 initData.mWindowType = eWindowType_plugin;
michael@0 2795 initData.mUnicode = false;
michael@0 2796 initData.clipChildren = true;
michael@0 2797 initData.clipSiblings = true;
michael@0 2798 rv = mWidget->Create(parentWidget.get(), nullptr, nsIntRect(0,0,0,0),
michael@0 2799 nullptr, &initData);
michael@0 2800 if (NS_FAILED(rv)) {
michael@0 2801 mWidget->Destroy();
michael@0 2802 mWidget = nullptr;
michael@0 2803 return rv;
michael@0 2804 }
michael@0 2805
michael@0 2806 mWidget->EnableDragDrop(true);
michael@0 2807 mWidget->Show(false);
michael@0 2808 mWidget->Enable(false);
michael@0 2809
michael@0 2810 #ifdef XP_MACOSX
michael@0 2811 // Now that we have a widget we want to set the event model before
michael@0 2812 // any events are processed.
michael@0 2813 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
michael@0 2814 if (!pluginWidget) {
michael@0 2815 return NS_ERROR_FAILURE;
michael@0 2816 }
michael@0 2817 pluginWidget->SetPluginEventModel(GetEventModel());
michael@0 2818 pluginWidget->SetPluginDrawingModel(GetDrawingModel());
michael@0 2819
michael@0 2820 if (GetDrawingModel() == NPDrawingModelCoreAnimation) {
michael@0 2821 AddToCARefreshTimer();
michael@0 2822 }
michael@0 2823 #endif
michael@0 2824 }
michael@0 2825
michael@0 2826 if (mObjectFrame) {
michael@0 2827 // nullptr widget is fine, will result in windowless setup.
michael@0 2828 mObjectFrame->PrepForDrawing(mWidget);
michael@0 2829 }
michael@0 2830
michael@0 2831 if (windowless) {
michael@0 2832 mPluginWindow->type = NPWindowTypeDrawable;
michael@0 2833
michael@0 2834 // this needs to be a HDC according to the spec, but I do
michael@0 2835 // not see the right way to release it so let's postpone
michael@0 2836 // passing HDC till paint event when it is really
michael@0 2837 // needed. Change spec?
michael@0 2838 mPluginWindow->window = nullptr;
michael@0 2839 #ifdef MOZ_X11
michael@0 2840 // Fill in the display field.
michael@0 2841 NPSetWindowCallbackStruct* ws_info =
michael@0 2842 static_cast<NPSetWindowCallbackStruct*>(mPluginWindow->ws_info);
michael@0 2843 ws_info->display = DefaultXDisplay();
michael@0 2844
michael@0 2845 nsAutoCString description;
michael@0 2846 GetPluginDescription(description);
michael@0 2847 NS_NAMED_LITERAL_CSTRING(flash10Head, "Shockwave Flash 10.");
michael@0 2848 mFlash10Quirks = StringBeginsWith(description, flash10Head);
michael@0 2849 #endif
michael@0 2850 } else if (mWidget) {
michael@0 2851 // mPluginWindow->type is used in |GetPluginPort| so it must
michael@0 2852 // be initialized first
michael@0 2853 mPluginWindow->type = NPWindowTypeWindow;
michael@0 2854 mPluginWindow->window = GetPluginPortFromWidget();
michael@0 2855 // tell the plugin window about the widget
michael@0 2856 mPluginWindow->SetPluginWidget(mWidget);
michael@0 2857
michael@0 2858 // tell the widget about the current plugin instance owner.
michael@0 2859 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
michael@0 2860 if (pluginWidget) {
michael@0 2861 pluginWidget->SetPluginInstanceOwner(this);
michael@0 2862 }
michael@0 2863 }
michael@0 2864
michael@0 2865 mWidgetCreationComplete = true;
michael@0 2866
michael@0 2867 return NS_OK;
michael@0 2868 }
michael@0 2869
michael@0 2870 // Mac specific code to fix up the port location and clipping region
michael@0 2871 #ifdef XP_MACOSX
michael@0 2872
michael@0 2873 void* nsPluginInstanceOwner::FixUpPluginWindow(int32_t inPaintState)
michael@0 2874 {
michael@0 2875 if (!mWidget || !mPluginWindow || !mInstance || !mObjectFrame)
michael@0 2876 return nullptr;
michael@0 2877
michael@0 2878 nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
michael@0 2879 if (!pluginWidget)
michael@0 2880 return nullptr;
michael@0 2881
michael@0 2882 // If we've already set up a CGContext in nsObjectFrame::PaintPlugin(), we
michael@0 2883 // don't want calls to SetPluginPortAndDetectChange() to step on our work.
michael@0 2884 if (mInCGPaintLevel < 1) {
michael@0 2885 SetPluginPortAndDetectChange();
michael@0 2886 }
michael@0 2887
michael@0 2888 // We'll need the top-level Cocoa window for the Cocoa event model.
michael@0 2889 nsIWidget* widget = mObjectFrame->GetNearestWidget();
michael@0 2890 if (!widget)
michael@0 2891 return nullptr;
michael@0 2892 void *cocoaTopLevelWindow = widget->GetNativeData(NS_NATIVE_WINDOW);
michael@0 2893 if (!cocoaTopLevelWindow)
michael@0 2894 return nullptr;
michael@0 2895
michael@0 2896 nsIntPoint pluginOrigin;
michael@0 2897 nsIntRect widgetClip;
michael@0 2898 bool widgetVisible;
michael@0 2899 pluginWidget->GetPluginClipRect(widgetClip, pluginOrigin, widgetVisible);
michael@0 2900 mWidgetVisible = widgetVisible;
michael@0 2901
michael@0 2902 // printf("GetPluginClipRect returning visible %d\n", widgetVisible);
michael@0 2903
michael@0 2904 // This would be a lot easier if we could use obj-c here,
michael@0 2905 // but we can't. Since we have only nsIWidget and we can't
michael@0 2906 // use its native widget (an obj-c object) we have to go
michael@0 2907 // from the widget's screen coordinates to its window coords
michael@0 2908 // instead of straight to window coords.
michael@0 2909 nsIntPoint geckoScreenCoords = mWidget->WidgetToScreenOffset();
michael@0 2910
michael@0 2911 nsRect windowRect;
michael@0 2912 NS_NPAPI_CocoaWindowFrame(cocoaTopLevelWindow, windowRect);
michael@0 2913
michael@0 2914 double scaleFactor = 1.0;
michael@0 2915 GetContentsScaleFactor(&scaleFactor);
michael@0 2916 int intScaleFactor = ceil(scaleFactor);
michael@0 2917
michael@0 2918 // Convert geckoScreenCoords from device pixels to "display pixels"
michael@0 2919 // for HiDPI modes.
michael@0 2920 mPluginWindow->x = geckoScreenCoords.x/intScaleFactor - windowRect.x;
michael@0 2921 mPluginWindow->y = geckoScreenCoords.y/intScaleFactor - windowRect.y;
michael@0 2922
michael@0 2923 NPRect oldClipRect = mPluginWindow->clipRect;
michael@0 2924
michael@0 2925 // fix up the clipping region
michael@0 2926 mPluginWindow->clipRect.top = widgetClip.y;
michael@0 2927 mPluginWindow->clipRect.left = widgetClip.x;
michael@0 2928
michael@0 2929 if (!mWidgetVisible || inPaintState == ePluginPaintDisable) {
michael@0 2930 mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top;
michael@0 2931 mPluginWindow->clipRect.right = mPluginWindow->clipRect.left;
michael@0 2932 }
michael@0 2933 else if (inPaintState == ePluginPaintEnable)
michael@0 2934 {
michael@0 2935 mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top + widgetClip.height;
michael@0 2936 mPluginWindow->clipRect.right = mPluginWindow->clipRect.left + widgetClip.width;
michael@0 2937 }
michael@0 2938
michael@0 2939 // if the clip rect changed, call SetWindow()
michael@0 2940 // (RealPlayer needs this to draw correctly)
michael@0 2941 if (mPluginWindow->clipRect.left != oldClipRect.left ||
michael@0 2942 mPluginWindow->clipRect.top != oldClipRect.top ||
michael@0 2943 mPluginWindow->clipRect.right != oldClipRect.right ||
michael@0 2944 mPluginWindow->clipRect.bottom != oldClipRect.bottom ||
michael@0 2945 mPluginPortChanged)
michael@0 2946 {
michael@0 2947 if (UseAsyncRendering()) {
michael@0 2948 mInstance->AsyncSetWindow(mPluginWindow);
michael@0 2949 }
michael@0 2950 else {
michael@0 2951 mPluginWindow->CallSetWindow(mInstance);
michael@0 2952 }
michael@0 2953 mPluginPortChanged = false;
michael@0 2954 }
michael@0 2955
michael@0 2956 // After the first NPP_SetWindow call we need to send an initial
michael@0 2957 // top-level window focus event.
michael@0 2958 if (!mSentInitialTopLevelWindowEvent) {
michael@0 2959 // Set this before calling ProcessEvent to avoid endless recursion.
michael@0 2960 mSentInitialTopLevelWindowEvent = true;
michael@0 2961
michael@0 2962 WidgetPluginEvent pluginEvent(true, NS_PLUGIN_FOCUS_EVENT, nullptr);
michael@0 2963 NPCocoaEvent cocoaEvent;
michael@0 2964 InitializeNPCocoaEvent(&cocoaEvent);
michael@0 2965 cocoaEvent.type = NPCocoaEventWindowFocusChanged;
michael@0 2966 cocoaEvent.data.focus.hasFocus = NS_NPAPI_CocoaWindowIsMain(cocoaTopLevelWindow);
michael@0 2967 pluginEvent.pluginEvent = &cocoaEvent;
michael@0 2968 ProcessEvent(pluginEvent);
michael@0 2969 }
michael@0 2970
michael@0 2971 return nullptr;
michael@0 2972 }
michael@0 2973
michael@0 2974 void
michael@0 2975 nsPluginInstanceOwner::HidePluginWindow()
michael@0 2976 {
michael@0 2977 if (!mPluginWindow || !mInstance) {
michael@0 2978 return;
michael@0 2979 }
michael@0 2980
michael@0 2981 mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top;
michael@0 2982 mPluginWindow->clipRect.right = mPluginWindow->clipRect.left;
michael@0 2983 mWidgetVisible = false;
michael@0 2984 if (UseAsyncRendering()) {
michael@0 2985 mInstance->AsyncSetWindow(mPluginWindow);
michael@0 2986 } else {
michael@0 2987 mInstance->SetWindow(mPluginWindow);
michael@0 2988 }
michael@0 2989 }
michael@0 2990
michael@0 2991 #else // XP_MACOSX
michael@0 2992
michael@0 2993 void nsPluginInstanceOwner::UpdateWindowPositionAndClipRect(bool aSetWindow)
michael@0 2994 {
michael@0 2995 if (!mPluginWindow)
michael@0 2996 return;
michael@0 2997
michael@0 2998 // For windowless plugins a non-empty clip rectangle will be
michael@0 2999 // passed to the plugin during paint, an additional update
michael@0 3000 // of the the clip rectangle here is not required
michael@0 3001 if (aSetWindow && !mWidget && mPluginWindowVisible && !UseAsyncRendering())
michael@0 3002 return;
michael@0 3003
michael@0 3004 const NPWindow oldWindow = *mPluginWindow;
michael@0 3005
michael@0 3006 bool windowless = (mPluginWindow->type == NPWindowTypeDrawable);
michael@0 3007 nsIntPoint origin = mObjectFrame->GetWindowOriginInPixels(windowless);
michael@0 3008
michael@0 3009 mPluginWindow->x = origin.x;
michael@0 3010 mPluginWindow->y = origin.y;
michael@0 3011
michael@0 3012 mPluginWindow->clipRect.left = 0;
michael@0 3013 mPluginWindow->clipRect.top = 0;
michael@0 3014
michael@0 3015 if (mPluginWindowVisible && mPluginDocumentActiveState) {
michael@0 3016 mPluginWindow->clipRect.right = mPluginWindow->width;
michael@0 3017 mPluginWindow->clipRect.bottom = mPluginWindow->height;
michael@0 3018 } else {
michael@0 3019 mPluginWindow->clipRect.right = 0;
michael@0 3020 mPluginWindow->clipRect.bottom = 0;
michael@0 3021 }
michael@0 3022
michael@0 3023 if (!aSetWindow)
michael@0 3024 return;
michael@0 3025
michael@0 3026 if (mPluginWindow->x != oldWindow.x ||
michael@0 3027 mPluginWindow->y != oldWindow.y ||
michael@0 3028 mPluginWindow->clipRect.left != oldWindow.clipRect.left ||
michael@0 3029 mPluginWindow->clipRect.top != oldWindow.clipRect.top ||
michael@0 3030 mPluginWindow->clipRect.right != oldWindow.clipRect.right ||
michael@0 3031 mPluginWindow->clipRect.bottom != oldWindow.clipRect.bottom) {
michael@0 3032 CallSetWindow();
michael@0 3033 }
michael@0 3034 }
michael@0 3035
michael@0 3036 void
michael@0 3037 nsPluginInstanceOwner::UpdateWindowVisibility(bool aVisible)
michael@0 3038 {
michael@0 3039 mPluginWindowVisible = aVisible;
michael@0 3040 UpdateWindowPositionAndClipRect(true);
michael@0 3041 }
michael@0 3042
michael@0 3043 void
michael@0 3044 nsPluginInstanceOwner::UpdateDocumentActiveState(bool aIsActive)
michael@0 3045 {
michael@0 3046 mPluginDocumentActiveState = aIsActive;
michael@0 3047 UpdateWindowPositionAndClipRect(true);
michael@0 3048
michael@0 3049 #ifdef MOZ_WIDGET_ANDROID
michael@0 3050 if (mInstance) {
michael@0 3051 if (!mPluginDocumentActiveState)
michael@0 3052 RemovePluginView();
michael@0 3053
michael@0 3054 mInstance->NotifyOnScreen(mPluginDocumentActiveState);
michael@0 3055
michael@0 3056 // This is, perhaps, incorrect. It is supposed to be sent
michael@0 3057 // when "the webview has paused or resumed". The side effect
michael@0 3058 // is that Flash video players pause or resume (if they were
michael@0 3059 // playing before) based on the value here. I personally think
michael@0 3060 // we want that on Android when switching to another tab, so
michael@0 3061 // that's why we call it here.
michael@0 3062 mInstance->NotifyForeground(mPluginDocumentActiveState);
michael@0 3063 }
michael@0 3064 #endif
michael@0 3065 }
michael@0 3066 #endif // XP_MACOSX
michael@0 3067
michael@0 3068 NS_IMETHODIMP
michael@0 3069 nsPluginInstanceOwner::CallSetWindow()
michael@0 3070 {
michael@0 3071 if (mObjectFrame) {
michael@0 3072 mObjectFrame->CallSetWindow(false);
michael@0 3073 } else if (mInstance) {
michael@0 3074 if (UseAsyncRendering()) {
michael@0 3075 mInstance->AsyncSetWindow(mPluginWindow);
michael@0 3076 } else {
michael@0 3077 mInstance->SetWindow(mPluginWindow);
michael@0 3078 }
michael@0 3079 }
michael@0 3080
michael@0 3081 return NS_OK;
michael@0 3082 }
michael@0 3083
michael@0 3084 NS_IMETHODIMP
michael@0 3085 nsPluginInstanceOwner::GetContentsScaleFactor(double *result)
michael@0 3086 {
michael@0 3087 NS_ENSURE_ARG_POINTER(result);
michael@0 3088 double scaleFactor = 1.0;
michael@0 3089 // On Mac, device pixels need to be translated to (and from) "display pixels"
michael@0 3090 // for plugins. On other platforms, plugin coordinates are always in device
michael@0 3091 // pixels.
michael@0 3092 #if defined(XP_MACOSX)
michael@0 3093 nsIPresShell* presShell = nsContentUtils::FindPresShellForDocument(mContent->OwnerDoc());
michael@0 3094 if (presShell) {
michael@0 3095 scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
michael@0 3096 presShell->GetPresContext()->DeviceContext()->UnscaledAppUnitsPerDevPixel();
michael@0 3097 }
michael@0 3098 #endif
michael@0 3099 *result = scaleFactor;
michael@0 3100 return NS_OK;
michael@0 3101 }
michael@0 3102
michael@0 3103 void nsPluginInstanceOwner::SetFrame(nsObjectFrame *aFrame)
michael@0 3104 {
michael@0 3105 // Don't do anything if the frame situation hasn't changed.
michael@0 3106 if (mObjectFrame == aFrame) {
michael@0 3107 return;
michael@0 3108 }
michael@0 3109
michael@0 3110 // If we already have a frame that is changing or going away...
michael@0 3111 if (mObjectFrame) {
michael@0 3112 // Make sure the old frame isn't holding a reference to us.
michael@0 3113 mObjectFrame->SetInstanceOwner(nullptr);
michael@0 3114 }
michael@0 3115
michael@0 3116 // Swap in the new frame (or no frame)
michael@0 3117 mObjectFrame = aFrame;
michael@0 3118
michael@0 3119 // Set up a new frame
michael@0 3120 if (mObjectFrame) {
michael@0 3121 mObjectFrame->SetInstanceOwner(this);
michael@0 3122 // Can only call PrepForDrawing on an object frame once. Don't do it here unless
michael@0 3123 // widget creation is complete. Doesn't matter if we actually have a widget.
michael@0 3124 if (mWidgetCreationComplete) {
michael@0 3125 mObjectFrame->PrepForDrawing(mWidget);
michael@0 3126 }
michael@0 3127 mObjectFrame->FixupWindow(mObjectFrame->GetContentRectRelativeToSelf().Size());
michael@0 3128 mObjectFrame->InvalidateFrame();
michael@0 3129
michael@0 3130 nsFocusManager* fm = nsFocusManager::GetFocusManager();
michael@0 3131 const nsIContent* content = aFrame->GetContent();
michael@0 3132 if (fm && content) {
michael@0 3133 mContentFocused = (content == fm->GetFocusedContent());
michael@0 3134 }
michael@0 3135 }
michael@0 3136 }
michael@0 3137
michael@0 3138 nsObjectFrame* nsPluginInstanceOwner::GetFrame()
michael@0 3139 {
michael@0 3140 return mObjectFrame;
michael@0 3141 }
michael@0 3142
michael@0 3143 // Little helper function to resolve relative URL in
michael@0 3144 // |value| for certain inputs of |name|
michael@0 3145 void nsPluginInstanceOwner::FixUpURLS(const nsString &name, nsAString &value)
michael@0 3146 {
michael@0 3147 if (name.LowerCaseEqualsLiteral("pluginspage")) {
michael@0 3148 nsCOMPtr<nsIURI> baseURI = GetBaseURI();
michael@0 3149 nsAutoString newURL;
michael@0 3150 NS_MakeAbsoluteURI(newURL, value, baseURI);
michael@0 3151 if (!newURL.IsEmpty())
michael@0 3152 value = newURL;
michael@0 3153 }
michael@0 3154 }
michael@0 3155
michael@0 3156 NS_IMETHODIMP nsPluginInstanceOwner::PrivateModeChanged(bool aEnabled)
michael@0 3157 {
michael@0 3158 return mInstance ? mInstance->PrivateModeStateChanged(aEnabled) : NS_OK;
michael@0 3159 }
michael@0 3160
michael@0 3161 already_AddRefed<nsIURI> nsPluginInstanceOwner::GetBaseURI() const
michael@0 3162 {
michael@0 3163 if (!mContent) {
michael@0 3164 return nullptr;
michael@0 3165 }
michael@0 3166 return mContent->GetBaseURI();
michael@0 3167 }
michael@0 3168
michael@0 3169 // nsPluginDOMContextMenuListener class implementation
michael@0 3170
michael@0 3171 nsPluginDOMContextMenuListener::nsPluginDOMContextMenuListener(nsIContent* aContent)
michael@0 3172 {
michael@0 3173 aContent->AddEventListener(NS_LITERAL_STRING("contextmenu"), this, true);
michael@0 3174 }
michael@0 3175
michael@0 3176 nsPluginDOMContextMenuListener::~nsPluginDOMContextMenuListener()
michael@0 3177 {
michael@0 3178 }
michael@0 3179
michael@0 3180 NS_IMPL_ISUPPORTS(nsPluginDOMContextMenuListener,
michael@0 3181 nsIDOMEventListener)
michael@0 3182
michael@0 3183 NS_IMETHODIMP
michael@0 3184 nsPluginDOMContextMenuListener::HandleEvent(nsIDOMEvent* aEvent)
michael@0 3185 {
michael@0 3186 aEvent->PreventDefault(); // consume event
michael@0 3187
michael@0 3188 return NS_OK;
michael@0 3189 }
michael@0 3190
michael@0 3191 void nsPluginDOMContextMenuListener::Destroy(nsIContent* aContent)
michael@0 3192 {
michael@0 3193 // Unregister context menu listener
michael@0 3194 aContent->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this, true);
michael@0 3195 }

mercurial