Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/plugins/base/nsPluginInstanceOwner.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
// vim:set ts=2 sts=2 sw=2 et cin:
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifdef MOZ_X11
8
#include <cairo-xlib.h>
9
#include "gfxXlibSurface.h"
10
/* X headers suck */
11
enum { XKeyPress = KeyPress };
12
#include "mozilla/X11Util.h"
13
using mozilla::DefaultXDisplay;
14
#endif
15
16
#include "nsPluginInstanceOwner.h"
17
18
#include "gfxUtils.h"
19
#include "nsIRunnable.h"
20
#include "nsContentUtils.h"
21
#include "nsRect.h"
22
#include "nsSize.h"
23
#include "nsDisplayList.h"
24
#include "ImageLayers.h"
25
#include "GLImages.h"
26
#include "nsPluginFrame.h"
27
#include "nsIPluginDocument.h"
28
#include "nsIStringStream.h"
29
#include "nsNetUtil.h"
30
#include "mozilla/Preferences.h"
31
#include "nsILinkHandler.h"
32
#include "nsIDocShellTreeItem.h"
33
#include "nsIWebBrowserChrome.h"
34
#include "nsLayoutUtils.h"
35
#include "nsIPluginWidget.h"
36
#include "nsViewManager.h"
37
#include "nsIDocShellTreeOwner.h"
38
#include "nsIAppShell.h"
39
#include "nsIObjectLoadingContent.h"
40
#include "nsObjectLoadingContent.h"
41
#include "nsAttrName.h"
42
#include "nsIFocusManager.h"
43
#include "nsFocusManager.h"
44
#include "nsIScriptSecurityManager.h"
45
#include "nsIScrollableFrame.h"
46
#include "nsIDocShell.h"
47
#include "ImageContainer.h"
48
#include "GLContext.h"
49
#include "EGLUtils.h"
50
#include "nsIContentInlines.h"
51
#include "mozilla/MiscEvents.h"
52
#include "mozilla/MouseEvents.h"
53
#include "mozilla/TextEvents.h"
54
#include "mozilla/dom/DragEvent.h"
55
#include "mozilla/dom/Element.h"
56
#include "mozilla/dom/Event.h"
57
#include "mozilla/dom/HTMLObjectElementBinding.h"
58
#include "mozilla/dom/TabChild.h"
59
#include "mozilla/dom/WheelEventBinding.h"
60
#include "nsFrameSelection.h"
61
#include "PuppetWidget.h"
62
#include "nsPIWindowRoot.h"
63
#include "mozilla/IMEStateManager.h"
64
#include "mozilla/TextComposition.h"
65
#include "mozilla/AutoRestore.h"
66
67
#include "nsContentCID.h"
68
#include "nsWidgetsCID.h"
69
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
70
71
#ifdef XP_WIN
72
#include <wtypes.h>
73
#include <winuser.h>
74
#include "mozilla/widget/WinMessages.h"
75
#endif // #ifdef XP_WIN
76
77
#ifdef XP_MACOSX
78
#include "ComplexTextInputPanel.h"
79
#endif
80
81
#ifdef MOZ_WIDGET_GTK
82
#include <gdk/gdk.h>
83
#include <gtk/gtk.h>
84
#endif
85
86
using namespace mozilla;
87
using namespace mozilla::dom;
88
using namespace mozilla::layers;
89
90
// special class for handeling DOM context menu events because for
91
// some reason it starves other mouse events if implemented on the
92
// same class
93
class nsPluginDOMContextMenuListener : public nsIDOMEventListener
94
{
95
  virtual ~nsPluginDOMContextMenuListener();
96
97
public:
98
  explicit nsPluginDOMContextMenuListener(nsIContent* aContent);
99
100
  NS_DECL_ISUPPORTS
101
  NS_DECL_NSIDOMEVENTLISTENER
102
103
  void Destroy(nsIContent* aContent);
104
105
  nsEventStatus ProcessEvent(const WidgetGUIEvent& anEvent)
106
0
  {
107
0
    return nsEventStatus_eConsumeNoDefault;
108
0
  }
109
};
110
111
class AsyncPaintWaitEvent : public Runnable
112
{
113
public:
114
  AsyncPaintWaitEvent(nsIContent* aContent, bool aFinished) :
115
    Runnable("AsyncPaintWaitEvent"),
116
    mContent(aContent),
117
    mFinished(aFinished)
118
0
  {
119
0
  }
120
121
  NS_IMETHOD Run() override
122
0
  {
123
0
    nsContentUtils::DispatchTrustedEvent(mContent->OwnerDoc(), mContent,
124
0
        mFinished ? NS_LITERAL_STRING("MozPaintWaitFinished") : NS_LITERAL_STRING("MozPaintWait"),
125
0
        CanBubble::eYes, Cancelable::eYes);
126
0
    return NS_OK;
127
0
  }
128
129
private:
130
  nsCOMPtr<nsIContent> mContent;
131
  bool                 mFinished;
132
};
133
134
void
135
nsPluginInstanceOwner::NotifyPaintWaiter(nsDisplayListBuilder* aBuilder)
136
0
{
137
0
  // This is notification for reftests about async plugin paint start
138
0
  if (!mWaitingForPaint && !IsUpToDate() && aBuilder->ShouldSyncDecodeImages()) {
139
0
    nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
140
0
    nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(content, false);
141
0
    // Run this event as soon as it's safe to do so, since listeners need to
142
0
    // receive it immediately
143
0
    nsContentUtils::AddScriptRunner(event);
144
0
    mWaitingForPaint = true;
145
0
  }
146
0
}
147
148
bool
149
nsPluginInstanceOwner::NeedsScrollImageLayer()
150
0
{
151
#if defined(XP_WIN)
152
  // If this is a windowed plugin and we're doing layout in the content
153
  // process, force the creation of an image layer for the plugin. We'll
154
  // paint to this when scrolling.
155
  return XRE_IsContentProcess() &&
156
         mPluginWindow &&
157
         mPluginWindow->type == NPWindowTypeWindow;
158
#else
159
  return false;
160
0
#endif
161
0
}
162
163
already_AddRefed<ImageContainer>
164
nsPluginInstanceOwner::GetImageContainer()
165
0
{
166
0
  if (!mInstance)
167
0
    return nullptr;
168
0
169
0
  RefPtr<ImageContainer> container;
170
0
171
0
  if (NeedsScrollImageLayer()) {
172
0
    // windowed plugin under e10s
173
#if defined(XP_WIN)
174
    mInstance->GetScrollCaptureContainer(getter_AddRefs(container));
175
#endif
176
0
  } else {
177
0
    // async windowless rendering
178
0
    mInstance->GetImageContainer(getter_AddRefs(container));
179
0
  }
180
0
181
0
  return container.forget();
182
0
}
183
184
void
185
nsPluginInstanceOwner::DidComposite()
186
0
{
187
0
  if (mInstance) {
188
0
    mInstance->DidComposite();
189
0
  }
190
0
}
191
192
void
193
nsPluginInstanceOwner::SetBackgroundUnknown()
194
0
{
195
0
  if (mInstance) {
196
0
    mInstance->SetBackgroundUnknown();
197
0
  }
198
0
}
199
200
already_AddRefed<mozilla::gfx::DrawTarget>
201
nsPluginInstanceOwner::BeginUpdateBackground(const nsIntRect& aRect)
202
0
{
203
0
  nsIntRect rect = aRect;
204
0
  RefPtr<DrawTarget> dt;
205
0
  if (mInstance &&
206
0
      NS_SUCCEEDED(mInstance->BeginUpdateBackground(&rect, getter_AddRefs(dt)))) {
207
0
    return dt.forget();
208
0
  }
209
0
  return nullptr;
210
0
}
211
212
void
213
nsPluginInstanceOwner::EndUpdateBackground(const nsIntRect& aRect)
214
0
{
215
0
  nsIntRect rect = aRect;
216
0
  if (mInstance) {
217
0
    mInstance->EndUpdateBackground(&rect);
218
0
  }
219
0
}
220
221
bool
222
nsPluginInstanceOwner::UseAsyncRendering()
223
0
{
224
#ifdef XP_MACOSX
225
  if (mUseAsyncRendering) {
226
    return true;
227
  }
228
#endif
229
230
0
  bool isOOP;
231
0
  bool result = (mInstance &&
232
0
          NS_SUCCEEDED(mInstance->GetIsOOP(&isOOP)) && isOOP
233
0
#ifndef XP_MACOSX
234
0
          && (!mPluginWindow ||
235
0
           mPluginWindow->type == NPWindowTypeDrawable)
236
0
#endif
237
0
          );
238
0
239
#ifdef XP_MACOSX
240
  if (result) {
241
    mUseAsyncRendering = true;
242
  }
243
#endif
244
245
0
  return result;
246
0
}
247
248
nsIntSize
249
nsPluginInstanceOwner::GetCurrentImageSize()
250
0
{
251
0
  nsIntSize size(0,0);
252
0
  if (mInstance) {
253
0
    mInstance->GetImageSize(&size);
254
0
  }
255
0
  return size;
256
0
}
257
258
nsPluginInstanceOwner::nsPluginInstanceOwner()
259
  : mPluginWindow(nullptr)
260
  , mLastEventloopNestingLevel(0)
261
0
{
262
0
  // create nsPluginNativeWindow object, it is derived from NPWindow
263
0
  // struct and allows to manipulate native window procedure
264
0
  nsCOMPtr<nsIPluginHost> pluginHostCOM = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
265
0
  mPluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
266
0
  if (mPluginHost)
267
0
    mPluginHost->NewPluginNativeWindow(&mPluginWindow);
268
0
269
0
  mPluginFrame = nullptr;
270
0
  mWidgetCreationComplete = false;
271
#ifdef XP_MACOSX
272
  mSentInitialTopLevelWindowEvent = false;
273
  mLastWindowIsActive = false;
274
  mLastContentFocused = false;
275
  mLastScaleFactor = 1.0;
276
  mShouldBlurOnActivate = false;
277
#endif
278
  mLastCSSZoomFactor = 1.0;
279
0
  mContentFocused = false;
280
0
  mWidgetVisible = true;
281
0
  mPluginWindowVisible = false;
282
0
  mPluginDocumentActiveState = true;
283
0
  mLastMouseDownButtonType = -1;
284
0
285
#ifdef XP_MACOSX
286
#ifndef NP_NO_CARBON
287
  // We don't support Carbon, but it is still the default model for i386 NPAPI.
288
  mEventModel = NPEventModelCarbon;
289
#else
290
  mEventModel = NPEventModelCocoa;
291
#endif
292
  mUseAsyncRendering = false;
293
#endif
294
295
0
  mWaitingForPaint = false;
296
0
297
#ifdef XP_WIN
298
  mGotCompositionData = false;
299
  mSentStartComposition = false;
300
  mPluginDidNotHandleIMEComposition = false;
301
#endif
302
}
303
304
nsPluginInstanceOwner::~nsPluginInstanceOwner()
305
0
{
306
0
  if (mWaitingForPaint) {
307
0
    nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
308
0
    if (content) {
309
0
      // We don't care when the event is dispatched as long as it's "soon",
310
0
      // since whoever needs it will be waiting for it.
311
0
      nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(content, true);
312
0
      NS_DispatchToMainThread(event);
313
0
    }
314
0
  }
315
0
316
0
  mPluginFrame = nullptr;
317
0
318
0
  PLUG_DeletePluginNativeWindow(mPluginWindow);
319
0
  mPluginWindow = nullptr;
320
0
321
0
  if (mInstance) {
322
0
    mInstance->SetOwner(nullptr);
323
0
  }
324
0
}
325
326
NS_IMPL_ISUPPORTS(nsPluginInstanceOwner,
327
                  nsIPluginInstanceOwner,
328
                  nsIDOMEventListener,
329
                  nsIPrivacyTransitionObserver,
330
                  nsIKeyEventInPluginCallback,
331
                  nsISupportsWeakReference)
332
333
nsresult
334
nsPluginInstanceOwner::SetInstance(nsNPAPIPluginInstance *aInstance)
335
0
{
336
0
  NS_ASSERTION(!mInstance || !aInstance, "mInstance should only be set or unset!");
337
0
338
0
  // If we're going to null out mInstance after use, be sure to call
339
0
  // mInstance->SetOwner(nullptr) here, since it now won't be called
340
0
  // from our destructor.  This fixes bug 613376.
341
0
  if (mInstance && !aInstance) {
342
0
    mInstance->SetOwner(nullptr);
343
0
  }
344
0
345
0
  mInstance = aInstance;
346
0
347
0
  nsCOMPtr<nsIDocument> doc;
348
0
  GetDocument(getter_AddRefs(doc));
349
0
  if (doc) {
350
0
    if (nsCOMPtr<nsPIDOMWindowOuter> domWindow = doc->GetWindow()) {
351
0
      nsCOMPtr<nsIDocShell> docShell = domWindow->GetDocShell();
352
0
      if (docShell)
353
0
        docShell->AddWeakPrivacyTransitionObserver(this);
354
0
    }
355
0
  }
356
0
357
0
  return NS_OK;
358
0
}
359
360
NS_IMETHODIMP nsPluginInstanceOwner::GetWindow(NPWindow *&aWindow)
361
0
{
362
0
  NS_ASSERTION(mPluginWindow, "the plugin window object being returned is null");
363
0
  aWindow = mPluginWindow;
364
0
  return NS_OK;
365
0
}
366
367
NS_IMETHODIMP nsPluginInstanceOwner::GetMode(int32_t *aMode)
368
0
{
369
0
  nsCOMPtr<nsIDocument> doc;
370
0
  nsresult rv = GetDocument(getter_AddRefs(doc));
371
0
  nsCOMPtr<nsIPluginDocument> pDoc (do_QueryInterface(doc));
372
0
373
0
  if (pDoc) {
374
0
    *aMode = NP_FULL;
375
0
  } else {
376
0
    *aMode = NP_EMBED;
377
0
  }
378
0
379
0
  return rv;
380
0
}
381
382
void nsPluginInstanceOwner::GetAttributes(nsTArray<MozPluginParameter>& attributes)
383
0
{
384
0
  nsCOMPtr<nsIObjectLoadingContent> content = do_QueryReferent(mContent);
385
0
  nsObjectLoadingContent *loadingContent =
386
0
    static_cast<nsObjectLoadingContent*>(content.get());
387
0
388
0
  loadingContent->GetPluginAttributes(attributes);
389
0
}
390
391
NS_IMETHODIMP nsPluginInstanceOwner::GetDOMElement(Element** result)
392
0
{
393
0
  return CallQueryReferent(mContent.get(), result);
394
0
}
395
396
nsresult nsPluginInstanceOwner::GetInstance(nsNPAPIPluginInstance **aInstance)
397
0
{
398
0
  NS_ENSURE_ARG_POINTER(aInstance);
399
0
400
0
  *aInstance = mInstance;
401
0
  NS_IF_ADDREF(*aInstance);
402
0
  return NS_OK;
403
0
}
404
405
NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL,
406
                                            const char *aTarget,
407
                                            nsIInputStream *aPostStream,
408
                                            void *aHeadersData,
409
                                            uint32_t aHeadersDataLen,
410
                                            bool aDoCheckLoadURIChecks)
411
0
{
412
0
  nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
413
0
  if (!content) {
414
0
    return NS_ERROR_NULL_POINTER;
415
0
  }
416
0
417
0
  if (content->IsEditable()) {
418
0
    return NS_OK;
419
0
  }
420
0
421
0
  nsIDocument *doc = content->GetComposedDoc();
422
0
  if (!doc) {
423
0
    return NS_ERROR_FAILURE;
424
0
  }
425
0
426
0
  nsPresContext* presContext = doc->GetPresContext();
427
0
  if (!presContext) {
428
0
    return NS_ERROR_FAILURE;
429
0
  }
430
0
431
0
  // the container of the pres context will give us the link handler
432
0
  nsCOMPtr<nsISupports> container = presContext->GetContainerWeak();
433
0
  NS_ENSURE_TRUE(container,NS_ERROR_FAILURE);
434
0
  nsCOMPtr<nsILinkHandler> lh = do_QueryInterface(container);
435
0
  NS_ENSURE_TRUE(lh, NS_ERROR_FAILURE);
436
0
437
0
  nsAutoString unitarget;
438
0
  if ((0 == PL_strcmp(aTarget, "newwindow")) ||
439
0
      (0 == PL_strcmp(aTarget, "_new"))) {
440
0
    unitarget.AssignLiteral("_blank");
441
0
  }
442
0
  else if (0 == PL_strcmp(aTarget, "_current")) {
443
0
    unitarget.AssignLiteral("_self");
444
0
  }
445
0
  else {
446
0
    unitarget.AssignASCII(aTarget); // XXX could this be nonascii?
447
0
  }
448
0
449
0
  nsCOMPtr<nsIURI> baseURI = GetBaseURI();
450
0
451
0
  // Create an absolute URL
452
0
  nsCOMPtr<nsIURI> uri;
453
0
  nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, baseURI);
454
0
  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
455
0
456
0
  nsCOMPtr<nsIInputStream> headersDataStream;
457
0
  if (aPostStream && aHeadersData) {
458
0
    if (!aHeadersDataLen)
459
0
      return NS_ERROR_UNEXPECTED;
460
0
461
0
    nsCOMPtr<nsIStringInputStream> sis = do_CreateInstance("@mozilla.org/io/string-input-stream;1");
462
0
    if (!sis)
463
0
      return NS_ERROR_OUT_OF_MEMORY;
464
0
465
0
    rv = sis->SetData((char *)aHeadersData, aHeadersDataLen);
466
0
    NS_ENSURE_SUCCESS(rv, rv);
467
0
    headersDataStream = do_QueryInterface(sis);
468
0
  }
469
0
470
0
  int32_t blockPopups =
471
0
    Preferences::GetInt("privacy.popups.disable_from_plugins");
472
0
  nsAutoPopupStatePusher popupStatePusher((PopupControlState)blockPopups);
473
0
474
0
475
0
  // if security checks (in particular CheckLoadURIWithPrincipal) needs
476
0
  // to be skipped we are creating a codebasePrincipal to make sure
477
0
  // that security check succeeds. Please note that we do not want to
478
0
  // fall back to using the systemPrincipal, because that would also
479
0
  // bypass ContentPolicy checks which should still be enforced.
480
0
  nsCOMPtr<nsIPrincipal> triggeringPrincipal;
481
0
  if (!aDoCheckLoadURIChecks) {
482
0
    mozilla::OriginAttributes attrs =
483
0
      BasePrincipal::Cast(content->NodePrincipal())->OriginAttributesRef();
484
0
    triggeringPrincipal = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
485
0
  }
486
0
487
0
  rv = lh->OnLinkClick(content, uri, unitarget.get(), VoidString(),
488
0
                       aPostStream, headersDataStream,
489
0
                       /* isUserTriggered */ false,
490
0
                       /* isTrusted */ true, triggeringPrincipal);
