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/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"
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.
50 frameView()->addPart(this);
54 void LayoutPart::deref()
56 if (--m_refCount
<= 0)
60 void LayoutPart::willBeDestroyed()
62 frameView()->removePart(this);
64 if (AXObjectCache
* cache
= document().existingAXObjectCache()) {
65 cache
->childrenChanged(this->parent());
69 Element
* element
= toElement(node());
70 if (element
&& element
->isFrameOwnerElement())
71 toHTMLFrameOwnerElement(element
)->setWidget(nullptr);
73 LayoutReplaced::willBeDestroyed();
76 void LayoutPart::destroy()
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.
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();
108 DeprecatedPaintLayerType
LayoutPart::layerTypeRequired() const
110 DeprecatedPaintLayerType type
= LayoutReplaced::layerTypeRequired();
111 if (type
!= NoDeprecatedPaintLayer
)
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
122 if (widget() && widget()->isPluginView() && toPluginView(widget())->platformLayer())
125 if (!node() || !node()->isFrameOwnerElement())
128 HTMLFrameOwnerElement
* element
= toHTMLFrameOwnerElement(node());
129 if (element
->contentFrame() && element
->contentFrame()->isRemoteFrame())
132 if (Document
* contentDocument
= element
->contentDocument()) {
133 if (LayoutView
* view
= contentDocument
->layoutView())
134 return view
->usesCompositing();
140 bool LayoutPart::needsPreferredWidthsRecalculation() const
142 if (LayoutReplaced::needsPreferredWidthsRecalculation())
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()));
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())
195 HitTestResult pointOverWidgetResult
= result
;
196 bool pointOverWidget
= nodeAtPointOverWidget(pointOverWidgetResult
, locationInContainer
, accumulatedOffset
, action
);
199 result
= pointOverWidgetResult
;
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();
223 // If the iframe has custom scrollbars, recalculate their style.
224 if (widget
&& widget
->isFrameView())
225 toFrameView(widget
)->recalculateCustomScrollbarStyle();
227 if (style()->visibility() != VISIBLE
) {
234 void LayoutPart::layout()
236 ASSERT(needsLayout());
237 LayoutAnalyzer::Scope
analyzer(*this);
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();
270 updateWidgetGeometry();
272 if (style()->visibility() != VISIBLE
) {
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.
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())
299 void LayoutPart::widgetPositionsUpdated()
301 Widget
* widget
= this->widget();
304 widget
->widgetPositionsUpdated();
307 bool LayoutPart::updateWidgetGeometry()
309 Widget
* widget
= this->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
)
335 Widget
* widget
= this->widget();
338 IntRect newFrame
= roundedIntRect(frame
);
340 if (widget
->frameRect() == newFrame
)
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
);