Home | History | Annotate | Download | only in plugins
      1 /*
      2  * Copyright (C) 2011 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "core/plugins/IFrameShimSupport.h"
     33 
     34 #include "HTMLNames.h"
     35 #include "core/dom/Element.h"
     36 #include "core/html/HTMLElement.h"
     37 #include "core/html/HTMLFrameOwnerElement.h"
     38 #include "core/page/Frame.h"
     39 #include "core/page/FrameView.h"
     40 #include "core/platform/Widget.h"
     41 #include "core/rendering/RenderBox.h"
     42 #include "core/rendering/RenderObject.h"
     43 #include "wtf/HashSet.h"
     44 
     45 // This file provides plugin-related utility functions for iframe shims and is shared by platforms that inherit
     46 // from PluginView (e.g. Qt) and those that do not (e.g. Chromium).
     47 
     48 namespace WebCore {
     49 
     50 static void getObjectStack(const RenderObject* ro, Vector<const RenderObject*>* roStack)
     51 {
     52     roStack->clear();
     53     while (ro) {
     54         roStack->append(ro);
     55         ro = ro->parent();
     56     }
     57 }
     58 
     59 // Returns true if stack1 is at or above stack2
     60 static bool iframeIsAbovePlugin(const Vector<const RenderObject*>& iframeZstack, const Vector<const RenderObject*>& pluginZstack)
     61 {
     62     for (size_t i = 0; i < iframeZstack.size() && i < pluginZstack.size(); i++) {
     63         // The root is at the end of these stacks.  We want to iterate
     64         // root-downwards so we index backwards from the end.
     65         const RenderObject* ro1 = iframeZstack[iframeZstack.size() - 1 - i];
     66         const RenderObject* ro2 = pluginZstack[pluginZstack.size() - 1 - i];
     67 
     68         if (ro1 != ro2) {
     69             // When we find nodes in the stack that are not the same, then
     70             // we've found the nodes just below the lowest comment ancestor.
     71             // Determine which should be on top.
     72 
     73             // See if z-index determines an order.
     74             if (ro1->style() && ro2->style()) {
     75                 int z1 = ro1->style()->zIndex();
     76                 int z2 = ro2->style()->zIndex();
     77                 if (z1 > z2)
     78                     return true;
     79                 if (z1 < z2)
     80                     return false;
     81             }
     82 
     83             // If the plugin does not have an explicit z-index it stacks behind the iframe.
     84             // This is for maintaining compatibility with IE.
     85             if (ro2->style()->position() == StaticPosition) {
     86                 // The 0'th elements of these RenderObject arrays represent the plugin node and
     87                 // the iframe.
     88                 const RenderObject* pluginRenderObject = pluginZstack[0];
     89                 const RenderObject* iframeRenderObject = iframeZstack[0];
     90 
     91                 if (pluginRenderObject->style() && iframeRenderObject->style()) {
     92                     if (pluginRenderObject->style()->zIndex() > iframeRenderObject->style()->zIndex())
     93                         return false;
     94                 }
     95                 return true;
     96             }
     97 
     98             // Inspect the document order.  Later order means higher stacking.
     99             const RenderObject* parent = ro1->parent();
    100             if (!parent)
    101                 return false;
    102             ASSERT(parent == ro2->parent());
    103 
    104             for (const RenderObject* ro = parent->firstChild(); ro; ro = ro->nextSibling()) {
    105                 if (ro == ro1)
    106                     return false;
    107                 if (ro == ro2)
    108                     return true;
    109             }
    110             ASSERT(false); // We should have seen ro1 and ro2 by now.
    111             return false;
    112         }
    113     }
    114     return true;
    115 }
    116 
    117 // Return a set of rectangles that should not be overdrawn by the
    118 // plugin ("cutouts").  This helps implement the "iframe shim"
    119 // technique of overlaying a windowed plugin with content from the
    120 // page.  In a nutshell, iframe elements should occlude plugins when
    121 // they occur higher in the stacking order.
    122 void getPluginOcclusions(Element* element, Widget* parentWidget, const IntRect& frameRect, Vector<IntRect>& occlusions)
    123 {
    124     RenderObject* pluginNode = element->renderer();
    125     ASSERT(pluginNode);
    126     if (!pluginNode->style())
    127         return;
    128     Vector<const RenderObject*> pluginZstack;
    129     Vector<const RenderObject*> iframeZstack;
    130     getObjectStack(pluginNode, &pluginZstack);
    131 
    132     if (!parentWidget->isFrameView())
    133         return;
    134 
    135     FrameView* parentFrameView = toFrameView(parentWidget);
    136 
    137     const HashSet<RefPtr<Widget> >* children = parentFrameView->children();
    138     for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != children->end(); ++it) {
    139         // We only care about FrameView's because iframes show up as FrameViews.
    140         if (!(*it)->isFrameView())
    141             continue;
    142 
    143         const FrameView* frameView = toFrameView((*it).get());
    144         // Check to make sure we can get both the element and the RenderObject
    145         // for this FrameView, if we can't just move on to the next object.
    146         if (!frameView->frame() || !frameView->frame()->ownerElement()
    147             || !frameView->frame()->ownerElement()->renderer())
    148             continue;
    149 
    150         HTMLElement* element = frameView->frame()->ownerElement();
    151         RenderObject* iframeRenderer = element->renderer();
    152 
    153         if (element->hasTagName(HTMLNames::iframeTag)
    154             && iframeRenderer->absoluteBoundingBoxRectIgnoringTransforms().intersects(frameRect)
    155             && (!iframeRenderer->style() || iframeRenderer->style()->visibility() == VISIBLE)) {
    156             getObjectStack(iframeRenderer, &iframeZstack);
    157             if (iframeIsAbovePlugin(iframeZstack, pluginZstack)) {
    158                 IntPoint point = roundedIntPoint(iframeRenderer->localToAbsolute());
    159                 RenderBox* rbox = toRenderBox(iframeRenderer);
    160                 IntSize size(rbox->width(), rbox->height());
    161                 occlusions.append(IntRect(point, size));
    162             }
    163         }
    164     }
    165 }
    166 
    167 } // namespace WebCore
    168