491
0
492
0
  return rv;
493
0
}
494
495
NS_IMETHODIMP nsPluginInstanceOwner::GetDocument(nsIDocument* *aDocument)
496
0
{
497
0
  nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
498
0
  if (!aDocument || !content) {
499
0
    return NS_ERROR_NULL_POINTER;
500
0
  }
501
0
502
0
  // XXX sXBL/XBL2 issue: current doc or owner doc?
503
0
  // But keep in mind bug 322414 comment 33
504
0
  NS_ADDREF(*aDocument = content->OwnerDoc());
505
0
  return NS_OK;
506
0
}
507
508
NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(NPRect *invalidRect)
509
0
{
510
0
  // If our object frame has gone away, we won't be able to determine
511
0
  // up-to-date-ness, so just fire off the event.
512
0
  if (mWaitingForPaint && (!mPluginFrame || IsUpToDate())) {
513
0
    nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
514
0
    // We don't care when the event is dispatched as long as it's "soon",
515
0
    // since whoever needs it will be waiting for it.
516
0
    nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(content, true);
517
0
    NS_DispatchToMainThread(event);
518
0
    mWaitingForPaint = false;
519
0
  }
520
0
521
0
  if (!mPluginFrame || !invalidRect || !mWidgetVisible)
522
0
    return NS_ERROR_FAILURE;
523
0
524
#if defined(XP_MACOSX)
525
  // Each time an asynchronously-drawing plugin sends a new surface to display,
526
  // the image in the ImageContainer is updated and InvalidateRect is called.
527
  RefPtr<ImageContainer> container;
528
  mInstance->GetImageContainer(getter_AddRefs(container));
529
#endif
530
531
0
#ifndef XP_MACOSX
532
0
  // Invalidate for windowed plugins needs to work.
533
0
  if (mWidget) {
534
0
    mWidget->Invalidate(
535
0
      LayoutDeviceIntRect(invalidRect->left, invalidRect->top,
536
0
                          invalidRect->right - invalidRect->left,
537
0
                          invalidRect->bottom - invalidRect->top));
538
0
    // Plugin instances also call invalidate when plugin windows are hidden
539
0
    // during scrolling. In this case fall through so we invalidate the
540
0
    // underlying layer.
541
0
    if (!NeedsScrollImageLayer()) {
542
0
      return NS_OK;
543
0
    }
544
0
  }
545
0
#endif
546
0
  nsIntRect rect(invalidRect->left,
547
0
                 invalidRect->top,
548
0
                 invalidRect->right - invalidRect->left,
549
0
                 invalidRect->bottom - invalidRect->top);
550
0
  // invalidRect is in "display pixels".  In non-HiDPI modes "display pixels"
551
0
  // are device pixels.  But in HiDPI modes each display pixel corresponds
552
0
  // to more than one device pixel.
553
0
  double scaleFactor = 1.0;
554
0
  GetContentsScaleFactor(&scaleFactor);
555
0
  rect.ScaleRoundOut(scaleFactor);
556
0
  mPluginFrame->InvalidateLayer(DisplayItemType::TYPE_PLUGIN, &rect);
557
0
  return NS_OK;
558
0
}
559
560
NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(NPRegion invalidRegion)
561
0
{
562
0
  return NS_ERROR_NOT_IMPLEMENTED;
563
0
}
564
565
NS_IMETHODIMP
566
nsPluginInstanceOwner::RedrawPlugin()
567
0
{
568
0
  if (mPluginFrame) {
569
0
    mPluginFrame->InvalidateLayer(DisplayItemType::TYPE_PLUGIN);
570
0
  }
571
0
  return NS_OK;
572
0
}
573
574
#if defined(XP_WIN)
575
nsIWidget*
576
nsPluginInstanceOwner::GetContainingWidgetIfOffset()
577
{
578
  MOZ_ASSERT(mPluginFrame, "Caller should have checked for null mPluginFrame.");
579
580
  // This property is provided to allow a "windowless" plugin to determine the window it is drawing
581
  // in, so it can translate mouse coordinates it receives directly from the operating system
582
  // to coordinates relative to itself.
583
584
  // The original code returns the document's window, which is OK if the window the "windowless" plugin
585
  // 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
586
587
  // To make sure "windowless" plugins always get the right origin for translating mouse coordinates, this code
588
  // determines the window handle of the mozilla window containing the "windowless" plugin.
589
590
  // Given that this HWND may not be that of the document's window, there is a slight risk
591
  // of confusing a plugin that is using this HWND for illicit purposes, but since the documentation
592
  // does not suggest this HWND IS that of the document window, rather that of the window
593
  // the plugin is drawn in, this seems like a safe fix.
594
595
  // we only attempt to get the nearest window if this really is a "windowless" plugin so as not
596
  // to change any behaviour for the much more common windowed plugins,
597
  // though why this method would even be being called for a windowed plugin escapes me.
598
  if (!XRE_IsContentProcess() &&
599
      mPluginWindow && mPluginWindow->type == NPWindowTypeDrawable) {
600
    // it turns out that flash also uses this window for determining focus, and is currently
601
    // unable to show a caret correctly if we return the enclosing window. Therefore for
602
    // now we only return the enclosing window when there is an actual offset which
603
    // would otherwise cause coordinates to be offset incorrectly. (i.e.
604
    // if the enclosing window if offset from the document window)
605
    //
606
    // fixing both the caret and ability to interact issues for a windowless control in a non document aligned windw
607
    // does not seem to be possible without a change to the flash plugin
608
609
    nsIWidget* win = mPluginFrame->GetNearestWidget();
610
    if (win) {
611
      nsView *view = nsView::GetViewFor(win);
612
      NS_ASSERTION(view, "No view for widget");
613
      nsPoint offset = view->GetOffsetTo(nullptr);
614
615
      if (offset.x || offset.y) {
616
        // in the case the two windows are offset from eachother, we do go ahead and return the correct enclosing window
617
        // so that mouse co-ordinates are not messed up.
618
        return win;
619
      }
620
    }
621
  }
622
623
  return nullptr;
624
}
625
626
static already_AddRefed<nsIWidget>
627
GetRootWidgetForPluginFrame(const nsPluginFrame* aPluginFrame)
628
{
629
  MOZ_ASSERT(aPluginFrame);
630
631
  nsViewManager* vm =
632
    aPluginFrame->PresContext()->GetPresShell()->GetViewManager();
633
  if (!vm) {
634
    NS_WARNING("Could not find view manager for plugin frame.");
635
    return nullptr;
636
  }
637
638
  nsCOMPtr<nsIWidget> rootWidget;
639
  vm->GetRootWidget(getter_AddRefs(rootWidget));
640
  return rootWidget.forget();
641
}
642
#endif
643
644
NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value)
645
0
{
646
0
  if (!mPluginFrame) {
647
0
    NS_WARNING("plugin owner has no owner in getting doc's window handle");
648
0
    return NS_ERROR_FAILURE;
649
0
  }
650
0
651
#if defined(XP_WIN)
652
  void** pvalue = (void**)value;
653
  nsIWidget* offsetContainingWidget = GetContainingWidgetIfOffset();
654
  if (offsetContainingWidget) {
655
    *pvalue = (void*)offsetContainingWidget->GetNativeData(NS_NATIVE_WINDOW);
656
    if (*pvalue) {
657
      return NS_OK;
658
    }
659
  }
660
661
  // simply return the topmost document window
662
  nsCOMPtr<nsIWidget> widget = GetRootWidgetForPluginFrame(mPluginFrame);
663
  if (widget) {
664
    *pvalue = widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW);
665
  } else {
666
    NS_ASSERTION(widget, "couldn't get doc's widget in getting doc's window handle");
667
  }
668
669
  return NS_OK;
670
#elif defined(MOZ_WIDGET_GTK) && defined(MOZ_X11)
671
  // X11 window managers want the toplevel window for WM_TRANSIENT_FOR.
672
0
  nsIWidget* win = mPluginFrame->GetNearestWidget();
673
0
  if (!win)
674
0
    return NS_ERROR_FAILURE;
675
0
  *static_cast<Window*>(value) = (long unsigned int)win->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW);
676
0
  return NS_OK;
677
#else
678
  return NS_ERROR_NOT_IMPLEMENTED;
679
#endif
680
}
681
682
#if defined(XP_WIN)
683
void
684
nsPluginInstanceOwner::SetWidgetWindowAsParent(HWND aWindowToAdopt)
685
{
686
  if (!mWidget) {
687
    NS_ERROR("mWidget should exist before this gets called.");
688
    return;
689
  }
690
691
  mWidget->SetNativeData(NS_NATIVE_CHILD_WINDOW,
692
                         reinterpret_cast<uintptr_t>(aWindowToAdopt));
693
}
694
695
nsresult
696
nsPluginInstanceOwner::SetNetscapeWindowAsParent(HWND aWindowToAdopt)
697
{
698
  if (!mPluginFrame) {
699
    NS_WARNING("Plugin owner has no plugin frame.");
700
    return NS_ERROR_FAILURE;
701
  }
702
703
  // If there is a containing window that is offset then ask that to adopt.
704
  nsIWidget* offsetWidget = GetContainingWidgetIfOffset();
705
  if (offsetWidget) {
706
    offsetWidget->SetNativeData(NS_NATIVE_CHILD_WINDOW,
707
                                reinterpret_cast<uintptr_t>(aWindowToAdopt));
708
    return NS_OK;
709
  }
710
711
  // Otherwise ask the topmost document window to adopt.
712
  nsCOMPtr<nsIWidget> rootWidget = GetRootWidgetForPluginFrame(mPluginFrame);
713
  if (!rootWidget) {
714
    NS_ASSERTION(rootWidget, "Couldn't get topmost document's widget.");
715
    return NS_ERROR_FAILURE;
716
  }
717
718
  rootWidget->SetNativeData(NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW,
719
                            reinterpret_cast<uintptr_t>(aWindowToAdopt));
720
  return NS_OK;
721
}
722
723
bool
724
nsPluginInstanceOwner::GetCompositionString(uint32_t aType,
725
                                            nsTArray<uint8_t>* aDist,
726
                                            int32_t* aLength)
727
{
728
  // Mark pkugin calls ImmGetCompositionStringW correctly
729
  mGotCompositionData = true;
730
731
  RefPtr<TextComposition> composition = GetTextComposition();
732
  if (NS_WARN_IF(!composition)) {
733
    return false;
734
  }
735
736
  switch(aType) {
737
    case GCS_COMPSTR: {
738
      if (!composition->IsComposing()) {
739
        *aLength = 0;
740
        return true;
741
      }
742
743
      uint32_t len = composition->LastData().Length() * sizeof(char16_t);
744
      if (len) {
745
        aDist->SetLength(len);
746
        memcpy(aDist->Elements(), composition->LastData().get(), len);
747
      }
748
      *aLength = len;
749
      return true;
750
    }
751
752
    case GCS_RESULTSTR: {
753
      if (composition->IsComposing()) {
754
        *aLength = 0;
755
        return true;
756
      }
757
758
      uint32_t len = composition->LastData().Length() * sizeof(char16_t);
759
      if (len) {
760
        aDist->SetLength(len);
761
        memcpy(aDist->Elements(), composition->LastData().get(), len);
762
      }
763
      *aLength = len;
764
      return true;
765
    }
766
767
    case GCS_CURSORPOS: {
768
      *aLength = 0;
769
      TextRangeArray* ranges = composition->GetLastRanges();
770
      if (!ranges) {
771
        return true;
772
      }
773
      *aLength = ranges->GetCaretPosition();
774
      if (*aLength < 0) {
775
        return false;
776
      }
777
      return true;
778
    }
779
780
    case GCS_COMPATTR: {
781
      TextRangeArray* ranges = composition->GetLastRanges();
782
      if (!ranges || ranges->IsEmpty()) {
783
        *aLength = 0;
784
        return true;
785
      }
786
787
      aDist->SetLength(composition->LastData().Length());
788
      memset(aDist->Elements(), ATTR_INPUT, aDist->Length());
789
790
      for (TextRange& range : *ranges) {
791
        uint8_t type = ATTR_INPUT;
792
        switch(range.mRangeType) {
793
          case TextRangeType::eRawClause:
794
            type = ATTR_INPUT;
795
            break;
796
          case TextRangeType::eSelectedRawClause:
797
            type = ATTR_TARGET_NOTCONVERTED;
798
            break;
799
          case TextRangeType::eConvertedClause:
800
            type = ATTR_CONVERTED;
801
            break;
802
          case TextRangeType::eSelectedClause:
803
            type = ATTR_TARGET_CONVERTED;
804
            break;
805
          default:
806
            continue;
807
        }
808
809
        size_t minLen = std::min<size_t>(range.mEndOffset, aDist->Length());
810
        for (size_t i = range.mStartOffset; i < minLen; i++) {
811
          (*aDist)[i] = type;
812
        }
813
      }
814
      *aLength = aDist->Length();
815
      return true;
816
    }
817
818
    case GCS_COMPCLAUSE: {
819
      RefPtr<TextRangeArray> ranges = composition->GetLastRanges();
820
      if (!ranges || ranges->IsEmpty()) {
821
        aDist->SetLength(sizeof(uint32_t));
822
        memset(aDist->Elements(), 0, sizeof(uint32_t));
823
        *aLength = aDist->Length();
824
        return true;
825
      }
826
      AutoTArray<uint32_t, 16> clauses;
827
      clauses.AppendElement(0);
828
      for (TextRange& range : *ranges) {
829
        if (!range.IsClause()) {
830
          continue;
831
        }
832
        clauses.AppendElement(range.mEndOffset);
833
      }
834
835
      aDist->SetLength(clauses.Length() * sizeof(uint32_t));
836
      memcpy(aDist->Elements(), clauses.Elements(), aDist->Length());
837
      *aLength = aDist->Length();
838
      return true;
839
    }
840
841
    case GCS_RESULTREADSTR: {
842
      // When returning error causes unexpected error, so we return 0 instead.
843
      *aLength = 0;
844
      return true;
845
    }
846
847
    case GCS_RESULTCLAUSE: {
848
      // When returning error causes unexpected error, so we return 0 instead.
849
      *aLength = 0;
850
      return true;
851
    }
852
853
    default:
854
      NS_WARNING(
855
        nsPrintfCString("Unsupported type %x of ImmGetCompositionStringW hook",
856
                        aType).get());
857
      break;
858
  }
859
860
  return false;
861
}
862
863
bool
864
nsPluginInstanceOwner::SetCandidateWindow(
865
    const widget::CandidateWindowPosition& aPosition)
866
{
867
  if (NS_WARN_IF(!mPluginFrame)) {
868
    return false;
869
  }
870
871
  nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
872
  if (!widget) {
873
    widget = GetRootWidgetForPluginFrame(mPluginFrame);
874
    if (NS_WARN_IF(!widget)) {
875
      return false;
876
    }
877
  }
878
879
  widget->SetCandidateWindowForPlugin(aPosition);
880
  return true;
881
}
882
883
bool
884
nsPluginInstanceOwner::RequestCommitOrCancel(bool aCommitted)
885
{
886
  nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
887
  if (!widget) {
888
    widget = GetRootWidgetForPluginFrame(mPluginFrame);
889
    if (NS_WARN_IF(!widget)) {
890
      return false;
891
    }
892
  }
893
894
  // Retrieve TextComposition for the widget with IMEStateManager instead of
895
  // using GetTextComposition() because we cannot know whether the method
896
  // failed due to no widget or no composition.
897
  RefPtr<TextComposition> composition =
898
    IMEStateManager::GetTextCompositionFor(widget);
899
  if (!composition) {
900
    // If there is composition, we should just ignore this request since
901
    // the composition may have been committed after the plugin process
902
    // sent this request.
903
    return true;
904
  }
905
906
  nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
907
  if (content != composition->GetEventTargetNode()) {
908
    // If the composition is handled in different node, that means that
909
    // the composition for the plugin has gone and new composition has
910
    // already started.  So, request from the plugin should be ignored
911
    // since user inputs different text now.
912
    return true;
913
  }
914
915
  // If active composition is being handled in the plugin, let's request to
916
  // commit/cancel the composition via both IMEStateManager and TextComposition
917
  // for avoid breaking the status management of composition.  I.e., don't
918
  // call nsIWidget::NotifyIME() directly from here.
919
  IMEStateManager::NotifyIME(aCommitted ?
920
                                widget::REQUEST_TO_COMMIT_COMPOSITION :
921
                                widget::REQUEST_TO_CANCEL_COMPOSITION,
922
                             widget, composition->GetTabParent());
923
  // FYI: This instance may have been destroyed.  Be careful if you need to
924
  //      access members of this class.
925
  return true;
926
}
927
928
bool
929
nsPluginInstanceOwner::EnableIME(bool aEnable)
930
{
931
  if (NS_WARN_IF(!mPluginFrame)) {
932
    return false;
933
  }
934
935
  nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
936
  if (!widget) {
937
    widget = GetRootWidgetForPluginFrame(mPluginFrame);
938
    if (NS_WARN_IF(!widget)) {
939
      return false;
940
    }
941
  }
942
943
  widget->EnableIMEForPlugin(aEnable);
944
  return true;
945
}
946
947
#endif // #ifdef XP_WIN
948
949
void
950
nsPluginInstanceOwner::HandledWindowedPluginKeyEvent(
951
                         const NativeEventData& aKeyEventData,
952
                         bool aIsConsumed)
953
0
{
954
0
  if (NS_WARN_IF(!mInstance)) {
955
0
    return;
956
0
  }
957
0
  DebugOnly<nsresult> rv =
958
0
    mInstance->HandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed);
959
0
  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HandledWindowedPluginKeyEvent fail");
960
0
}
961
962
void
963
nsPluginInstanceOwner::OnWindowedPluginKeyEvent(
964
                         const NativeEventData& aKeyEventData)
965
0
{
966
0
  if (NS_WARN_IF(!mPluginFrame)) {
967
0
    // Notifies the plugin process of the key event being not consumed by us.
968
0
    HandledWindowedPluginKeyEvent(aKeyEventData, false);
969
0
    return;
970
0
  }
971
0
972
0
  nsCOMPtr<nsIWidget> widget = mPluginFrame->PresContext()->GetRootWidget();
973
0
  if (NS_WARN_IF(!widget)) {
974
0
    // Notifies the plugin process of the key event being not consumed by us.
975
0
    HandledWindowedPluginKeyEvent(aKeyEventData, false);
976
0
    return;
977
0
  }
978
0
979
0
  nsresult rv = widget->OnWindowedPluginKeyEvent(aKeyEventData, this);
980
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
981
0
    // Notifies the plugin process of the key event being not consumed by us.
982
0
    HandledWindowedPluginKeyEvent(aKeyEventData, false);
983
0
    return;
984
0
  }
