Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / rendering / RenderPart.cpp
index abd183a..56a0d2c 100644 (file)
 #include "config.h"
 #include "core/rendering/RenderPart.h"
 
+#include "core/accessibility/AXObjectCache.h"
 #include "core/frame/FrameView.h"
 #include "core/frame/LocalFrame.h"
 #include "core/html/HTMLFrameElementBase.h"
+#include "core/paint/BoxPainter.h"
 #include "core/plugins/PluginView.h"
+#include "core/rendering/GraphicsContextAnnotator.h"
 #include "core/rendering/HitTestResult.h"
 #include "core/rendering/RenderLayer.h"
 #include "core/rendering/RenderView.h"
 
 namespace blink {
 
-RenderPart::RenderPart(Element* node)
-    : RenderWidget(node)
+RenderPart::RenderPart(Element* element)
+    : RenderReplaced(element)
+#if !ENABLE(OILPAN)
+    // Reference counting is used to prevent the part from being destroyed
+    // while inside the Widget code, which might not be able to handle that.
+    , m_refCount(1)
+#endif
 {
+    ASSERT(element);
+    frameView()->addPart(this);
     setInline(false);
 }
 
+#if !ENABLE(OILPAN)
+void RenderPart::deref()
+{
+    if (--m_refCount <= 0)
+        postDestroy();
+}
+#endif
+
+void RenderPart::willBeDestroyed()
+{
+    frameView()->removePart(this);
+
+    if (AXObjectCache* cache = document().existingAXObjectCache()) {
+        cache->childrenChanged(this->parent());
+        cache->remove(this);
+    }
+
+    Element* element = toElement(node());
+    if (element && element->isFrameOwnerElement())
+        toHTMLFrameOwnerElement(element)->setWidget(nullptr);
+
+    RenderReplaced::willBeDestroyed();
+}
+
+void RenderPart::destroy()
+{
+#if ENABLE(ASSERT) && ENABLE(OILPAN)
+    ASSERT(!m_didCallDestroy);
+    m_didCallDestroy = true;
+#endif
+    willBeDestroyed();
+    clearNode();
+#if ENABLE(OILPAN)
+    // In Oilpan, postDestroy doesn't delete |this|. So calling it here is safe
+    // though |this| will be referred in FrameView.
+    postDestroy();
+#else
+    deref();
+#endif
+}
+
 RenderPart::~RenderPart()
 {
+#if !ENABLE(OILPAN)
+    ASSERT(m_refCount <= 0);
+#endif
+}
+
+Widget* RenderPart::widget() const
+{
+    // Plugin widgets are stored in their DOM node. This includes HTMLAppletElement.
+    Element* element = toElement(node());
+
+    if (element && element->isFrameOwnerElement())
+        return toHTMLFrameOwnerElement(element)->ownedWidget();
+
+    return 0;
 }
 
 LayerType RenderPart::layerTypeRequired() const
 {
-    LayerType type = RenderWidget::layerTypeRequired();
+    LayerType type = RenderReplaced::layerTypeRequired();
     if (type != NoLayer)
         return type;
     return ForcedLayer;
@@ -80,19 +145,30 @@ bool RenderPart::requiresAcceleratedCompositing() const
 
 bool RenderPart::needsPreferredWidthsRecalculation() const
 {
-    if (RenderWidget::needsPreferredWidthsRecalculation())
+    if (RenderReplaced::needsPreferredWidthsRecalculation())
         return true;
     return embeddedContentBox();
 }
 
+bool RenderPart::nodeAtPointOverWidget(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
+{
+    bool hadResult = result.innerNode();
+    bool inside = RenderReplaced::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action);
+
+    // Check to see if we are really over the widget itself (and not just in the border/padding area).
+    if ((inside || result.isRectBasedTest()) && !hadResult && result.innerNode() == node())
+        result.setIsOverWidget(contentBoxRect().contains(result.localPoint()));
+    return inside;
+}
+
 bool RenderPart::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
 {
     if (!widget() || !widget()->isFrameView() || !request.allowsChildFrameContent())
-        return RenderWidget::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action);
+        return nodeAtPointOverWidget(request, result, locationInContainer, accumulatedOffset, action);
 
     // FIXME: Until RemoteFrames use RemoteFrameViews, we need an explicit check here.
     if (toFrameView(widget())->frame().isRemoteFrameTemporary())
-        return RenderWidget::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action);
+        return nodeAtPointOverWidget(request, result, locationInContainer, accumulatedOffset, action);
 
     FrameView* childFrameView = toFrameView(widget());
     RenderView* childRoot = childFrameView->renderView();
@@ -115,7 +191,7 @@ bool RenderPart::nodeAtPoint(const HitTestRequest& request, HitTestResult& resul
             return true;
     }
 
-    return RenderWidget::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action);
+    return nodeAtPointOverWidget(request, result, locationInContainer, accumulatedOffset, action);
 }
 
 CompositingReasons RenderPart::additionalCompositingReasons() const
