bug 794038 pt 3 - plugins support for resolution change. r=bgirard
authorSteven Michaud <smichaud@pobox.com>
Tue, 16 Oct 2012 20:41:21 +0100
changeset 110591 eaccb5bb50c05ecbed2b7b301ca3d44e458cefe3
parent 110590 0cedf8847b2d426862e134e0beb87f209fc99ca7
child 110592 e5386e4e6f541c85b59a57c569102732ee0ce43f
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersbgirard
bugs794038
milestone19.0a1
bug 794038 pt 3 - plugins support for resolution change. r=bgirard
dom/plugins/base/PluginPRLibrary.cpp
dom/plugins/base/PluginPRLibrary.h
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/plugins/base/nsNPAPIPluginInstance.h
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/plugins/base/nsPluginInstanceOwner.h
dom/plugins/ipc/PPluginInstance.ipdl
dom/plugins/ipc/PluginInstanceChild.cpp
dom/plugins/ipc/PluginInstanceChild.h
dom/plugins/ipc/PluginInstanceParent.cpp
dom/plugins/ipc/PluginInstanceParent.h
dom/plugins/ipc/PluginLibrary.h
dom/plugins/ipc/PluginModuleParent.cpp
dom/plugins/ipc/PluginModuleParent.h
dom/plugins/ipc/PluginUtilsOSX.h
dom/plugins/ipc/PluginUtilsOSX.mm
gfx/2d/QuartzSupport.mm
layout/generic/nsObjectFrame.cpp
view/src/nsViewManager.cpp
widget/cocoa/nsChildView.mm
widget/nsGUIEvent.h
--- a/dom/plugins/base/PluginPRLibrary.cpp
+++ b/dom/plugins/base/PluginPRLibrary.cpp
@@ -272,16 +272,23 @@ PluginPRLibrary::GetImageContainer(NPP i
 nsresult
 PluginPRLibrary::IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing)
 {
   nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)instance->ndata;
   NS_ENSURE_TRUE(inst, NS_ERROR_NULL_POINTER);
   *aDrawing = false; 
   return NS_OK;
 }
+nsresult
+PluginPRLibrary::ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor)
+{
+  nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)instance->ndata;
+  NS_ENSURE_TRUE(inst, NS_ERROR_NULL_POINTER);
+  return NS_OK;
+}
 #endif
 
 nsresult
 PluginPRLibrary::GetImageSize(NPP instance, nsIntSize* aSize)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
--- a/dom/plugins/base/PluginPRLibrary.h
+++ b/dom/plugins/base/PluginPRLibrary.h
@@ -109,16 +109,17 @@ public:
     virtual nsresult NPP_GetSitesWithData(InfallibleTArray<nsCString>& result);
 
     virtual nsresult AsyncSetWindow(NPP instance, NPWindow* window);
     virtual nsresult GetImageContainer(NPP instance, ImageContainer** aContainer);
     virtual nsresult GetImageSize(NPP instance, nsIntSize* aSize);
     virtual bool IsOOP() MOZ_OVERRIDE { return false; }
 #if defined(XP_MACOSX)
     virtual nsresult IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing);
+    virtual nsresult ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor);
 #endif
     virtual nsresult SetBackgroundUnknown(NPP instance) MOZ_OVERRIDE;
     virtual nsresult BeginUpdateBackground(NPP instance,
                                            const nsIntRect&, gfxContext** aCtx) MOZ_OVERRIDE;
     virtual nsresult EndUpdateBackground(NPP instance,
                                          gfxContext* aCtx, const nsIntRect&) MOZ_OVERRIDE;
 #if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
     virtual nsresult HandleGUIEvent(NPP instance,
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -1076,16 +1076,36 @@ nsresult nsNPAPIPluginInstance::IsRemote
       return NS_ERROR_FAILURE;
   
   return library->IsRemoteDrawingCoreAnimation(&mNPP, aDrawing);
 #else
   return NS_ERROR_FAILURE;
 #endif
 }
 