985
0
986
0
  // If the key event is posted to another process, we need to wait a call
987
0
  // of HandledWindowedPluginKeyEvent().  So, nothing to do here in this case.
988
0
  if (rv == NS_SUCCESS_EVENT_HANDLED_ASYNCHRONOUSLY) {
989
0
    return;
990
0
  }
991
0
992
0
  // Otherwise, the key event is handled synchronously.  Let's notify the
993
0
  // plugin process of the key event's result.
994
0
  bool consumed = (rv == NS_SUCCESS_EVENT_CONSUMED);
995
0
  HandledWindowedPluginKeyEvent(aKeyEventData, consumed);
996
0
}
997
998
NS_IMETHODIMP nsPluginInstanceOwner::SetEventModel(int32_t eventModel)
999
0
{
1000
#ifdef XP_MACOSX
1001
  mEventModel = static_cast<NPEventModel>(eventModel);
1002
  return NS_OK;
1003
#else
1004
  return NS_ERROR_NOT_IMPLEMENTED;
1005
0
#endif
1006
0
}
1007
1008
#ifdef XP_MACOSX
1009
NPBool nsPluginInstanceOwner::ConvertPointPuppet(PuppetWidget *widget,
1010
                                                 nsPluginFrame* pluginFrame,
1011
                                                 double sourceX, double sourceY,
1012
                                                 NPCoordinateSpace sourceSpace,
1013
                                                 double *destX, double *destY,
1014
                                                 NPCoordinateSpace destSpace)
1015
{
1016
  NS_ENSURE_TRUE(widget && widget->GetOwningTabChild() && pluginFrame, false);
1017
  // Caller has to want a result.
1018
  NS_ENSURE_TRUE(destX || destY, false);
1019
1020
  if (sourceSpace == destSpace) {
1021
    if (destX) {
1022
      *destX = sourceX;
1023
    }
1024
    if (destY) {
1025
      *destY = sourceY;
1026
    }
1027
    return true;
1028
  }
1029
1030
  nsPresContext* presContext = pluginFrame->PresContext();
1031
  CSSToLayoutDeviceScale scaleFactor(
1032
    double(AppUnitsPerCSSPixel()) /
1033
    presContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
1034
1035
  PuppetWidget *puppetWidget = static_cast<PuppetWidget*>(widget);
1036
  PuppetWidget *rootWidget = static_cast<PuppetWidget*>(widget->GetTopLevelWidget());
1037
  if (!rootWidget) {
1038
    return false;
1039
  }
1040
  CSSIntPoint chromeSize = CSSIntPoint::Truncate(
1041
    rootWidget->GetChromeOffset() / scaleFactor);
1042
  nsIntSize intScreenDims = rootWidget->GetScreenDimensions();
1043
  CSSIntSize screenDims = CSSIntSize::Truncate(
1044
    LayoutDeviceIntSize::FromUnknownSize(intScreenDims) / scaleFactor);
1045
  int32_t screenH = screenDims.height;
1046
  CSSIntPoint windowPosition = CSSIntPoint::Truncate(
1047
    rootWidget->GetWindowPosition() / scaleFactor);
1048
1049
  // Window size is tab size + chrome size.
1050
  LayoutDeviceIntRect tabContentBounds = puppetWidget->GetBounds();
1051
  tabContentBounds.ScaleInverseRoundOut(scaleFactor.scale);
1052
  int32_t windowH = tabContentBounds.height + int(chromeSize.y);
1053
1054
  CSSIntPoint pluginPosition = pluginFrame->GetScreenRect().TopLeft();
1055
1056
  // Convert (sourceX, sourceY) to 'real' (not PuppetWidget) screen space.
1057
  // In OSX, the Y-axis increases upward, which is the reverse of ours.
1058
  // We want OSX coordinates for window and screen so those equations are swapped.
1059
  CSSIntPoint sourcePoint = CSSIntPoint::Truncate(sourceX, sourceY);
1060
  CSSIntPoint screenPoint;
1061
  switch (sourceSpace) {
1062
    case NPCoordinateSpacePlugin:
1063
      screenPoint = sourcePoint + pluginPosition +
1064
        CSSIntPoint::Truncate(CSSPoint::FromAppUnits(
1065
          pluginFrame->GetContentRectRelativeToSelf().TopLeft()));
1066
      break;
1067
    case NPCoordinateSpaceWindow:
1068
      screenPoint = CSSIntPoint(sourcePoint.x, windowH-sourcePoint.y) +
1069
        windowPosition;
1070
      break;
1071
    case NPCoordinateSpaceFlippedWindow:
1072
      screenPoint = sourcePoint + windowPosition;
1073
      break;
1074
    case NPCoordinateSpaceScreen:
1075
      screenPoint = CSSIntPoint(sourcePoint.x, screenH-sourcePoint.y);
1076
      break;
1077
    case NPCoordinateSpaceFlippedScreen:
1078
      screenPoint = sourcePoint;
1079
      break;
1080
    default:
1081
      return false;
1082
  }
1083
1084
  // Convert from screen to dest space.
1085
  CSSIntPoint destPoint;
1086
  switch (destSpace) {
1087
    case NPCoordinateSpacePlugin:
1088
      destPoint = screenPoint - pluginPosition -
1089
        CSSIntPoint::Truncate(CSSPoint::FromAppUnits(
1090
          pluginFrame->GetContentRectRelativeToSelf().TopLeft()));
1091
      break;
1092
    case NPCoordinateSpaceWindow:
1093
      destPoint = screenPoint - windowPosition;
1094
      destPoint.y = windowH - destPoint.y;
1095
      break;
1096
    case NPCoordinateSpaceFlippedWindow:
1097
      destPoint = screenPoint - windowPosition;
1098
      break;
1099
    case NPCoordinateSpaceScreen:
1100
      destPoint = CSSIntPoint(screenPoint.x, screenH-screenPoint.y);
1101
      break;
1102
    case NPCoordinateSpaceFlippedScreen:
1103
      destPoint = screenPoint;
1104
      break;
1105
    default:
1106
      return false;
1107
  }
1108
1109
  if (destX) {
1110
    *destX = destPoint.x;
1111
  }
1112
  if (destY) {
1113
    *destY = destPoint.y;
1114
  }
1115
1116
  return true;
1117
}
1118
1119
NPBool nsPluginInstanceOwner::ConvertPointNoPuppet(nsIWidget *widget,
1120
                                                   nsPluginFrame* pluginFrame,
1121
                                                   double sourceX, double sourceY,
1122
                                                   NPCoordinateSpace sourceSpace,
1123
                                                   double *destX, double *destY,
1124
                                                   NPCoordinateSpace destSpace)
1125
{
1126
  NS_ENSURE_TRUE(widget && pluginFrame, false);
1127
  // Caller has to want a result.
1128
  NS_ENSURE_TRUE(destX || destY, false);
1129
1130
  if (sourceSpace == destSpace) {
1131
    if (destX) {
1132
      *destX = sourceX;
1133
    }
1134
    if (destY) {
1135
      *destY = sourceY;
1136
    }
1137
    return true;
1138
  }
1139
1140
  nsPresContext* presContext = pluginFrame->PresContext();
1141
  double scaleFactor = double(AppUnitsPerCSSPixel())/
1142
    presContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
1143
1144
  nsCOMPtr<nsIScreen> screen = widget->GetWidgetScreen();
1145
  if (!screen) {
1146
    return false;
1147
  }
1148
1149
  int32_t screenX, screenY, screenWidth, screenHeight;
1150
  screen->GetRect(&screenX, &screenY, &screenWidth, &screenHeight);
1151
  screenHeight /= scaleFactor;
1152
1153
  LayoutDeviceIntRect windowScreenBounds = widget->GetScreenBounds();
1154
  windowScreenBounds.ScaleInverseRoundOut(scaleFactor);
1155
  int32_t windowX = windowScreenBounds.x;
1156
  int32_t windowY = windowScreenBounds.y;
1157
  int32_t windowHeight = windowScreenBounds.height;
1158
1159
  CSSIntRect pluginScreenRect = pluginFrame->GetScreenRect();
1160
1161
  double screenXGecko, screenYGecko;
1162
  switch (sourceSpace) {
1163
    case NPCoordinateSpacePlugin:
1164
      screenXGecko = pluginScreenRect.x + sourceX;
1165
      screenYGecko = pluginScreenRect.y + sourceY;
1166
      break;
1167
    case NPCoordinateSpaceWindow:
1168
      screenXGecko = windowX + sourceX;
1169
      screenYGecko = windowY + (windowHeight - sourceY);
1170
      break;
1171
    case NPCoordinateSpaceFlippedWindow:
1172
      screenXGecko = windowX + sourceX;
1173
      screenYGecko = windowY + sourceY;
1174
      break;
1175
    case NPCoordinateSpaceScreen:
1176
      screenXGecko = sourceX;
1177
      screenYGecko = screenHeight - sourceY;
1178
      break;
1179
    case NPCoordinateSpaceFlippedScreen:
1180
      screenXGecko = sourceX;
1181
      screenYGecko = sourceY;
1182
      break;
1183
    default:
1184
      return false;
1185
  }
1186
1187
  double destXCocoa, destYCocoa;
1188
  switch (destSpace) {
1189
    case NPCoordinateSpacePlugin:
1190
      destXCocoa = screenXGecko - pluginScreenRect.x;
1191
      destYCocoa = screenYGecko - pluginScreenRect.y;
1192
      break;
1193
    case NPCoordinateSpaceWindow:
1194
      destXCocoa = screenXGecko - windowX;
1195
      destYCocoa = windowHeight - (screenYGecko - windowY);
1196
      break;
1197
    case NPCoordinateSpaceFlippedWindow:
1198
      destXCocoa = screenXGecko - windowX;
1199
      destYCocoa = screenYGecko - windowY;
1200
      break;
1201
    case NPCoordinateSpaceScreen:
1202
      destXCocoa = screenXGecko;
1203
      destYCocoa = screenHeight - screenYGecko;
1204
      break;
1205
    case NPCoordinateSpaceFlippedScreen:
1206
      destXCocoa = screenXGecko;
1207
      destYCocoa = screenYGecko;
1208
      break;
1209
    default:
1210
      return false;
1211
  }
1212
1213
  if (destX) {
1214
    *destX = destXCocoa;
1215
  }
1216
  if (destY) {
1217
    *destY = destYCocoa;
1218
  }
1219
1220
  return true;
1221
}
1222
#endif // XP_MACOSX
1223
1224
NPBool nsPluginInstanceOwner::ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
1225
                                           double *destX, double *destY, NPCoordinateSpace destSpace)
1226
0
{
1227
#ifdef XP_MACOSX
1228
  if (!mPluginFrame) {
1229
    return false;
1230
  }
1231
1232
  MOZ_ASSERT(mPluginFrame->GetNearestWidget());
1233
1234
  if (nsIWidget::UsePuppetWidgets()) {
1235
    return ConvertPointPuppet(static_cast<PuppetWidget*>(mPluginFrame->GetNearestWidget()),
1236
                               mPluginFrame, sourceX, sourceY, sourceSpace,
1237
                               destX, destY, destSpace);
1238
  }
1239
1240
  return ConvertPointNoPuppet(mPluginFrame->GetNearestWidget(),
1241
                              mPluginFrame, sourceX, sourceY, sourceSpace,
1242
                              destX, destY, destSpace);
1243
#else
1244
  return false;
1245
0
#endif
1246
0
}
1247
1248
NPError nsPluginInstanceOwner::InitAsyncSurface(NPSize *size, NPImageFormat format,
1249
                                                void *initData, NPAsyncSurface *surface)
1250
0
{
1251
0
  return NPERR_INCOMPATIBLE_VERSION_ERROR;
1252
0
}
1253
1254
NPError nsPluginInstanceOwner::FinalizeAsyncSurface(NPAsyncSurface *)
1255
0
{
1256
0
  return NPERR_INCOMPATIBLE_VERSION_ERROR;
1257
0
}
1258
1259
void nsPluginInstanceOwner::SetCurrentAsyncSurface(NPAsyncSurface *, NPRect*)
1260
0
{
1261
0
}
1262
1263
NS_IMETHODIMP nsPluginInstanceOwner::GetTagType(nsPluginTagType *result)
1264
0
{
1265
0
  NS_ENSURE_ARG_POINTER(result);
1266
0
1267
0
  *result = nsPluginTagType_Unknown;
1268
0
1269
0
  nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
1270
0
  if (content->IsHTMLElement(nsGkAtoms::embed))
1271
0
    *result = nsPluginTagType_Embed;
1272
0
  else if (content->IsHTMLElement(nsGkAtoms::object))
1273
0
    *result = nsPluginTagType_Object;
1274
0
1275
0
  return NS_OK;
1276
0
}
1277
1278
void nsPluginInstanceOwner::GetParameters(nsTArray<MozPluginParameter>& parameters)
1279
0
{
1280
0
  nsCOMPtr<nsIObjectLoadingContent> content = do_QueryReferent(mContent);
1281
0
  nsObjectLoadingContent *loadingContent =
1282
0
    static_cast<nsObjectLoadingContent*>(content.get());
1283
0
1284
0
  loadingContent->GetPluginParameters(parameters);
1285
0
}
1286
1287
#ifdef XP_MACOSX
1288
1289
static void InitializeNPCocoaEvent(NPCocoaEvent* event)
1290
{
1291
  memset(event, 0, sizeof(NPCocoaEvent));
1292
}
1293
1294
NPDrawingModel nsPluginInstanceOwner::GetDrawingModel()
1295
{
1296
#ifndef NP_NO_QUICKDRAW
1297
  // We don't support the Quickdraw drawing model any more but it's still
1298
  // the default model for i386 per NPAPI.
1299
  NPDrawingModel drawingModel = NPDrawingModelQuickDraw;
1300
#else
1301
  NPDrawingModel drawingModel = NPDrawingModelCoreGraphics;
1302
#endif
1303
1304
  if (!mInstance)
1305
    return drawingModel;
1306
1307
  mInstance->GetDrawingModel((int32_t*)&drawingModel);
1308
  return drawingModel;
1309
}
1310
1311
bool nsPluginInstanceOwner::IsRemoteDrawingCoreAnimation()
1312
{
1313
  if (!mInstance)
1314
    return false;
1315
1316
  bool coreAnimation;
1317
  if (!NS_SUCCEEDED(mInstance->IsRemoteDrawingCoreAnimation(&coreAnimation)))
1318
    return false;
1319
1320
  return coreAnimation;
1321
}
1322
1323
NPEventModel nsPluginInstanceOwner::GetEventModel()
1324
{
1325
  return mEventModel;
1326
}
1327
1328
#define DEFAULT_REFRESH_RATE 20 // 50 FPS
1329
StaticRefPtr<nsITimer>            nsPluginInstanceOwner::sCATimer;
1330
nsTArray<nsPluginInstanceOwner*> *nsPluginInstanceOwner::sCARefreshListeners = nullptr;
1331
1332
void nsPluginInstanceOwner::CARefresh(nsITimer *aTimer, void *aClosure) {
1333
  if (!sCARefreshListeners) {
1334
    return;
1335
  }
1336
  for (size_t i = 0; i < sCARefreshListeners->Length(); i++) {
1337
    nsPluginInstanceOwner* instanceOwner = (*sCARefreshListeners)[i];
1338
    NPWindow *window;
1339
    instanceOwner->GetWindow(window);
1340
    if (!window) {
1341
      continue;
1342
    }
1343
    NPRect r;
1344
    r.left = 0;
1345
    r.top = 0;
1346
    r.right = window->width;
1347
    r.bottom = window->height;
1348
    instanceOwner->InvalidateRect(&r);
1349
  }
1350
}
1351
1352
void nsPluginInstanceOwner::AddToCARefreshTimer() {
1353
  if (!mInstance) {
1354
    return;
1355
  }
1356
1357
  // Flash invokes InvalidateRect for us.
1358
  const char* mime = nullptr;
1359
  if (NS_SUCCEEDED(mInstance->GetMIMEType(&mime)) && mime &&
1360
      nsPluginHost::GetSpecialType(nsDependentCString(mime)) ==
1361
      nsPluginHost::eSpecialType_Flash) {
1362
    return;
1363
  }
1364
1365
  if (!sCARefreshListeners) {
1366
    sCARefreshListeners = new nsTArray<nsPluginInstanceOwner*>();
1367
  }
1368
1369
  if (sCARefreshListeners->Contains(this)) {
1370
    return;
1371
  }
1372
1373
  sCARefreshListeners->AppendElement(this);
1374
1375
  if (sCARefreshListeners->Length() == 1) {
1376
    nsCOMPtr<nsITimer> timer;
1377
    NS_NewTimerWithFuncCallback(getter_AddRefs(timer),
1378
                                CARefresh, nullptr,
1379
                                DEFAULT_REFRESH_RATE, nsITimer::TYPE_REPEATING_SLACK,
1380
                                "nsPluginInstanceOwner::CARefresh");
1381
    sCATimer = timer.forget();
1382
  }
1383
}
1384
1385
void nsPluginInstanceOwner::RemoveFromCARefreshTimer() {
1386
  if (!sCARefreshListeners || sCARefreshListeners->Contains(this) == false) {
1387
    return;
1388
  }
1389
1390
  sCARefreshListeners->RemoveElement(this);
1391
1392
  if (sCARefreshListeners->Length() == 0) {
1393
    if (sCATimer) {
1394
      sCATimer->Cancel();
1395
      sCATimer = nullptr;
1396
    }
1397
    delete sCARefreshListeners;
1398
    sCARefreshListeners = nullptr;
1399
  }
1400
}
1401
1402
void nsPluginInstanceOwner::SetPluginPort()
1403
{
1404
  void* pluginPort = GetPluginPort();
1405
  if (!pluginPort || !mPluginWindow)
1406
    return;
1407
  mPluginWindow->window = pluginPort;
1408
}
1409
#endif
1410
#if defined(XP_MACOSX) || defined(XP_WIN)
1411
nsresult nsPluginInstanceOwner::ContentsScaleFactorChanged(double aContentsScaleFactor)
1412
{
1413
  if (!mInstance) {
1414
    return NS_ERROR_NULL_POINTER;
1415
  }
1416
  return mInstance->ContentsScaleFactorChanged(aContentsScaleFactor);
1417
}
1418
#endif
1419
1420
1421
// static
1422
uint32_t
1423
nsPluginInstanceOwner::GetEventloopNestingLevel()
1424
0
{
1425
0
  nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
1426
0
  uint32_t currentLevel = 0;
1427
0
  if (appShell) {
1428
0
    appShell->GetEventloopNestingLevel(&currentLevel);
1429
#ifdef XP_MACOSX
1430
    // Cocoa widget code doesn't process UI events through the normal
1431
    // appshell event loop, so it needs an additional count here.
1432
    currentLevel++;
1433
#endif
1434
  }
1435
0
1436
0
  // No idea how this happens... but Linux doesn't consistently
1437
0
  // process UI events through the appshell event loop. If we get a 0
1438
0
  // here on any platform we increment the level just in case so that
1439
0
  // we make sure we always tear the plugin down eventually.
1440
0
  if (!currentLevel) {
1441
0
    currentLevel++;
1442
0
  }
1443
0
1444
0
  return currentLevel;
1445
0
}
1446
1447
nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(Event* aFocusEvent)
1448
0
{
1449
0
#ifndef XP_MACOSX
1450
0
  if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow)) {
1451
0
    // continue only for cases without child window
1452
0
    aFocusEvent->PreventDefault(); // consume event
1453
0
    return NS_OK;
1454
0
  }
