Title: [147579] trunk/Source
Revision
147579
Author
[email protected]
Date
2013-04-03 13:13:20 -0700 (Wed, 03 Apr 2013)

Log Message

Cross fade into restarted plugin
https://bugs.webkit.org/show_bug.cgi?id=113868

Reviewed by Tim Horton.

Source/WebCore:

Allow a restarted plugin to fade in over its snapshot, avoiding the abrupt
flash of empty content. The WebCore part of this patch marks the plugin
element as restarted, and draws the snapshot for a short amount of time
as the plugin is restarting. After the plugin has reappeared, we stop drawing
the snapshot.

There is a little bit of drive-by whitespace removal in HTMLPlugInImageElement.

* html/HTMLPlugInElement.h:
(WebCore::HTMLPlugInElement::restartedPlugin): New method indicating if the plugin has been restarted.
* html/HTMLPlugInImageElement.cpp:
(WebCore::HTMLPlugInImageElement::HTMLPlugInImageElement): Initialise new timer and member variable.
(WebCore::HTMLPlugInImageElement::setDisplayState): If we are moving into a restarting state, make sure
    to remember this and also start a timer so that we show the snapshot for while.
(WebCore::HTMLPlugInImageElement::removeSnapshotTimerFired): No need to draw the snapshot from here on.
* html/HTMLPlugInImageElement.h:
(HTMLPlugInImageElement): Member variable to remember if we've restarted.
* rendering/RenderEmbeddedObject.cpp:
(WebCore::RenderEmbeddedObject::paintContents): Only exit early from the paint if we're not a restarting
    plugin, otherwise we do want to draw the snapshot if there is one.
* rendering/RenderLayerBacking.cpp:
(WebCore::isRestartedPlugin): Detects a restarted plugin.
(WebCore::RenderLayerBacking::isSimpleContainerCompositingLayer): Don't become a simple container
    compositing layer if you're a restarted plugin.

Source/WebKit2:

Add a new plugin process type that indicates this is a plugin that
has been restarted from snapshotting. On Apple ports, this allows
us to animate the appearance of the plugin so that it crossfades
with the snapshot. Other ports will have to add their own fading.

* PluginProcess/PluginProcess.h: New Type: TypeRestartedProcess.
* WebProcess/Plugins/Netscape/mac/PluginProxyMac.mm:
(WebKit::PluginProxy::pluginLayer): When the plugin's CALayer is created, if it
    is a restarted plugin, add an opacity animation to fade it in.
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::createPlugin): Mark restarted plugins with the new process type.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (147578 => 147579)


--- trunk/Source/WebCore/ChangeLog	2013-04-03 20:05:43 UTC (rev 147578)
+++ trunk/Source/WebCore/ChangeLog	2013-04-03 20:13:20 UTC (rev 147579)
@@ -1,3 +1,35 @@
+2013-04-03  Dean Jackson  <[email protected]>
+
+        Cross fade into restarted plugin
+        https://bugs.webkit.org/show_bug.cgi?id=113868
+
+        Reviewed by Tim Horton.
+
+        Allow a restarted plugin to fade in over its snapshot, avoiding the abrupt
+        flash of empty content. The WebCore part of this patch marks the plugin
+        element as restarted, and draws the snapshot for a short amount of time
+        as the plugin is restarting. After the plugin has reappeared, we stop drawing
+        the snapshot.
+
+        There is a little bit of drive-by whitespace removal in HTMLPlugInImageElement.
+
+        * html/HTMLPlugInElement.h:
+        (WebCore::HTMLPlugInElement::restartedPlugin): New method indicating if the plugin has been restarted.
+        * html/HTMLPlugInImageElement.cpp:
+        (WebCore::HTMLPlugInImageElement::HTMLPlugInImageElement): Initialise new timer and member variable.
+        (WebCore::HTMLPlugInImageElement::setDisplayState): If we are moving into a restarting state, make sure
+            to remember this and also start a timer so that we show the snapshot for while.
+        (WebCore::HTMLPlugInImageElement::removeSnapshotTimerFired): No need to draw the snapshot from here on.
+        * html/HTMLPlugInImageElement.h:
+        (HTMLPlugInImageElement): Member variable to remember if we've restarted.
+        * rendering/RenderEmbeddedObject.cpp:
+        (WebCore::RenderEmbeddedObject::paintContents): Only exit early from the paint if we're not a restarting
+            plugin, otherwise we do want to draw the snapshot if there is one.
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::isRestartedPlugin): Detects a restarted plugin.
+        (WebCore::RenderLayerBacking::isSimpleContainerCompositingLayer): Don't become a simple container
+            compositing layer if you're a restarted plugin.
+
 2013-04-03  John Griggs  <[email protected]>
 
         [BlackBerry] Adjustments to media controls appearance.

