Title: [218913] trunk/Source
Revision
218913
Author
[email protected]
Date
2017-06-28 20:54:05 -0700 (Wed, 28 Jun 2017)

Log Message

Move RenderEmbeddedObject::isReplacementObscured to HTMLPlugInElement
https://bugs.webkit.org/show_bug.cgi?id=173802
<rdar://problem/32884389>

Reviewed by Simon Fraser.

Source/WebCore:

Hittesting could potentially destroy "this" renderer so calling it inside RenderEmbeddedObject
could leave the caller with a stale pointer.
This patch protects the plugin element from getting destroyed and checks if the renderer got
deleted during the hittest to avoid nullptr dereference.

Speculative fix.

* html/HTMLPlugInElement.cpp:
(WebCore::HTMLPlugInElement::isReplacementObscured):
* html/HTMLPlugInElement.h:
* rendering/RenderEmbeddedObject.cpp:
(WebCore::RenderEmbeddedObject::isReplacementObscured): Deleted.
* rendering/RenderEmbeddedObject.h:
* testing/Internals.cpp:
(WebCore::Internals::isPluginUnavailabilityIndicatorObscured):

Source/WebKit2:

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::createPlugin):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (218912 => 218913)


--- trunk/Source/WebCore/ChangeLog	2017-06-29 03:28:47 UTC (rev 218912)
+++ trunk/Source/WebCore/ChangeLog	2017-06-29 03:54:05 UTC (rev 218913)
@@ -1,3 +1,27 @@
+2017-06-28  Zalan Bujtas  <[email protected]>
+
+        Move RenderEmbeddedObject::isReplacementObscured to HTMLPlugInElement
+        https://bugs.webkit.org/show_bug.cgi?id=173802
+        <rdar://problem/32884389>
+
+        Reviewed by Simon Fraser.
+
+        Hittesting could potentially destroy "this" renderer so calling it inside RenderEmbeddedObject
+        could leave the caller with a stale pointer.
+        This patch protects the plugin element from getting destroyed and checks if the renderer got
+        deleted during the hittest to avoid nullptr dereference.
+
+        Speculative fix.
+
+        * html/HTMLPlugInElement.cpp:
+        (WebCore::HTMLPlugInElement::isReplacementObscured):
+        * html/HTMLPlugInElement.h:
+        * rendering/RenderEmbeddedObject.cpp:
+        (WebCore::RenderEmbeddedObject::isReplacementObscured): Deleted.
+        * rendering/RenderEmbeddedObject.h:
+        * testing/Internals.cpp:
+        (WebCore::Internals::isPluginUnavailabilityIndicatorObscured):
+
 2017-06-28  Chris Dumez  <[email protected]>
 
         Avoid copying statistics in ResourceLoadStatisticsStore::readDataFromDecoder()

Modified: trunk/Source/WebCore/html/HTMLPlugInElement.cpp (218912 => 218913)


--- trunk/Source/WebCore/html/HTMLPlugInElement.cpp	2017-06-29 03:28:47 UTC (rev 218912)
+++ trunk/Source/WebCore/html/HTMLPlugInElement.cpp	2017-06-29 03:54:05 UTC (rev 218913)
@@ -32,6 +32,7 @@
 #include "FrameLoader.h"
 #include "FrameTree.h"
 #include "HTMLNames.h"
+#include "HitTestResult.h"
 #include "Logging.h"
 #include "MIMETypeRegistry.h"
 #include "Page.h"
@@ -39,7 +40,9 @@
 #include "PluginReplacement.h"
 #include "PluginViewBase.h"
 #include "RenderEmbeddedObject.h"
+#include "RenderLayer.h"
 #include "RenderSnapshottedPlugIn.h"
+#include "RenderView.h"
 #include "RenderWidget.h"
 #include "RuntimeEnabledFeatures.h"
 #include "ScriptController.h"
@@ -396,4 +399,78 @@
     return nullptr;
 }
 
+// Return whether or not the replacement content for blocked plugins is accessible to the user.
+bool HTMLPlugInElement::isReplacementObscured(const String& unavailabilityDescription)
+{
+    if (!is<RenderEmbeddedObject>(renderer()))
+        return false;
+    Ref<HTMLPlugInElement> protectedThis(*this);
+    downcast<RenderEmbeddedObject>(*renderer()).setPluginUnavailabilityReasonWithDescription(RenderEmbeddedObject::InsecurePluginVersion, unavailabilityDescription);
+    bool replacementIsObscured = isReplacementObscured();
+    // hittest in isReplacementObscured() method could destroy the renderer. Let's refetch it.
+    if (is<RenderEmbeddedObject>(renderer()))
+        downcast<RenderEmbeddedObject>(*renderer()).setUnavailablePluginIndicatorIsHidden(replacementIsObscured);
+    return replacementIsObscured;
 }