1455
0
#endif
1456
0
1457
0
  WidgetEvent* theEvent = aFocusEvent->WidgetEventPtr();
1458
0
  if (theEvent) {
1459
0
    WidgetGUIEvent focusEvent(theEvent->IsTrusted(), theEvent->mMessage,
1460
0
                              nullptr);
1461
0
    nsEventStatus rv = ProcessEvent(focusEvent);
1462
0
    if (nsEventStatus_eConsumeNoDefault == rv) {
1463
0
      aFocusEvent->PreventDefault();
1464
0
      aFocusEvent->StopPropagation();
1465
0
    }
1466
0
  }
1467
0
1468
0
  return NS_OK;
1469
0
}
1470
1471
nsresult nsPluginInstanceOwner::ProcessKeyPress(Event* aKeyEvent)
1472
0
{
1473
0
  // ProcessKeyPress() may be called twice with same eKeyPress event.  One is
1474
0
  // by the event listener in the default event group and the other is by the
1475
0
  // event listener in the system event group.  When this is called in the
1476
0
  // latter case and the event must be fired in the default event group too,
1477
0
  // we don't need to do nothing anymore.
1478
0
  // XXX Do we need to check whether the document is in chrome?  In strictly
1479
0
  //     speaking, it must be yes.  However, our UI must not use plugin in
1480
0
  //     chrome.
1481
0
  if (!aKeyEvent->WidgetEventPtr()->mFlags.mOnlySystemGroupDispatchInContent &&
1482
0
      aKeyEvent->WidgetEventPtr()->mFlags.mInSystemGroup) {
1483
0
    return NS_OK;
1484
0
  }
1485
0
1486
#ifdef XP_MACOSX
1487
  return DispatchKeyToPlugin(aKeyEvent);
1488
#else
1489
0
  if (SendNativeEvents())
1490
0
    DispatchKeyToPlugin(aKeyEvent);
1491
0
1492
0
  if (mInstance) {
1493
0
    // If this event is going to the plugin, we want to kill it.
1494
0
    // Not actually sending keypress to the plugin, since we didn't before.
1495
0
    aKeyEvent->PreventDefault();
1496
0
    aKeyEvent->StopPropagation();
1497
0
  }
1498
0
  return NS_OK;
1499
0
#endif
1500
0
}
1501
1502
nsresult nsPluginInstanceOwner::DispatchKeyToPlugin(Event* aKeyEvent)
1503
0
{
1504
0
#if !defined(XP_MACOSX)
1505
0
  if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow)) {
1506
0
    aKeyEvent->PreventDefault(); // consume event
1507
0
    return NS_OK;
1508
0
  }
1509
0
  // continue only for cases without child window
1510
0
#endif
1511
0
1512
0
  if (mInstance) {
1513
0
    WidgetKeyboardEvent* keyEvent =
1514
0
      aKeyEvent->WidgetEventPtr()->AsKeyboardEvent();
1515
0
    if (keyEvent && keyEvent->mClass == eKeyboardEventClass) {
1516
0
      nsEventStatus rv = ProcessEvent(*keyEvent);
1517
0
      if (nsEventStatus_eConsumeNoDefault == rv) {
1518
0
        aKeyEvent->PreventDefault();
1519
0
        aKeyEvent->StopPropagation();
1520
0
      }
1521
0
    }
1522
0
  }
1523
0
1524
0
  return NS_OK;
1525
0
}
1526
1527
nsresult
1528
nsPluginInstanceOwner::ProcessMouseDown(Event* aMouseEvent)
1529
0
{
1530
0
#if !defined(XP_MACOSX)
1531
0
  if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow)) {
1532
0
    aMouseEvent->PreventDefault(); // consume event
1533
0
    return NS_OK;
1534
0
  }
1535
0
  // continue only for cases without child window
1536
0
#endif
1537
0
1538
0
  // if the plugin is windowless, we need to set focus ourselves
1539
0
  // otherwise, we might not get key events
1540
0
  if (mPluginFrame && mPluginWindow &&
1541
0
      mPluginWindow->type == NPWindowTypeDrawable) {
1542
0
1543
0
    nsIFocusManager* fm = nsFocusManager::GetFocusManager();
1544
0
    if (fm) {
1545
0
      nsCOMPtr<Element> elem = do_QueryReferent(mContent);
1546
0
      fm->SetFocus(elem, 0);
1547
0
    }
1548
0
  }
1549
0
1550
0
  WidgetMouseEvent* mouseEvent =
1551
0
    aMouseEvent->WidgetEventPtr()->AsMouseEvent();
1552
0
  if (mouseEvent && mouseEvent->mClass == eMouseEventClass) {
1553
0
    mLastMouseDownButtonType = mouseEvent->button;
1554
0
    nsEventStatus rv = ProcessEvent(*mouseEvent);
1555
0
    if (nsEventStatus_eConsumeNoDefault == rv) {
1556
0
      aMouseEvent->PreventDefault(); // consume event
1557
0
      return NS_OK;
1558
0
    }
1559
0
  }
1560
0
1561
0
  return NS_OK;
1562
0
}
1563
1564
nsresult nsPluginInstanceOwner::DispatchMouseToPlugin(Event* aMouseEvent,
1565
                                                      bool aAllowPropagate)
1566
0
{
1567
0
#if !defined(XP_MACOSX)
1568
0
  if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow)) {
1569
0
    aMouseEvent->PreventDefault(); // consume event
1570
0
    return NS_OK;
1571
0
  }
1572
0
  // continue only for cases without child window
1573
0
#endif
1574
0
  // don't send mouse events if we are hidden
1575
0
  if (!mWidgetVisible)
1576
0
    return NS_OK;
1577
0
1578
0
  WidgetMouseEvent* mouseEvent =
1579
0
    aMouseEvent->WidgetEventPtr()->AsMouseEvent();
1580
0
  if (mouseEvent && mouseEvent->mClass == eMouseEventClass) {
1581
0
    nsEventStatus rv = ProcessEvent(*mouseEvent);
1582
0
    if (nsEventStatus_eConsumeNoDefault == rv) {
1583
0
      aMouseEvent->PreventDefault();
1584
0
      if (!aAllowPropagate) {
1585
0
        aMouseEvent->StopPropagation();
1586
0
      }
1587
0
    }
1588
0
    if (mouseEvent->mMessage == eMouseUp) {
1589
0
      mLastMouseDownButtonType = -1;
1590
0
    }
1591
0
  }
1592
0
  return NS_OK;
1593
0
}
1594
1595
#ifdef XP_WIN
1596
void
1597
nsPluginInstanceOwner::CallDefaultProc(const WidgetGUIEvent* aEvent)
1598
{
1599
  nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
1600
  if (!widget) {
1601
    widget = GetRootWidgetForPluginFrame(mPluginFrame);
1602
    if (NS_WARN_IF(!widget)) {
1603
      return;
1604
    }
1605
  }
1606
1607
  const NPEvent* npEvent =
1608
    static_cast<const NPEvent*>(aEvent->mPluginEvent);
1609
  if (NS_WARN_IF(!npEvent)) {
1610
    return;
1611
  }
1612
1613
  WidgetPluginEvent pluginEvent(true, ePluginInputEvent, widget);
1614
  pluginEvent.mPluginEvent.Copy(*npEvent);
1615
  widget->DefaultProcOfPluginEvent(pluginEvent);
1616
}
1617
1618
already_AddRefed<TextComposition>
1619
nsPluginInstanceOwner::GetTextComposition()
1620
{
1621
  if (NS_WARN_IF(!mPluginFrame)) {
1622
    return nullptr;
1623
  }
1624
1625
  nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
1626
  if (!widget) {
1627
    widget = GetRootWidgetForPluginFrame(mPluginFrame);
1628
    if (NS_WARN_IF(!widget)) {
1629
      return nullptr;
1630
    }
1631
  }
1632
1633
  RefPtr<TextComposition> composition =
1634
    IMEStateManager::GetTextCompositionFor(widget);
1635
  if (NS_WARN_IF(!composition)) {
1636
    return nullptr;
1637
  }
1638
1639
  return composition.forget();
1640
}
1641
1642
void
1643
nsPluginInstanceOwner::HandleNoConsumedCompositionMessage(
1644
  WidgetCompositionEvent* aCompositionEvent,
1645
  const NPEvent* aPluginEvent)
1646
{
1647
  nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
1648
  if (!widget) {
1649
    widget = GetRootWidgetForPluginFrame(mPluginFrame);
1650
    if (NS_WARN_IF(!widget)) {
1651
      return;
1652
    }
1653
  }
1654
1655
  NPEvent npevent;
1656
  if (aPluginEvent->lParam & GCS_RESULTSTR) {
1657
    // GCS_RESULTSTR's default proc will generate WM_CHAR. So emulate it.
1658
    for (size_t i = 0; i < aCompositionEvent->mData.Length(); i++) {
1659
      WidgetPluginEvent charEvent(true, ePluginInputEvent, widget);
1660
      npevent.event = WM_CHAR;
1661
      npevent.wParam = aCompositionEvent->mData[i];
1662
      npevent.lParam = 0;
1663
      charEvent.mPluginEvent.Copy(npevent);
1664
      ProcessEvent(charEvent);
1665
    }
1666
    return;
1667
  }
1668
  if (!mSentStartComposition) {
1669
    // We post WM_IME_COMPOSITION to default proc, but
1670
    // WM_IME_STARTCOMPOSITION isn't post yet.  We should post it at first.
1671
    WidgetPluginEvent startEvent(true, ePluginInputEvent, widget);
1672
    npevent.event = WM_IME_STARTCOMPOSITION;
1673
    npevent.wParam = 0;
1674
    npevent.lParam = 0;
1675
    startEvent.mPluginEvent.Copy(npevent);
1676
    CallDefaultProc(&startEvent);
1677
    mSentStartComposition = true;
1678
  }
1679
1680
  CallDefaultProc(aCompositionEvent);
1681
}
1682
#endif
1683
1684
nsresult
1685
nsPluginInstanceOwner::DispatchCompositionToPlugin(Event* aEvent)
1686
0
{
1687
#ifdef XP_WIN
1688
  if (!mPluginWindow) {
1689
    // CompositionEvent isn't cancellable.  So it is unnecessary to call
1690
    // PreventDefaults() to consume event
1691
    return NS_OK;
1692
  }
1693
  WidgetCompositionEvent* compositionEvent =
1694
    aEvent->WidgetEventPtr()->AsCompositionEvent();
1695
  if (NS_WARN_IF(!compositionEvent)) {
1696
      return NS_ERROR_INVALID_ARG;
1697
  }
1698
1699
  if (compositionEvent->mMessage == eCompositionChange) {
1700
    RefPtr<TextComposition> composition = GetTextComposition();
1701
    if (NS_WARN_IF(!composition)) {
1702
      return NS_ERROR_FAILURE;
1703
    }
1704
    TextComposition::CompositionChangeEventHandlingMarker
1705
      compositionChangeEventHandlingMarker(composition, compositionEvent);
1706
  }
1707
1708
  const NPEvent* pPluginEvent =
1709
    static_cast<const NPEvent*>(compositionEvent->mPluginEvent);
1710
  if (pPluginEvent && pPluginEvent->event == WM_IME_COMPOSITION &&
1711
      mPluginDidNotHandleIMEComposition) {
1712
    // This is a workaround when running windowed and windowless Flash on
1713
    // same process.
1714
    // Flash with protected mode calls IMM APIs on own render process.  This
1715
    // is a bug of Flash's protected mode.
1716
    // ImmGetCompositionString with GCS_RESULTSTR returns *LAST* committed
1717
    // string.  So when windowed mode Flash handles IME composition,
1718
    // windowless plugin can get windowed mode's commited string by that API.
1719
    // So we never post WM_IME_COMPOSITION when plugin doesn't call
1720
    // ImmGetCompositionString() during WM_IME_COMPOSITION correctly.
1721
    HandleNoConsumedCompositionMessage(compositionEvent, pPluginEvent);
1722
    aEvent->StopImmediatePropagation();
1723
    return NS_OK;
1724
  }
1725
1726
  // Protected mode Flash returns noDefault by NPP_HandleEvent, but
1727
  // composition information into plugin is invalid because plugin's bug.
1728
  // So if plugin doesn't get composition data by WM_IME_COMPOSITION, we
1729
  // recongnize it isn't handled
1730
  AutoRestore<bool> restore(mGotCompositionData);
1731
  mGotCompositionData = false;
1732
1733
  nsEventStatus status = ProcessEvent(*compositionEvent);
1734
  aEvent->StopImmediatePropagation();
1735
1736
  // Composition event isn't handled by plugin, so we have to call default proc.
1737
1738
  if (NS_WARN_IF(!pPluginEvent)) {
1739
    return NS_OK;
1740
  }
1741
1742
  if (pPluginEvent->event == WM_IME_STARTCOMPOSITION) {
1743
    // Flash's protected mode lies that composition event is handled, but it
1744
    // cannot do it well.  So even if handled, we should post this message when
1745
    // no IMM API calls during WM_IME_COMPOSITION.
1746
    if (nsEventStatus_eConsumeNoDefault != status)  {
1747
      CallDefaultProc(compositionEvent);
1748
      mSentStartComposition = true;
1749
    } else {
1750
      mSentStartComposition = false;
1751
    }
1752
    mPluginDidNotHandleIMEComposition = false;
1753
    return NS_OK;
1754
  }
1755
1756
  if (pPluginEvent->event == WM_IME_ENDCOMPOSITION) {
1757
    // Always post WM_END_COMPOSITION to default proc. Because Flash may lie
1758
    // that it doesn't handle composition well, but event is handled.
1759
    // Even if posting this message, default proc do nothing if unnecessary.
1760
    CallDefaultProc(compositionEvent);
1761
    return NS_OK;
1762
  }
1763
1764
  if (pPluginEvent->event == WM_IME_COMPOSITION && !mGotCompositionData) {
1765
    // If plugin doesn't handle WM_IME_COMPOSITION correctly, we don't send
1766
    // composition event until end composition.
1767
    mPluginDidNotHandleIMEComposition = true;
1768
1769
    HandleNoConsumedCompositionMessage(compositionEvent, pPluginEvent);
1770
  }
1771
#endif // #ifdef XP_WIN
1772
  return NS_OK;
1773
0
}
1774
1775
nsresult
1776
nsPluginInstanceOwner::HandleEvent(Event* aEvent)
1777
0
{
1778
0
  NS_ASSERTION(mInstance, "Should have a valid plugin instance or not receive events.");
1779
0
1780
0
  nsAutoString eventType;
1781
0
  aEvent->GetType(eventType);
1782
0
1783
#ifdef XP_MACOSX
1784
  if (eventType.EqualsLiteral("activate") ||
1785
      eventType.EqualsLiteral("deactivate")) {
1786
    WindowFocusMayHaveChanged();
1787
    return NS_OK;
1788
  }
1789
  if (eventType.EqualsLiteral("MozPerformDelayedBlur")) {
1790
    if (mShouldBlurOnActivate) {
1791
      WidgetGUIEvent blurEvent(true, eBlur, nullptr);
1792
      ProcessEvent(blurEvent);
1793
      mShouldBlurOnActivate = false;
1794
    }
1795
    return NS_OK;
1796
  }
1797
#endif
1798
1799
0
  if (eventType.EqualsLiteral("focus")) {
1800
0
    mContentFocused = true;
1801
0
    return DispatchFocusToPlugin(aEvent);
1802
0
  }
1803
0
  if (eventType.EqualsLiteral("blur")) {
1804
0
    mContentFocused = false;
1805
0
    return DispatchFocusToPlugin(aEvent);
1806
0
  }
1807
0
  if (eventType.EqualsLiteral("mousedown")) {
1808
0
    return ProcessMouseDown(aEvent);
1809
0
  }
1810
0
  if (eventType.EqualsLiteral("mouseup")) {
1811
0
    return DispatchMouseToPlugin(aEvent);
1812
0
  }
1813
0
  if (eventType.EqualsLiteral("mousemove")) {
1814
0
    return DispatchMouseToPlugin(aEvent, true);
1815
0
  }
1816
0
  if (eventType.EqualsLiteral("click") ||
1817
0
      eventType.EqualsLiteral("dblclick") ||
1818
0
      eventType.EqualsLiteral("mouseover") ||
1819
0
      eventType.EqualsLiteral("mouseout")) {
1820
0
    return DispatchMouseToPlugin(aEvent);
1821
0
  }
1822
0
  if (eventType.EqualsLiteral("keydown") ||
1823
0
      eventType.EqualsLiteral("keyup")) {
1824
0
    return DispatchKeyToPlugin(aEvent);
1825
0
  }
1826
0
  if (eventType.EqualsLiteral("keypress")) {
1827
0
    return ProcessKeyPress(aEvent);
1828
0
  }
1829
0
  if (eventType.EqualsLiteral("compositionstart") ||
1830
0
      eventType.EqualsLiteral("compositionend") ||
1831
0
      eventType.EqualsLiteral("text")) {
1832
0
    return DispatchCompositionToPlugin(aEvent);
1833
0
  }
1834
0
1835
0
  DragEvent* dragEvent = aEvent->AsDragEvent();
1836
0
  if (dragEvent && mInstance) {
1837
0
    WidgetEvent* ievent = aEvent->WidgetEventPtr();
1838
0
    if (ievent && ievent->IsTrusted() &&
1839
0
        ievent->mMessage != eDragEnter && ievent->mMessage != eDragOver) {
1840
0
      aEvent->PreventDefault();
1841
0
    }
1842
0
1843
0
    // Let the plugin handle drag events.
1844
0
    aEvent->StopPropagation();
1845
0
  }
1846
0
  return NS_OK;
1847
0
}
1848
1849
#ifdef MOZ_X11
1850
static unsigned int XInputEventState(const WidgetInputEvent& anEvent)
1851
0
{
1852
0
  unsigned int state = 0;
1853
0
  if (anEvent.IsShift()) state |= ShiftMask;
1854
0
  if (anEvent.IsControl()) state |= ControlMask;
1855
0
  if (anEvent.IsAlt()) state |= Mod1Mask;
1856
0
  if (anEvent.IsMeta()) state |= Mod4Mask;
1857
0
  return state;
1858
0
}
1859
#endif
1860
1861
#ifdef XP_MACOSX
1862
1863
// Returns whether or not content is the content that is or would be
1864
// focused if the top-level chrome window was active.
1865
static bool
1866
ContentIsFocusedWithinWindow(nsIContent* aContent)
1867
{
1868
  nsPIDOMWindowOuter* outerWindow = aContent->OwnerDoc()->GetWindow();
1869
  if (!outerWindow) {
1870
    return false;
1871
  }
1872
1873
  nsPIDOMWindowOuter* rootWindow = outerWindow->GetPrivateRoot();
1874
  if (!rootWindow) {
1875
    return false;
1876
  }
1877
1878
  nsFocusManager* fm = nsFocusManager::GetFocusManager();
1879
  if (!fm) {
1880
    return false;
1881
  }
1882
1883
  nsCOMPtr<nsPIDOMWindowOuter> focusedFrame;
1884
  nsCOMPtr<nsIContent> focusedContent =
1885
    nsFocusManager::GetFocusedDescendant(rootWindow,
1886
                                         nsFocusManager::eIncludeAllDescendants,
1887
                                         getter_AddRefs(focusedFrame));
1888
  return (focusedContent.get() == aContent);
1889
}
1890
1891
static NPCocoaEventType
1892
CocoaEventTypeForEvent(const WidgetGUIEvent& anEvent, nsIFrame* aObjectFrame)
1893
{
1894
  const NPCocoaEvent* event = static_cast<const NPCocoaEvent*>(anEvent.mPluginEvent);
1895
  if (event) {
1896
    return event->type;
1897
  }
1898
1899
  switch (anEvent.mMessage) {
1900
    case eMouseOver:
1901
      return NPCocoaEventMouseEntered;
1902
    case eMouseOut:
1903
      return NPCocoaEventMouseExited;
1904
    case eMouseMove: {
1905
      // We don't know via information on events from the widget code whether or not
1906
      // we're dragging. The widget code just generates mouse move events from native
1907
      // drag events. If anybody is capturing, this is a drag event.
1908
      if (nsIPresShell::GetCapturingContent()) {
1909
        return NPCocoaEventMouseDragged;
1910
      }
1911
1912
      return NPCocoaEventMouseMoved;
1913
    }
1914
    case eMouseDown:
1915
      return NPCocoaEventMouseDown;
1916
    case eMouseUp:
1917
      return NPCocoaEventMouseUp;
1918
    case eKeyDown:
1919
      return NPCocoaEventKeyDown;
1920
    case eKeyUp:
1921
      return NPCocoaEventKeyUp;
1922
    case eFocus:
1923
    case eBlur:
1924
      return NPCocoaEventFocusChanged;
1925
    case eLegacyMouseLineOrPageScroll:
1926
      return NPCocoaEventScrollWheel;
1927
    default:
1928
      return (NPCocoaEventType)0;
1929
  }
1930
}
1931
1932
static NPCocoaEvent
1933
TranslateToNPCocoaEvent(WidgetGUIEvent* anEvent, nsIFrame* aObjectFrame)
1934
{
1935
  NPCocoaEvent cocoaEvent;
1936
  InitializeNPCocoaEvent(&cocoaEvent);
1937
  cocoaEvent.type = CocoaEventTypeForEvent(*anEvent, aObjectFrame);
1938
1939
  if (anEvent->mMessage == eMouseMove ||
1940
      anEvent->mMessage == eMouseDown ||
1941
      anEvent->mMessage == eMouseUp ||
1942
      anEvent->mMessage == eLegacyMouseLineOrPageScroll ||
1943
      anEvent->mMessage == eMouseOver ||
1944
      anEvent->mMessage == eMouseOut)
1945
  {
1946
    nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(anEvent, aObjectFrame) -
1947
                 aObjectFrame->GetContentRectRelativeToSelf().TopLeft();
1948
    nsPresContext* presContext = aObjectFrame->PresContext();
1949
    // Plugin event coordinates need to be translated from device pixels
1950
    // into "display pixels" in HiDPI modes.
1951
    double scaleFactor = double(AppUnitsPerCSSPixel())/
1952
      aObjectFrame->PresContext()->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
1953
    size_t intScaleFactor = ceil(scaleFactor);
1954
    nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x) / intScaleFactor,
1955
                    presContext->AppUnitsToDevPixels(pt.y) / intScaleFactor);
