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.
7 *
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.
12 *
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.
17 *
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.
22 *
23 */
24
25 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
26
27 #include "third_party/blink/public/common/features.h"
28 #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
29 #include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
30 #include "third_party/blink/renderer/core/frame/embedded_content_view.h"
31 #include "third_party/blink/renderer/core/frame/local_frame.h"
32 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
33 #include "third_party/blink/renderer/core/frame/remote_frame.h"
34 #include "third_party/blink/renderer/core/frame/remote_frame_view.h"
35 #include "third_party/blink/renderer/core/html/html_frame_element_base.h"
36 #include "third_party/blink/renderer/core/html/html_plugin_element.h"
37 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
38 #include "third_party/blink/renderer/core/layout/layout_analyzer.h"
39 #include "third_party/blink/renderer/core/layout/layout_view.h"
40 #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
41 #include "third_party/blink/renderer/core/paint/embedded_content_painter.h"
42 #include "third_party/blink/renderer/core/paint/paint_layer.h"
43
44 namespace blink {
45
LayoutEmbeddedContent(HTMLFrameOwnerElement * element)46 LayoutEmbeddedContent::LayoutEmbeddedContent(HTMLFrameOwnerElement* element)
47 : LayoutReplaced(element),
48 // Reference counting is used to prevent the part from being destroyed
49 // while inside the EmbeddedContentView code, which might not be able to
50 // handle that.
51 ref_count_(1) {
52 DCHECK(element);
53 SetInline(false);
54 }
55
Release()56 void LayoutEmbeddedContent::Release() {
57 NOT_DESTROYED();
58 if (--ref_count_ <= 0)
59 delete this;
60 }
61
WillBeDestroyed()62 void LayoutEmbeddedContent::WillBeDestroyed() {
63 NOT_DESTROYED();
64 if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache()) {
65 cache->ChildrenChanged(Parent());
66 cache->Remove(this);
67 }
68
69 if (auto* frame_owner = GetFrameOwnerElement())
70 frame_owner->SetEmbeddedContentView(nullptr);
71
72 LayoutReplaced::WillBeDestroyed();
73 }
74
DeleteThis()75 void LayoutEmbeddedContent::DeleteThis() {
76 NOT_DESTROYED();
77 // We call clearNode here because LayoutEmbeddedContent is ref counted. This
78 // call to destroy may not actually destroy the layout object. We can keep it
79 // around because of references from the LocalFrameView class. (The actual
80 // destruction of the class happens in PostDestroy() which is called from
81 // Release()).
82 //
83 // But, we've told the system we've destroyed the layoutObject, which happens
84 // when the DOM node is destroyed. So there is a good chance the DOM node this
85 // object points too is invalid, so we have to clear the node so we make sure
86 // we don't access it in the future.
87 ClearNode();
88 Release();
89 }
90
~LayoutEmbeddedContent()91 LayoutEmbeddedContent::~LayoutEmbeddedContent() {
92 DCHECK_LE(ref_count_, 0);
93 }
94
ChildFrameView() const95 FrameView* LayoutEmbeddedContent::ChildFrameView() const {
96 NOT_DESTROYED();
97 return DynamicTo<FrameView>(GetEmbeddedContentView());
98 }
99
ChildLayoutView() const100 LayoutView* LayoutEmbeddedContent::ChildLayoutView() const {
101 NOT_DESTROYED();
102 if (HTMLFrameOwnerElement* owner_element = GetFrameOwnerElement()) {
103 if (Document* content_document = owner_element->contentDocument())
104 return content_document->GetLayoutView();
105 }
106 return nullptr;
107 }
108
Plugin() const109 WebPluginContainerImpl* LayoutEmbeddedContent::Plugin() const {
110 NOT_DESTROYED();
111 EmbeddedContentView* embedded_content_view = GetEmbeddedContentView();
112 if (embedded_content_view && embedded_content_view->IsPluginView())
113 return To<WebPluginContainerImpl>(embedded_content_view);
114 return nullptr;
115 }
116
GetEmbeddedContentView() const117 EmbeddedContentView* LayoutEmbeddedContent::GetEmbeddedContentView() const {
118 NOT_DESTROYED();
119 if (auto* frame_owner = GetFrameOwnerElement())
120 return frame_owner->OwnedEmbeddedContentView();
121 return nullptr;
122 }
123
LayerTypeRequired() const124 PaintLayerType LayoutEmbeddedContent::LayerTypeRequired() const {
125 NOT_DESTROYED();
126 if (AdditionalCompositingReasons())
127 return kNormalPaintLayer;
128
129 PaintLayerType type = LayoutReplaced::LayerTypeRequired();
130 if (type != kNoPaintLayer)
131 return type;
132
133 // We can't check layout_view->Layer()->GetCompositingReasons() here because
134 // we're only in style update, so haven't run compositing update yet.
135 if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
136 if (LayoutView* child_layout_view = ChildLayoutView()) {
137 if (child_layout_view->AdditionalCompositingReasons())
138 return kNormalPaintLayer;
139 }
140 }
141
142 return kForcedPaintLayer;
143 }
144
ContentDocumentIsCompositing() const145 bool LayoutEmbeddedContent::ContentDocumentIsCompositing() const {
146 NOT_DESTROYED();
147 if (PaintLayerCompositor* inner_compositor =
148 PaintLayerCompositor::FrameContentsCompositor(*this)) {
149 return inner_compositor->StaleInCompositingMode();
150 }
151 return false;
152 }
153
NodeAtPointOverEmbeddedContentView(HitTestResult & result,const HitTestLocation & hit_test_location,const PhysicalOffset & accumulated_offset,HitTestAction action)154 bool LayoutEmbeddedContent::NodeAtPointOverEmbeddedContentView(
155 HitTestResult& result,
156 const HitTestLocation& hit_test_location,
157 const PhysicalOffset& accumulated_offset,
158 HitTestAction action) {
159 NOT_DESTROYED();
160 bool had_result = result.InnerNode();
161 bool inside = LayoutReplaced::NodeAtPoint(result, hit_test_location,
162 accumulated_offset, action);
163
164 // Check to see if we are really over the EmbeddedContentView itself (and not
165 // just in the border/padding area).
166 if ((inside || hit_test_location.IsRectBasedTest()) && !had_result &&
167 result.InnerNode() == GetNode()) {
168 result.SetIsOverEmbeddedContentView(
169 PhysicalContentBoxRect().Contains(result.LocalPoint()));
170 }
171 return inside;
172 }
173
NodeAtPoint(HitTestResult & result,const HitTestLocation & hit_test_location,const PhysicalOffset & accumulated_offset,HitTestAction action)174 bool LayoutEmbeddedContent::NodeAtPoint(
175 HitTestResult& result,
176 const HitTestLocation& hit_test_location,
177 const PhysicalOffset& accumulated_offset,
178 HitTestAction action) {
179 NOT_DESTROYED();
180 auto* local_frame_view = DynamicTo<LocalFrameView>(ChildFrameView());
181 bool skip_contents = (result.GetHitTestRequest().GetStopNode() == this ||
182 !result.GetHitTestRequest().AllowsChildFrameContent());
183 if (!local_frame_view || skip_contents) {
184 return NodeAtPointOverEmbeddedContentView(result, hit_test_location,
185 accumulated_offset, action);
186 }
187
188 // A hit test can never hit an off-screen element; only off-screen iframes are
189 // throttled; therefore, hit tests can skip descending into throttled iframes.
190 // We also check the document lifecycle state because the frame may have been
191 // throttled at the time lifecycle updates happened, in which case it will not
192 // be up-to-date and we can't hit test it.
193 if (local_frame_view->ShouldThrottleRendering() ||
194 !local_frame_view->GetFrame().GetDocument() ||
195 local_frame_view->GetFrame().GetDocument()->Lifecycle().GetState() <
196 DocumentLifecycle::kPrePaintClean) {
197 return NodeAtPointOverEmbeddedContentView(result, hit_test_location,
198 accumulated_offset, action);
199 }
200
201 DCHECK_GE(GetDocument().Lifecycle().GetState(),
202 DocumentLifecycle::kPrePaintClean);
203
204 if (action == kHitTestForeground) {
205 auto* child_layout_view = local_frame_view->GetLayoutView();
206
207 if (VisibleToHitTestRequest(result.GetHitTestRequest()) &&
208 child_layout_view) {
209 PhysicalOffset content_offset(BorderLeft() + PaddingLeft(),
210 BorderTop() + PaddingTop());
211 HitTestLocation new_hit_test_location(
212 hit_test_location, -accumulated_offset - content_offset);
213 HitTestRequest new_hit_test_request(
214 result.GetHitTestRequest().GetType() |
215 HitTestRequest::kChildFrameHitTest,
216 result.GetHitTestRequest().GetStopNode());
217 HitTestResult child_frame_result(new_hit_test_request,
218 new_hit_test_location);
219 child_frame_result.SetInertNode(result.InertNode());
220
221 // The frame's layout and style must be up to date if we reach here.
222 bool is_inside_child_frame = child_layout_view->HitTestNoLifecycleUpdate(
223 new_hit_test_location, child_frame_result);
224
225 if (result.GetHitTestRequest().ListBased()) {
226 result.Append(child_frame_result);
227 } else if (is_inside_child_frame) {
228 // Force the result not to be cacheable because the parent frame should
229 // not cache this result; as it won't be notified of changes in the
230 // child.
231 child_frame_result.SetCacheable(false);
232 result = child_frame_result;
233 }
234
235 // Don't trust |isInsideChildFrame|. For rect-based hit-test, returns
236 // true only when the hit test rect is totally within the iframe,
237 // i.e. nodeAtPointOverEmbeddedContentView() also returns true.
238 // Use a temporary HitTestResult because we don't want to collect the
239 // iframe element itself if the hit-test rect is totally within the
240 // iframe.
241 if (is_inside_child_frame) {
242 if (!hit_test_location.IsRectBasedTest())
243 return true;
244 HitTestResult point_over_embedded_content_view_result = result;
245 bool point_over_embedded_content_view =
246 NodeAtPointOverEmbeddedContentView(
247 point_over_embedded_content_view_result, hit_test_location,
248 accumulated_offset, action);
249 if (point_over_embedded_content_view)
250 return true;
251 result = point_over_embedded_content_view_result;
252 return false;
253 }
254 }
255 }
256
257 return NodeAtPointOverEmbeddedContentView(result, hit_test_location,
258 accumulated_offset, action);
259 }
260
AdditionalCompositingReasons() const261 CompositingReasons LayoutEmbeddedContent::AdditionalCompositingReasons() const {
262 NOT_DESTROYED();
263 WebPluginContainerImpl* plugin_view = Plugin();
264 if (plugin_view && plugin_view->CcLayer())
265 return CompositingReason::kPlugin;
266 if (auto* element = GetFrameOwnerElement()) {
267 if (Frame* content_frame = element->ContentFrame()) {
268 if (content_frame->IsRemoteFrame())
269 return CompositingReason::kIFrame;
270 }
271 }
272 return CompositingReason::kNone;
273 }
274
StyleDidChange(StyleDifference diff,const ComputedStyle * old_style)275 void LayoutEmbeddedContent::StyleDidChange(StyleDifference diff,
276 const ComputedStyle* old_style) {
277 NOT_DESTROYED();
278 LayoutReplaced::StyleDidChange(diff, old_style);
279
280 if (EmbeddedContentView* embedded_content_view = GetEmbeddedContentView()) {
281 if (StyleRef().Visibility() != EVisibility::kVisible) {
282 embedded_content_view->Hide();
283 } else {
284 embedded_content_view->Show();
285 }
286 }
287
288 if (old_style &&
289 StyleRef().VisibleToHitTesting() == old_style->VisibleToHitTesting()) {
290 return;
291 }
292
293 auto* frame_owner = GetFrameOwnerElement();
294 if (!frame_owner)
295 return;
296
297 auto* frame = frame_owner->ContentFrame();
298 if (!frame)
299 return;
300
301 frame->UpdateVisibleToHitTesting();
302 }
303
UpdateLayout()304 void LayoutEmbeddedContent::UpdateLayout() {
305 NOT_DESTROYED();
306 DCHECK(NeedsLayout());
307 LayoutAnalyzer::Scope analyzer(*this);
308 UpdateAfterLayout();
309 ClearNeedsLayout();
310 }
311
PaintReplaced(const PaintInfo & paint_info,const PhysicalOffset & paint_offset) const312 void LayoutEmbeddedContent::PaintReplaced(
313 const PaintInfo& paint_info,
314 const PhysicalOffset& paint_offset) const {
315 NOT_DESTROYED();
316 if (ChildPaintBlockedByDisplayLock())
317 return;
318 EmbeddedContentPainter(*this).PaintReplaced(paint_info, paint_offset);
319 }
320
InvalidatePaint(const PaintInvalidatorContext & context) const321 void LayoutEmbeddedContent::InvalidatePaint(
322 const PaintInvalidatorContext& context) const {
323 NOT_DESTROYED();
324 LayoutReplaced::InvalidatePaint(context);
325 if (auto* plugin = Plugin())
326 plugin->InvalidatePaint();
327 }
328
GetCursor(const PhysicalOffset & point,ui::Cursor & cursor) const329 CursorDirective LayoutEmbeddedContent::GetCursor(const PhysicalOffset& point,
330 ui::Cursor& cursor) const {
331 NOT_DESTROYED();
332 if (Plugin()) {
333 // A plugin is responsible for setting the cursor when the pointer is over
334 // it.
335 return kDoNotSetCursor;
336 }
337 return LayoutReplaced::GetCursor(point, cursor);
338 }
339
ReplacedContentRect() const340 PhysicalRect LayoutEmbeddedContent::ReplacedContentRect() const {
341 NOT_DESTROYED();
342 PhysicalRect content_rect = PhysicalContentBoxRect();
343 // IFrames set as the root scroller should get their size from their parent.
344 if (ChildFrameView() && View() && IsEffectiveRootScroller()) {
345 content_rect.offset = PhysicalOffset();
346 content_rect.size = View()->ViewRect().size;
347 }
348
349 // We don't propagate sub-pixel into sub-frame layout, in other words, the
350 // rect is snapped at the document boundary, and sub-pixel movement could
351 // cause the sub-frame to layout due to the 1px snap difference. In order to
352 // avoid that, the size of sub-frame is rounded in advance.
353 return PreSnappedRectForPersistentSizing(content_rect);
354 }
355
UpdateOnEmbeddedContentViewChange()356 void LayoutEmbeddedContent::UpdateOnEmbeddedContentViewChange() {
357 NOT_DESTROYED();
358 if (!Style())
359 return;
360
361 if (EmbeddedContentView* embedded_content_view = GetEmbeddedContentView()) {
362 if (!NeedsLayout())
363 UpdateGeometry(*embedded_content_view);
364
365 if (StyleRef().Visibility() != EVisibility::kVisible)
366 embedded_content_view->Hide();
367 else
368 embedded_content_view->Show();
369 }
370
371 // One of the reasons of the following is that the layout tree in the new
372 // embedded content view may have already had some paint property and paint
373 // invalidation flags set, and we need to propagate the flags into the host
374 // view. Adding, changing and removing are also significant changes to the
375 // tree so setting the flags ensures the required updates.
376 SetNeedsPaintPropertyUpdate();
377 SetShouldDoFullPaintInvalidation();
378 // Showing/hiding the embedded content view and changing the view between null
379 // and non-null affect compositing (see: PaintLayerCompositor::CanBeComposited
380 // and RootShouldAlwaysComposite).
381 if (HasLayer())
382 Layer()->SetNeedsCompositingInputsUpdate();
383 }
384
UpdateGeometry(EmbeddedContentView & embedded_content_view)385 void LayoutEmbeddedContent::UpdateGeometry(
386 EmbeddedContentView& embedded_content_view) {
387 NOT_DESTROYED();
388 // TODO(wangxianzhu): We reset subpixel accumulation at some boundaries, so
389 // the following code is incorrect when some ancestors are such boundaries.
390 // What about multicol? Need a LayoutBox function to query sub-pixel
391 // accumulation.
392 PhysicalRect replaced_rect = ReplacedContentRect();
393 TransformState transform_state(TransformState::kApplyTransformDirection,
394 FloatPoint(),
395 FloatQuad(FloatRect(replaced_rect)));
396 MapLocalToAncestor(nullptr, transform_state, 0);
397 transform_state.Flatten();
398 PhysicalOffset absolute_location =
399 PhysicalOffset::FromFloatPointRound(transform_state.LastPlanarPoint());
400 PhysicalRect absolute_replaced_rect = replaced_rect;
401 absolute_replaced_rect.Move(absolute_location);
402 FloatRect absolute_bounding_box =
403 transform_state.LastPlanarQuad().BoundingBox();
404 IntRect frame_rect(IntPoint(),
405 PixelSnappedIntRect(absolute_replaced_rect).Size());
406 // Normally the location of the frame rect is ignored by the painter, but
407 // currently it is still used by a family of coordinate conversion function in
408 // LocalFrameView. This is incorrect because coordinate conversion
409 // needs to take transform and into account. A few callers still use the
410 // family of conversion function, including but not exhaustive:
411 // LocalFrameView::updateViewportIntersectionIfNeeded()
412 // RemoteFrameView::frameRectsChanged().
413 // WebPluginContainerImpl::reportGeometry()
414 // TODO(trchen): Remove this hack once we fixed all callers.
415 frame_rect.SetLocation(RoundedIntPoint(absolute_bounding_box.Location()));
416
417 // As an optimization, we don't include the root layer's scroll offset in the
418 // frame rect. As a result, we don't need to recalculate the frame rect every
419 // time the root layer scrolls; however, each implementation of
420 // EmbeddedContentView::FrameRect() must add the root layer's scroll offset
421 // into its position.
422 // TODO(szager): Refactor this functionality into EmbeddedContentView, rather
423 // than reimplementing in each concrete subclass.
424 LayoutView* layout_view = View();
425 if (layout_view && layout_view->IsScrollContainer()) {
426 // Floored because the PixelSnappedScrollOffset returns a ScrollOffset
427 // which is a float-type but frame_rect in a content view is an IntRect. We
428 // may want to reevaluate the use of pixel snapping that since scroll
429 // offsets/layout can be fractional.
430 frame_rect.Move(
431 FlooredIntSize(layout_view->PixelSnappedScrolledContentOffset()));
432 }
433
434 embedded_content_view.SetFrameRect(frame_rect);
435 }
436
IsThrottledFrameView() const437 bool LayoutEmbeddedContent::IsThrottledFrameView() const {
438 NOT_DESTROYED();
439 if (auto* local_frame_view = DynamicTo<LocalFrameView>(ChildFrameView()))
440 return local_frame_view->ShouldThrottleRendering();
441 return false;
442 }
443
444 } // namespace blink
445