+nsresult nsNPAPIPluginInstance::ContentsScaleFactorChanged(double aContentsScaleFactor)
+{
+#ifdef XP_MACOSX
+  if (!mPlugin)
+      return NS_ERROR_FAILURE;
+
+  PluginLibrary* library = mPlugin->GetLibrary();
+  if (!library)
+      return NS_ERROR_FAILURE;
+
+  // We only need to call this if the plugin is running OOP.
+  if (!library->IsOOP())
+      return NS_OK;
+  
+  return library->ContentsScaleFactorChanged(&mNPP, aContentsScaleFactor);
+#else
+  return NS_ERROR_FAILURE;
+#endif
+}
+
 nsresult
 nsNPAPIPluginInstance::GetJSObject(JSContext *cx, JSObject** outObject)
 {
   if (mHaveJavaC2PJSObjectQuirk) {
     return NS_ERROR_FAILURE;
   }
 
   NPObject *npobj = nullptr;
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -73,16 +73,17 @@ public:
   nsresult Stop();
   nsresult SetWindow(NPWindow* window);
   nsresult NewStreamFromPlugin(const char* type, const char* target, nsIOutputStream* *result);
   nsresult Print(NPPrint* platformPrint);
   nsresult HandleEvent(void* event, int16_t* result);
   nsresult GetValueFromPlugin(NPPVariable variable, void* value);
   nsresult GetDrawingModel(int32_t* aModel);
   nsresult IsRemoteDrawingCoreAnimation(bool* aDrawing);
+  nsresult ContentsScaleFactorChanged(double aContentsScaleFactor);
   nsresult GetJSObject(JSContext *cx, JSObject** outObject);
   bool ShouldCache();
   nsresult IsWindowless(bool* isWindowless);
   nsresult AsyncSetWindow(NPWindow* window);
   nsresult GetImageContainer(ImageContainer **aContainer);
   nsresult GetImageSize(nsIntSize* aSize);
   nsresult NotifyPainted(void);
   nsresult GetIsOOP(bool* aIsOOP);
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -1365,16 +1365,24 @@ bool nsPluginInstanceOwner::IsRemoteDraw
 
   bool coreAnimation;
   if (!NS_SUCCEEDED(mInstance->IsRemoteDrawingCoreAnimation(&coreAnimation)))
     return false;
 
   return coreAnimation;
 }
 
+nsresult nsPluginInstanceOwner::ContentsScaleFactorChanged(double aContentsScaleFactor)
+{
+  if (!mInstance) {
+    return NS_ERROR_NULL_POINTER;
+  }
+  return mInstance->ContentsScaleFactorChanged(aContentsScaleFactor);
+}
+
 NPEventModel nsPluginInstanceOwner::GetEventModel()
 {
   return mEventModel;
 }
 
 #define DEFAULT_REFRESH_RATE 20 // 50 FPS
 
 nsCOMPtr<nsITimer>                *nsPluginInstanceOwner::sCATimer = NULL;
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -111,16 +111,17 @@ public:
 
   nsEventStatus ProcessEvent(const nsGUIEvent & anEvent);
   
 #ifdef XP_MACOSX
   enum { ePluginPaintEnable, ePluginPaintDisable };
   
   NPDrawingModel GetDrawingModel();
   bool IsRemoteDrawingCoreAnimation();
+  nsresult ContentsScaleFactorChanged(double aContentsScaleFactor);
   NPEventModel GetEventModel();
   static void CARefresh(nsITimer *aTimer, void *aClosure);
   void AddToCARefreshTimer();
   void RemoveFromCARefreshTimer();
   // This calls into the plugin (NPP_SetWindow) and can run script.
   void* FixUpPluginWindow(int32_t inPaintState);
   void HidePluginWindow();
   // Set a flag that (if true) indicates the plugin port info has changed and
--- a/dom/plugins/ipc/PPluginInstance.ipdl
+++ b/dom/plugins/ipc/PPluginInstance.ipdl
@@ -113,16 +113,19 @@ child:
   // special cases where we need an iosurface
   rpc NPP_HandleEvent_IOSurface(NPRemoteEvent event, uint32_t surfaceid)
     returns (int16_t handled);
   // special cases of HandleEvent to make mediating races simpler
   rpc Paint(NPRemoteEvent event)
     returns (int16_t handled);
   // this is only used on windows to forward WM_WINDOWPOSCHANGE
   async WindowPosChanged(NPRemoteEvent event);