Modified: trunk/Source/WebCore/html/HTMLPlugInElement.h (147578 => 147579)


--- trunk/Source/WebCore/html/HTMLPlugInElement.h	2013-04-03 20:05:43 UTC (rev 147578)
+++ trunk/Source/WebCore/html/HTMLPlugInElement.h	2013-04-03 20:13:20 UTC (rev 147579)
@@ -59,6 +59,7 @@
     virtual void setDisplayState(DisplayState state) { m_displayState = state; }
     virtual void updateSnapshot(PassRefPtr<Image>) { }
     virtual void dispatchPendingMouseClick() { }
+    virtual bool restartedPlugin() const { return false; }
 
 #if ENABLE(NETSCAPE_PLUGIN_API)
     NPObject* getNPObject();

Modified: trunk/Source/WebCore/html/HTMLPlugInImageElement.cpp (147578 => 147579)


--- trunk/Source/WebCore/html/HTMLPlugInImageElement.cpp	2013-04-03 20:05:43 UTC (rev 147578)
+++ trunk/Source/WebCore/html/HTMLPlugInImageElement.cpp	2013-04-03 20:13:20 UTC (rev 147579)
@@ -65,6 +65,7 @@
 
 // This delay should not exceed the snapshot delay in PluginView.cpp
 static const double simulatedMouseClickTimerDelay = .75;
+static const double removeSnapshotTimerDelay = 1.5;
 
 HTMLPlugInImageElement::HTMLPlugInImageElement(const QualifiedName& tagName, Document* document, bool createdByParser, PreferPlugInsForImagesOption preferPlugInsForImagesOption)
     : HTMLPlugInElement(tagName, document)
@@ -77,7 +78,9 @@
     , m_needsDocumentActivationCallbacks(false)
     , m_simulatedMouseClickTimer(this, &HTMLPlugInImageElement::simulatedMouseClickTimerFired, simulatedMouseClickTimerDelay)
     , m_swapRendererTimer(this, &HTMLPlugInImageElement::swapRendererTimerFired)
+    , m_removeSnapshotTimer(this, &HTMLPlugInImageElement::removeSnapshotTimerFired)
     , m_createdDuringUserGesture(ScriptController::processingUserGesture())
+    , m_restartedPlugin(false)
 {
     setHasCustomStyleCallbacks();
 }
@@ -93,6 +96,13 @@
     HTMLPlugInElement::setDisplayState(state);
     if (displayState() == DisplayingSnapshot)
         m_swapRendererTimer.startOneShot(0);
+
+#if PLATFORM(MAC)
+    if (displayState() == RestartingWithPendingMouseClick || displayState() == Restarting) {
+        m_restartedPlugin = true;
+        m_removeSnapshotTimer.startOneShot(removeSnapshotTimerDelay);
+    }
+#endif
 }
 
 RenderEmbeddedObject* HTMLPlugInImageElement::renderEmbeddedObject() const
@@ -118,7 +128,7 @@
 }
 
 // We don't use m_url, as it may not be the final URL that the object loads,
-// depending on <param> values. 
+// depending on <param> values.
 bool HTMLPlugInImageElement::allowedToLoadFrameURL(const String& url)
 {
     KURL completeURL = document()->completeURL(url);
@@ -131,7 +141,7 @@
 }
 
 // We don't use m_url, or m_serviceType as they may not be the final values
