Plugins that resize might need to be snapshotted.
authordino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 16 Apr 2013 01:05:39 +0000 (01:05 +0000)
committerdino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 16 Apr 2013 01:05:39 +0000 (01:05 +0000)
https://bugs.webkit.org/show_bug.cgi?id=102157
<rdar://problem/12696259>

Reviewed by Tim Horton.

Source/WebCore:

A plugin could avoid snapshotting if it started very
small (below the threshold where we autostart), and then
resized to be large (above the threshold). Detect this
case and tell the plugin to snapshot.

There unfortunately is a bit of state to track when doing
this. We have to start the snapshotting in a post-layout
task, so we carry a flag to say we're checking size but
not wanting the plugin to update (which would restart it).
We also might be a plugin that would have already restarted
due to a similar plugin being clicked or detected as dominant.
So this patch introduces a member variable that tracks what
decision has been made on snapshotting.

I also added some more logging to be more clear about what is
happening to plugins going through the snapshot process, and
changed the order of the tests in the algorithm so that domain
detection comes before examining the size.

* html/HTMLPlugInImageElement.cpp:
(WebCore::HTMLPlugInImageElement::HTMLPlugInImageElement): Initialise
    the two new member variables.
(WebCore::HTMLPlugInImageElement::setDisplayState): Mark a restarted
    plugin as NeverSnapshot. This means that if it later resizes above the
    threshold, it won't trigger the snapshot detection.
(WebCore::HTMLPlugInImageElement::checkSnapshotStatus): Renamed from
    updateSnapshotInfo. This now updates the snapshot, but also runs
    the check for size changes.
(WebCore::addPlugInsFromNodeListMatchingPlugInOrigin): Gather all plugins
    that look like a restarting plugin, not just those snapshotted. That
    way they can all be marked as NeverSnapshot.
(WebCore::HTMLPlugInImageElement::restartSimilarPlugIns): Bless every
    plugin that looks similar, whether or not it is snapshotted.
(WebCore::HTMLPlugInImageElement::userDidClickSnapshot): More logging.
(WebCore::HTMLPlugInImageElement::setIsPrimarySnapshottedPlugIn): Ditto.
(WebCore::HTMLPlugInImageElement::checkSizeChangeForSnapshotting): New
    method. If the plugin was below the threshold and is now above it,
    begin the snapshotting process.
(WebCore::HTMLPlugInImageElement::subframeLoaderWillCreatePlugIn): Plugins
    that were marked as NeverSnapshot should start immediately. Move the origin
    test earlier in the method. If a plugin avoided snapshotting due to size,
    remember the size.
(WebCore::HTMLPlugInImageElement::subframeLoaderDidCreatePlugIn): Mark the
    plugin as NeverSnapshot.

* html/HTMLPlugInImageElement.h:
(HTMLPlugInImageElement): Four new member variables:
    - the decision we made regarding snapshotting (or not), uses the SnapshotDecision enum
    - the size when it avoided snapshotting
    - a flag to indicate the post layout update was triggered due to
      a size change
(WebCore::HTMLPlugInImageElement::needsCheckForSizeChange): New method.
(WebCore::HTMLPlugInImageElement::setNeedsCheckForSizeChange): New method.
(WebCore::HTMLPlugInImageElement::snapshotDecision): Return the decision
    regarding snapshotting or not snapshotting.

* page/FrameView.cpp:
(WebCore::FrameView::addWidgetToUpdate): Guard updating the widget. We don't
    want to do it when we're checking for a size change in the plugin.
(WebCore::FrameView::updateWidget): Call new name.

* plugins/PluginViewBase.h:
(WebCore::PluginViewBase::beginSnapshottingRunningPlugin): Empty virtual
    method to snapshot a running plugin.

* rendering/RenderEmbeddedObject.cpp:
(WebCore::RenderEmbeddedObject::layout): If the plugin has increased in
    size add it to the post layout list so that it will be checked.

Source/WebKit2:

Allow a running plugin to be snapshotted. All this
means is that we start the snapshot timer again.

* WebProcess/Plugins/PluginView.cpp:
(WebKit::PluginView::beginSnapshottingRunningPlugin): Restart
    the timer.