+
+bool HTMLPlugInElement::isReplacementObscured()
+{
+    // We should always start hit testing a clean tree.
+    if (document().view())
+        document().view()->updateLayoutAndStyleIfNeededRecursive();
+    // Check if style recalc/layout destroyed the associated renderer.
+    auto* renderView = document().topDocument().renderView();
+    if (!document().view() || !renderView)
+        return false;
+    if (!renderer() || !is<RenderEmbeddedObject>(*renderer()))
+        return false;
+    auto& pluginRenderer = downcast<RenderEmbeddedObject>(*renderer());
+    // Check the opacity of each layer containing the element or its ancestors.
+    float opacity = 1.0;
+    for (auto* layer = pluginRenderer.enclosingLayer(); layer; layer = layer->parent()) {
+        opacity *= layer->renderer().style().opacity();
+        if (opacity < 0.1)
+            return true;
+    }
+    // Calculate the absolute rect for the blocked plugin replacement text.
+    LayoutPoint absoluteLocation(pluginRenderer.absoluteBoundingBoxRect().location());
+    LayoutRect rect = pluginRenderer.unavailablePluginIndicatorBounds(absoluteLocation);
+    if (rect.isEmpty())
+        return true;
+    auto viewRect = document().view()->convertToRootView(snappedIntRect(rect));
+    auto x = viewRect.x();
+    auto y = viewRect.y();
+    auto width = viewRect.width();
+    auto height = viewRect.height();
+    // Hit test the center and near the corners of the replacement text to ensure
+    // it is visible and is not masked by other elements.
+    HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowUserAgentShadowContent | HitTestRequest::AllowChildFrameContent);
+    HitTestResult result;
+    HitTestLocation location = LayoutPoint(x + width / 2, y + height / 2);
+    bool hit = renderView->hitTest(request, location, result);
+    if (!hit || result.innerNode() != &pluginRenderer.frameOwnerElement())
+        return true;
+
+    location = LayoutPoint(x, y);
+    hit = renderView->hitTest(request, location, result);
+    if (!hit || result.innerNode() != &pluginRenderer.frameOwnerElement())
+        return true;
+
+    location = LayoutPoint(x + width, y);
+    hit = renderView->hitTest(request, location, result);
+    if (!hit || result.innerNode() != &pluginRenderer.frameOwnerElement())
+        return true;
+
+    location = LayoutPoint(x + width, y + height);
+    hit = renderView->hitTest(request, location, result);
+    if (!hit || result.innerNode() != &pluginRenderer.frameOwnerElement())
+        return true;
+
+    location = LayoutPoint(x, y + height);
+    hit = renderView->hitTest(request, location, result);
+    if (!hit || result.innerNode() != &pluginRenderer.frameOwnerElement())
+        return true;
+    return false;
+}
+
+}

Modified: trunk/Source/WebCore/html/HTMLPlugInElement.h (218912 => 218913)


--- trunk/Source/WebCore/html/HTMLPlugInElement.h	2017-06-29 03:28:47 UTC (rev 218912)
+++ trunk/Source/WebCore/html/HTMLPlugInElement.h	2017-06-29 03:54:05 UTC (rev 218913)
@@ -81,7 +81,10 @@
     virtual bool isPlugInImageElement() const { return false; }
 
     bool isUserObservable() const;
-    
+
+    WEBCORE_EXPORT bool isReplacementObscured(const String& unavailabilityDescription);
+    WEBCORE_EXPORT bool isReplacementObscured();
+
 protected:
     HTMLPlugInElement(const QualifiedName& tagName, Document&);
 

Modified: trunk/Source/WebCore/rendering/RenderEmbeddedObject.cpp (218912 => 218913)


--- trunk/Source/WebCore/rendering/RenderEmbeddedObject.cpp	2017-06-29 03:28:47 UTC (rev 218912)
+++ trunk/Source/WebCore/rendering/RenderEmbeddedObject.cpp	2017-06-29 03:54:05 UTC (rev 218913)
@@ -49,7 +49,6 @@
 #include "Path.h"
 #include "PlatformMouseEvent.h"
 #include "PluginViewBase.h"