-// that <object> uses depending on <param> values. 
+// that <object> uses depending on <param> values.
 bool HTMLPlugInImageElement::wouldLoadAsNetscapePlugin(const String& url, const String& serviceType)
 {
     ASSERT(document());
@@ -190,7 +200,7 @@
     PostAttachCallbackDisabler disabler(this);
 
     bool isImage = isImageType();
-    
+
     if (!isImage)
         queuePostAttachCallback(&HTMLPlugInImageElement::updateWidgetCallback, this);
 
@@ -232,10 +242,10 @@
     HTMLPlugInElement::finishParsingChildren();
     if (useFallbackContent())
         return;
-    
+
     setNeedsWidgetUpdate(true);
     if (inDocument())
-        setNeedsStyleRecalc();    
+        setNeedsStyleRecalc();
 }
 
 void HTMLPlugInImageElement::didMoveToNewDocument(Document* oldDocument)
@@ -268,7 +278,7 @@
         m_customStyleForPageCache = 0;
         recalcStyle(Force);
     }
-    
+
     HTMLPlugInElement::documentDidResumeFromPageCache();
 }
 
@@ -396,6 +406,13 @@
     ensureUserAgentShadowRoot();
 }
 
+void HTMLPlugInImageElement::removeSnapshotTimerFired(Timer<HTMLPlugInImageElement>*)
+{
+    m_snapshotImage = nullptr;
+    m_restartedPlugin = false;
+    renderer()->repaint();
+}
+
 static void addPlugInsFromNodeListMatchingPlugInOrigin(HTMLPlugInImageElementList& plugInList, PassRefPtr<NodeList> collection, const String& plugInOrigin, const String& mimeType)
 {
     for (unsigned i = 0, length = collection->length(); i < length; i++) {

Modified: trunk/Source/WebCore/html/HTMLPlugInImageElement.h (147578 => 147579)


--- trunk/Source/WebCore/html/HTMLPlugInImageElement.h	2013-04-03 20:05:43 UTC (rev 147578)
+++ trunk/Source/WebCore/html/HTMLPlugInImageElement.h	2013-04-03 20:13:20 UTC (rev 147579)
@@ -81,7 +81,7 @@
     // Plug-in URL might not be the same as url() with overriding parameters.
     void subframeLoaderWillCreatePlugIn(const KURL& plugInURL);
     void subframeLoaderDidCreatePlugIn(const Widget*);
-    
+
     void setIsPrimarySnapshottedPlugIn(bool);
 
 protected:
@@ -93,7 +93,7 @@
     String m_serviceType;
     String m_url;
     KURL m_loadedUrl;
-    
+
     static void updateWidgetCallback(Node*, unsigned = 0);
     virtual void attach();
     virtual void detach();
@@ -102,13 +102,14 @@
     bool wouldLoadAsNetscapePlugin(const String& url, const String& serviceType);
 
     virtual void didMoveToNewDocument(Document* oldDocument) OVERRIDE;
-    
+
     virtual void documentWillSuspendForPageCache() OVERRIDE;
     virtual void documentDidResumeFromPageCache() OVERRIDE;
 
     virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE;
 
     void restartSnapshottedPlugIn();
+    virtual bool restartedPlugin() const OVERRIDE { return m_restartedPlugin; }
 
 private:
     virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
@@ -131,6 +132,8 @@
 
     virtual bool isPlugInImageElement() const OVERRIDE { return true; }
 
+    void removeSnapshotTimerFired(Timer<HTMLPlugInImageElement>*);
+
     bool m_needsWidgetUpdate;
     bool m_shouldPreferPlugInsForImages;
     bool m_needsDocumentActivationCallbacks;
@@ -138,8 +141,10 @@
     RefPtr<MouseEvent> m_pendingClickEventFromSnapshot;
     DeferrableOneShotTimer<HTMLPlugInImageElement> m_simulatedMouseClickTimer;
     Timer<HTMLPlugInImageElement> m_swapRendererTimer;
+    Timer<HTMLPlugInImageElement> m_removeSnapshotTimer;
     RefPtr<Image> m_snapshotImage;
     bool m_createdDuringUserGesture;
+    bool m_restartedPlugin;
 };
 
 inline HTMLPlugInImageElement* toHTMLPlugInImageElement(Node* node)

Modified: trunk/Source/WebCore/rendering/RenderEmbeddedObject.cpp (147578 => 147579)


--- trunk/Source/WebCore/rendering/RenderEmbeddedObject.cpp	2013-04-03 20:05:43 UTC (rev 147578)
+++ trunk/Source/WebCore/rendering/RenderEmbeddedObject.cpp	2013-04-03 20:13:20 UTC (rev 147579)
@@ -177,9 +177,11 @@
         return;
 
     HTMLPlugInElement* plugInElement = toHTMLPlugInElement(element);
+
     if (plugInElement->displayState() > HTMLPlugInElement::DisplayingSnapshot) {
         RenderPart::paintContents(paintInfo, paintOffset);
-        return;
+        if (!plugInElement->restartedPlugin())
+            return;
     }
 
     if (!plugInElement->isPlugInImageElement())

Modified: trunk/Source/WebCore/rendering/RenderLayerBacking.cpp (147578 => 147579)


--- trunk/Source/WebCore/rendering/RenderLayerBacking.cpp	2013-04-03 20:05:43 UTC (rev 147578)
+++ trunk/Source/WebCore/rendering/RenderLayerBacking.cpp	2013-04-03 20:13:20 UTC (rev 147579)
@@ -42,6 +42,7 @@
 #include "HTMLIFrameElement.h"
 #include "HTMLMediaElement.h"
 #include "HTMLNames.h"
+#include "HTMLPlugInElement.h"
 #include "InspectorInstrumentation.h"
 #include "KeyframeList.h"
 #include "PluginViewBase.h"
@@ -1449,6 +1450,18 @@
     return false;
 }
 