* WebProcess/Plugins/PluginView.h: Virtual method declaration.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@148482 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/html/HTMLPlugInImageElement.cpp
Source/WebCore/html/HTMLPlugInImageElement.h
Source/WebCore/page/FrameView.cpp
Source/WebCore/plugins/PluginViewBase.h
Source/WebCore/rendering/RenderEmbeddedObject.cpp
Source/WebKit2/ChangeLog
Source/WebKit2/WebProcess/Plugins/PluginView.cpp
Source/WebKit2/WebProcess/Plugins/PluginView.h

index 1448f38..4152402 100644 (file)
@@ -1,3 +1,80 @@
+2013-04-15  Dean Jackson  <dino@apple.com>
+
+        Plugins that resize might need to be snapshotted.
+        https://bugs.webkit.org/show_bug.cgi?id=102157
+        <rdar://problem/12696259>
+
+        Reviewed by Tim Horton.
+
+        A plugin could avoid snapshotting if it started very
+        small (below the threshold where we autostart), and then
+        resized to be large (above the threshold). Detect this
+        case and tell the plugin to snapshot.
+
+        There unfortunately is a bit of state to track when doing
+        this. We have to start the snapshotting in a post-layout
+        task, so we carry a flag to say we're checking size but
+        not wanting the plugin to update (which would restart it).
+        We also might be a plugin that would have already restarted
+        due to a similar plugin being clicked or detected as dominant.
+        So this patch introduces a member variable that tracks what
+        decision has been made on snapshotting.
+
+        I also added some more logging to be more clear about what is
+        happening to plugins going through the snapshot process, and
+        changed the order of the tests in the algorithm so that domain
+        detection comes before examining the size.
+
+        * html/HTMLPlugInImageElement.cpp:
+        (WebCore::HTMLPlugInImageElement::HTMLPlugInImageElement): Initialise
+            the two new member variables.
+        (WebCore::HTMLPlugInImageElement::setDisplayState): Mark a restarted
+            plugin as NeverSnapshot. This means that if it later resizes above the
+            threshold, it won't trigger the snapshot detection.
+        (WebCore::HTMLPlugInImageElement::checkSnapshotStatus): Renamed from
+            updateSnapshotInfo. This now updates the snapshot, but also runs
+            the check for size changes.
+        (WebCore::addPlugInsFromNodeListMatchingPlugInOrigin): Gather all plugins
+            that look like a restarting plugin, not just those snapshotted. That
+            way they can all be marked as NeverSnapshot.
+        (WebCore::HTMLPlugInImageElement::restartSimilarPlugIns): Bless every
+            plugin that looks similar, whether or not it is snapshotted.
+        (WebCore::HTMLPlugInImageElement::userDidClickSnapshot): More logging.
+        (WebCore::HTMLPlugInImageElement::setIsPrimarySnapshottedPlugIn): Ditto.
+        (WebCore::HTMLPlugInImageElement::checkSizeChangeForSnapshotting): New
+            method. If the plugin was below the threshold and is now above it,
+            begin the snapshotting process.
+        (WebCore::HTMLPlugInImageElement::subframeLoaderWillCreatePlugIn): Plugins
+            that were marked as NeverSnapshot should start immediately. Move the origin
+            test earlier in the method. If a plugin avoided snapshotting due to size,
+            remember the size.
+        (WebCore::HTMLPlugInImageElement::subframeLoaderDidCreatePlugIn): Mark the
+            plugin as NeverSnapshot.
+
+        * html/HTMLPlugInImageElement.h:
+        (HTMLPlugInImageElement): Four new member variables:
+            - the decision we made regarding snapshotting (or not), uses the SnapshotDecision enum
+            - the size when it avoided snapshotting
+            - a flag to indicate the post layout update was triggered due to
+              a size change
+        (WebCore::HTMLPlugInImageElement::needsCheckForSizeChange): New method.
+        (WebCore::HTMLPlugInImageElement::setNeedsCheckForSizeChange): New method.
+        (WebCore::HTMLPlugInImageElement::snapshotDecision): Return the decision
+            regarding snapshotting or not snapshotting.
+
+        * page/FrameView.cpp:
+        (WebCore::FrameView::addWidgetToUpdate): Guard updating the widget. We don't
+            want to do it when we're checking for a size change in the plugin.
+        (WebCore::FrameView::updateWidget): Call new name.
+
+        * plugins/PluginViewBase.h:
+        (WebCore::PluginViewBase::beginSnapshottingRunningPlugin): Empty virtual
+            method to snapshot a running plugin.
+
+        * rendering/RenderEmbeddedObject.cpp:
+        (WebCore::RenderEmbeddedObject::layout): If the plugin has increased in
+            size add it to the post layout list so that it will be checked.
+
 2013-04-15  Chris Fleizach  <cfleizach@apple.com>
 
         activating a focused link to an in-page fragment ID should transfer focus to the target of the link when possible