-#include "RenderLayer.h"
 #include "RenderTheme.h"
 #include "RenderView.h"
 #include "Settings.h"
@@ -400,74 +399,6 @@
     return getReplacementTextGeometry(accumulatedOffset);
 }
 
-bool RenderEmbeddedObject::isReplacementObscured() const
-{
-    // Return whether or not the replacement content for blocked plugins is accessible to the user.
-
-    // Check the opacity of each layer containing the element or its ancestors.
-    float opacity = 1.0;
-    for (RenderLayer* layer = enclosingLayer(); layer; layer = layer->parent()) {
-        opacity *= layer->renderer().style().opacity();
-        if (opacity < 0.1)
-            return true;
-    }
-
-    // Calculate the absolute rect for the blocked plugin replacement text.
-    IntRect absoluteBoundingBox = absoluteBoundingBoxRect();
-    LayoutPoint absoluteLocation(absoluteBoundingBox.location());
-    LayoutRect rect = unavailablePluginIndicatorBounds(absoluteLocation);
-    if (rect.isEmpty())
-        return true;
-
-    RenderView* rootRenderView = document().topDocument().renderView();
-    ASSERT(rootRenderView);
-    if (!rootRenderView)
-        return true;
-
-    // We should always start hit testing a clean tree.
-    view().frameView().updateLayoutAndStyleIfNeededRecursive();
-
-    HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowUserAgentShadowContent | HitTestRequest::AllowChildFrameContent);
-    HitTestResult result;
-    HitTestLocation location;
-    
-    IntRect rootViewRect = view().frameView().convertToRootView(snappedIntRect(rect));
-    LayoutUnit x = rootViewRect.x();
-    LayoutUnit y = rootViewRect.y();
-    LayoutUnit width = rootViewRect.width();
-    LayoutUnit height = rootViewRect.height();
-    
-    // Hit test the center and near the corners of the replacement text to ensure
-    // it is visible and is not masked by other elements.
-    bool hit = false;
-    location = LayoutPoint(x + width / 2, y + height / 2);
-    hit = rootRenderView->hitTest(request, location, result);
-    if (!hit || result.innerNode() != &frameOwnerElement())
-        return true;
-    
-    location = LayoutPoint(x, y);
-    hit = rootRenderView->hitTest(request, location, result);
-    if (!hit || result.innerNode() != &frameOwnerElement())
-        return true;
-    
-    location = LayoutPoint(x + width, y);
-    hit = rootRenderView->hitTest(request, location, result);
-    if (!hit || result.innerNode() != &frameOwnerElement())
-        return true;
-    
-    location = LayoutPoint(x + width, y + height);
-    hit = rootRenderView->hitTest(request, location, result);
-    if (!hit || result.innerNode() != &frameOwnerElement())
-        return true;
-    
-    location = LayoutPoint(x, y + height);
-    hit = rootRenderView->hitTest(request, location, result);
-    if (!hit || result.innerNode() != &frameOwnerElement())
-        return true;
-
-    return false;
-}
-
 void RenderEmbeddedObject::layout()
 {
     StackStats::LayoutCheckPoint layoutCheckPoint;

Modified: trunk/Source/WebCore/rendering/RenderEmbeddedObject.h (218912 => 218913)


--- trunk/Source/WebCore/rendering/RenderEmbeddedObject.h	2017-06-29 03:28:47 UTC (rev 218912)
+++ trunk/Source/WebCore/rendering/RenderEmbeddedObject.h	2017-06-29 03:54:05 UTC (rev 218913)
@@ -54,10 +54,9 @@
 
     void handleUnavailablePluginIndicatorEvent(Event*);
 
-    WEBCORE_EXPORT bool isReplacementObscured() const;
-
     bool allowsAcceleratedCompositing() const;
 
+    LayoutRect unavailablePluginIndicatorBounds(const LayoutPoint& accumulatedOffset) const;
 protected:
     void paintReplaced(PaintInfo&, const LayoutPoint&) final;
     void paint(PaintInfo&, const LayoutPoint&) override;
@@ -88,7 +87,6 @@
     bool isInUnavailablePluginIndicator(const FloatPoint&) const;
     void getReplacementTextGeometry(const LayoutPoint& accumulatedOffset, FloatRect& contentRect, FloatRect& indicatorRect, FloatRect& replacementTextRect, FloatRect& arrowRect, FontCascade&, TextRun&, float& textWidth) const;
     LayoutRect getReplacementTextGeometry(const LayoutPoint& accumulatedOffset) const;
-    LayoutRect unavailablePluginIndicatorBounds(const LayoutPoint&) const;
 
     bool canHaveChildren() const final;
     virtual bool canHaveWidget() const { return true; }

Modified: trunk/Source/WebCore/testing/Internals.cpp (218912 => 218913)


--- trunk/Source/WebCore/testing/Internals.cpp	2017-06-29 03:28:47 UTC (rev 218912)
+++ trunk/Source/WebCore/testing/Internals.cpp	2017-06-29 03:54:05 UTC (rev 218913)
@@ -3196,10 +3196,10 @@
 ExceptionOr<bool> Internals::isPluginUnavailabilityIndicatorObscured(Element& element)
 {
     auto* renderer = element.renderer();
-    if (!is<RenderEmbeddedObject>(renderer))
+    if (!is<HTMLPlugInElement>(element) || !is<RenderEmbeddedObject>(renderer))
         return Exception { INVALID_ACCESS_ERR };
 
-    return downcast<RenderEmbeddedObject>(*renderer).isReplacementObscured();
+    return downcast<HTMLPlugInElement>(element).isReplacementObscured();
 }
 
 bool Internals::isPluginSnapshotted(Element& element)

Modified: trunk/Source/WebKit2/ChangeLog (218912 => 218913)


--- trunk/Source/WebKit2/ChangeLog	2017-06-29 03:28:47 UTC (rev 218912)
+++ trunk/Source/WebKit2/ChangeLog	2017-06-29 03:54:05 UTC (rev 218913)
@@ -1,3 +1,14 @@
+2017-06-29  Zalan Bujtas  <[email protected]>
+
+        Move RenderEmbeddedObject::isReplacementObscured to HTMLPlugInElement
+        https://bugs.webkit.org/show_bug.cgi?id=173802
+        <rdar://problem/32884389>
+
+        Reviewed by Simon Fraser.
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::createPlugin):
+
 2017-06-28  Ryosuke Niwa  <[email protected]>
 
         REGRESSION (r218842): com.apple.WebKit crash in WebKit::ProcessLauncher::launchProcess

Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp (218912 => 218913)