+static bool isRestartedPlugin(RenderObject* renderer)
+{
+    if (!renderer->isEmbeddedObject())
+        return false;
+
+    Element* element = toElement(renderer->node());
+    if (!element || !element->isPluginElement())
+        return false;
+
+    return toHTMLPlugInElement(element)->restartedPlugin();
+}
+
 static bool isCompositedPlugin(RenderObject* renderer)
 {
     return renderer->isEmbeddedObject() && toRenderEmbeddedObject(renderer)->allowsAcceleratedCompositing();
@@ -1463,9 +1476,9 @@
     if (renderObject->hasMask()) // masks require special treatment
         return false;
 
-    if (renderObject->isReplaced() && !isCompositedPlugin(renderObject))
+    if (renderObject->isReplaced() && (!isCompositedPlugin(renderObject) || isRestartedPlugin(renderObject)))
         return false;
-    
+
     if (paintsBoxDecorations() || paintsChildren())
         return false;
 

Modified: trunk/Source/WebKit2/ChangeLog (147578 => 147579)


--- trunk/Source/WebKit2/ChangeLog	2013-04-03 20:05:43 UTC (rev 147578)
+++ trunk/Source/WebKit2/ChangeLog	2013-04-03 20:13:20 UTC (rev 147579)
@@ -1,3 +1,22 @@
+2013-04-03  Dean Jackson  <[email protected]>
+
+        Cross fade into restarted plugin
+        https://bugs.webkit.org/show_bug.cgi?id=113868
+
+        Reviewed by Tim Horton.
+
+        Add a new plugin process type that indicates this is a plugin that
+        has been restarted from snapshotting. On Apple ports, this allows
+        us to animate the appearance of the plugin so that it crossfades
+        with the snapshot. Other ports will have to add their own fading.
+
+        * PluginProcess/PluginProcess.h: New Type: TypeRestartedProcess.
+        * WebProcess/Plugins/Netscape/mac/PluginProxyMac.mm:
+        (WebKit::PluginProxy::pluginLayer): When the plugin's CALayer is created, if it
+            is a restarted plugin, add an opacity animation to fade it in.
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::createPlugin): Mark restarted plugins with the new process type.
+
 2013-04-03  Alexey Proskuryakov  <[email protected]>
 
         <rdar://problem/13564588> Add a temporary workaround for a build failure.