+  // used on OS X to tell the child the contents scale factor
+  // of its parent has changed
+  async ContentsScaleFactorChanged(double aContentsScaleFactor);
 
   // ********************** Async plugins rendering
   // see https://wiki.mozilla.org/Gecko:AsyncPluginPainting
   // **********************
 
   // Async version of SetWindow call
   // @param surfaceType - gfxASurface::gfxSurfaceType
   //        plugin child must create offscreen buffer
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -1008,16 +1008,34 @@ PluginInstanceChild::RecvWindowPosChange
     int16_t dontcare;
     return AnswerNPP_HandleEvent(event, &dontcare);
 #else
     NS_RUNTIMEABORT("WindowPosChanged is a windows-only message");
     return false;
 #endif
 }
 
+bool
+PluginInstanceChild::RecvContentsScaleFactorChanged(const double& aContentsScaleFactor)
+{
+#ifdef XP_MACOSX
+    mContentsScaleFactor = aContentsScaleFactor;
+    if (mShContext) {
+        // Release the shared context so that it is reallocated
+        // with the new size. 
+        ::CGContextRelease(mShContext);
+        mShContext = nullptr;
+    }
+    return true;
+#else
+    NS_RUNTIMEABORT("ContentsScaleFactorChanged is an OSX-only message");
+    return false;
+#endif
+}
+
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
 // Create a new window from NPWindow
 bool PluginInstanceChild::CreateWindow(const NPRemoteWindow& aWindow)
 { 
     PLUGIN_LOG_DEBUG(("%s (aWindow=<window: 0x%lx, x: %d, y: %d, width: %d, height: %d>)",
                       FULLFUNCTION,
                       aWindow.window,
                       aWindow.x, aWindow.y,
@@ -3952,17 +3970,19 @@ PluginInstanceChild::SwapSurfaces()
 
     // Outdated back surface... not usable anymore due to changed plugin size.
     // Dropping obsolete surface
     if (mDoubleBufferCARenderer.HasFrontSurface() && 
         mDoubleBufferCARenderer.HasBackSurface() &&
         (mDoubleBufferCARenderer.GetFrontSurfaceWidth() != 
             mDoubleBufferCARenderer.GetBackSurfaceWidth() ||
         mDoubleBufferCARenderer.GetFrontSurfaceHeight() != 
-            mDoubleBufferCARenderer.GetBackSurfaceHeight())) {
+            mDoubleBufferCARenderer.GetBackSurfaceHeight() ||
+        mDoubleBufferCARenderer.GetFrontSurfaceContentsScaleFactor() != 
+            mDoubleBufferCARenderer.GetBackSurfaceContentsScaleFactor())) {
 
         mDoubleBufferCARenderer.ClearFrontSurface();
     }
 #else
     if (mCurrentSurface && mBackSurface &&
         (mCurrentSurface->GetSize() != mBackSurface->GetSize() ||
          mCurrentSurface->GetContentType() != mBackSurface->GetContentType())) {
         ClearCurrentSurface();
--- a/dom/plugins/ipc/PluginInstanceChild.h
+++ b/dom/plugins/ipc/PluginInstanceChild.h
@@ -122,16 +122,19 @@ protected:
         PaintTracker pt;
         return AnswerNPP_HandleEvent(event, handled);
     }
 
     virtual bool
     RecvWindowPosChanged(const NPRemoteEvent& event) MOZ_OVERRIDE;
 
     virtual bool
+    RecvContentsScaleFactorChanged(const double& aContentsScaleFactor) MOZ_OVERRIDE;
+
+    virtual bool
     AnswerNPP_Destroy(NPError* result);
 
     virtual PPluginScriptableObjectChild*
     AllocPPluginScriptableObject();
 
     virtual bool
     DeallocPPluginScriptableObject(PPluginScriptableObjectChild* aObject);
 
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -794,17 +794,24 @@ PluginInstanceParent::GetImageSize(nsInt
 #ifdef XP_MACOSX
 nsresult
 PluginInstanceParent::IsRemoteDrawingCoreAnimation(bool *aDrawing)
 {
     *aDrawing = (NPDrawingModelCoreAnimation == (NPDrawingModel)mDrawingModel ||
                  NPDrawingModelInvalidatingCoreAnimation == (NPDrawingModel)mDrawingModel);
     return NS_OK;
 }
-#endif
+
+nsresult
+PluginInstanceParent::ContentsScaleFactorChanged(double aContentsScaleFactor)
+{
+    bool rv = SendContentsScaleFactorChanged(aContentsScaleFactor);
+    return rv ? NS_OK : NS_ERROR_FAILURE;
+}
+#endif // #ifdef XP_MACOSX
 
 nsresult
 PluginInstanceParent::SetBackgroundUnknown()
 {
     PLUGIN_LOG_DEBUG(("[InstanceParent][%p] SetBackgroundUnknown", this));
 
     if (mBackground) {
         DestroyBackground();
--- a/dom/plugins/ipc/PluginInstanceParent.h
+++ b/dom/plugins/ipc/PluginInstanceParent.h
@@ -266,16 +266,17 @@ public:
     virtual bool
     AnswerPluginFocusChange(const bool& gotFocus);
 
     nsresult AsyncSetWindow(NPWindow* window);
     nsresult GetImageContainer(mozilla::layers::ImageContainer** aContainer);
     nsresult GetImageSize(nsIntSize* aSize);
 #ifdef XP_MACOSX
     nsresult IsRemoteDrawingCoreAnimation(bool *aDrawing);
+    nsresult ContentsScaleFactorChanged(double aContentsScaleFactor);
 #endif
     nsresult SetBackgroundUnknown();
     nsresult BeginUpdateBackground(const nsIntRect& aRect,
                                    gfxContext** aCtx);
     nsresult EndUpdateBackground(gfxContext* aCtx,
                                  const nsIntRect& aRect);
 #if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
     nsresult HandleGUIEvent(const nsGUIEvent& anEvent, bool* handled);
--- a/dom/plugins/ipc/PluginLibrary.h
+++ b/dom/plugins/ipc/PluginLibrary.h
@@ -68,16 +68,17 @@ public:
   virtual nsresult NPP_GetSitesWithData(InfallibleTArray<nsCString>& aResult) = 0;
 
   virtual nsresult AsyncSetWindow(NPP instance, NPWindow* window) = 0;
   virtual nsresult GetImageContainer(NPP instance, ImageContainer** aContainer) = 0;
   virtual nsresult GetImageSize(NPP instance, nsIntSize* aSize) = 0;
   virtual bool IsOOP() = 0;
 #if defined(XP_MACOSX)
   virtual nsresult IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing) = 0;
+  virtual nsresult ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor) = 0;
 #endif
 
   /**
    * The next three methods are the third leg in the trip to
    * PluginInstanceParent.  They approximately follow the ReadbackSink
    * API.
    */
   virtual nsresult SetBackgroundUnknown(NPP instance) = 0;
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -1180,17 +1180,27 @@ nsresult
 PluginModuleParent::IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing)
 {
     PluginInstanceParent* i = InstCast(instance);
     if (!i)
         return NS_ERROR_FAILURE;
 
     return i->IsRemoteDrawingCoreAnimation(aDrawing);
 }
-#endif
+
+nsresult
+PluginModuleParent::ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor)
+{
+    PluginInstanceParent* i = InstCast(instance);
+    if (!i)
+        return NS_ERROR_FAILURE;
+
+    return i->ContentsScaleFactorChanged(aContentsScaleFactor);
+}
+#endif // #if defined(XP_MACOSX)
 
 bool
 PluginModuleParent::AnswerNPN_GetValue_WithBoolReturn(const NPNVariable& aVariable,
                                                       NPError* aError,
                                                       bool* aBoolVal)
 {
     NPBool boolVal = false;
     *aError = mozilla::plugins::parent::_getvalue(nullptr, aVariable, &boolVal);
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -266,16 +266,17 @@ private:
                              char* argv[], NPSavedData* saved,
                              NPError* error);
     virtual nsresult NPP_ClearSiteData(const char* site, uint64_t flags,
                                        uint64_t maxAge);
     virtual nsresult NPP_GetSitesWithData(InfallibleTArray<nsCString>& result);
 
 #if defined(XP_MACOSX)
     virtual nsresult IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing);
