Index: Source/core/rendering/RenderPart.cpp |
diff --git a/Source/core/rendering/RenderPart.cpp b/Source/core/rendering/RenderPart.cpp |
index abd183a3abd9d24b4585db3dccf857f43a2b067c..56a0d2c6aaa4f23b7380b3d04024442ebd20f221 100644 |
--- a/Source/core/rendering/RenderPart.cpp |
+++ b/Source/core/rendering/RenderPart.cpp |
@@ -25,10 +25,13 @@ |
#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" |
@@ -36,19 +39,81 @@ |
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(); |
+} |
+ |
} |