1956
    cocoaEvent.data.mouse.pluginX = double(ptPx.x);
1957
    cocoaEvent.data.mouse.pluginY = double(ptPx.y);
1958
  }
1959
1960
  switch (anEvent->mMessage) {
1961
    case eMouseDown:
1962
    case eMouseUp: {
1963
      WidgetMouseEvent* mouseEvent = anEvent->AsMouseEvent();
1964
      if (mouseEvent) {
1965
        switch (mouseEvent->button) {
1966
          case WidgetMouseEvent::eLeftButton:
1967
            cocoaEvent.data.mouse.buttonNumber = 0;
1968
            break;
1969
          case WidgetMouseEvent::eRightButton:
1970
            cocoaEvent.data.mouse.buttonNumber = 1;
1971
            break;
1972
          case WidgetMouseEvent::eMiddleButton:
1973
            cocoaEvent.data.mouse.buttonNumber = 2;
1974
            break;
1975
          default:
1976
            NS_WARNING("Mouse button we don't know about?");
1977
        }
1978
        cocoaEvent.data.mouse.clickCount = mouseEvent->mClickCount;
1979
      } else {
1980
        NS_WARNING("eMouseUp/DOWN is not a WidgetMouseEvent?");
1981
      }
1982
      break;
1983
    }
1984
    case eLegacyMouseLineOrPageScroll: {
1985
      WidgetWheelEvent* wheelEvent = anEvent->AsWheelEvent();
1986
      if (wheelEvent) {
1987
        cocoaEvent.data.mouse.deltaX = wheelEvent->mLineOrPageDeltaX;
1988
        cocoaEvent.data.mouse.deltaY = wheelEvent->mLineOrPageDeltaY;
1989
      } else {
1990
        NS_WARNING("eLegacyMouseLineOrPageScroll is not a WidgetWheelEvent? "
1991
                   "(could be, haven't checked)");
1992
      }
1993
      break;
1994
    }
1995
    case eKeyDown:
1996
    case eKeyUp:
1997
    {
1998
      WidgetKeyboardEvent* keyEvent = anEvent->AsKeyboardEvent();
1999
2000
      // That keyEvent->mPluginTextEventString is non-empty is a signal that we should
2001
      // create a text event for the plugin, instead of a key event.
2002
      if (anEvent->mMessage == eKeyDown &&
2003
          !keyEvent->mPluginTextEventString.IsEmpty()) {
2004
        cocoaEvent.type = NPCocoaEventTextInput;
2005
        const char16_t* pluginTextEventString = keyEvent->mPluginTextEventString.get();
2006
        cocoaEvent.data.text.text = (NPNSString*)
2007
          ::CFStringCreateWithCharacters(NULL,
2008
                                         reinterpret_cast<const UniChar*>(pluginTextEventString),
2009
                                         keyEvent->mPluginTextEventString.Length());
2010
      } else {
2011
        cocoaEvent.data.key.keyCode = keyEvent->mNativeKeyCode;
2012
        cocoaEvent.data.key.isARepeat = keyEvent->mIsRepeat;
2013
        cocoaEvent.data.key.modifierFlags = keyEvent->mNativeModifierFlags;
2014
        const char16_t* nativeChars = keyEvent->mNativeCharacters.get();
2015
        cocoaEvent.data.key.characters = (NPNSString*)
2016
          ::CFStringCreateWithCharacters(NULL,
2017
                                         reinterpret_cast<const UniChar*>(nativeChars),
2018
                                         keyEvent->mNativeCharacters.Length());
2019
        const char16_t* nativeCharsIgnoringModifiers = keyEvent->mNativeCharactersIgnoringModifiers.get();
2020
        cocoaEvent.data.key.charactersIgnoringModifiers = (NPNSString*)
2021
          ::CFStringCreateWithCharacters(NULL,
2022
                                         reinterpret_cast<const UniChar*>(nativeCharsIgnoringModifiers),
2023
                                         keyEvent->mNativeCharactersIgnoringModifiers.Length());
2024
      }
2025
      break;
2026
    }
2027
    case eFocus:
2028
    case eBlur:
2029
      cocoaEvent.data.focus.hasFocus = (anEvent->mMessage == eFocus);
2030
      break;
2031
    default:
2032
      break;
2033
  }
2034
  return cocoaEvent;
2035
}
2036
2037
void nsPluginInstanceOwner::PerformDelayedBlurs()
2038
{
2039
  nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
2040
  nsCOMPtr<EventTarget> windowRoot = content->OwnerDoc()->GetWindow()->GetTopWindowRoot();
2041
  nsContentUtils::DispatchTrustedEvent(content->OwnerDoc(),
2042
                                       windowRoot,
2043
                                       NS_LITERAL_STRING("MozPerformDelayedBlur"),
2044
                                       CanBubble::eNo, Cancelable::eNo, nullptr);
2045
}
2046
2047
#endif
2048
2049
nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
2050
0
{
2051
0
  nsEventStatus rv = nsEventStatus_eIgnore;
2052
0
2053
0
  if (!mInstance || !mPluginFrame) {
2054
0
    return nsEventStatus_eIgnore;
2055
0
  }
2056
0
2057
#ifdef XP_MACOSX
2058
  NPEventModel eventModel = GetEventModel();
2059
  if (eventModel != NPEventModelCocoa) {
2060
    return nsEventStatus_eIgnore;
2061
  }
2062
2063
  // In the Cocoa event model, focus is per-window. Don't tell a plugin it lost
2064
  // focus unless it lost focus within the window. For example, ignore a blur
2065
  // event if it's coming due to the plugin's window deactivating.
2066
  nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
2067
  if (anEvent.mMessage == eBlur && ContentIsFocusedWithinWindow(content)) {
2068
    mShouldBlurOnActivate = true;
2069
    return nsEventStatus_eIgnore;
2070
  }
2071
2072
  // Also, don't tell the plugin it gained focus again after we've already given
2073
  // it focus. This might happen if it has focus, its window is blurred, then the
2074
  // window is made active again. The plugin never lost in-window focus, so it
2075
  // shouldn't get a focus event again.
2076
  if (anEvent.mMessage == eFocus && mLastContentFocused == true) {
2077
    mShouldBlurOnActivate = false;
2078
    return nsEventStatus_eIgnore;
2079
  }
2080
2081
  // Now, if we're going to send a focus event, update mLastContentFocused and
2082
  // tell any plugins in our window that we have taken focus, so they should
2083
  // perform any delayed blurs.
2084
  if (anEvent.mMessage == eFocus || anEvent.mMessage == eBlur) {
2085
    mLastContentFocused = (anEvent.mMessage == eFocus);
2086
    mShouldBlurOnActivate = false;
2087
    PerformDelayedBlurs();
2088
  }
2089
2090
  NPCocoaEvent cocoaEvent = TranslateToNPCocoaEvent(const_cast<WidgetGUIEvent*>(&anEvent), mPluginFrame);
2091
  if (cocoaEvent.type == (NPCocoaEventType)0) {
2092
    return nsEventStatus_eIgnore;
2093
  }
2094
2095
  if (cocoaEvent.type == NPCocoaEventTextInput) {
2096
    mInstance->HandleEvent(&cocoaEvent, nullptr);
2097
    return nsEventStatus_eConsumeNoDefault;
2098
  }
2099
2100
  int16_t response = kNPEventNotHandled;
2101
  mInstance->HandleEvent(&cocoaEvent,
2102
                         &response,
2103
                         NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
2104
  if ((response == kNPEventStartIME) && (cocoaEvent.type == NPCocoaEventKeyDown)) {
2105
    nsIWidget* widget = mPluginFrame->GetNearestWidget();
2106
    if (widget) {
2107
      const WidgetKeyboardEvent* keyEvent = anEvent.AsKeyboardEvent();
2108
      double screenX, screenY;
2109
      ConvertPoint(0.0, mPluginFrame->GetScreenRect().height,
2110
                   NPCoordinateSpacePlugin, &screenX, &screenY,
2111
                   NPCoordinateSpaceScreen);
2112
      nsAutoString outText;
2113
      if (NS_SUCCEEDED(widget->StartPluginIME(*keyEvent, screenX, screenY, outText)) &&
2114
          !outText.IsEmpty()) {
2115
        CFStringRef cfString =
2116
          ::CFStringCreateWithCharacters(kCFAllocatorDefault,
2117
                                         reinterpret_cast<const UniChar*>(outText.get()),
2118
                                         outText.Length());
2119
        NPCocoaEvent textEvent;
2120
        InitializeNPCocoaEvent(&textEvent);
2121
        textEvent.type = NPCocoaEventTextInput;
2122
        textEvent.data.text.text = (NPNSString*)cfString;
2123
        mInstance->HandleEvent(&textEvent, nullptr);
2124
      }
2125
    }
2126
  }
2127
2128
  bool handled = (response == kNPEventHandled || response == kNPEventStartIME);
2129
  bool leftMouseButtonDown = (anEvent.mMessage == eMouseDown) &&
2130
                             (anEvent.AsMouseEvent()->button == WidgetMouseEvent::eLeftButton);
2131
  if (handled && !(leftMouseButtonDown && !mContentFocused)) {
2132
    rv = nsEventStatus_eConsumeNoDefault;
2133
  }
2134
#endif
2135
2136
#ifdef XP_WIN
2137
  // this code supports windowless plugins
2138
  const NPEvent *pPluginEvent = static_cast<const NPEvent*>(anEvent.mPluginEvent);
2139
  // we can get synthetic events from the EventStateManager... these
2140
  // have no pluginEvent
2141
  NPEvent pluginEvent;
2142
  if (anEvent.mClass == eMouseEventClass ||
2143
      anEvent.mClass == eWheelEventClass) {
2144
    if (!pPluginEvent) {
2145
      // XXX Should extend this list to synthesize events for more event
2146
      // types
2147
      pluginEvent.event = 0;
2148
      bool initWParamWithCurrentState = true;
2149
      switch (anEvent.mMessage) {
2150
      case eMouseMove: {
2151
        pluginEvent.event = WM_MOUSEMOVE;
2152
        break;
2153
      }
2154
      case eMouseDown: {
2155
        static const int downMsgs[] =
2156
          { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
2157
        static const int dblClickMsgs[] =
2158
          { WM_LBUTTONDBLCLK, WM_MBUTTONDBLCLK, WM_RBUTTONDBLCLK };
2159
        const WidgetMouseEvent* mouseEvent = anEvent.AsMouseEvent();
2160
        if (mouseEvent->mClickCount == 2) {
2161
          pluginEvent.event = dblClickMsgs[mouseEvent->button];
2162
        } else {
2163
          pluginEvent.event = downMsgs[mouseEvent->button];
2164
        }
2165
        break;
2166
      }
2167
      case eMouseUp: {
2168
        static const int upMsgs[] =
2169
          { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
2170
        const WidgetMouseEvent* mouseEvent = anEvent.AsMouseEvent();
2171
        pluginEvent.event = upMsgs[mouseEvent->button];
2172
        break;
2173
      }
2174
      // For plugins which don't support high-resolution scroll, we should
2175
      // generate legacy resolution wheel messages.  I.e., the delta value
2176
      // should be WHEEL_DELTA * n.
2177
      case eWheel: {
2178
        const WidgetWheelEvent* wheelEvent = anEvent.AsWheelEvent();
2179
        int32_t delta = 0;
2180
        if (wheelEvent->mLineOrPageDeltaY) {
2181
          switch (wheelEvent->mDeltaMode) {
2182
            case WheelEvent_Binding::DOM_DELTA_PAGE:
2183
              pluginEvent.event = WM_MOUSEWHEEL;
2184
              delta = -WHEEL_DELTA * wheelEvent->mLineOrPageDeltaY;
2185
              break;
2186
            case WheelEvent_Binding::DOM_DELTA_LINE: {
2187
              UINT linesPerWheelDelta = 0;
2188
              if (NS_WARN_IF(!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
2189
                                                     &linesPerWheelDelta, 0))) {
2190
                // Use system default scroll amount, 3, when
2191
                // SPI_GETWHEELSCROLLLINES isn't available.
2192
                linesPerWheelDelta = 3;
2193
              }
2194
              if (!linesPerWheelDelta) {
2195
                break;
2196
              }
2197
              pluginEvent.event = WM_MOUSEWHEEL;
2198
              delta = -WHEEL_DELTA / linesPerWheelDelta;
2199
              delta *= wheelEvent->mLineOrPageDeltaY;
2200
              break;
2201
            }
2202
            case WheelEvent_Binding::DOM_DELTA_PIXEL:
2203
            default:
2204
              // We don't support WM_GESTURE with this path.
2205
              MOZ_ASSERT(!pluginEvent.event);
2206
              break;
2207
          }
2208
        } else if (wheelEvent->mLineOrPageDeltaX) {
2209
          switch (wheelEvent->mDeltaMode) {
2210
            case WheelEvent_Binding::DOM_DELTA_PAGE:
2211
              pluginEvent.event = WM_MOUSEHWHEEL;
2212
              delta = -WHEEL_DELTA * wheelEvent->mLineOrPageDeltaX;
2213
              break;
2214
            case WheelEvent_Binding::DOM_DELTA_LINE: {
2215
              pluginEvent.event = WM_MOUSEHWHEEL;
2216
              UINT charsPerWheelDelta = 0;
2217
              // FYI: SPI_GETWHEELSCROLLCHARS is available on Vista or later.
2218
              if (::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
2219
                                         &charsPerWheelDelta, 0)) {
2220
                // Use system default scroll amount, 3, when
2221
                // SPI_GETWHEELSCROLLCHARS isn't available.
2222
                charsPerWheelDelta = 3;
2223
              }
2224
              if (!charsPerWheelDelta) {
2225
                break;
2226
              }
2227
              delta = WHEEL_DELTA / charsPerWheelDelta;
2228
              delta *= wheelEvent->mLineOrPageDeltaX;
2229
              break;
2230
            }
2231
            case WheelEvent_Binding::DOM_DELTA_PIXEL:
2232
            default:
2233
              // We don't support WM_GESTURE with this path.
2234
              MOZ_ASSERT(!pluginEvent.event);
2235
              break;
2236
          }
2237
        }
2238
2239
        if (!pluginEvent.event) {
2240
          break;
2241
        }
2242
2243
        initWParamWithCurrentState = false;
2244
        int32_t modifiers =
2245
          (wheelEvent->IsControl() ?             MK_CONTROL  : 0) |
2246
          (wheelEvent->IsShift() ?               MK_SHIFT    : 0) |
2247
          (wheelEvent->IsLeftButtonPressed() ?   MK_LBUTTON  : 0) |
2248
          (wheelEvent->IsMiddleButtonPressed() ? MK_MBUTTON  : 0) |
2249
          (wheelEvent->IsRightButtonPressed() ?  MK_RBUTTON  : 0) |
2250
          (wheelEvent->Is4thButtonPressed() ?    MK_XBUTTON1 : 0) |
2251
          (wheelEvent->Is5thButtonPressed() ?    MK_XBUTTON2 : 0);
2252
        pluginEvent.wParam = MAKEWPARAM(modifiers, delta);
2253
        pPluginEvent = &pluginEvent;
2254
        break;
2255
      }
2256
      // don't synthesize anything for eMouseDoubleClick, since that
2257
      // is a synthetic event generated on mouse-up, and Windows WM_*DBLCLK
2258
      // messages are sent on mouse-down
2259
      default:
2260
        break;
2261
      }
2262
      if (pluginEvent.event && initWParamWithCurrentState) {
2263
        pPluginEvent = &pluginEvent;
2264
        pluginEvent.wParam =
2265
          (::GetKeyState(VK_CONTROL) ? MK_CONTROL : 0) |
2266
          (::GetKeyState(VK_SHIFT) ? MK_SHIFT : 0) |
2267
          (::GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0) |
2268
          (::GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0) |
2269
          (::GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0) |
2270
          (::GetKeyState(VK_XBUTTON1) ? MK_XBUTTON1 : 0) |
2271
          (::GetKeyState(VK_XBUTTON2) ? MK_XBUTTON2 : 0);
2272
      }
2273
    }
2274
    if (pPluginEvent) {
2275
      // Make event coordinates relative to our enclosing widget,
2276
      // not the widget they were received on.
2277
      // See use of NPEvent in widget/windows/nsWindow.cpp
2278
      // for why this assert should be safe
2279
      NS_ASSERTION(anEvent.mMessage == eMouseDown ||
2280
                   anEvent.mMessage == eMouseUp ||
2281
                   anEvent.mMessage == eMouseDoubleClick ||
2282
                   anEvent.mMessage == eMouseAuxClick ||
2283
                   anEvent.mMessage == eMouseOver ||
2284
                   anEvent.mMessage == eMouseOut ||
2285
                   anEvent.mMessage == eMouseMove ||
2286
                   anEvent.mMessage == eWheel,
2287
                   "Incorrect event type for coordinate translation");
2288
      nsPoint pt =
2289
        nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) -
2290
        mPluginFrame->GetContentRectRelativeToSelf().TopLeft();
2291
      nsPresContext* presContext = mPluginFrame->PresContext();
2292
      nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x),
2293
                      presContext->AppUnitsToDevPixels(pt.y));
2294
      nsIntPoint widgetPtPx = ptPx + mPluginFrame->GetWindowOriginInPixels(true);
2295
      const_cast<NPEvent*>(pPluginEvent)->lParam = MAKELPARAM(widgetPtPx.x, widgetPtPx.y);
2296
    }
