- 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);