+    virtual nsresult ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor);
 #endif
 #if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
     virtual nsresult HandleGUIEvent(NPP instance, const nsGUIEvent& anEvent,
                                     bool* handled);
 #endif
 
 private:
     CrashReporterParent* CrashReporter();
--- a/dom/plugins/ipc/PluginUtilsOSX.h
+++ b/dom/plugins/ipc/PluginUtilsOSX.h
@@ -45,22 +45,24 @@ public:
   // Returns width in "display pixels".  A "display pixel" is the smallest
   // fully addressable part of a display.  But in HiDPI modes each "display
   // pixel" corresponds to more than one device pixel.  Multiply display pixels
   // by mContentsScaleFactor to get device pixels.
   size_t GetFrontSurfaceWidth();
   // Returns height in "display pixels".  Multiply by
   // mContentsScaleFactor to get device pixels.
   size_t GetFrontSurfaceHeight();
+  double GetFrontSurfaceContentsScaleFactor();
   // Returns width in "display pixels".  Multiply by
   // mContentsScaleFactor to get device pixels.
   size_t GetBackSurfaceWidth();
   // Returns height in "display pixels".  Multiply by
   // mContentsScaleFactor to get device pixels.
   size_t GetBackSurfaceHeight();
+  double GetBackSurfaceContentsScaleFactor();
   IOSurfaceID GetFrontSurfaceID();
 
   bool HasBackSurface();
   bool HasFrontSurface();
   bool HasCALayer();
 
   void SetCALayer(void *aCALayer);
   // aWidth and aHeight are in "display pixels".  Multiply by