Modified: trunk/Source/WebKit2/PluginProcess/PluginProcess.h (147578 => 147579)


--- trunk/Source/WebKit2/PluginProcess/PluginProcess.h	2013-04-03 20:05:43 UTC (rev 147578)
+++ trunk/Source/WebKit2/PluginProcess/PluginProcess.h	2013-04-03 20:13:20 UTC (rev 147579)
@@ -44,7 +44,8 @@
     enum Type {
         // Start with value one since default HashTraits<> disallows zero as key.
         TypeRegularProcess = 1,
-        TypeSnapshotProcess
+        TypeSnapshotProcess,
+        TypeRestartedProcess
     };
 
     static PluginProcess& shared();

Modified: trunk/Source/WebKit2/WebProcess/Plugins/Netscape/mac/PluginProxyMac.mm (147578 => 147579)


--- trunk/Source/WebKit2/WebProcess/Plugins/Netscape/mac/PluginProxyMac.mm	2013-04-03 20:05:43 UTC (rev 147578)
+++ trunk/Source/WebKit2/WebProcess/Plugins/Netscape/mac/PluginProxyMac.mm	2013-04-03 20:13:20 UTC (rev 147579)
@@ -31,8 +31,11 @@
 #import "PluginController.h"
 #import "PluginControllerProxyMessages.h"
 #import "PluginProcessConnection.h"
+#import <QuartzCore/QuartzCore.h>
 #import <WebKitSystemInterface.h>
 
+const static double fadeInDuration = 0.5;
+
 namespace WebKit {
 
 static void makeRenderLayer(CALayer *pluginLayer, uint32_t layerHostingContextID)
@@ -51,6 +54,15 @@
         m_pluginLayer.adoptNS([[CALayer alloc] init]);
         [m_pluginLayer.get() setGeometryFlipped:YES];
 
+        if (m_processType == PluginProcess::TypeRestartedProcess) {
+            CABasicAnimation *fadeInAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
+            fadeInAnimation.fromValue = [NSNumber numberWithFloat:0];
+            fadeInAnimation.toValue = [NSNumber numberWithFloat:1];
+            fadeInAnimation.duration = fadeInDuration;
+            fadeInAnimation.removedOnCompletion = NO;
+            [m_pluginLayer.get() addAnimation:fadeInAnimation forKey:@"restarted-plugin-fade-in"];
+        }
+
         makeRenderLayer(m_pluginLayer.get(), m_remoteLayerClientID);
     }
 

Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp (147578 => 147579)


--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp	2013-04-03 20:05:43 UTC (rev 147578)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp	2013-04-03 20:13:20 UTC (rev 147579)
@@ -558,7 +558,12 @@
     }
 
 #if ENABLE(PLUGIN_PROCESS)
-    PluginProcess::Type processType = (pluginElement->displayState() == HTMLPlugInElement::WaitingForSnapshot ? PluginProcess::TypeSnapshotProcess : PluginProcess::TypeRegularProcess);
+
+    PluginProcess::Type processType = PluginProcess::TypeRegularProcess;
+    if (pluginElement->displayState() == HTMLPlugInElement::WaitingForSnapshot)
+        processType = PluginProcess::TypeSnapshotProcess;
+    else if (pluginElement->displayState() == HTMLPlugInElement::Restarting || pluginElement->displayState() == HTMLPlugInElement::RestartingWithPendingMouseClick)
+        processType = PluginProcess::TypeRestartedProcess;
     return PluginProxy::create(pluginPath, processType);
 #else
     NetscapePlugin::setSetExceptionFunction(NPRuntimeObjectMap::setGlobalException);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to