2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2000 Simon Hausmann <hausmann@kde.org>
4 * (C) 2000 Stefan Schimanski (1Stein@gmx.de)
5 * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved.
6 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
26 #include "core/rendering/RenderPart.h"
28 #include "core/accessibility/AXObjectCache.h"
29 #include "core/frame/FrameView.h"
30 #include "core/frame/LocalFrame.h"
31 #include "core/html/HTMLFrameElementBase.h"
32 #include "core/paint/BoxPainter.h"
33 #include "core/plugins/PluginView.h"
34 #include "core/rendering/GraphicsContextAnnotator.h"
35 #include "core/rendering/HitTestResult.h"
36 #include "core/rendering/RenderLayer.h"
37 #include "core/rendering/RenderView.h"
38 #include "core/rendering/svg/RenderSVGRoot.h"
42 RenderPart::RenderPart(Element* element)
43 : RenderReplaced(element)
45 // Reference counting is used to prevent the part from being destroyed
46 // while inside the Widget code, which might not be able to handle that.
51 frameView()->addPart(this);
56 void RenderPart::deref()
58 if (--m_refCount <= 0)
63 void RenderPart::willBeDestroyed()
65 frameView()->removePart(this);
67 if (AXObjectCache* cache = document().existingAXObjectCache()) {
68 cache->childrenChanged(this->parent());
72 Element* element = toElement(node());
73 if (element && element->isFrameOwnerElement())
74 toHTMLFrameOwnerElement(element)->setWidget(nullptr);
76 RenderReplaced::willBeDestroyed();
79 void RenderPart::destroy()
81 #if ENABLE(ASSERT) && ENABLE(OILPAN)
82 ASSERT(!m_didCallDestroy);
83 m_didCallDestroy = true;
88 // In Oilpan, postDestroy doesn't delete |this|. So calling it here is safe
89 // though |this| will be referred in FrameView.
96 RenderPart::~RenderPart()
99 ASSERT(m_refCount <= 0);
103 Widget* RenderPart::widget() const
105 // Plugin widgets are stored in their DOM node. This includes HTMLAppletElement.
106 Element* element = toElement(node());
108 if (element && element->isFrameOwnerElement())
109 return toHTMLFrameOwnerElement(element)->ownedWidget();
114 LayerType RenderPart::layerTypeRequired() const
116 LayerType type = RenderReplaced::layerTypeRequired();
122 bool RenderPart::requiresAcceleratedCompositing() const
124 // There are two general cases in which we can return true. First, if this is a plugin
125 // renderer and the plugin has a layer, then we need a layer. Second, if this is
126 // a renderer with a contentDocument and that document needs a layer, then we need
128 if (widget() && widget()->isPluginView() && toPluginView(widget())->platformLayer())
131 if (!node() || !node()->isFrameOwnerElement())
134 HTMLFrameOwnerElement* element = toHTMLFrameOwnerElement(node());
135 if (element->contentFrame() && element->contentFrame()->remotePlatformLayer())
138 if (Document* contentDocument = element->contentDocument()) {
139 if (RenderView* view = contentDocument->renderView())
140 return view->usesCompositing();
146 bool RenderPart::needsPreferredWidthsRecalculation() const
148 if (RenderReplaced::needsPreferredWidthsRecalculation())
150 return embeddedContentBox();
153 bool RenderPart::nodeAtPointOverWidget(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
155 bool hadResult = result.innerNode();
156 bool inside = RenderReplaced::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action);
158 // Check to see if we are really over the widget itself (and not just in the border/padding area).
159 if ((inside || result.isRectBasedTest()) && !hadResult && result.innerNode() == node())
160 result.setIsOverWidget(contentBoxRect().contains(result.localPoint()));
164 bool RenderPart::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
166 if (!widget() || !widget()->isFrameView() || !request.allowsChildFrameContent())
167 return nodeAtPointOverWidget(request, result, locationInContainer, accumulatedOffset, action);
169 // FIXME: Until RemoteFrames use RemoteFrameViews, we need an explicit check here.
170 if (toFrameView(widget())->frame().isRemoteFrameTemporary())
171 return nodeAtPointOverWidget(request, result, locationInContainer, accumulatedOffset, action);
173 FrameView* childFrameView = toFrameView(widget());
174 RenderView* childRoot = childFrameView->renderView();
177 LayoutPoint adjustedLocation = accumulatedOffset + location();
178 LayoutPoint contentOffset = LayoutPoint(borderLeft() + paddingLeft(), borderTop() + paddingTop()) - childFrameView->scrollOffset();
179 HitTestLocation newHitTestLocation(locationInContainer, -adjustedLocation - contentOffset);
180 HitTestRequest newHitTestRequest(request.type() | HitTestRequest::ChildFrameHitTest);
181 HitTestResult childFrameResult(newHitTestLocation);
183 bool isInsideChildFrame = childRoot->hitTest(newHitTestRequest, newHitTestLocation, childFrameResult);
185 if (newHitTestLocation.isRectBasedTest())
186 result.append(childFrameResult);
187 else if (isInsideChildFrame)
188 result = childFrameResult;
190 if (isInsideChildFrame)
194 return nodeAtPointOverWidget(request, result, locationInContainer, accumulatedOffset, action);
197 CompositingReasons RenderPart::additionalCompositingReasons() const
199 if (requiresAcceleratedCompositing())
200 return CompositingReasonIFrame;
201 return CompositingReasonNone;
204 void RenderPart::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
206 RenderReplaced::styleDidChange(diff, oldStyle);
207 Widget* widget = this->widget();
212 if (style()->visibility() != VISIBLE) {
219 void RenderPart::layout()
221 ASSERT(needsLayout());
226 void RenderPart::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
228 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
230 if (!shouldPaint(paintInfo, paintOffset))
233 LayoutPoint adjustedPaintOffset = paintOffset + location();
235 if (hasBoxDecorationBackground() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection))
236 paintBoxDecorationBackground(paintInfo, adjustedPaintOffset);
238 if (paintInfo.phase == PaintPhaseMask) {
239 paintMask(paintInfo, adjustedPaintOffset);
243 if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->hasOutline())
244 paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, size()));
246 if (paintInfo.phase != PaintPhaseForeground)
249 if (style()->hasBorderRadius()) {
250 LayoutRect borderRect = LayoutRect(adjustedPaintOffset, size());
252 if (borderRect.isEmpty())
255 // Push a clip if we have a border radius, since we want to round the foreground content that gets painted.
256 paintInfo.context->save();
257 RoundedRect roundedInnerRect = style()->getRoundedInnerBorderFor(borderRect,
258 paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddingLeft() + borderLeft(), paddingRight() + borderRight(), true, true);
259 BoxPainter::clipRoundedInnerRect(paintInfo.context, borderRect, roundedInnerRect);
263 paintContents(paintInfo, paintOffset);
265 if (style()->hasBorderRadius())
266 paintInfo.context->restore();
268 // Paint a partially transparent wash over selected widgets.
269 if (isSelected() && !document().printing()) {
270 LayoutRect rect = localSelectionRect();
271 rect.moveBy(adjustedPaintOffset);
272 paintInfo.context->fillRect(pixelSnappedIntRect(rect), selectionBackgroundColor());
276 layer()->scrollableArea()->paintResizer(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect);
279 void RenderPart::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
281 LayoutPoint adjustedPaintOffset = paintOffset + location();
283 Widget* widget = this->widget();
284 RELEASE_ASSERT(widget);
286 // Tell the widget to paint now. This is the only time the widget is allowed
287 // to paint itself. That way it will composite properly with z-indexed layers.
288 IntPoint widgetLocation = widget->frameRect().location();
289 IntPoint paintLocation(roundToInt(adjustedPaintOffset.x() + borderLeft() + paddingLeft()),
290 roundToInt(adjustedPaintOffset.y() + borderTop() + paddingTop()));
291 IntRect paintRect = paintInfo.rect;
293 IntSize widgetPaintOffset = paintLocation - widgetLocation;
294 // When painting widgets into compositing layers, tx and ty are relative to the enclosing compositing layer,
295 // not the root. In this case, shift the CTM and adjust the paintRect to be root-relative to fix plug-in drawing.
296 if (!widgetPaintOffset.isZero()) {
297 paintInfo.context->translate(widgetPaintOffset.width(), widgetPaintOffset.height());
298 paintRect.move(-widgetPaintOffset);
300 widget->paint(paintInfo.context, paintRect);
302 if (!widgetPaintOffset.isZero())
303 paintInfo.context->translate(-widgetPaintOffset.width(), -widgetPaintOffset.height());
306 CursorDirective RenderPart::getCursor(const LayoutPoint& point, Cursor& cursor) const
308 if (widget() && widget()->isPluginView()) {
309 // A plug-in is responsible for setting the cursor when the pointer is over it.
310 return DoNotSetCursor;
312 return RenderReplaced::getCursor(point, cursor);
315 void RenderPart::updateOnWidgetChange()
317 Widget* widget = this->widget();
325 updateWidgetGeometry();
327 if (style()->visibility() != VISIBLE) {
331 // FIXME: Why do we issue a full paint invalidation in this case, but not the other?
332 setShouldDoFullPaintInvalidation();
336 void RenderPart::updateWidgetPosition()
338 Widget* widget = this->widget();
339 if (!widget || !node()) // Check the node in case destroy() has been called.
342 bool boundsChanged = updateWidgetGeometry();
344 // If the frame bounds got changed, or if view needs layout (possibly indicating
345 // content size is wrong) we have to do a layout to set the right widget size.
346 if (widget && widget->isFrameView()) {
347 FrameView* frameView = toFrameView(widget);
348 // Check the frame's page to make sure that the frame isn't in the process of being destroyed.
349 if ((boundsChanged || frameView->needsLayout()) && frameView->frame().page())
354 void RenderPart::widgetPositionsUpdated()
356 Widget* widget = this->widget();
359 widget->widgetPositionsUpdated();
362 bool RenderPart::updateWidgetGeometry()
364 Widget* widget = this->widget();
367 LayoutRect contentBox = contentBoxRect();
368 LayoutRect absoluteContentBox(localToAbsoluteQuad(FloatQuad(contentBox)).boundingBox());
369 if (widget->isFrameView()) {
370 contentBox.setLocation(absoluteContentBox.location());
371 return setWidgetGeometry(contentBox);
374 return setWidgetGeometry(absoluteContentBox);
377 // Widgets are always placed on integer boundaries, so rounding the size is actually
378 // the desired behavior. This function is here because it's otherwise seldom what we
379 // want to do with a LayoutRect.
380 static inline IntRect roundedIntRect(const LayoutRect& rect)
382 return IntRect(roundedIntPoint(rect.location()), roundedIntSize(rect.size()));
385 bool RenderPart::setWidgetGeometry(const LayoutRect& frame)
390 Widget* widget = this->widget();
393 IntRect newFrame = roundedIntRect(frame);
395 if (widget->frameRect() == newFrame)
398 RefPtrWillBeRawPtr<RenderPart> protector(this);
399 RefPtrWillBeRawPtr<Node> protectedNode(node());
400 widget->setFrameRect(newFrame);
401 return widget->frameRect().size() != newFrame.size();