--- a/dom/plugins/ipc/PluginUtilsOSX.mm
+++ b/dom/plugins/ipc/PluginUtilsOSX.mm
@@ -264,32 +264,48 @@ size_t nsDoubleBufferCARenderer::GetFron
 size_t nsDoubleBufferCARenderer::GetFrontSurfaceHeight() {
   if (!HasFrontSurface()) {
     return 0;
   }
 
   return mFrontSurface->GetHeight();
 }
 
+double nsDoubleBufferCARenderer::GetFrontSurfaceContentsScaleFactor() {
+  if (!HasFrontSurface()) {
+    return 1.0;
+  }
+
+  return mFrontSurface->GetContentsScaleFactor();
+}
+
 size_t nsDoubleBufferCARenderer::GetBackSurfaceWidth() {
   if (!HasBackSurface()) {
     return 0;
   }
 
   return mBackSurface->GetWidth();
 }
 
 size_t nsDoubleBufferCARenderer::GetBackSurfaceHeight() {
   if (!HasBackSurface()) {
     return 0;
   }
 
   return mBackSurface->GetHeight();
 }
 
+double nsDoubleBufferCARenderer::GetBackSurfaceContentsScaleFactor() {
+  if (!HasBackSurface()) {
+    return 1.0;
+  }
+
+  return mBackSurface->GetContentsScaleFactor();
+}
+
 IOSurfaceID nsDoubleBufferCARenderer::GetFrontSurfaceID() {
   if (!HasFrontSurface()) {
     return 0;
   }
 
   return mFrontSurface->GetIOSurfaceID();
 }
 
--- a/gfx/2d/QuartzSupport.mm
+++ b/gfx/2d/QuartzSupport.mm
@@ -738,16 +738,31 @@ void nsCARenderer::SetBounds(int aWidth,
     MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
       Class CGBridgeLayerClass = ::NSClassFromString(@"CGBridgeLayer");
       if (!CGBridgeLayerClass || ![layer isKindOfClass:CGBridgeLayerClass])
 #endif
       {
         layer.contentsScale = mContentsScaleFactor;
       }
     }