2297
  }
2298
  else if (!pPluginEvent) {
2299
    switch (anEvent.mMessage) {
2300
      case eFocus:
2301
        pluginEvent.event = WM_SETFOCUS;
2302
        pluginEvent.wParam = 0;
2303
        pluginEvent.lParam = 0;
2304
        pPluginEvent = &pluginEvent;
2305
        break;
2306
      case eBlur:
2307
        pluginEvent.event = WM_KILLFOCUS;
2308
        pluginEvent.wParam = 0;
2309
        pluginEvent.lParam = 0;
2310
        pPluginEvent = &pluginEvent;
2311
        break;
2312
      default:
2313
        break;
2314
    }
2315
  }
2316
2317
  if (pPluginEvent && !pPluginEvent->event) {
2318
    // Don't send null events to plugins.
2319
    NS_WARNING("nsPluginFrame ProcessEvent: trying to send null event to plugin.");
2320
    return rv;
2321
  }
2322
2323
  if (pPluginEvent) {
2324
    int16_t response = kNPEventNotHandled;
2325
    mInstance->HandleEvent(const_cast<NPEvent*>(pPluginEvent),
2326
                           &response,
2327
                           NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
2328
    if (response == kNPEventHandled)
2329
      rv = nsEventStatus_eConsumeNoDefault;
2330
  }
2331
#endif
2332
2333
0
#ifdef MOZ_X11
2334
0
  // this code supports windowless plugins
2335
0
  nsIWidget* widget = anEvent.mWidget;
2336
0
  XEvent pluginEvent = XEvent();
2337
0
  pluginEvent.type = 0;
2338
0
2339
0
  switch(anEvent.mClass) {
2340
0
    case eMouseEventClass:
2341
0
      {
2342
0
        switch (anEvent.mMessage) {
2343
0
          case eMouseClick:
2344
0
          case eMouseDoubleClick:
2345
0
          case eMouseAuxClick:
2346
0
            // Button up/down events sent instead.
2347
0
            return rv;
2348
0
          default:
2349
0
            break;
2350
0
          }
2351
0
2352
0
        // Get reference point relative to plugin origin.
2353
0
        const nsPresContext* presContext = mPluginFrame->PresContext();
2354
0
        nsPoint appPoint =
2355
0
          nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) -
2356
0
          mPluginFrame->GetContentRectRelativeToSelf().TopLeft();
2357
0
        nsIntPoint pluginPoint(presContext->AppUnitsToDevPixels(appPoint.x),
2358
0
                               presContext->AppUnitsToDevPixels(appPoint.y));
2359
0
        const WidgetMouseEvent& mouseEvent = *anEvent.AsMouseEvent();
2360
0
        // Get reference point relative to screen:
2361
0
        LayoutDeviceIntPoint rootPoint(-1, -1);
2362
0
        if (widget) {
2363
0
          rootPoint = anEvent.mRefPoint + widget->WidgetToScreenOffset();
2364
0
        }
2365
0
#ifdef MOZ_WIDGET_GTK
2366
0
        Window root = GDK_ROOT_WINDOW();
2367
#else
2368
        Window root = X11None; // Could XQueryTree, but this is not important.
2369
#endif
2370
2371
0
        switch (anEvent.mMessage) {
2372
0
          case eMouseOver:
2373
0
          case eMouseOut:
2374
0
            {
2375
0
              XCrossingEvent& event = pluginEvent.xcrossing;
2376
0
              event.type = anEvent.mMessage == eMouseOver ?
2377
0
                EnterNotify : LeaveNotify;
2378
0
              event.root = root;
2379
0
              event.time = anEvent.mTime;
2380
0
              event.x = pluginPoint.x;
2381
0
              event.y = pluginPoint.y;
2382
0
              event.x_root = rootPoint.x;
2383
0
              event.y_root = rootPoint.y;
2384
0
              event.state = XInputEventState(mouseEvent);
2385
0
              // information lost
2386
0
              event.subwindow = X11None;
2387
0
              event.mode = -1;
2388
0
              event.detail = NotifyDetailNone;
2389
0
              event.same_screen = True;
2390
0
              event.focus = mContentFocused;
2391
0
            }
2392
0
            break;
2393
0
          case eMouseMove:
2394
0
            {
2395
0
              XMotionEvent& event = pluginEvent.xmotion;
2396
0
              event.type = MotionNotify;
2397
0
              event.root = root;
2398
0
              event.time = anEvent.mTime;
2399
0
              event.x = pluginPoint.x;
2400
0
              event.y = pluginPoint.y;
2401
0
              event.x_root = rootPoint.x;
2402
0
              event.y_root = rootPoint.y;
2403
0
              event.state = XInputEventState(mouseEvent);
2404
0
              // information lost
2405
0
              event.subwindow = X11None;
2406
0
              event.is_hint = NotifyNormal;
2407
0
              event.same_screen = True;
2408
0
            }
2409
0
            break;
2410
0
          case eMouseDown:
2411
0
          case eMouseUp:
2412
0
            {
2413
0
              XButtonEvent& event = pluginEvent.xbutton;
2414
0
              event.type = anEvent.mMessage == eMouseDown ?
2415
0
                ButtonPress : ButtonRelease;
2416
0
              event.root = root;
2417
0
              event.time = anEvent.mTime;
2418
0
              event.x = pluginPoint.x;
2419
0
              event.y = pluginPoint.y;
2420
0
              event.x_root = rootPoint.x;
2421
0
              event.y_root = rootPoint.y;
2422
0
              event.state = XInputEventState(mouseEvent);
2423
0
              switch (mouseEvent.button)
2424
0
                {
2425
0
                case WidgetMouseEvent::eMiddleButton:
2426
0
                  event.button = 2;
2427
0
                  break;
2428
0
                case WidgetMouseEvent::eRightButton:
2429
0
                  event.button = 3;
2430
0
                  break;
2431
0
                default: // WidgetMouseEvent::eLeftButton;
2432
0
                  event.button = 1;
2433
0
                  break;
2434
0
                }
2435
0
              // information lost:
2436
0
              event.subwindow = X11None;
2437
0
              event.same_screen = True;
2438
0
            }
2439
0
            break;
2440
0
          default:
2441
0
            break;
2442
0
          }
2443
0
      }
2444
0
      break;
2445
0
2446
0
   //XXX case eMouseScrollEventClass: not received.
2447
0
2448
0
   case eKeyboardEventClass:
2449
0
      if (anEvent.mPluginEvent)
2450
0
        {
2451
0
          XKeyEvent &event = pluginEvent.xkey;
2452
0
#ifdef MOZ_WIDGET_GTK
2453
0
          event.root = GDK_ROOT_WINDOW();
2454
0
          event.time = anEvent.mTime;
2455
0
          const GdkEventKey* gdkEvent =
2456
0
            static_cast<const GdkEventKey*>(anEvent.mPluginEvent);
2457
0
          event.keycode = gdkEvent->hardware_keycode;
2458
0
          event.state = gdkEvent->state;
2459
0
          switch (anEvent.mMessage)
2460
0
            {
2461
0
            case eKeyDown:
2462
0
              // Handle eKeyDown for modifier key presses
2463
0
              // For non-modifiers we get eKeyPress
2464
0
              if (gdkEvent->is_modifier)
2465
0
                event.type = XKeyPress;
2466
0
              break;
2467
0
            case eKeyPress:
2468
0
              event.type = XKeyPress;
2469
0
              break;
2470
0
            case eKeyUp:
2471
0
              event.type = KeyRelease;
2472
0
              break;
2473
0
            default:
2474
0
              break;
2475
0
            }
2476
0
#endif
2477
0
2478
0
          // Information that could be obtained from pluginEvent but we may not
2479
0
          // want to promise to provide:
2480
0
          event.subwindow = X11None;
2481
0
          event.x = 0;
2482
0
          event.y = 0;
2483
0
          event.x_root = -1;
2484
0
          event.y_root = -1;
2485
0
          event.same_screen = False;
2486
0
        }
2487
0
      else
2488
0
        {
2489
0
          // If we need to send synthesized key events, then
2490
0
          // DOMKeyCodeToGdkKeyCode(keyEvent.keyCode) and
2491
0
          // gdk_keymap_get_entries_for_keyval will be useful, but the
2492
0
          // mappings will not be unique.
2493
0
          NS_WARNING("Synthesized key event not sent to plugin");
2494
0
        }
2495
0
      break;
2496
0
2497
0
    default:
2498
0
      switch (anEvent.mMessage) {
2499
0
        case eFocus:
2500
0
        case eBlur:
2501
0
          {
2502
0
            XFocusChangeEvent &event = pluginEvent.xfocus;
2503
0
            event.type = anEvent.mMessage == eFocus ? FocusIn : FocusOut;
2504
0
            // information lost:
2505
0
            event.mode = -1;
2506
0
            event.detail = NotifyDetailNone;
2507
0
          }
2508
0
          break;
2509
0
        default:
2510
0
          break;
2511
0
      }
2512
0
    }
2513
0
2514
0
  if (!pluginEvent.type) {
2515
0
    return rv;
2516
0
  }
2517
0
2518
0
  // Fill in (useless) generic event information.
2519
0
  XAnyEvent& event = pluginEvent.xany;
2520
0
  event.display = widget ?
2521
0
    static_cast<Display*>(widget->GetNativeData(NS_NATIVE_DISPLAY)) : nullptr;
2522
0
  event.window = X11None; // not a real window
2523
0
  // information lost:
2524
0
  event.serial = 0;
2525
0
  event.send_event = False;
2526
0
2527
0
  int16_t response = kNPEventNotHandled;
2528
0
  mInstance->HandleEvent(&pluginEvent, &response, NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
2529
0
  if (response == kNPEventHandled)
2530
0
    rv = nsEventStatus_eConsumeNoDefault;
2531
0
#endif
2532
0
2533
0
  return rv;
2534
0
}
2535
2536
nsresult
2537
nsPluginInstanceOwner::Destroy()
2538
0
{
2539
0
  SetFrame(nullptr);
2540
0
2541
#ifdef XP_MACOSX
2542
  RemoveFromCARefreshTimer();
2543
#endif
2544
2545
0
  nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
2546
0
2547
0
  // unregister context menu listener
2548
0
  if (mCXMenuListener) {
2549
0
    mCXMenuListener->Destroy(content);
2550
0
    mCXMenuListener = nullptr;
2551
0
  }
2552
0
2553
0
  content->RemoveEventListener(NS_LITERAL_STRING("focus"), this, false);
2554
0
  content->RemoveEventListener(NS_LITERAL_STRING("blur"), this, false);
2555
0
  content->RemoveEventListener(NS_LITERAL_STRING("mouseup"), this, false);
2556
0
  content->RemoveEventListener(NS_LITERAL_STRING("mousedown"), this, false);
2557
0
  content->RemoveEventListener(NS_LITERAL_STRING("mousemove"), this, false);
2558
0
  content->RemoveEventListener(NS_LITERAL_STRING("click"), this, false);
2559
0
  content->RemoveEventListener(NS_LITERAL_STRING("dblclick"), this, false);
2560
0
  content->RemoveEventListener(NS_LITERAL_STRING("mouseover"), this, false);
2561
0
  content->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this, false);
2562
0
  content->RemoveEventListener(NS_LITERAL_STRING("keypress"), this, true);
2563
0
  content->RemoveSystemEventListener(NS_LITERAL_STRING("keypress"), this, true);
2564
0
  content->RemoveEventListener(NS_LITERAL_STRING("keydown"), this, true);
2565
0
  content->RemoveEventListener(NS_LITERAL_STRING("keyup"), this, true);
2566
0
  content->RemoveEventListener(NS_LITERAL_STRING("drop"), this, true);
2567
0
  content->RemoveEventListener(NS_LITERAL_STRING("drag"), this, true);
2568
0
  content->RemoveEventListener(NS_LITERAL_STRING("dragenter"), this, true);
2569
0
  content->RemoveEventListener(NS_LITERAL_STRING("dragover"), this, true);
2570
0
  content->RemoveEventListener(NS_LITERAL_STRING("dragleave"), this, true);
2571
0
  content->RemoveEventListener(NS_LITERAL_STRING("dragexit"), this, true);
2572
0
  content->RemoveEventListener(NS_LITERAL_STRING("dragstart"), this, true);
2573
0
  content->RemoveEventListener(NS_LITERAL_STRING("dragend"), this, true);
2574
0
  content->RemoveSystemEventListener(NS_LITERAL_STRING("compositionstart"),
2575
0
                                     this, true);
2576
0
  content->RemoveSystemEventListener(NS_LITERAL_STRING("compositionend"),
2577
0
                                     this, true);
2578
0
  content->RemoveSystemEventListener(NS_LITERAL_STRING("text"), this, true);
2579
0
2580
0
  if (mWidget) {
2581
0
    if (mPluginWindow) {
2582
0
      mPluginWindow->SetPluginWidget(nullptr);
2583
0
    }
2584
0
2585
0
    nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
2586
0
    if (pluginWidget) {
2587
0
      pluginWidget->SetPluginInstanceOwner(nullptr);
2588
0
    }
2589
0
    mWidget->Destroy();
2590
0
  }
2591
0
2592
0
  return NS_OK;
2593
0
}
2594
2595
// Paints are handled differently, so we just simulate an update event.
2596
2597
#ifdef XP_MACOSX
2598
void nsPluginInstanceOwner::Paint(const gfxRect& aDirtyRect, CGContextRef cgContext)
2599
{
2600
  if (!mInstance || !mPluginFrame)
2601
    return;
2602
2603
  gfxRect dirtyRectCopy = aDirtyRect;
2604
  double scaleFactor = 1.0;
2605
  GetContentsScaleFactor(&scaleFactor);
2606
  if (scaleFactor != 1.0) {
2607
    ::CGContextScaleCTM(cgContext, scaleFactor, scaleFactor);
2608
    // Convert aDirtyRect from device pixels to "display pixels"
2609
    // for HiDPI modes
2610
    dirtyRectCopy.ScaleRoundOut(1.0 / scaleFactor);
2611
  }
2612
2613
  DoCocoaEventDrawRect(dirtyRectCopy, cgContext);
2614
}
2615
2616
void nsPluginInstanceOwner::DoCocoaEventDrawRect(const gfxRect& aDrawRect, CGContextRef cgContext)
2617
{
2618
  if (!mInstance || !mPluginFrame)
2619
    return;
2620
2621
  // The context given here is only valid during the HandleEvent call.
2622
  NPCocoaEvent updateEvent;
2623
  InitializeNPCocoaEvent(&updateEvent);
2624
  updateEvent.type = NPCocoaEventDrawRect;
2625
  updateEvent.data.draw.context = cgContext;
2626
  updateEvent.data.draw.x = aDrawRect.X();
2627
  updateEvent.data.draw.y = aDrawRect.Y();
2628
  updateEvent.data.draw.width = aDrawRect.Width();
2629
  updateEvent.data.draw.height = aDrawRect.Height();
2630
2631
  mInstance->HandleEvent(&updateEvent, nullptr);
2632
}
2633
#endif
2634
2635
#ifdef XP_WIN
2636
void nsPluginInstanceOwner::Paint(const RECT& aDirty, HDC aDC)
2637
{
2638
  if (!mInstance || !mPluginFrame)
2639
    return;
2640
2641
  NPEvent pluginEvent;
2642
  pluginEvent.event = WM_PAINT;
2643
  pluginEvent.wParam = WPARAM(aDC);
2644
  pluginEvent.lParam = LPARAM(&aDirty);
2645
  mInstance->HandleEvent(&pluginEvent, nullptr);
2646
}
2647
#endif
2648
2649
#if defined(MOZ_X11)
2650
void nsPluginInstanceOwner::Paint(gfxContext* aContext,
2651
                                  const gfxRect& aFrameRect,
2652
                                  const gfxRect& aDirtyRect)