@@ -125,4 +201,204 @@ CompositingReasons RenderPart::additionalCompositingReasons() const
     return CompositingReasonNone;
 }
 
+void RenderPart::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+    RenderReplaced::styleDidChange(diff, oldStyle);
+    Widget* widget = this->widget();
+
+    if (!widget)
+        return;
+
+    if (style()->visibility() != VISIBLE) {
+        widget->hide();
+    } else {
+        widget->show();
+    }
+}
+
+void RenderPart::layout()
+{
+    ASSERT(needsLayout());
+
+    clearNeedsLayout();
+}
+
+void RenderPart::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
+{
+    ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
+
+    if (!shouldPaint(paintInfo, paintOffset))
+        return;
+
+    LayoutPoint adjustedPaintOffset = paintOffset + location();
+
+    if (hasBoxDecorationBackground() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection))
+        paintBoxDecorationBackground(paintInfo, adjustedPaintOffset);
+
+    if (paintInfo.phase == PaintPhaseMask) {
+        paintMask(paintInfo, adjustedPaintOffset);
+        return;
+    }
+
+    if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->hasOutline())
+        paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, size()));
+
+    if (paintInfo.phase != PaintPhaseForeground)
+        return;
+
+    if (style()->hasBorderRadius()) {
+        LayoutRect borderRect = LayoutRect(adjustedPaintOffset, size());
+
+        if (borderRect.isEmpty())
+            return;
+
+        // Push a clip if we have a border radius, since we want to round the foreground content that gets painted.
+        paintInfo.context->save();
+        RoundedRect roundedInnerRect = style()->getRoundedInnerBorderFor(borderRect,
+            paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddingLeft() + borderLeft(), paddingRight() + borderRight(), true, true);
+        BoxPainter::clipRoundedInnerRect(paintInfo.context, borderRect, roundedInnerRect);
+    }
+
+    if (this->widget())
+        paintContents(paintInfo, paintOffset);
+
+    if (style()->hasBorderRadius())
+        paintInfo.context->restore();
+
+    // Paint a partially transparent wash over selected widgets.
+    if (isSelected() && !document().printing()) {
+        LayoutRect rect = localSelectionRect();
+        rect.moveBy(adjustedPaintOffset);
+        paintInfo.context->fillRect(pixelSnappedIntRect(rect), selectionBackgroundColor());
+    }
+
+    if (canResize())
+        layer()->scrollableArea()->paintResizer(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect);
+}
+
+void RenderPart::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
+{
+    LayoutPoint adjustedPaintOffset = paintOffset + location();
+
+    Widget* widget = this->widget();
+    RELEASE_ASSERT(widget);
+
+    // Tell the widget to paint now. This is the only time the widget is allowed
+    // to paint itself. That way it will composite properly with z-indexed layers.
+    IntPoint widgetLocation = widget->frameRect().location();
+    IntPoint paintLocation(roundToInt(adjustedPaintOffset.x() + borderLeft() + paddingLeft()),
+        roundToInt(adjustedPaintOffset.y() + borderTop() + paddingTop()));
+    IntRect paintRect = paintInfo.rect;
+
+    IntSize widgetPaintOffset = paintLocation - widgetLocation;
+    // When painting widgets into compositing layers, tx and ty are relative to the enclosing compositing layer,
+    // not the root. In this case, shift the CTM and adjust the paintRect to be root-relative to fix plug-in drawing.
+    if (!widgetPaintOffset.isZero()) {
+        paintInfo.context->translate(widgetPaintOffset.width(), widgetPaintOffset.height());
+        paintRect.move(-widgetPaintOffset);
+    }
+    widget->paint(paintInfo.context, paintRect);
+
+    if (!widgetPaintOffset.isZero())
+        paintInfo.context->translate(-widgetPaintOffset.width(), -widgetPaintOffset.height());
+}
+
+CursorDirective RenderPart::getCursor(const LayoutPoint& point, Cursor& cursor) const
+{
+    if (widget() && widget()->isPluginView()) {
+        // A plug-in is responsible for setting the cursor when the pointer is over it.
+        return DoNotSetCursor;
+    }
+    return RenderReplaced::getCursor(point, cursor);
+}
+
+void RenderPart::updateOnWidgetChange()
+{
+    Widget* widget = this->widget();
+    if (!widget)
+        return;
+
+    if (!style())
+        return;
+
+    if (!needsLayout())
+        updateWidgetGeometry();
+
+    if (style()->visibility() != VISIBLE) {
+        widget->hide();
+    } else {
+        widget->show();
+        // FIXME: Why do we issue a full paint invalidation in this case, but not the other?
+        setShouldDoFullPaintInvalidation();
+    }
+}
+
+void RenderPart::updateWidgetPosition()
+{
+    Widget* widget = this->widget();
+    if (!widget || !node()) // Check the node in case destroy() has been called.
+        return;
+
+    bool boundsChanged = updateWidgetGeometry();
+
+    // If the frame bounds got changed, or if view needs layout (possibly indicating
+    // content size is wrong) we have to do a layout to set the right widget size.
+    if (widget && widget->isFrameView()) {
+        FrameView* frameView = toFrameView(widget);
+        // Check the frame's page to make sure that the frame isn't in the process of being destroyed.
+        if ((boundsChanged || frameView->needsLayout()) && frameView->frame().page())
+            frameView->layout();
+    }
+}
+
+void RenderPart::widgetPositionsUpdated()
+{
+    Widget* widget = this->widget();
+    if (!widget)
+        return;
+    widget->widgetPositionsUpdated();
+}
+
+bool RenderPart::updateWidgetGeometry()
+{
+    Widget* widget = this->widget();
+    ASSERT(widget);
+
+    LayoutRect contentBox = contentBoxRect();
+    LayoutRect absoluteContentBox(localToAbsoluteQuad(FloatQuad(contentBox)).boundingBox());
+    if (widget->isFrameView()) {
+        contentBox.setLocation(absoluteContentBox.location());
+        return setWidgetGeometry(contentBox);
+    }
+
+    return setWidgetGeometry(absoluteContentBox);
+}
+
+// Widgets are always placed on integer boundaries, so rounding the size is actually
+// the desired behavior. This function is here because it's otherwise seldom what we
+// want to do with a LayoutRect.
+static inline IntRect roundedIntRect(const LayoutRect& rect)
+{
+    return IntRect(roundedIntPoint(rect.location()), roundedIntSize(rect.size()));
+}
+
+bool RenderPart::setWidgetGeometry(const LayoutRect& frame)
+{
+    if (!node())
+        return false;
+
+    Widget* widget = this->widget();
+    ASSERT(widget);
+
+    IntRect newFrame = roundedIntRect(frame);
+
+    if (widget->frameRect() == newFrame)
+        return false;
+
+    RefPtrWillBeRawPtr<RenderPart> protector(this);
+    RefPtrWillBeRawPtr<Node> protectedNode(node());
+    widget->setFrameRect(newFrame);
+    return widget->frameRect().size() != newFrame.size();
+}
+
 }