+  } else {
+    // These settings are the default values.  But they might have been
+    // changed as above if we were previously running in a HiDPI mode
+    // (i.e. if we just switched from that to a non-HiDPI mode).
+    [layer setAffineTransform:CGAffineTransformIdentity];
+    if ([layer respondsToSelector:@selector(setContentsScale:)]) {
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+      Class CGBridgeLayerClass = ::NSClassFromString(@"CGBridgeLayer");
+      if (!CGBridgeLayerClass || ![layer isKindOfClass:CGBridgeLayerClass])
+#endif
+      {
+        layer.contentsScale = 1.0;
+      }
+    }
   }
   [CATransaction commit];
 
 }
 
 void nsCARenderer::SetViewport(int aWidth, int aHeight) {
   size_t intScaleFactor = ceil(mContentsScaleFactor);
   aWidth *= intScaleFactor;
@@ -833,21 +848,29 @@ nsresult nsCARenderer::Render(int aWidth
     return NS_ERROR_FAILURE;
   }
 
   CARenderer* caRenderer = (CARenderer*)mCARenderer;
   size_t intScaleFactor = ceil(aContentsScaleFactor);
   int renderer_width = caRenderer.bounds.size.width / intScaleFactor;
   int renderer_height = caRenderer.bounds.size.height / intScaleFactor;
 
-  if (renderer_width != aWidth || renderer_height != aHeight) {
+  if (renderer_width != aWidth || renderer_height != aHeight ||
+      mContentsScaleFactor != aContentsScaleFactor) {
     // XXX: This should be optimized to not rescale the buffer
     //      if we are resizing down.
+    // caLayer is the CALayer* provided by the plugin, so we need to preserve
+    // it across the call to Destroy().
     CALayer* caLayer = [caRenderer layer];
+    // mIOSurface is set by AttachIOSurface(), not by SetupRenderer().  So
+    // since it may have been set by a prior call to AttachIOSurface(), we
+    // need to preserve it across the call to Destroy().
+    mozilla::RefPtr<MacIOSurface> ioSurface = mIOSurface;
     Destroy();
+    mIOSurface = ioSurface;
     if (SetupRenderer(caLayer, aWidth, aHeight, aContentsScaleFactor,
                       mAllowOfflineRenderer) != NS_OK) {
       return NS_ERROR_FAILURE;
     }
 
     caRenderer = (CARenderer*)mCARenderer;
   }
 
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -2067,16 +2067,25 @@ nsObjectFrame::HandleEvent(nsPresContext
       return fm->SetFocus(elem, 0);
   }
   else if (anEvent->message == NS_PLUGIN_FOCUS) {
     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
     if (fm)
       return fm->FocusPlugin(GetContent());
   }
 
+#ifdef XP_MACOSX
+  if (anEvent->message == NS_PLUGIN_RESOLUTION_CHANGED) {
+    double scaleFactor = 1.0;
+    mInstanceOwner->GetContentsScaleFactor(&scaleFactor);
+    mInstanceOwner->ContentsScaleFactorChanged(scaleFactor);
+    return NS_OK;
+  }
+#endif
+
   if (mInstanceOwner->SendNativeEvents() &&
       NS_IS_PLUGIN_EVENT(anEvent)) {
     *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
     return rv;
   }
 
 #ifdef XP_WIN
   rv = nsObjectFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus);
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -746,17 +746,18 @@ nsresult nsViewManager::DispatchEvent(ns
 
   // If the view has no frame, look for a view that does.
   nsIFrame* frame = view->GetFrame();
   if (!frame &&
       (dispatchUsingCoordinates || NS_IS_KEY_EVENT(aEvent) ||
        NS_IS_IME_RELATED_EVENT(aEvent) ||
        NS_IS_NON_RETARGETED_PLUGIN_EVENT(aEvent) ||
        aEvent->message == NS_PLUGIN_ACTIVATE ||
-       aEvent->message == NS_PLUGIN_FOCUS)) {
+       aEvent->message == NS_PLUGIN_FOCUS ||
+       aEvent->message == NS_PLUGIN_RESOLUTION_CHANGED)) {
     while (view && !view->GetFrame()) {
       view = view->GetParent();
     }
 
     if (view) {
       frame = view->GetFrame();
     }
   }
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -773,23 +773,28 @@ nsChildView::BackingScaleFactorChanged()
   // ignore notification if it hasn't really changed (or maybe we have
   // disabled HiDPI mode via prefs)
   if (mBackingScaleFactor == newScale) {
     return;
   }
 
   mBackingScaleFactor = newScale;
 
-  if (!mWidgetListener || mWidgetListener->GetXULWindow()) {
-    return;
+  if (mWidgetListener && !mWidgetListener->GetXULWindow()) {
+    nsIPresShell* presShell = mWidgetListener->GetPresShell();
+    if (presShell) {
+      presShell->BackingScaleFactorChanged();
+    }
   }
 
-  nsIPresShell* presShell = mWidgetListener->GetPresShell();
-  if (presShell) {
-    presShell->BackingScaleFactorChanged();
+  if (IsPluginView()) {
+    nsEventStatus status = nsEventStatus_eIgnore;
+    nsGUIEvent guiEvent(true, NS_PLUGIN_RESOLUTION_CHANGED, this);
+    guiEvent.time = PR_IntervalNow();
+    DispatchEvent(&guiEvent, status);
   }
 }
 
 NS_IMETHODIMP nsChildView::ConstrainPosition(bool aAllowSlop,
                                              int32_t *aX, int32_t *aY)
 {
   return NS_OK;
 }
--- a/widget/nsGUIEvent.h
+++ b/widget/nsGUIEvent.h
@@ -168,16 +168,21 @@ class nsHashKey;
 
 // Indicates a resize will occur
 #define NS_BEFORERESIZE_EVENT            (NS_WINDOW_START + 66)
 
 // Indicates that the user is either idle or active
 #define NS_MOZ_USER_IDLE                 (NS_WINDOW_START + 67)
 #define NS_MOZ_USER_ACTIVE               (NS_WINDOW_START + 68)
 
+// The resolution at which a plugin should draw has changed, for
+// example as the result of changing from a HiDPI mode to a non-
+// HiDPI mode.
+#define NS_PLUGIN_RESOLUTION_CHANGED     (NS_WINDOW_START + 69)
+
 #define NS_MOUSE_MESSAGE_START          300
 #define NS_MOUSE_MOVE                   (NS_MOUSE_MESSAGE_START)
 #define NS_MOUSE_BUTTON_UP              (NS_MOUSE_MESSAGE_START + 1)
 #define NS_MOUSE_BUTTON_DOWN            (NS_MOUSE_MESSAGE_START + 2)
 #define NS_MOUSE_ENTER                  (NS_MOUSE_MESSAGE_START + 22)
 #define NS_MOUSE_EXIT                   (NS_MOUSE_MESSAGE_START + 23)
 #define NS_MOUSE_DOUBLECLICK            (NS_MOUSE_MESSAGE_START + 24)
 #define NS_MOUSE_CLICK                  (NS_MOUSE_MESSAGE_START + 27)
@@ -1773,17 +1778,18 @@ enum {
  * position or not.  When it should be handled there (e.g., the mouse events),
  * this returns TRUE.
  */
 inline bool NS_IsEventUsingCoordinates(nsEvent* aEvent)
 {
   return !NS_IS_KEY_EVENT(aEvent) && !NS_IS_IME_RELATED_EVENT(aEvent) &&
          !NS_IS_CONTEXT_MENU_KEY(aEvent) && !NS_IS_ACTIVATION_EVENT(aEvent) &&
          !NS_IS_PLUGIN_EVENT(aEvent) &&
-         !NS_IS_CONTENT_COMMAND_EVENT(aEvent);
+         !NS_IS_CONTENT_COMMAND_EVENT(aEvent) &&
+         aEvent->message != NS_PLUGIN_RESOLUTION_CHANGED;
 }
 
 /**
  * Whether the event should be handled by the focused DOM window in the
  * same top level window's or not.  E.g., key events, IME related events
  * (including the query content events, they are used in IME transaction)
  * should be handled by the (last) focused window rather than the dispatched
  * window.