2653
0
{
2654
0
  if (!mInstance || !mPluginFrame)
2655
0
    return;
2656
0
2657
0
  // to provide crisper and faster drawing.
2658
0
  gfxRect pluginRect = aFrameRect;
2659
0
  if (aContext->UserToDevicePixelSnapped(pluginRect)) {
2660
0
    pluginRect = aContext->DeviceToUser(pluginRect);
2661
0
  }
2662
0
2663
0
  // Round out the dirty rect to plugin pixels to ensure the plugin draws
2664
0
  // enough pixels for interpolation to device pixels.
2665
0
  gfxRect dirtyRect = aDirtyRect - pluginRect.TopLeft();
2666
0
  dirtyRect.RoundOut();
2667
0
2668
0
  // Plugins can only draw an integer number of pixels.
2669
0
  //
2670
0
  // With translation-only transformation matrices, pluginRect is already
2671
0
  // pixel-aligned.
2672
0
  //
2673
0
  // With more complex transformations, modifying the scales in the
2674
0
  // transformation matrix could retain subpixel accuracy and let the plugin
2675
0
  // draw a suitable number of pixels for interpolation to device pixels in
2676
0
  // Renderer::Draw, but such cases are not common enough to warrant the
2677
0
  // effort now.
2678
0
  nsIntSize pluginSize(NS_lround(pluginRect.width),
2679
0
                       NS_lround(pluginRect.height));
2680
0
2681
0
  // Determine what the plugin needs to draw.
2682
0
  nsIntRect pluginDirtyRect(int32_t(dirtyRect.x),
2683
0
                            int32_t(dirtyRect.y),
2684
0
                            int32_t(dirtyRect.width),
2685
0
                            int32_t(dirtyRect.height));
2686
0
  if (!pluginDirtyRect.
2687
0
      IntersectRect(nsIntRect(0, 0, pluginSize.width, pluginSize.height),
2688
0
                    pluginDirtyRect))
2689
0
    return;
2690
0
2691
0
  NPWindow* window;
2692
0
  GetWindow(window);
2693
0
2694
0
  uint32_t rendererFlags = 0;
2695
0
  if (!mFlash10Quirks) {
2696
0
    rendererFlags |=
2697
0
      Renderer::DRAW_SUPPORTS_CLIP_RECT |
2698
0
      Renderer::DRAW_SUPPORTS_ALTERNATE_VISUAL;
2699
0
  }
2700
0
2701
0
  bool transparent;
2702
0
  mInstance->IsTransparent(&transparent);
2703
0
  if (!transparent)
2704
0
    rendererFlags |= Renderer::DRAW_IS_OPAQUE;
2705
0
2706
0
  // Renderer::Draw() draws a rectangle with top-left at the aContext origin.
2707
0
  gfxContextAutoSaveRestore autoSR(aContext);
2708
0
  aContext->SetMatrixDouble(
2709
0
    aContext->CurrentMatrixDouble().PreTranslate(pluginRect.TopLeft()));
2710
0
2711
0
  Renderer renderer(window, this, pluginSize, pluginDirtyRect);
2712
0
2713
0
  Display* dpy = mozilla::DefaultXDisplay();
2714
0
  Screen* screen = DefaultScreenOfDisplay(dpy);
2715
0
  Visual* visual = DefaultVisualOfScreen(screen);
2716
0
2717
0
  renderer.Draw(aContext, nsIntSize(window->width, window->height),
2718
0
                rendererFlags, screen, visual);
2719
0
}
2720
nsresult
2721
nsPluginInstanceOwner::Renderer::DrawWithXlib(cairo_surface_t* xsurface,
2722
                                              nsIntPoint offset,
2723
                                              nsIntRect *clipRects,
2724
                                              uint32_t numClipRects)
2725
0
{
2726
0
  Screen *screen = cairo_xlib_surface_get_screen(xsurface);
2727
0
  Colormap colormap;
2728
0
  Visual* visual;
2729
0
  if (!gfxXlibSurface::GetColormapAndVisual(xsurface, &colormap, &visual)) {
2730
0
    NS_ERROR("Failed to get visual and colormap");
2731
0
    return NS_ERROR_UNEXPECTED;
2732
0
  }
2733
0
2734
0
  nsNPAPIPluginInstance *instance = mInstanceOwner->mInstance;
2735
0
  if (!instance)
2736
0
    return NS_ERROR_FAILURE;
2737
0
2738
0
  // See if the plugin must be notified of new window parameters.
2739
0
  bool doupdatewindow = false;
2740
0
2741
0
  if (mWindow->x != offset.x || mWindow->y != offset.y) {
2742
0
    mWindow->x = offset.x;
2743
0
    mWindow->y = offset.y;
2744
0
    doupdatewindow = true;
2745
0
  }
2746
0
2747
0
  if (nsIntSize(mWindow->width, mWindow->height) != mPluginSize) {
2748
0
    mWindow->width = mPluginSize.width;
2749
0
    mWindow->height = mPluginSize.height;
2750
0
    doupdatewindow = true;
2751
0
  }
2752
0
2753
0
  // The clip rect is relative to drawable top-left.
2754
0
  NS_ASSERTION(numClipRects <= 1, "We don't support multiple clip rectangles!");
2755
0
  nsIntRect clipRect;
2756
0
  if (numClipRects) {
2757
0
    clipRect.x = clipRects[0].x;
2758
0
    clipRect.y = clipRects[0].y;
2759
0
    clipRect.width  = clipRects[0].width;
2760
0
    clipRect.height = clipRects[0].height;
2761
0
    // NPRect members are unsigned, but clip rectangles should be contained by
2762
0
    // the surface.
2763
0
    NS_ASSERTION(clipRect.x >= 0 && clipRect.y >= 0,
2764
0
                 "Clip rectangle offsets are negative!");
2765
0
  }
2766
0
  else {
2767
0
    clipRect.x = offset.x;
2768
0
    clipRect.y = offset.y;
2769
0
    clipRect.width  = mWindow->width;
2770
0
    clipRect.height = mWindow->height;
2771
0
    // Don't ask the plugin to draw outside the drawable.
2772
0
    // This also ensures that the unsigned clip rectangle offsets won't be -ve.
2773
0
    clipRect.IntersectRect(clipRect,
2774
0
                           nsIntRect(0, 0,
2775
0
                                     cairo_xlib_surface_get_width(xsurface),
2776
0
                                     cairo_xlib_surface_get_height(xsurface)));
2777
0
  }
2778
0
2779
0
  NPRect newClipRect;
2780
0
  newClipRect.left = clipRect.x;
2781
0
  newClipRect.top = clipRect.y;
2782
0
  newClipRect.right = clipRect.XMost();
2783
0
  newClipRect.bottom = clipRect.YMost();
2784
0
  if (mWindow->clipRect.left    != newClipRect.left   ||
2785
0
      mWindow->clipRect.top     != newClipRect.top    ||
2786
0
      mWindow->clipRect.right   != newClipRect.right  ||
2787
0
      mWindow->clipRect.bottom  != newClipRect.bottom) {
2788
0
    mWindow->clipRect = newClipRect;
2789
0
    doupdatewindow = true;
2790
0
  }
2791
0
2792
0
  NPSetWindowCallbackStruct* ws_info =
2793
0
    static_cast<NPSetWindowCallbackStruct*>(mWindow->ws_info);
2794
0
#ifdef MOZ_X11
2795
0
  if (ws_info->visual != visual || ws_info->colormap != colormap) {
2796
0
    ws_info->visual = visual;
2797
0
    ws_info->colormap = colormap;
2798
0
    ws_info->depth = gfxXlibSurface::DepthOfVisual(screen, visual);
2799
0
    doupdatewindow = true;
2800
0
  }
2801
0
#endif
2802
0
2803
0
  {
2804
0
    if (doupdatewindow)
2805
0
      instance->SetWindow(mWindow);
2806
0
  }
2807
0
2808
0
  // Translate the dirty rect to drawable coordinates.
2809
0
  nsIntRect dirtyRect = mDirtyRect + offset;
2810
0
  if (mInstanceOwner->mFlash10Quirks) {
2811
0
    // Work around a bug in Flash up to 10.1 d51 at least, where expose event
2812
0
    // top left coordinates within the plugin-rect and not at the drawable
2813
0
    // origin are misinterpreted.  (We can move the top left coordinate
2814
0
    // provided it is within the clipRect.)
2815
0
    dirtyRect.SetRect(offset.x, offset.y,
2816
0
                      mDirtyRect.XMost(), mDirtyRect.YMost());
2817
0
  }
2818
0
  // Intersect the dirty rect with the clip rect to ensure that it lies within
2819
0
  // the drawable.
2820
0
  if (!dirtyRect.IntersectRect(dirtyRect, clipRect))
2821
0
    return NS_OK;
2822
0
2823
0
  {
2824
0
    XEvent pluginEvent = XEvent();
2825
0
    XGraphicsExposeEvent& exposeEvent = pluginEvent.xgraphicsexpose;
2826
0
    // set the drawing info
2827
0
    exposeEvent.type = GraphicsExpose;
2828
0
    exposeEvent.display = DisplayOfScreen(screen);
2829
0
    exposeEvent.drawable = cairo_xlib_surface_get_drawable(xsurface);
2830
0
    exposeEvent.x = dirtyRect.x;
2831
0
    exposeEvent.y = dirtyRect.y;
2832
0
    exposeEvent.width  = dirtyRect.width;
2833
0
    exposeEvent.height = dirtyRect.height;
2834
0
    exposeEvent.count = 0;
2835
0
    // information not set:
2836
0
    exposeEvent.serial = 0;
2837
0
    exposeEvent.send_event = False;
2838
0
    exposeEvent.major_code = 0;
2839
0
    exposeEvent.minor_code = 0;
2840
0
2841
0
    instance->HandleEvent(&pluginEvent, nullptr);
2842
0
  }
2843
0
  return NS_OK;
2844
0
}
2845
#endif
2846
2847
nsresult nsPluginInstanceOwner::Init(nsIContent* aContent)
2848
0
{
2849
0
  mLastEventloopNestingLevel = GetEventloopNestingLevel();
2850
0
2851
0
  mContent = do_GetWeakReference(aContent);
2852
0
2853
0
  // Get a frame, don't reflow. If a reflow was necessary it should have been
2854
0
  // done at a higher level than this (content).
2855
0
  nsIFrame* frame = aContent->GetPrimaryFrame();
2856
0
  nsIObjectFrame* iObjFrame = do_QueryFrame(frame);
2857
0
  nsPluginFrame* objFrame =  static_cast<nsPluginFrame*>(iObjFrame);
2858
0
  if (objFrame) {
2859
0
    SetFrame(objFrame);
2860
0
    // Some plugins require a specific sequence of shutdown and startup when
2861
0
    // a page is reloaded. Shutdown happens usually when the last instance
2862
0
    // is destroyed. Here we make sure the plugin instance in the old
2863
0
    // document is destroyed before we try to create the new one.
2864
0
    objFrame->PresContext()->EnsureVisible();
2865
0
  } else {
2866
0
    MOZ_ASSERT_UNREACHABLE("Should not be initializing plugin without a frame");
2867
0
    return NS_ERROR_FAILURE;
2868
0
  }
2869
0
2870
0
  // register context menu listener
2871
0
  mCXMenuListener = new nsPluginDOMContextMenuListener(aContent);
2872
0
2873
0
  aContent->AddEventListener(NS_LITERAL_STRING("focus"), this, false,
2874
0
                             false);
2875
0
  aContent->AddEventListener(NS_LITERAL_STRING("blur"), this, false,
2876
0
                             false);
2877
0
  aContent->AddEventListener(NS_LITERAL_STRING("mouseup"), this, false,
2878
0
                             false);
2879
0
  aContent->AddEventListener(NS_LITERAL_STRING("mousedown"), this, false,
2880
0
                             false);
2881
0
  aContent->AddEventListener(NS_LITERAL_STRING("mousemove"), this, false,
2882
0
                             false);
2883
0
  aContent->AddEventListener(NS_LITERAL_STRING("click"), this, false,
2884
0
                             false);
2885
0
  aContent->AddEventListener(NS_LITERAL_STRING("dblclick"), this, false,
2886
0
                             false);
2887
0
  aContent->AddEventListener(NS_LITERAL_STRING("mouseover"), this, false,
2888
0
                             false);
2889
0
  aContent->AddEventListener(NS_LITERAL_STRING("mouseout"), this, false,
2890
0
                             false);
2891
0
  // "keypress" event should be handled when it's in the default event group
2892
0
  // if the event is fired in content.  Otherwise, it should be handled when
2893
0
  // it's in the system event group.
2894
0
  aContent->AddEventListener(NS_LITERAL_STRING("keypress"), this, true);
2895
0
  aContent->AddSystemEventListener(NS_LITERAL_STRING("keypress"), this, true);
2896
0
  aContent->AddEventListener(NS_LITERAL_STRING("keydown"), this, true);
2897
0
  aContent->AddEventListener(NS_LITERAL_STRING("keyup"), this, true);
2898
0
  aContent->AddEventListener(NS_LITERAL_STRING("drop"), this, true);
2899
0
  aContent->AddEventListener(NS_LITERAL_STRING("drag"), this, true);
2900
0
  aContent->AddEventListener(NS_LITERAL_STRING("dragenter"), this, true);
2901
0
  aContent->AddEventListener(NS_LITERAL_STRING("dragover"), this, true);
2902
0
  aContent->AddEventListener(NS_LITERAL_STRING("dragleave"), this, true);
2903
0
  aContent->AddEventListener(NS_LITERAL_STRING("dragexit"), this, true);
2904
0
  aContent->AddEventListener(NS_LITERAL_STRING("dragstart"), this, true);
2905
0
  aContent->AddEventListener(NS_LITERAL_STRING("dragend"), this, true);
2906
0
  aContent->AddSystemEventListener(NS_LITERAL_STRING("compositionstart"),
2907
0
    this, true);
2908
0
  aContent->AddSystemEventListener(NS_LITERAL_STRING("compositionend"), this,
2909
0
    true);
2910
0
  aContent->AddSystemEventListener(NS_LITERAL_STRING("text"), this, true);
2911
0
2912
0
  return NS_OK;
2913
0
}
2914
2915
void* nsPluginInstanceOwner::GetPluginPort()
2916
0
{
2917
0
  void* result = nullptr;
2918
0
  if (mWidget) {
2919
#ifdef XP_WIN
2920
    if (!mPluginWindow || mPluginWindow->type == NPWindowTypeWindow)
2921
#endif
2922
0
      result = mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT); // HWND/gdk window
2923
0
  }
2924
0
2925
0
  return result;
2926
0
}
2927
2928
void nsPluginInstanceOwner::ReleasePluginPort(void * pluginPort)
2929
0
{
2930
0
}
2931
2932
NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void)
2933
0
{
2934
0
  NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER);
2935
0
2936
0
  // Can't call this twice!
2937
0
  if (mWidget) {
2938
0
    NS_WARNING("Trying to create a plugin widget twice!");
2939
0
    return NS_ERROR_FAILURE;
2940
0
  }
2941
0
2942
0
  bool windowless = false;
2943
0
  mInstance->IsWindowless(&windowless);
2944
0
  if (!windowless) {
2945
0
#ifndef XP_WIN
2946
0
    // Only Windows supports windowed mode!
2947
0
    MOZ_ASSERT_UNREACHABLE();
2948
0
    return NS_ERROR_FAILURE;
2949
#else
2950
    // Try to get a parent widget, on some platforms widget creation will fail without
2951
    // a parent.
2952
    nsresult rv = NS_ERROR_FAILURE;
2953
2954
    nsCOMPtr<nsIWidget> parentWidget;
2955
    nsIDocument *doc = nullptr;
2956
    nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
2957
    if (content) {
2958
      doc = content->OwnerDoc();
2959
      parentWidget = nsContentUtils::WidgetForDocument(doc);
2960
      // If we're running in the content process, we need a remote widget created in chrome.
2961
      if (XRE_IsContentProcess()) {
2962
        if (nsCOMPtr<nsPIDOMWindowOuter> window = doc->GetWindow()) {
2963
          if (nsCOMPtr<nsPIDOMWindowOuter> topWindow = window->GetTop()) {
2964
            dom::TabChild* tc = dom::TabChild::GetFrom(topWindow);
2965
            if (tc) {
2966
              // This returns a PluginWidgetProxy which remotes a number of calls.
2967
              rv = tc->CreatePluginWidget(parentWidget.get(), getter_AddRefs(mWidget));
2968
              if (NS_FAILED(rv)) {
2969
                return rv;
2970
              }
2971
            }
2972
          }
2973
        }
2974
      }
2975
    }
2976
2977
    // A failure here is terminal since we can't fall back on the non-e10s code
2978
    // path below.
2979
    if (!mWidget && XRE_IsContentProcess()) {
2980
      return NS_ERROR_UNEXPECTED;
2981
    }
2982
2983
    if (!mWidget) {
2984
      // native (single process)
2985
      mWidget = nsIWidget::CreateChildWindow();
2986
      nsWidgetInitData initData;
2987
      initData.mWindowType = eWindowType_plugin;
2988
      initData.mUnicode = false;
2989
      initData.clipChildren = true;
2990
      initData.clipSiblings = true;
2991
      rv = mWidget->Create(parentWidget.get(), nullptr,
2992
                           LayoutDeviceIntRect(0, 0, 0, 0), &initData);
2993
      if (NS_FAILED(rv)) {
2994
        mWidget->Destroy();
2995
        mWidget = nullptr;
2996
        return rv;
2997
      }
2998
    }
2999
3000
    mWidget->EnableDragDrop(true);
3001
    mWidget->Show(false);
3002
    mWidget->Enable(false);
3003
#endif // XP_WIN
3004
  }
3005
0
3006
0
  if (mPluginFrame) {
3007
0
    // nullptr widget is fine, will result in windowless setup.
3008
0
    mPluginFrame->PrepForDrawing(mWidget);
3009
0
  }
3010
0
3011
0
  if (windowless) {
3012
0
    mPluginWindow->type = NPWindowTypeDrawable;
3013
0
3014
0
    // this needs to be a HDC according to the spec, but I do
3015
0
    // not see the right way to release it so let's postpone
3016
0
    // passing HDC till paint event when it is really
3017
0
    // needed. Change spec?
3018
0
    mPluginWindow->window = nullptr;
3019
0
#ifdef MOZ_X11
3020
0
    // Fill in the display field.
3021
0
    NPSetWindowCallbackStruct* ws_info =
3022
0
    static_cast<NPSetWindowCallbackStruct*>(mPluginWindow->ws_info);
3023
0
    ws_info->display = DefaultXDisplay();
3024
0
3025
0
    nsAutoCString description;
3026
0
    GetPluginDescription(description);
3027
0
    NS_NAMED_LITERAL_CSTRING(flash10Head, "Shockwave Flash 10.");
3028
0
    mFlash10Quirks = StringBeginsWith(description, flash10Head);
3029
0
#endif
3030
0
  } else if (mWidget) {
3031
0
    // mPluginWindow->type is used in |GetPluginPort| so it must
3032
0
    // be initialized first
3033
0
    mPluginWindow->type = NPWindowTypeWindow;
3034
0
    mPluginWindow->window = GetPluginPort();
3035
0
    // tell the plugin window about the widget
3036
0
    mPluginWindow->SetPluginWidget(mWidget);
3037
0
3038
0
    // tell the widget about the current plugin instance owner.
3039
0
    nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
3040
0
    if (pluginWidget) {
3041
0
      pluginWidget->SetPluginInstanceOwner(this);
3042
0
    }
3043
0
  }
