Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / core / layout / LayoutPart.cpp
blob63243c8bff743a17d6374763d02e6a58bc72f440
1 /*
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.
25 #include "config.h"
26 #include "core/layout/LayoutPart.h"
28 #include "core/dom/AXObjectCache.h"
29 #include "core/frame/FrameView.h"
30 #include "core/frame/LocalFrame.h"
31 #include "core/html/HTMLFrameElementBase.h"
32 #include "core/layout/HitTestResult.h"
33 #include "core/layout/LayoutAnalyzer.h"
34 #include "core/layout/LayoutView.h"
35 #include "core/layout/svg/LayoutSVGRoot.h"
36 #include "core/paint/BoxPainter.h"
37 #include "core/paint/DeprecatedPaintLayer.h"
38 #include "core/paint/PartPainter.h"
39 #include "core/plugins/PluginView.h"
41 namespace blink {
43 LayoutPart::LayoutPart(Element* element)
44 : LayoutReplaced(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.
47 , m_refCount(1)
49 ASSERT(element);
50 frameView()->addPart(this);
51 setInline(false);
54 void LayoutPart::deref()
56 if (--m_refCount <= 0)
57 delete this;
60 void LayoutPart::willBeDestroyed()
62 frameView()->removePart(this);
64 if (AXObjectCache* cache = document().existingAXObjectCache()) {
65 cache->childrenChanged(this->parent());
66 cache->remove(this);
69 Element* element = toElement(node());
70 if (element && element->isFrameOwnerElement())
71 toHTMLFrameOwnerElement(element)->setWidget(nullptr);
73 LayoutReplaced::willBeDestroyed();
76 void LayoutPart::destroy()
78 willBeDestroyed();
79 // We call clearNode here because LayoutPart is ref counted. This call to destroy
80 // may not actually destroy the layout object. We can keep it around because of
81 // references from the FrameView class. (The actual destruction of the class happens
82 // in postDestroy() which is called from deref()).
84 // But, we've told the system we've destroyed the layoutObject, which happens when
85 // the DOM node is destroyed. So there is a good change the DOM node this object
86 // points too is invalid, so we have to clear the node so we make sure we don't
87 // access it in the future.
88 clearNode();
89 deref();
92 LayoutPart::~LayoutPart()
94 ASSERT(m_refCount <= 0);
97 Widget* LayoutPart::widget() const
99 // Plugin widgets are stored in their DOM node.
100 Element* element = toElement(node());
102 if (element && element->isFrameOwnerElement())
103 return toHTMLFrameOwnerElement(element)->ownedWidget();
105 return nullptr;
108 DeprecatedPaintLayerType LayoutPart::layerTypeRequired() const
110 DeprecatedPaintLayerType type = LayoutReplaced::layerTypeRequired();
111 if (type != NoDeprecatedPaintLayer)
112 return type;
113 return ForcedDeprecatedPaintLayer;
116 bool LayoutPart::requiresAcceleratedCompositing() const
118 // There are two general cases in which we can return true. First, if this is a plugin
119 // LayoutObject and the plugin has a layer, then we need a layer. Second, if this is
120 // a LayoutObject with a contentDocument and that document needs a layer, then we need
121 // a layer.
122 if (widget() && widget()->isPluginView() && toPluginView(widget())->platformLayer())
123 return true;
125 if (!node() || !node()->isFrameOwnerElement())
126 return false;
128 HTMLFrameOwnerElement* element = toHTMLFrameOwnerElement(node());
129 if (element->contentFrame() && element->contentFrame()->isRemoteFrame())
130 return true;
132 if (Document* contentDocument = element->contentDocument()) {
133 if (LayoutView* view = contentDocument->layoutView())
134 return view->usesCompositing();
137 return false;
140 bool LayoutPart::needsPreferredWidthsRecalculation() const
142 if (LayoutReplaced::needsPreferredWidthsRecalculation())
143 return true;
144 return embeddedContentBox();
147 bool LayoutPart::nodeAtPointOverWidget(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
149 bool hadResult = result.innerNode();
150 bool inside = LayoutReplaced::nodeAtPoint(result, locationInContainer, accumulatedOffset, action);
152 // Check to see if we are really over the widget itself (and not just in the border/padding area).
153 if ((inside || result.isRectBasedTest()) && !hadResult && result.innerNode() == node())
154 result.setIsOverWidget(contentBoxRect().contains(result.localPoint()));
155 return inside;
158 bool LayoutPart::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
160 if (!widget() || !widget()->isFrameView() || !result.hitTestRequest().allowsChildFrameContent())
161 return nodeAtPointOverWidget(result, locationInContainer, accumulatedOffset, action);
163 if (action == HitTestForeground) {
164 FrameView* childFrameView = toFrameView(widget());
165 LayoutView* childRoot = childFrameView->layoutView();
167 if (visibleToHitTestRequest(result.hitTestRequest()) && childRoot) {
168 LayoutPoint adjustedLocation = accumulatedOffset + location();
169 LayoutPoint contentOffset = LayoutPoint(borderLeft() + paddingLeft(), borderTop() + paddingTop()) - LayoutSize(childFrameView->scrollOffset());
170 HitTestLocation newHitTestLocation(locationInContainer, -adjustedLocation - contentOffset);
171 HitTestRequest newHitTestRequest(result.hitTestRequest().type() | HitTestRequest::ChildFrameHitTest);
172 HitTestResult childFrameResult(newHitTestRequest, newHitTestLocation);
174 // The frame's layout and style must be up-to-date if we reach here.
175 bool isInsideChildFrame = childRoot->hitTestNoLifecycleUpdate(childFrameResult);
177 if (result.hitTestRequest().listBased()) {
178 result.append(childFrameResult);
179 } else if (isInsideChildFrame) {
180 // Force the result not to be cacheable because the parent
181 // frame should not cache this result; as it won't be notified of
182 // changes in the child.
183 childFrameResult.setCacheable(false);
184 result = childFrameResult;
187 // Don't trust |isInsideChildFrame|. For rect-based hit-test, returns
188 // true only when the hit test rect is totally within the iframe,
189 // i.e. nodeAtPointOverWidget() also returns true.
190 // Use a temporary HitTestResult because we don't want to collect the
191 // iframe element itself if the hit-test rect is totally within the iframe.
192 if (isInsideChildFrame) {
193 if (!locationInContainer.isRectBasedTest())
194 return true;
195 HitTestResult pointOverWidgetResult = result;
196 bool pointOverWidget = nodeAtPointOverWidget(pointOverWidgetResult, locationInContainer, accumulatedOffset, action);
197 if (pointOverWidget)
198 return true;
199 result = pointOverWidgetResult;
200 return false;
205 return nodeAtPointOverWidget(result, locationInContainer, accumulatedOffset, action);
208 CompositingReasons LayoutPart::additionalCompositingReasons() const
210 if (requiresAcceleratedCompositing())
211 return CompositingReasonIFrame;
212 return CompositingReasonNone;
215 void LayoutPart::styleDidChange(StyleDifference diff, const ComputedStyle* oldStyle)
217 LayoutReplaced::styleDidChange(diff, oldStyle);
218 Widget* widget = this->widget();
220 if (!widget)
221 return;
223 // If the iframe has custom scrollbars, recalculate their style.
224 if (widget && widget->isFrameView())
225 toFrameView(widget)->recalculateCustomScrollbarStyle();
227 if (style()->visibility() != VISIBLE) {
228 widget->hide();
229 } else {
230 widget->show();
234 void LayoutPart::layout()
236 ASSERT(needsLayout());
237 LayoutAnalyzer::Scope analyzer(*this);
238 clearNeedsLayout();
241 void LayoutPart::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset)
243 PartPainter(*this).paint(paintInfo, paintOffset);
246 void LayoutPart::paintContents(const PaintInfo& paintInfo, const LayoutPoint& paintOffset)
248 PartPainter(*this).paintContents(paintInfo, paintOffset);
251 CursorDirective LayoutPart::getCursor(const LayoutPoint& point, Cursor& cursor) const
253 if (widget() && widget()->isPluginView()) {
254 // A plugin is responsible for setting the cursor when the pointer is over it.
255 return DoNotSetCursor;
257 return LayoutReplaced::getCursor(point, cursor);
260 void LayoutPart::updateOnWidgetChange()
262 Widget* widget = this->widget();
263 if (!widget)
264 return;
266 if (!style())
267 return;
269 if (!needsLayout())
270 updateWidgetGeometry();
272 if (style()->visibility() != VISIBLE) {
273 widget->hide();
274 } else {
275 widget->show();
276 // FIXME: Why do we issue a full paint invalidation in this case, but not the other?
277 setShouldDoFullPaintInvalidation();
281 void LayoutPart::updateWidgetPosition()
283 Widget* widget = this->widget();
284 if (!widget || !node()) // Check the node in case destroy() has been called.
285 return;
287 bool boundsChanged = updateWidgetGeometry();
289 // If the frame bounds got changed, or if view needs layout (possibly indicating
290 // content size is wrong) we have to do a layout to set the right widget size.
291 if (widget && widget->isFrameView()) {
292 FrameView* frameView = toFrameView(widget);
293 // Check the frame's page to make sure that the frame isn't in the process of being destroyed.
294 if ((boundsChanged || frameView->needsLayout()) && frameView->frame().page())
295 frameView->layout();
299 void LayoutPart::widgetPositionsUpdated()
301 Widget* widget = this->widget();
302 if (!widget)
303 return;
304 widget->widgetPositionsUpdated();
307 bool LayoutPart::updateWidgetGeometry()
309 Widget* widget = this->widget();
310 ASSERT(widget);
312 LayoutRect contentBox = contentBoxRect();
313 LayoutRect absoluteContentBox(localToAbsoluteQuad(FloatQuad(FloatRect(contentBox))).boundingBox());
314 if (widget->isFrameView()) {
315 contentBox.setLocation(absoluteContentBox.location());
316 return setWidgetGeometry(contentBox);
319 return setWidgetGeometry(absoluteContentBox);
322 // Widgets are always placed on integer boundaries, so rounding the size is actually
323 // the desired behavior. This function is here because it's otherwise seldom what we
324 // want to do with a LayoutRect.
325 static inline IntRect roundedIntRect(const LayoutRect& rect)
327 return IntRect(roundedIntPoint(rect.location()), roundedIntSize(rect.size()));
330 bool LayoutPart::setWidgetGeometry(const LayoutRect& frame)
332 if (!node())
333 return false;
335 Widget* widget = this->widget();
336 ASSERT(widget);
338 IntRect newFrame = roundedIntRect(frame);
340 if (widget->frameRect() == newFrame)
341 return false;
343 RefPtr<LayoutPart> protector(this);
344 RefPtrWillBeRawPtr<Node> protectedNode(node());
345 widget->setFrameRect(newFrame);
346 return widget->frameRect().size() != newFrame.size();
349 void LayoutPart::invalidatePaintOfSubtreesIfNeeded(PaintInvalidationState& paintInvalidationState)
351 if (widget() && widget()->isFrameView()) {
352 FrameView* childFrameView = toFrameView(widget());
353 PaintInvalidationState childViewPaintInvalidationState(*childFrameView->layoutView(), paintInvalidationState);
354 toFrameView(widget())->invalidateTreeIfNeeded(childViewPaintInvalidationState);
357 LayoutReplaced::invalidatePaintOfSubtreesIfNeeded(paintInvalidationState);