index 9baf002..b38d1db 100644 (file)
@@ -82,6 +82,8 @@ HTMLPlugInImageElement::HTMLPlugInImageElement(const QualifiedName& tagName, Doc
     , m_removeSnapshotTimer(this, &HTMLPlugInImageElement::removeSnapshotTimerFired)
     , m_createdDuringUserGesture(ScriptController::processingUserGesture())
     , m_restartedPlugin(false)
+    , m_needsCheckForSizeChange(false)
+    , m_snapshotDecision(SnapshotNotYetDecided)
 {
     setHasCustomStyleCallbacks();
 }
@@ -97,6 +99,7 @@ void HTMLPlugInImageElement::setDisplayState(DisplayState state)
 #if PLATFORM(MAC)
     if (state == RestartingWithPendingMouseClick || state == Restarting) {
         m_restartedPlugin = true;
+        m_snapshotDecision = NeverSnapshot;
         if (displayState() == DisplayingSnapshot)
             m_removeSnapshotTimer.startOneShot(removeSnapshotTimerDelay);
     }
@@ -336,8 +339,14 @@ static AtomicString classNameForShadowRoot(const Node* node)
     return plugInLargeSizeClassName;
 }
 
-void HTMLPlugInImageElement::updateSnapshotInfo()
+void HTMLPlugInImageElement::checkSnapshotStatus()
 {
+    if (!renderer()->isSnapshottedPlugIn()) {
+        if (displayState() == Playing)
+            checkSizeChangeForSnapshotting();
+        return;
+    }
+
     ShadowRoot* root = userAgentShadowRoot();
     if (!root)
         return;
@@ -428,7 +437,7 @@ static void addPlugInsFromNodeListMatchingPlugInOrigin(HTMLPlugInImageElementLis
         Node* node = collection->item(i);
         if (node->isPluginElement()) {
             HTMLPlugInElement* plugInElement = toHTMLPlugInElement(node);
-            if (plugInElement->isPlugInImageElement() && plugInElement->displayState() <= HTMLPlugInElement::DisplayingSnapshot) {
+            if (plugInElement->isPlugInImageElement()) {
                 HTMLPlugInImageElement* plugInImageElement = toHTMLPlugInImageElement(node);
                 const KURL& loadedURL = plugInImageElement->loadedUrl();
                 String otherMimeType = plugInImageElement->loadedMimeType();
@@ -446,29 +455,35 @@ void HTMLPlugInImageElement::restartSimilarPlugIns()
 
     String plugInOrigin = m_loadedUrl.host();
     String mimeType = loadedMimeType();
-    HTMLPlugInImageElementList pluginsNeedingRestart;
+    HTMLPlugInImageElementList similarPlugins;
 
     if (!document()->page())
         return;
 
     for (Frame* frame = document()->page()->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
-        if (frame->loader()->subframeLoader()->containsPlugins()) {
-            if (!frame->document())
-                continue;
-
-            RefPtr<NodeList> plugins = frame->document()->getElementsByTagName(embedTag.localName());
-            if (plugins)
-                addPlugInsFromNodeListMatchingPlugInOrigin(pluginsNeedingRestart, plugins, plugInOrigin, mimeType);
-
-            plugins = frame->document()->getElementsByTagName(objectTag.localName());
-            if (plugins)
-                addPlugInsFromNodeListMatchingPlugInOrigin(pluginsNeedingRestart, plugins, plugInOrigin, mimeType);
-        }
+        if (!frame->loader()->subframeLoader()->containsPlugins())
+            continue;
+        
+        if (!frame->document())
+            continue;
+
+        RefPtr<NodeList> plugIns = frame->document()->getElementsByTagName(embedTag.localName());
+        if (plugIns)
+            addPlugInsFromNodeListMatchingPlugInOrigin(similarPlugins, plugIns, plugInOrigin, mimeType);
+
+        plugIns = frame->document()->getElementsByTagName(objectTag.localName());
+        if (plugIns)
+            addPlugInsFromNodeListMatchingPlugInOrigin(similarPlugins, plugIns, plugInOrigin, mimeType);
     }
 
-    for (size_t i = 0, length = pluginsNeedingRestart.size(); i < length; i++) {
-        pluginsNeedingRestart[i]->setDisplayState(Playing);
-        pluginsNeedingRestart[i]->restartSnapshottedPlugIn();
+    for (size_t i = 0, length = similarPlugins.size(); i < length; ++i) {
+        HTMLPlugInImageElement* plugInToRestart = similarPlugins[i].get();
+        if (plugInToRestart->displayState() <= HTMLPlugInElement::DisplayingSnapshot) {
+            LOG(Plugins, "%p Plug-in looks similar to a restarted plug-in. Restart.", plugInToRestart);
+            plugInToRestart->setDisplayState(Playing);
+            plugInToRestart->restartSnapshottedPlugIn();
+        }
+        plugInToRestart->m_snapshotDecision = NeverSnapshot;
     }
 }
 
@@ -481,6 +496,7 @@ void HTMLPlugInImageElement::userDidClickSnapshot(PassRefPtr<MouseEvent> event,
     if (document()->page() && !SchemeRegistry::shouldTreatURLSchemeAsLocal(document()->page()->mainFrame()->document()->baseURL().protocol()) && document()->page()->settings()->autostartOriginPlugInSnapshottingEnabled())
         document()->page()->plugInClient()->didStartFromOrigin(document()->page()->mainFrame()->document()->baseURL().host(), plugInOrigin, loadedMimeType());
 
+    LOG(Plugins, "%p User clicked on snapshotted plug-in. Restart.", this);
     restartSnapshottedPlugIn();
     restartSimilarPlugIns();
 }
@@ -491,6 +507,7 @@ void HTMLPlugInImageElement::setIsPrimarySnapshottedPlugIn(bool isPrimarySnapsho
         return;
 
     if (isPrimarySnapshottedPlugIn) {
+        LOG(Plugins, "%p Plug-in was detected as the primary element in the page. Restart.", this);
         restartSnapshottedPlugIn();
         restartSimilarPlugIns();
     }
@@ -521,6 +538,27 @@ void HTMLPlugInImageElement::simulatedMouseClickTimerFired(DeferrableOneShotTime
     m_pendingClickEventFromSnapshot = nullptr;
 }
 
+void HTMLPlugInImageElement::checkSizeChangeForSnapshotting()
+{
+    if (!m_needsCheckForSizeChange || m_snapshotDecision != MaySnapshotWhenResized)
+        return;
+
+    m_needsCheckForSizeChange = false;
+    LayoutRect contentBoxRect = toRenderBox(renderer())->contentBoxRect();
+    int contentWidth = contentBoxRect.width();
+    int contentHeight = contentBoxRect.height();
+
+    if (contentWidth <= sizingTinyDimensionThreshold || contentHeight <= sizingTinyDimensionThreshold)
+        return;
+
+    LOG(Plugins, "%p Plug-in originally avoided snapshotting because it was sized %dx%d. Now it is %dx%d. Tell it to snapshot.\n", this, m_sizeWhenSnapshotted.width(), m_sizeWhenSnapshotted.height(), contentWidth, contentHeight);
+    setDisplayState(WaitingForSnapshot);
+    m_snapshotDecision = Snapshotted;
+    Widget* widget = pluginWidget();
+    if (widget && widget->isPluginViewBase())
+        toPluginViewBase(widget)->beginSnapshottingRunningPlugin();
+}
+
 void HTMLPlugInImageElement::subframeLoaderWillCreatePlugIn(const KURL& url)
 {
     LOG(Plugins, "%p Plug-in URL: %s", this, m_url.utf8().data());
@@ -528,35 +566,46 @@ void HTMLPlugInImageElement::subframeLoaderWillCreatePlugIn(const KURL& url)
 
     m_loadedUrl = url;
 
-    if (!document()->page()
-        || !document()->page()->settings()->plugInSnapshottingEnabled())
+    if (!document()->page() || !document()->page()->settings()->plugInSnapshottingEnabled()) {
+        m_snapshotDecision = NeverSnapshot;
         return;
+    }
 
     if (displayState() == Restarting) {
-        setDisplayState(Playing);
         LOG(Plugins, "%p Plug-in is explicitly restarting", this);
+        m_snapshotDecision = NeverSnapshot;
+        setDisplayState(Playing);
         return;
     }
 
     if (displayState() == RestartingWithPendingMouseClick) {
         LOG(Plugins, "%p Plug-in is explicitly restarting but also waiting for a click", this);
+        m_snapshotDecision = NeverSnapshot;
         return;
     }
 
+    if (m_snapshotDecision == NeverSnapshot) {
+        LOG(Plugins, "%p Plug-in is blessed, allow it to start", this);
+        return;
+    }
+    
     bool inMainFrame = document()->frame() == document()->page()->mainFrame();
 
     if (document()->isPluginDocument() && inMainFrame) {
         LOG(Plugins, "%p Plug-in document in main frame", this);
+        m_snapshotDecision = NeverSnapshot;
         return;
     }
 
     if (ScriptController::processingUserGesture()) {
         LOG(Plugins, "%p Script is currently processing user gesture, set to play", this);
+        m_snapshotDecision = NeverSnapshot;
         return;
     }
 
     if (m_createdDuringUserGesture) {
         LOG(Plugins, "%p Plug-in was created when processing user gesture, set to play", this);
+        m_snapshotDecision = NeverSnapshot;
         return;
     }
 
@@ -565,15 +614,23 @@ void HTMLPlugInImageElement::subframeLoaderWillCreatePlugIn(const KURL& url)
         lastKnownUserGestureTimestamp = std::max(lastKnownUserGestureTimestamp, document()->page()->mainFrame()->document()->lastHandledUserGestureTimestamp());
     if (currentTime() - lastKnownUserGestureTimestamp < autostartSoonAfterUserGestureThreshold) {
         LOG(Plugins, "%p Plug-in was created shortly after a user gesture, set to play", this);
+        m_snapshotDecision = NeverSnapshot;
         return;
     }
 
     if (document()->page()->settings()->snapshotAllPlugIns()) {
         LOG(Plugins, "%p Plug-in forced to snapshot by user preference", this);
+        m_snapshotDecision = Snapshotted;
         setDisplayState(WaitingForSnapshot);
         return;
     }
 
+    if (document()->page()->settings()->autostartOriginPlugInSnapshottingEnabled() && document()->page()->plugInClient()->shouldAutoStartFromOrigin(document()->page()->mainFrame()->document()->baseURL().host(), url.host(), loadedMimeType())) {
+        LOG(Plugins, "%p Plug-in from (%s, %s) is marked to auto-start, set to play", this, document()->page()->mainFrame()->document()->baseURL().host().utf8().data(), url.host().utf8().data());
+        m_snapshotDecision = NeverSnapshot;
+        return;
+    }
+
     RenderBox* renderEmbeddedObject = toRenderBox(renderer());
     Length styleWidth = renderEmbeddedObject->style()->width();
     Length styleHeight = renderEmbeddedObject->style()->height();
@@ -588,35 +645,36 @@ void HTMLPlugInImageElement::subframeLoaderWillCreatePlugIn(const KURL& url)
         && styleHeight.isPercent() && (styleHeight.percent() == 100)
         && (static_cast<float>(contentArea) / visibleArea > sizingFullPageAreaRatioThreshold)) {
         LOG(Plugins, "%p Plug-in is top level full page, set to play", this);
+        m_snapshotDecision = NeverSnapshot;
         return;
     }
 
     if (contentWidth <= sizingTinyDimensionThreshold || contentHeight <= sizingTinyDimensionThreshold) {
         LOG(Plugins, "%p Plug-in is very small %dx%d, set to play", this, contentWidth, contentHeight);
+        m_sizeWhenSnapshotted = IntSize(contentBoxRect.width().toInt(), contentBoxRect.height().toInt());
+        m_snapshotDecision = MaySnapshotWhenResized;
         return;
     }
 
     if (!document()->page()->plugInClient()) {
+        LOG(Plugins, "%p There is no plug-in client. Set to wait for snapshot", this);
+        m_snapshotDecision = NeverSnapshot;
         setDisplayState(WaitingForSnapshot);
         return;
     }
 
-    if (document()->page()->settings()->autostartOriginPlugInSnapshottingEnabled() && document()->page()->plugInClient()->shouldAutoStartFromOrigin(document()->page()->mainFrame()->document()->baseURL().host(), url.host(), loadedMimeType())) {
-        LOG(Plugins, "%p Plug-in from (%s, %s) is marked to auto-start, set to play", this, document()->page()->mainFrame()->document()->baseURL().host().utf8().data(), url.host().utf8().data());
-        return;
-    }
-
     LOG(Plugins, "%p Plug-in from (%s, %s) is not auto-start, sized at %dx%d, set to wait for snapshot", this, document()->page()->mainFrame()->document()->baseURL().host().utf8().data(), url.host().utf8().data(), contentWidth, contentHeight);
+    m_snapshotDecision = Snapshotted;
     setDisplayState(WaitingForSnapshot);
 }
 
 void HTMLPlugInImageElement::subframeLoaderDidCreatePlugIn(const Widget* widget)
 {
-    if (!widget->isPluginViewBase()
-        || !static_cast<const PluginViewBase*>(widget)->shouldAlwaysAutoStart())
+    if (!widget->isPluginViewBase() || !toPluginViewBase(widget)->shouldAlwaysAutoStart())
         return;
 
     LOG(Plugins, "%p Plug-in should auto-start, set to play", this);
+    m_snapshotDecision = NeverSnapshot;
     setDisplayState(Playing);
 }
 
index bdf87b9..4dc5ad6 100644 (file)
@@ -75,7 +75,7 @@ public:
     void setNeedsWidgetUpdate(bool needsWidgetUpdate) { m_needsWidgetUpdate = needsWidgetUpdate; }
 
     void userDidClickSnapshot(PassRefPtr<MouseEvent>, bool forwardEvent);
-    void updateSnapshotInfo();
+    void checkSnapshotStatus();
     Image* snapshotImage() const { return m_snapshotImage.get(); }
 
     // Plug-in URL might not be the same as url() with overriding parameters.
@@ -85,6 +85,18 @@ public:
     void setIsPrimarySnapshottedPlugIn(bool);
     bool partOfSnapshotLabel(Node*);
 
+    bool needsCheckForSizeChange() const { return m_needsCheckForSizeChange; }
+    void setNeedsCheckForSizeChange() { m_needsCheckForSizeChange = true; }
+    void checkSizeChangeForSnapshotting();
+
+    enum SnapshotDecision {
+        SnapshotNotYetDecided,
+        NeverSnapshot,
+        Snapshotted,
+        MaySnapshotWhenResized
+    };
+    SnapshotDecision snapshotDecision() const { return m_snapshotDecision; }
+
 protected:
     HTMLPlugInImageElement(const QualifiedName& tagName, Document*, bool createdByParser, PreferPlugInsForImagesOption);
 
@@ -147,6 +159,9 @@ private:
     RefPtr<Element> m_snapshotLabel;
     bool m_createdDuringUserGesture;
     bool m_restartedPlugin;
+    bool m_needsCheckForSizeChange;
+    IntSize m_sizeWhenSnapshotted;
+    SnapshotDecision m_snapshotDecision;
 };
 
 inline HTMLPlugInImageElement* toHTMLPlugInImageElement(Node* node)
index c23677e..036b342 100644 (file)
@@ -1432,7 +1432,8 @@ void FrameView::addWidgetToUpdate(RenderObject* object)
     Node* node = object->node();
     if (node->hasTagName(objectTag) || node->hasTagName(embedTag)) {
         HTMLPlugInImageElement* pluginElement = toHTMLPlugInImageElement(node);
-        pluginElement->setNeedsWidgetUpdate(true);
+        if (!pluginElement->needsCheckForSizeChange())
+            pluginElement->setNeedsWidgetUpdate(true);
     }
 
     m_widgetUpdateSet->add(object);
@@ -2610,7 +2611,7 @@ void FrameView::updateWidget(RenderObject* object)
         if (object->isSnapshottedPlugIn()) {
             if (ownerElement->hasTagName(objectTag) || ownerElement->hasTagName(embedTag)) {
                 HTMLPlugInImageElement* pluginElement = toHTMLPlugInImageElement(ownerElement);
-                pluginElement->updateSnapshotInfo();
+                pluginElement->checkSnapshotStatus();
             }
             return;
         }
@@ -2619,6 +2620,10 @@ void FrameView::updateWidget(RenderObject* object)
         // updateWidget(PluginCreationOption) on HTMLElement.
         if (ownerElement->hasTagName(objectTag) || ownerElement->hasTagName(embedTag) || ownerElement->hasTagName(appletTag)) {
             HTMLPlugInImageElement* pluginElement = toHTMLPlugInImageElement(ownerElement);
+            if (pluginElement->needsCheckForSizeChange()) {
+                pluginElement->checkSnapshotStatus();
+                return;
+            }
             if (pluginElement->needsWidgetUpdate())
                 pluginElement->updateWidget(CreateAnyWidgetType);
         }
index b60fa92..6c32e76 100644 (file)
@@ -64,6 +64,7 @@ public:
     virtual bool canProcessDrag() const { return false; }
 
     virtual bool shouldAlwaysAutoStart() const { return false; }
+    virtual void beginSnapshottingRunningPlugin() { }
 
     virtual bool shouldAllowNavigationFromDrags() const { return false; }
 
index d0d455a..6c061e1 100644 (file)
@@ -293,11 +293,27 @@ void RenderEmbeddedObject::layout()
 
     updateLayerTransform();
 
-    if (!widget() && frameView() && canHaveWidget())
+    bool wasMissingWidget = false;
+    if (!widget() && frameView() && canHaveWidget()) {
+        wasMissingWidget = true;
         frameView()->addWidgetToUpdate(this);
+    }
 
     setNeedsLayout(false);
 
+    LayoutSize newSize = contentBoxRect().size();
+
+    if (!wasMissingWidget && newSize.width() >= oldSize.width() && newSize.height() >= oldSize.height()) {
+        Element* element = toElement(node());
+        if (element && element->isPluginElement() && toHTMLPlugInElement(element)->isPlugInImageElement()) {
+            HTMLPlugInImageElement* plugInImageElement = toHTMLPlugInImageElement(element);
+            if (plugInImageElement->displayState() > HTMLPlugInElement::DisplayingSnapshot && plugInImageElement->snapshotDecision() == HTMLPlugInImageElement::MaySnapshotWhenResized && document()->view()) {
+                plugInImageElement->setNeedsCheckForSizeChange();
+                document()->view()->addWidgetToUpdate(this);
+            }
+        }
+    }
+
     if (!canHaveChildren())
         return;
 
@@ -312,7 +328,6 @@ void RenderEmbeddedObject::layout()
     if (!childBox)
         return;
     
-    LayoutSize newSize = contentBoxRect().size();
     if (newSize == oldSize && !childBox->needsLayout())
         return;
     
index c9f54e1..8f8e18f 100644 (file)
@@ -1,3 +1,19 @@
+2013-04-15  Dean Jackson  <dino@apple.com>
+
+        Plugins that resize might need to be snapshotted.
+        https://bugs.webkit.org/show_bug.cgi?id=102157
+        <rdar://problem/12696259>
+
+        Reviewed by Tim Horton.
+
+        Allow a running plugin to be snapshotted. All this
+        means is that we start the snapshot timer again.
+
+        * WebProcess/Plugins/PluginView.cpp:
+        (WebKit::PluginView::beginSnapshottingRunningPlugin): Restart
+            the timer.
+        * WebProcess/Plugins/PluginView.h: Virtual method declaration.
+
 2013-04-15  Seokju Kwon  <seokju.kwon@gmail.com>
 
         [EFL][WK2] build fix after r148434
index 1053db4..ec4658b 100644 (file)
@@ -1640,6 +1640,11 @@ void PluginView::pluginSnapshotTimerFired(DeferrableOneShotTimer<PluginView>*)
     m_pluginElement->setDisplayState(HTMLPlugInElement::DisplayingSnapshot);
 }
 
+void PluginView::beginSnapshottingRunningPlugin()
+{
+    m_pluginSnapshotTimer.restart();
+}
+
 bool PluginView::shouldAlwaysAutoStart() const
 {
     if (!m_plugin)
index 6bd2646..c6841bb 100644 (file)
@@ -148,6 +148,7 @@ private:
     virtual WebCore::Scrollbar* verticalScrollbar();
     virtual bool wantsWheelEvents();
     virtual bool shouldAlwaysAutoStart() const OVERRIDE;
+    virtual void beginSnapshottingRunningPlugin() OVERRIDE;
     virtual bool shouldAllowNavigationFromDrags() const OVERRIDE;
 
     // WebCore::Widget