3044
0
3045
#ifdef XP_MACOSX
3046
  if (GetDrawingModel() == NPDrawingModelCoreAnimation) {
3047
    AddToCARefreshTimer();
3048
  }
3049
#endif
3050
3051
0
  mWidgetCreationComplete = true;
3052
0
3053
0
  return NS_OK;
3054
0
}
3055
3056
// Mac specific code to fix up the port location and clipping region
3057
#ifdef XP_MACOSX
3058
3059
void nsPluginInstanceOwner::FixUpPluginWindow(int32_t inPaintState)
3060
{
3061
  if (!mPluginWindow || !mInstance || !mPluginFrame) {
3062
    return;
3063
  }
3064
3065
  SetPluginPort();
3066
3067
  LayoutDeviceIntSize widgetClip = mPluginFrame->GetWidgetlessClipRect().Size();
3068
3069
  mPluginWindow->x = 0;
3070
  mPluginWindow->y = 0;
3071
3072
  NPRect oldClipRect = mPluginWindow->clipRect;
3073
3074
  // fix up the clipping region
3075
  mPluginWindow->clipRect.top  = 0;
3076
  mPluginWindow->clipRect.left = 0;
3077
3078
  if (inPaintState == ePluginPaintDisable) {
3079
    mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top;
3080
    mPluginWindow->clipRect.right  = mPluginWindow->clipRect.left;
3081
  }
3082
  else if (inPaintState == ePluginPaintEnable)
3083
  {
3084
    mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top + widgetClip.height;
3085
    mPluginWindow->clipRect.right  = mPluginWindow->clipRect.left + widgetClip.width;
3086
  }
3087
3088
  // if the clip rect changed, call SetWindow()
3089
  // (RealPlayer needs this to draw correctly)
3090
  if (mPluginWindow->clipRect.left    != oldClipRect.left   ||
3091
      mPluginWindow->clipRect.top     != oldClipRect.top    ||
3092
      mPluginWindow->clipRect.right   != oldClipRect.right  ||
3093
      mPluginWindow->clipRect.bottom  != oldClipRect.bottom)
3094
  {
3095
    if (UseAsyncRendering()) {
3096
      mInstance->AsyncSetWindow(mPluginWindow);
3097
    }
3098
    else {
3099
      mPluginWindow->CallSetWindow(mInstance);
3100
    }
3101
  }
3102
3103
  // After the first NPP_SetWindow call we need to send an initial
3104
  // top-level window focus event.
3105
  if (!mSentInitialTopLevelWindowEvent) {
3106
    // Set this before calling ProcessEvent to avoid endless recursion.
3107
    mSentInitialTopLevelWindowEvent = true;
3108
3109
    bool isActive = WindowIsActive();
3110
    SendWindowFocusChanged(isActive);
3111
    mLastWindowIsActive = isActive;
3112
  }
3113
}
3114
3115
void
3116
nsPluginInstanceOwner::WindowFocusMayHaveChanged()
3117
{
3118
  if (!mSentInitialTopLevelWindowEvent) {
3119
    return;
3120
  }
3121
3122
  bool isActive = WindowIsActive();
3123
  if (isActive != mLastWindowIsActive) {
3124
    SendWindowFocusChanged(isActive);
3125
    mLastWindowIsActive = isActive;
3126
  }
3127
}
3128
3129
bool
3130
nsPluginInstanceOwner::WindowIsActive()
3131
{
3132
  if (!mPluginFrame) {
3133
    return false;
3134
  }
3135
3136
  EventStates docState = mPluginFrame->GetContent()->OwnerDoc()->GetDocumentState();
3137
  return !docState.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
3138
}
3139
3140
void
3141
nsPluginInstanceOwner::SendWindowFocusChanged(bool aIsActive)
3142
{
3143
  if (!mInstance) {
3144
    return;
3145
  }
3146
3147
  NPCocoaEvent cocoaEvent;
3148
  InitializeNPCocoaEvent(&cocoaEvent);
3149
  cocoaEvent.type = NPCocoaEventWindowFocusChanged;
3150
  cocoaEvent.data.focus.hasFocus = aIsActive;
3151
  mInstance->HandleEvent(&cocoaEvent,
3152
                         nullptr,
3153
                         NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
3154
}
3155
3156
void
3157
nsPluginInstanceOwner::HidePluginWindow()
3158
{
3159
  if (!mPluginWindow || !mInstance) {
3160
    return;
3161
  }
3162
3163
  mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top;
3164
  mPluginWindow->clipRect.right  = mPluginWindow->clipRect.left;
3165
  mWidgetVisible = false;
3166
  if (UseAsyncRendering()) {
3167
    mInstance->AsyncSetWindow(mPluginWindow);
3168
  } else {
3169
    mInstance->SetWindow(mPluginWindow);
3170
  }
3171
}
3172
3173
#else // XP_MACOSX
3174
3175
void nsPluginInstanceOwner::UpdateWindowPositionAndClipRect(bool aSetWindow)
3176
0
{
3177
0
  if (!mPluginWindow)
3178
0
    return;
3179
0
3180
0
  // For windowless plugins a non-empty clip rectangle will be
3181
0
  // passed to the plugin during paint, an additional update
3182
0
  // of the the clip rectangle here is not required
3183
0
  if (aSetWindow && !mWidget && mPluginWindowVisible && !UseAsyncRendering())
3184
0
    return;
3185
0
3186
0
  const NPWindow oldWindow = *mPluginWindow;
3187
0
3188
0
  bool windowless = (mPluginWindow->type == NPWindowTypeDrawable);
3189
0
  nsIntPoint origin = mPluginFrame->GetWindowOriginInPixels(windowless);
3190
0
3191
0
  mPluginWindow->x = origin.x;
3192
0
  mPluginWindow->y = origin.y;
3193
0
3194
0
  mPluginWindow->clipRect.left = 0;
3195
0
  mPluginWindow->clipRect.top = 0;
3196
0
3197
0
  if (mPluginWindowVisible && mPluginDocumentActiveState) {
3198
0
    mPluginWindow->clipRect.right = mPluginWindow->width;
3199
0
    mPluginWindow->clipRect.bottom = mPluginWindow->height;
3200
0
  } else {
3201
0
    mPluginWindow->clipRect.right = 0;
3202
0
    mPluginWindow->clipRect.bottom = 0;
3203
0
  }
3204
0
3205
0
  if (!aSetWindow)
3206
0
    return;
3207
0
3208
0
  if (mPluginWindow->x               != oldWindow.x               ||
3209
0
      mPluginWindow->y               != oldWindow.y               ||
3210
0
      mPluginWindow->clipRect.left   != oldWindow.clipRect.left   ||
3211
0
      mPluginWindow->clipRect.top    != oldWindow.clipRect.top    ||
3212
0
      mPluginWindow->clipRect.right  != oldWindow.clipRect.right  ||
3213
0
      mPluginWindow->clipRect.bottom != oldWindow.clipRect.bottom) {
3214
0
    CallSetWindow();
3215
0
  }
3216
0
}
3217
3218
void
3219
nsPluginInstanceOwner::UpdateWindowVisibility(bool aVisible)
3220
0
{
3221
0
  mPluginWindowVisible = aVisible;
3222
0
  UpdateWindowPositionAndClipRect(true);
3223
0
}
3224
#endif // XP_MACOSX
3225
3226
void
3227
nsPluginInstanceOwner::ResolutionMayHaveChanged()
3228
0
{
3229
#if defined(XP_MACOSX) || defined(XP_WIN)
3230
  double scaleFactor = 1.0;
3231
  GetContentsScaleFactor(&scaleFactor);
3232
  if (scaleFactor != mLastScaleFactor) {
3233
    ContentsScaleFactorChanged(scaleFactor);
3234
    mLastScaleFactor = scaleFactor;
3235
  }
3236
#endif
3237
  float zoomFactor = 1.0;
3238
0
  GetCSSZoomFactor(&zoomFactor);
3239
0
  if (zoomFactor != mLastCSSZoomFactor) {
3240
0
    if (mInstance) {
3241
0
      mInstance->CSSZoomFactorChanged(zoomFactor);
3242
0
    }
3243
0
    mLastCSSZoomFactor = zoomFactor;
3244
0
  }
3245
0
3246
0
}
3247
3248
void
3249
nsPluginInstanceOwner::UpdateDocumentActiveState(bool aIsActive)
3250
0
{
3251
0
  AUTO_PROFILER_LABEL("nsPluginInstanceOwner::UpdateDocumentActiveState",
3252
0
                      OTHER);
3253
0
3254
0
  mPluginDocumentActiveState = aIsActive;
3255
0
#ifndef XP_MACOSX
3256
0
  UpdateWindowPositionAndClipRect(true);
3257
0
3258
0
  // We don't have a connection to PluginWidgetParent in the chrome
3259
0
  // process when dealing with tab visibility changes, so this needs
3260
0
  // to be forwarded over after the active state is updated. If we
3261
0
  // don't hide plugin widgets in hidden tabs, the native child window
3262
0
  // in chrome will remain visible after a tab switch.
3263
0
  if (mWidget && XRE_IsContentProcess()) {
3264
0
    mWidget->Show(aIsActive);
3265
0
    mWidget->Enable(aIsActive);
3266
0
  }
3267
0
#endif // #ifndef XP_MACOSX
3268
0
}
3269
3270
NS_IMETHODIMP
3271
nsPluginInstanceOwner::CallSetWindow()
3272
0
{
3273
0
  if (!mWidgetCreationComplete) {
3274
0
    // No widget yet, we can't run this code
3275
0
    return NS_OK;
3276
0
  }
3277
0
  if (mPluginFrame) {
3278
0
    mPluginFrame->CallSetWindow(false);
3279
0
  } else if (mInstance) {
3280
0
    if (UseAsyncRendering()) {
3281
0
      mInstance->AsyncSetWindow(mPluginWindow);
3282
0
    } else {
3283
0
      mInstance->SetWindow(mPluginWindow);
3284
0
    }
3285
0
  }
3286
0
3287
0
  return NS_OK;
3288
0
}
3289
3290
NS_IMETHODIMP
3291
nsPluginInstanceOwner::GetContentsScaleFactor(double *result)
3292
0
{
3293
0
  NS_ENSURE_ARG_POINTER(result);
3294
0
  double scaleFactor = 1.0;
3295
0
  // On Mac, device pixels need to be translated to (and from) "display pixels"
3296
0
  // for plugins. On other platforms, plugin coordinates are always in device
3297
0
  // pixels.
3298
#if defined(XP_MACOSX) || defined(XP_WIN)
3299
  nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
3300
  nsIPresShell* presShell = nsContentUtils::FindPresShellForDocument(content->OwnerDoc());
3301
  if (presShell) {
3302
    scaleFactor = double(AppUnitsPerCSSPixel())/
3303
      presShell->GetPresContext()->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
3304
  }
3305
#endif
3306
  *result = scaleFactor;
3307
0
  return NS_OK;
3308
0
}
3309
3310
void
3311
nsPluginInstanceOwner::GetCSSZoomFactor(float *result)
3312
0
{
3313
0
  nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
3314
0
  nsIPresShell* presShell = nsContentUtils::FindPresShellForDocument(content->OwnerDoc());
3315
0
  if (presShell) {
3316
0
    *result = presShell->GetPresContext()->DeviceContext()->GetFullZoom();
3317
0
  } else {
3318
0
    *result = 1.0;
3319
0
  }
3320
0
}
3321
3322
void nsPluginInstanceOwner::SetFrame(nsPluginFrame *aFrame)
3323
0
{
3324
0
  // Don't do anything if the frame situation hasn't changed.
3325
0
  if (mPluginFrame == aFrame) {
3326
0
    return;
3327
0
  }
3328
0
3329
0
  nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
3330
0
3331
0
  // If we already have a frame that is changing or going away...
3332
0
  if (mPluginFrame) {
3333
0
    if (content && content->OwnerDoc() && content->OwnerDoc()->GetWindow()) {
3334
0
      nsCOMPtr<EventTarget> windowRoot = content->OwnerDoc()->GetWindow()->GetTopWindowRoot();
3335
0
      if (windowRoot) {
3336
0
        windowRoot->RemoveEventListener(NS_LITERAL_STRING("activate"),
3337
0
                                              this, false);
3338
0
        windowRoot->RemoveEventListener(NS_LITERAL_STRING("deactivate"),
3339
0
                                              this, false);
3340
0
        windowRoot->RemoveEventListener(NS_LITERAL_STRING("MozPerformDelayedBlur"),
3341
0
                                              this, false);
3342
0
      }
3343
0
    }
3344
0
3345
0
    // Make sure the old frame isn't holding a reference to us.
3346
0
    mPluginFrame->SetInstanceOwner(nullptr);
3347
0
  }
3348
0
3349
0
  // Swap in the new frame (or no frame)
3350
0
  mPluginFrame = aFrame;
3351
0
3352
0
  // Set up a new frame
3353
0
  if (mPluginFrame) {
3354
0
    mPluginFrame->SetInstanceOwner(this);
3355
0
    // Can only call PrepForDrawing on an object frame once. Don't do it here unless
3356
0
    // widget creation is complete. Doesn't matter if we actually have a widget.
3357
0
    if (mWidgetCreationComplete) {
3358
0
      mPluginFrame->PrepForDrawing(mWidget);
3359
0
    }
3360
0
    mPluginFrame->FixupWindow(mPluginFrame->GetContentRectRelativeToSelf().Size());
3361
0
    mPluginFrame->InvalidateFrame();
3362
0
3363
0
    nsFocusManager* fm = nsFocusManager::GetFocusManager();
3364
0
    const nsIContent* content = aFrame->GetContent();
3365
0
    if (fm && content) {
3366
0
      mContentFocused = (content == fm->GetFocusedElement());
3367
0
    }
3368
0
3369
0
    // Register for widget-focus events on the window root.
3370
0
    if (content && content->OwnerDoc()->GetWindow()) {
3371
0
      nsCOMPtr<EventTarget> windowRoot = content->OwnerDoc()->GetWindow()->GetTopWindowRoot();
3372
0
      if (windowRoot) {
3373
0
        windowRoot->AddEventListener(NS_LITERAL_STRING("activate"),
3374
0
                                           this, false, false);
3375
0
        windowRoot->AddEventListener(NS_LITERAL_STRING("deactivate"),
3376
0
                                           this, false, false);
3377
0
        windowRoot->AddEventListener(NS_LITERAL_STRING("MozPerformDelayedBlur"),
3378
0
                                           this, false, false);
3379
0
      }
3380
0
    }
3381
0
  }
3382
0
}
3383
3384
nsPluginFrame* nsPluginInstanceOwner::GetFrame()
3385
0
{
3386
0
  return mPluginFrame;
3387
0
}
3388
3389
NS_IMETHODIMP nsPluginInstanceOwner::PrivateModeChanged(bool aEnabled)
3390
0
{
3391
0
  return mInstance ? mInstance->PrivateModeStateChanged(aEnabled) : NS_OK;
3392
0
}
3393
3394
already_AddRefed<nsIURI> nsPluginInstanceOwner::GetBaseURI() const
3395
0
{
3396
0
  nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
3397
0
  if (!content) {
3398
0
    return nullptr;
3399
0
  }
3400
0
  return content->GetBaseURI();
3401
0
}
3402
3403
// static
3404
void
3405
nsPluginInstanceOwner::GeneratePluginEvent(
3406
  const WidgetCompositionEvent* aSrcCompositionEvent,
3407
  WidgetCompositionEvent* aDistCompositionEvent)
3408
0
{
3409
#ifdef XP_WIN
3410
  NPEvent newEvent;
3411
  switch (aDistCompositionEvent->mMessage) {
3412
    case eCompositionChange: {
3413
      newEvent.event = WM_IME_COMPOSITION;
3414
      newEvent.wParam = 0;
3415
      if (aSrcCompositionEvent &&
3416
          (aSrcCompositionEvent->mMessage == eCompositionCommit ||
3417
           aSrcCompositionEvent->mMessage == eCompositionCommitAsIs)) {
3418
        newEvent.lParam = GCS_RESULTSTR;
3419
      } else {
3420
        newEvent.lParam = GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE;
3421
      }
3422
      TextRangeArray* ranges = aDistCompositionEvent->mRanges;
3423
      if (ranges && ranges->HasCaret()) {
3424
        newEvent.lParam |= GCS_CURSORPOS;
3425
      }
3426
      break;
3427
    }
3428
3429
    case eCompositionStart:
3430
      newEvent.event = WM_IME_STARTCOMPOSITION;
3431
      newEvent.wParam = 0;
3432
      newEvent.lParam = 0;
3433
      break;
3434
3435
    case eCompositionEnd:
3436
      newEvent.event = WM_IME_ENDCOMPOSITION;
3437
      newEvent.wParam = 0;
3438
      newEvent.lParam = 0;
3439
      break;
3440
3441
    default:
3442
      return;
3443
  }
3444
  aDistCompositionEvent->mPluginEvent.Copy(newEvent);
3445
#endif
3446
}
3447
3448
// nsPluginDOMContextMenuListener class implementation
3449
3450
nsPluginDOMContextMenuListener::nsPluginDOMContextMenuListener(nsIContent* aContent)
3451
0
{
3452
0
  aContent->AddEventListener(NS_LITERAL_STRING("contextmenu"), this, true);
3453
0
}
3454
3455
nsPluginDOMContextMenuListener::~nsPluginDOMContextMenuListener()
3456
0
{
3457
0
}
3458
3459
NS_IMPL_ISUPPORTS(nsPluginDOMContextMenuListener,
3460
                  nsIDOMEventListener)
3461
3462
NS_IMETHODIMP
3463
nsPluginDOMContextMenuListener::HandleEvent(Event* aEvent)
3464
0
{
3465
0
  aEvent->PreventDefault(); // consume event
3466
0
3467
0
  return NS_OK;
3468
0
}
3469
3470
void nsPluginDOMContextMenuListener::Destroy(nsIContent* aContent)
3471
0
{
3472
0
  // Unregister context menu listener
3473
0
  aContent->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this, true);
3474
0
}