--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp	2017-06-29 03:28:47 UTC (rev 218912)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp	2017-06-29 03:54:05 UTC (rev 218913)
@@ -771,7 +771,6 @@
 #endif
 
 #if ENABLE(NETSCAPE_PLUGIN_API)
-
 RefPtr<Plugin> WebPage::createPlugin(WebFrame* frame, HTMLPlugInElement* pluginElement, const Plugin::Parameters& parameters, String& newMIMEType)
 {
     String frameURLString = frame->coreFrame()->loader().documentLoader()->responseURL().string();
@@ -809,16 +808,7 @@
     }
 
     if (isBlockedPlugin) {
-        bool replacementObscured = false;
-        auto* renderer = pluginElement->renderer();
-        if (is<RenderEmbeddedObject>(renderer)) {
-            auto& renderObject = downcast<RenderEmbeddedObject>(*renderer);
-            renderObject.setPluginUnavailabilityReasonWithDescription(RenderEmbeddedObject::InsecurePluginVersion, unavailabilityDescription);
-            replacementObscured = renderObject.isReplacementObscured();
-            renderObject.setUnavailablePluginIndicatorIsHidden(replacementObscured);
-        }
-
-        send(Messages::WebPageProxy::DidBlockInsecurePluginVersion(parameters.mimeType, parameters.url.string(), frameURLString, pageURLString, replacementObscured));
+        send(Messages::WebPageProxy::DidBlockInsecurePluginVersion(parameters.mimeType, parameters.url.string(), frameURLString, pageURLString, pluginElement->isReplacementObscured(unavailabilityDescription)));
         return nullptr;
     }
 
@@ -828,7 +818,6 @@
     bool isRestartedProcess = (pluginElement->displayState() == HTMLPlugInElement::Restarting || pluginElement->displayState() == HTMLPlugInElement::RestartingWithPendingMouseClick);
     return PluginProxy::create(pluginProcessToken, isRestartedProcess);
 }
-
 #endif // ENABLE(NETSCAPE_PLUGIN_API)
 
 #if ENABLE(WEBGL) && !PLATFORM(COCOA)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to