Handle LocalFrame being nestedly detached by subframe.
[chromium-blink-merge.git] / third_party / WebKit / Source / core / frame / LocalFrame.cpp
blob35975f313b488a5891afda26cba9c194895d7d12
1 /*
2 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3 * 1999 Lars Knoll <knoll@kde.org>
4 * 1999 Antti Koivisto <koivisto@kde.org>
5 * 2000 Simon Hausmann <hausmann@kde.org>
6 * 2000 Stefan Schimanski <1Stein@gmx.de>
7 * 2001 George Staikos <staikos@kde.org>
8 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
9 * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com>
10 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
11 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
12 * Copyright (C) 2008 Google Inc.
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public License
25 * along with this library; see the file COPYING.LIB. If not, write to
26 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
30 #include "config.h"
31 #include "core/frame/LocalFrame.h"
33 #include "bindings/core/v8/ScriptController.h"
34 #include "core/dom/DocumentType.h"
35 #include "core/editing/EditingUtilities.h"
36 #include "core/editing/Editor.h"
37 #include "core/editing/FrameSelection.h"
38 #include "core/editing/InputMethodController.h"
39 #include "core/editing/serializers/Serialization.h"
40 #include "core/editing/spellcheck/SpellChecker.h"
41 #include "core/events/Event.h"
42 #include "core/fetch/ResourceFetcher.h"
43 #include "core/frame/EventHandlerRegistry.h"
44 #include "core/frame/FrameConsole.h"
45 #include "core/frame/FrameHost.h"
46 #include "core/frame/FrameView.h"
47 #include "core/frame/LocalDOMWindow.h"
48 #include "core/frame/Settings.h"
49 #include "core/html/HTMLFrameElementBase.h"
50 #include "core/html/HTMLPlugInElement.h"
51 #include "core/input/EventHandler.h"
52 #include "core/inspector/ConsoleMessageStorage.h"
53 #include "core/inspector/InspectorInstrumentation.h"
54 #include "core/inspector/InstrumentingAgents.h"
55 #include "core/layout/HitTestResult.h"
56 #include "core/layout/LayoutView.h"
57 #include "core/layout/compositing/DeprecatedPaintLayerCompositor.h"
58 #include "core/loader/FrameLoadRequest.h"
59 #include "core/loader/FrameLoaderClient.h"
60 #include "core/page/FocusController.h"
61 #include "core/page/Page.h"
62 #include "core/page/scrolling/ScrollingCoordinator.h"
63 #include "core/paint/DeprecatedPaintLayer.h"
64 #include "core/paint/TransformRecorder.h"
65 #include "core/svg/SVGDocumentExtensions.h"
66 #include "platform/DragImage.h"
67 #include "platform/PluginScriptForbiddenScope.h"
68 #include "platform/RuntimeEnabledFeatures.h"
69 #include "platform/ScriptForbiddenScope.h"
70 #include "platform/graphics/GraphicsContext.h"
71 #include "platform/graphics/StaticBitmapImage.h"
72 #include "platform/graphics/paint/ClipRecorder.h"
73 #include "platform/graphics/paint/SkPictureBuilder.h"
74 #include "platform/text/TextStream.h"
75 #include "third_party/skia/include/core/SkImage.h"
76 #include "wtf/PassOwnPtr.h"
77 #include "wtf/StdLibExtras.h"
79 namespace blink {
81 using namespace HTMLNames;
83 namespace {
85 struct ScopedFramePaintingState {
86 STACK_ALLOCATED();
87 public:
88 ScopedFramePaintingState(LocalFrame* frame, Node* node)
89 : frame(frame)
90 , node(node)
92 ASSERT(!node || node->layoutObject());
93 if (node)
94 node->layoutObject()->updateDragState(true);
97 ~ScopedFramePaintingState()
99 if (node && node->layoutObject())
100 node->layoutObject()->updateDragState(false);
101 frame->view()->setNodeToDraw(0);
104 RawPtrWillBeMember<LocalFrame> frame;
105 RawPtrWillBeMember<Node> node;
108 inline float parentPageZoomFactor(LocalFrame* frame)
110 Frame* parent = frame->tree().parent();
111 if (!parent || !parent->isLocalFrame())
112 return 1;
113 return toLocalFrame(parent)->pageZoomFactor();
116 inline float parentTextZoomFactor(LocalFrame* frame)
118 Frame* parent = frame->tree().parent();
119 if (!parent || !parent->isLocalFrame())
120 return 1;
121 return toLocalFrame(parent)->textZoomFactor();
124 } // namespace
126 PassRefPtrWillBeRawPtr<LocalFrame> LocalFrame::create(FrameLoaderClient* client, FrameHost* host, FrameOwner* owner)
128 RefPtrWillBeRawPtr<LocalFrame> frame = adoptRefWillBeNoop(new LocalFrame(client, host, owner));
129 InspectorInstrumentation::frameAttachedToParent(frame.get());
130 return frame.release();
133 void LocalFrame::setView(PassRefPtrWillBeRawPtr<FrameView> view)
135 ASSERT(!m_view || m_view != view);
136 ASSERT(!document() || !document()->isActive());
138 eventHandler().clear();
140 m_view = view;
143 void LocalFrame::createView(const IntSize& viewportSize, const Color& backgroundColor, bool transparent,
144 ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
145 ScrollbarMode verticalScrollbarMode, bool verticalLock)
147 ASSERT(this);
148 ASSERT(page());
150 bool isLocalRoot = this->isLocalRoot();
152 if (isLocalRoot && view())
153 view()->setParentVisible(false);
155 setView(nullptr);
157 RefPtrWillBeRawPtr<FrameView> frameView = nullptr;
158 if (isLocalRoot) {
159 frameView = FrameView::create(this, viewportSize);
161 // The layout size is set by WebViewImpl to support @viewport
162 frameView->setLayoutSizeFixedToFrameSize(false);
163 } else {
164 frameView = FrameView::create(this);
167 frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
169 setView(frameView);
171 frameView->updateBackgroundRecursively(backgroundColor, transparent);
173 if (isLocalRoot)
174 frameView->setParentVisible(true);
176 // FIXME: Not clear what the right thing for OOPI is here.
177 if (ownerLayoutObject()) {
178 HTMLFrameOwnerElement* owner = deprecatedLocalOwner();
179 ASSERT(owner);
180 // FIXME: OOPI might lead to us temporarily lying to a frame and telling it
181 // that it's owned by a FrameOwner that knows nothing about it. If we're
182 // lying to this frame, don't let it clobber the existing widget.
183 if (owner->contentFrame() == this)
184 owner->setWidget(frameView);
187 if (HTMLFrameOwnerElement* owner = deprecatedLocalOwner())
188 view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
191 LocalFrame::~LocalFrame()
193 // Verify that the FrameView has been cleared as part of detaching
194 // the frame owner.
195 ASSERT(!m_view);
196 #if !ENABLE(OILPAN)
197 // Oilpan: see setDOMWindow() comment why it is acceptable not to
198 // explicitly call setDOMWindow() here.
199 setDOMWindow(nullptr);
200 #endif
203 DEFINE_TRACE(LocalFrame)
205 visitor->trace(m_instrumentingAgents);
206 #if ENABLE(OILPAN)
207 visitor->trace(m_loader);
208 visitor->trace(m_navigationScheduler);
209 visitor->trace(m_view);
210 visitor->trace(m_domWindow);
211 visitor->trace(m_pagePopupOwner);
212 visitor->trace(m_script);
213 visitor->trace(m_editor);
214 visitor->trace(m_spellChecker);
215 visitor->trace(m_selection);
216 visitor->trace(m_eventHandler);
217 visitor->trace(m_console);
218 visitor->trace(m_inputMethodController);
219 visitor->template registerWeakMembers<LocalFrame, &LocalFrame::clearWeakMembers>(this);
220 HeapSupplementable<LocalFrame>::trace(visitor);
221 #endif
222 LocalFrameLifecycleNotifier::trace(visitor);
223 Frame::trace(visitor);
226 DOMWindow* LocalFrame::domWindow() const
228 return m_domWindow.get();
231 WindowProxy* LocalFrame::windowProxy(DOMWrapperWorld& world)
233 return m_script->windowProxy(world);
236 void LocalFrame::navigate(Document& originDocument, const KURL& url, bool replaceCurrentItem, UserGestureStatus userGestureStatus)
238 // TODO(dcheng): Special case for window.open("about:blank") to ensure it loads synchronously into
239 // a new window. This is our historical behavior, and it's consistent with the creation of
240 // a new iframe with src="about:blank". Perhaps we could get rid of this if we started reporting
241 // the initial empty document's url as about:blank? See crbug.com/471239.
242 // TODO(japhet): This special case is also necessary for behavior asserted by some extensions tests.
243 // Using NavigationScheduler::scheduleNavigationChange causes the navigation to be flagged as a
244 // client redirect, which is observable via the webNavigation extension api.
245 if (isMainFrame() && !m_loader.stateMachine()->committedFirstRealDocumentLoad()) {
246 FrameLoadRequest request(&originDocument, url);
247 request.resourceRequest().setHasUserGesture(userGestureStatus == UserGestureStatus::Active);
248 m_loader.load(request);
249 } else {
250 m_navigationScheduler.scheduleLocationChange(&originDocument, url.string(), replaceCurrentItem);
254 void LocalFrame::navigate(const FrameLoadRequest& request)
256 m_loader.load(request);
259 void LocalFrame::reload(FrameLoadType loadType, ClientRedirectPolicy clientRedirectPolicy)
261 ASSERT(loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadFromOrigin);
262 ASSERT(clientRedirectPolicy == NotClientRedirect || loadType == FrameLoadTypeReload);
263 if (clientRedirectPolicy == NotClientRedirect) {
264 if (!m_loader.currentItem())
265 return;
266 FrameLoadRequest request = FrameLoadRequest(
267 nullptr, m_loader.resourceRequestForReload(loadType, KURL(), clientRedirectPolicy));
268 request.setClientRedirect(clientRedirectPolicy);
269 m_loader.load(request, loadType);
270 } else {
271 m_navigationScheduler.scheduleReload();
275 void LocalFrame::detach(FrameDetachType type)
277 PluginScriptForbiddenScope forbidPluginDestructorScripting;
278 // A lot of the following steps can result in the current frame being
279 // detached, so protect a reference to it.
280 RefPtrWillBeRawPtr<LocalFrame> protect(this);
281 m_loader.stopAllLoaders();
282 m_loader.dispatchUnloadEvent();
283 detachChildren();
285 // All done if detaching the subframes brought about a detach of this frame also.
286 if (!client())
287 return;
289 // stopAllLoaders() needs to be called after detachChildren(), because detachChildren()
290 // will trigger the unload event handlers of any child frames, and those event
291 // handlers might start a new subresource load in this frame.
292 m_loader.stopAllLoaders();
293 m_loader.detach();
294 document()->detach();
295 m_loader.clear();
296 if (!client())
297 return;
299 client()->willBeDetached();
300 // Notify ScriptController that the frame is closing, since its cleanup ends up calling
301 // back to FrameLoaderClient via WindowProxy.
302 script().clearForClose();
303 ScriptForbiddenScope forbidScript;
304 setView(nullptr);
305 willDetachFrameHost();
306 InspectorInstrumentation::frameDetachedFromParent(this);
307 Frame::detach(type);
309 // Signal frame destruction here rather than in the destructor.
310 // Main motivation is to avoid being dependent on its exact timing (Oilpan.)
311 LocalFrameLifecycleNotifier::notifyContextDestroyed();
312 m_supplements.clear();
313 WeakIdentifierMap<LocalFrame>::notifyObjectDestroyed(this);
316 bool LocalFrame::prepareForCommit()
318 return loader().prepareForCommit();
321 SecurityContext* LocalFrame::securityContext() const
323 return document();
326 void LocalFrame::printNavigationErrorMessage(const Frame& targetFrame, const char* reason)
328 // URLs aren't available for RemoteFrames, so the error message uses their
329 // origin instead.
330 String targetFrameDescription = targetFrame.isLocalFrame() ? "with URL '" + toLocalFrame(targetFrame).document()->url().string() + "'" : "with origin '" + targetFrame.securityContext()->securityOrigin()->toString() + "'";
331 String message = "Unsafe JavaScript attempt to initiate navigation for frame " + targetFrameDescription + " from frame with URL '" + document()->url().string() + "'. " + reason + "\n";
333 localDOMWindow()->printErrorMessage(message);
336 WindowProxyManager* LocalFrame::windowProxyManager() const
338 return m_script->windowProxyManager();
341 void LocalFrame::disconnectOwnerElement()
343 if (owner()) {
344 if (Document* document = this->document())
345 document->topDocument().clearAXObjectCache();
346 #if ENABLE(OILPAN)
347 // First give the plugin elements holding persisted,
348 // renderer-less plugins the opportunity to dispose of them.
349 for (const auto& pluginElement : m_pluginElements)
350 pluginElement->disconnectContentFrame();
351 m_pluginElements.clear();
352 #endif
354 Frame::disconnectOwnerElement();
357 bool LocalFrame::shouldClose()
359 // TODO(dcheng): This should be fixed to dispatch beforeunload events to
360 // both local and remote frames.
361 return m_loader.shouldClose();
364 void LocalFrame::willDetachFrameHost()
366 LocalFrameLifecycleNotifier::notifyWillDetachFrameHost();
368 // FIXME: Page should take care of updating focus/scrolling instead of Frame.
369 // FIXME: It's unclear as to why this is called more than once, but it is,
370 // so page() could be null.
371 if (page() && page()->focusController().focusedFrame() == this)
372 page()->focusController().setFocusedFrame(nullptr);
373 script().clearScriptObjects();
375 if (page() && page()->scrollingCoordinator() && m_view)
376 page()->scrollingCoordinator()->willDestroyScrollableArea(m_view.get());
379 void LocalFrame::setDOMWindow(PassRefPtrWillBeRawPtr<LocalDOMWindow> domWindow)
381 // Oilpan: setDOMWindow() cannot be used when finalizing. Which
382 // is acceptable as its actions are either not needed or handled
383 // by other means --
385 // - LocalFrameLifecycleObserver::willDetachFrameHost() will have
386 // signalled the Inspector frameWindowDiscarded() notifications.
387 // We assume that all LocalFrames are detached, where that notification
388 // will have been done.
390 // - Calling LocalDOMWindow::reset() is not needed (called from
391 // Frame::setDOMWindow().) The Member references it clears will now
392 // die with the window. And the registered DOMWindowProperty instances that don't,
393 // only keep a weak reference to this frame, so there's no need to be
394 // explicitly notified that this frame is going away.
395 if (m_domWindow && host())
396 host()->consoleMessageStorage().frameWindowDiscarded(m_domWindow.get());
397 if (domWindow)
398 script().clearWindowProxy();
400 if (m_domWindow)
401 m_domWindow->reset();
402 m_domWindow = domWindow;
405 Document* LocalFrame::document() const
407 return m_domWindow ? m_domWindow->document() : nullptr;
410 void LocalFrame::setPagePopupOwner(Element& owner)
412 m_pagePopupOwner = &owner;
415 LayoutView* LocalFrame::contentLayoutObject() const
417 return document() ? document()->layoutView() : nullptr;
420 void LocalFrame::didChangeVisibilityState()
422 if (document())
423 document()->didChangeVisibilityState();
425 WillBeHeapVector<RefPtrWillBeMember<LocalFrame>> childFrames;
426 for (Frame* child = tree().firstChild(); child; child = child->tree().nextSibling()) {
427 if (child->isLocalFrame())
428 childFrames.append(toLocalFrame(child));
431 for (size_t i = 0; i < childFrames.size(); ++i)
432 childFrames[i]->didChangeVisibilityState();
435 LocalFrame* LocalFrame::localFrameRoot()
437 LocalFrame* curFrame = this;
438 while (curFrame && curFrame->tree().parent() && curFrame->tree().parent()->isLocalFrame())
439 curFrame = toLocalFrame(curFrame->tree().parent());
441 return curFrame;
444 String LocalFrame::layerTreeAsText(LayerTreeFlags flags) const
446 TextStream textStream;
447 textStream << localLayerTreeAsText(flags);
449 for (Frame* child = tree().firstChild(); child; child = child->tree().traverseNext(this)) {
450 if (!child->isLocalFrame())
451 continue;
452 String childLayerTree = toLocalFrame(child)->localLayerTreeAsText(flags);
453 if (!childLayerTree.length())
454 continue;
456 textStream << "\n\n--------\nFrame: '";
457 textStream << child->tree().uniqueName();
458 textStream << "'\n--------\n";
459 textStream << childLayerTree;
462 return textStream.release();
465 void LocalFrame::setPrinting(bool printing, const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkRatio)
467 // In setting printing, we should not validate resources already cached for the document.
468 // See https://bugs.webkit.org/show_bug.cgi?id=43704
469 ResourceCacheValidationSuppressor validationSuppressor(document()->fetcher());
471 document()->setPrinting(printing);
472 view()->adjustMediaTypeForPrinting(printing);
474 document()->styleResolverChanged();
475 if (shouldUsePrintingLayout()) {
476 view()->forceLayoutForPagination(pageSize, originalPageSize, maximumShrinkRatio);
477 } else {
478 if (LayoutView* layoutView = view()->layoutView()) {
479 layoutView->setPreferredLogicalWidthsDirty();
480 layoutView->setNeedsLayout(LayoutInvalidationReason::PrintingChanged);
481 layoutView->setShouldDoFullPaintInvalidationForViewAndAllDescendants();
483 view()->layout();
484 view()->adjustViewSize();
487 // Subframes of the one we're printing don't lay out to the page size.
488 for (RefPtrWillBeRawPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling()) {
489 if (child->isLocalFrame())
490 toLocalFrame(child.get())->setPrinting(printing, FloatSize(), FloatSize(), 0);
494 bool LocalFrame::shouldUsePrintingLayout() const
496 // Only top frame being printed should be fit to page size.
497 // Subframes should be constrained by parents only.
498 return document()->printing() && (!tree().parent() || !tree().parent()->isLocalFrame() || !toLocalFrame(tree().parent())->document()->printing());
501 FloatSize LocalFrame::resizePageRectsKeepingRatio(const FloatSize& originalSize, const FloatSize& expectedSize)
503 FloatSize resultSize;
504 if (!contentLayoutObject())
505 return FloatSize();
507 if (contentLayoutObject()->style()->isHorizontalWritingMode()) {
508 ASSERT(fabs(originalSize.width()) > std::numeric_limits<float>::epsilon());
509 float ratio = originalSize.height() / originalSize.width();
510 resultSize.setWidth(floorf(expectedSize.width()));
511 resultSize.setHeight(floorf(resultSize.width() * ratio));
512 } else {
513 ASSERT(fabs(originalSize.height()) > std::numeric_limits<float>::epsilon());
514 float ratio = originalSize.width() / originalSize.height();
515 resultSize.setHeight(floorf(expectedSize.height()));
516 resultSize.setWidth(floorf(resultSize.height() * ratio));
518 return resultSize;
521 void LocalFrame::setPageZoomFactor(float factor)
523 setPageAndTextZoomFactors(factor, m_textZoomFactor);
526 void LocalFrame::setTextZoomFactor(float factor)
528 setPageAndTextZoomFactors(m_pageZoomFactor, factor);
531 void LocalFrame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
533 if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
534 return;
536 Page* page = this->page();
537 if (!page)
538 return;
540 Document* document = this->document();
541 if (!document)
542 return;
544 // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
545 // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
546 if (document->isSVGDocument()) {
547 if (!document->accessSVGExtensions().zoomAndPanEnabled())
548 return;
551 if (m_pageZoomFactor != pageZoomFactor) {
552 if (FrameView* view = this->view()) {
553 // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
554 LayoutPoint scrollPosition = view->scrollPosition();
555 float percentDifference = (pageZoomFactor / m_pageZoomFactor);
556 view->setScrollPosition(
557 DoublePoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference),
558 ProgrammaticScroll);
562 m_pageZoomFactor = pageZoomFactor;
563 m_textZoomFactor = textZoomFactor;
565 for (RefPtrWillBeRawPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling()) {
566 if (child->isLocalFrame())
567 toLocalFrame(child.get())->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
570 document->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::Zoom));
571 document->updateLayoutIgnorePendingStylesheets();
574 void LocalFrame::deviceScaleFactorChanged()
576 document()->mediaQueryAffectingValueChanged();
577 for (RefPtrWillBeRawPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling()) {
578 if (child->isLocalFrame())
579 toLocalFrame(child.get())->deviceScaleFactorChanged();
583 double LocalFrame::devicePixelRatio() const
585 if (!m_host)
586 return 0;
588 double ratio = m_host->deviceScaleFactor();
589 ratio *= pageZoomFactor();
590 return ratio;
593 PassOwnPtr<DragImage> LocalFrame::paintIntoDragImage(
594 const DisplayItemClientWrapper& displayItemClient,
595 RespectImageOrientationEnum shouldRespectImageOrientation,
596 const GlobalPaintFlags globalPaintFlags, IntRect paintingRect, float opacity)
598 ASSERT(document()->isActive());
599 // Not flattening compositing layers will result in a broken image being painted.
600 ASSERT(globalPaintFlags & GlobalPaintFlattenCompositingLayers);
602 float deviceScaleFactor = m_host->deviceScaleFactor();
603 paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
604 paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
606 // The content is shifted to origin, to fit within the image bounds - which are the same
607 // as the picture bounds.
608 SkRect pictureBounds = SkRect::MakeIWH(paintingRect.width(), paintingRect.height());
609 SkPictureBuilder pictureBuilder(pictureBounds);
611 GraphicsContext& paintContext = pictureBuilder.context();
613 AffineTransform transform;
614 transform.scale(deviceScaleFactor, deviceScaleFactor);
615 transform.translate(-paintingRect.x(), -paintingRect.y());
616 TransformRecorder transformRecorder(paintContext, displayItemClient, transform);
618 m_view->paintContents(&paintContext, globalPaintFlags, paintingRect);
621 RefPtr<const SkPicture> recording = pictureBuilder.endRecording();
622 RefPtr<SkImage> skImage = adoptRef(SkImage::NewFromPicture(recording.get(),
623 SkISize::Make(paintingRect.width(), paintingRect.height()), nullptr, nullptr));
624 RefPtr<Image> image = StaticBitmapImage::create(skImage.release());
626 return DragImage::create(image.get(), shouldRespectImageOrientation, deviceScaleFactor,
627 InterpolationHigh, opacity);
630 PassOwnPtr<DragImage> LocalFrame::nodeImage(Node& node)
632 if (!node.layoutObject())
633 return nullptr;
635 const ScopedFramePaintingState state(this, &node);
637 m_view->updateAllLifecyclePhases();
639 m_view->setNodeToDraw(&node); // Enable special sub-tree drawing mode.
641 // Document::updateLayout may have blown away the original LayoutObject.
642 LayoutObject* layoutObject = node.layoutObject();
643 if (!layoutObject)
644 return nullptr;
646 IntRect rect;
648 return paintIntoDragImage(*layoutObject, layoutObject->shouldRespectImageOrientation(),
649 GlobalPaintFlattenCompositingLayers, layoutObject->paintingRootRect(rect));
652 PassOwnPtr<DragImage> LocalFrame::dragImageForSelection(float opacity)
654 if (!selection().isRange())
655 return nullptr;
657 const ScopedFramePaintingState state(this, 0);
658 m_view->updateAllLifecyclePhases();
660 return paintIntoDragImage(*this, DoNotRespectImageOrientation,
661 GlobalPaintSelectionOnly | GlobalPaintFlattenCompositingLayers,
662 enclosingIntRect(selection().bounds()), opacity);
665 String LocalFrame::selectedText() const
667 return selection().selectedText();
670 String LocalFrame::selectedTextForClipboard() const
672 return selection().selectedTextForClipboard();
675 VisiblePosition LocalFrame::visiblePositionForPoint(const IntPoint& framePoint)
677 HitTestResult result = eventHandler().hitTestResultAtPoint(framePoint);
678 Node* node = result.innerNodeOrImageMapImage();
679 if (!node)
680 return VisiblePosition();
681 LayoutObject* layoutObject = node->layoutObject();
682 if (!layoutObject)
683 return VisiblePosition();
684 VisiblePosition visiblePos = VisiblePosition(layoutObject->positionForPoint(result.localPoint()));
685 if (visiblePos.isNull())
686 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(node));
687 return visiblePos;
690 Document* LocalFrame::documentAtPoint(const IntPoint& pointInRootFrame)
692 if (!view())
693 return nullptr;
695 IntPoint pt = view()->rootFrameToContents(pointInRootFrame);
697 if (!contentLayoutObject())
698 return nullptr;
699 HitTestResult result = eventHandler().hitTestResultAtPoint(pt, HitTestRequest::ReadOnly | HitTestRequest::Active);
700 return result.innerNode() ? &result.innerNode()->document() : nullptr;
703 EphemeralRange LocalFrame::rangeForPoint(const IntPoint& framePoint)
705 VisiblePosition position = visiblePositionForPoint(framePoint);
706 if (position.isNull())
707 return EphemeralRange();
709 VisiblePosition previous = position.previous();
710 if (previous.isNotNull()) {
711 const EphemeralRange previousCharacterRange = makeRange(previous, position);
712 IntRect rect = editor().firstRectForRange(previousCharacterRange);
713 if (rect.contains(framePoint))
714 return EphemeralRange(previousCharacterRange);
717 VisiblePosition next = position.next();
718 const EphemeralRange nextCharacterRange = makeRange(position, next);
719 if (nextCharacterRange.isNotNull()) {
720 IntRect rect = editor().firstRectForRange(nextCharacterRange);
721 if (rect.contains(framePoint))
722 return EphemeralRange(nextCharacterRange);
725 return EphemeralRange();
728 bool LocalFrame::isURLAllowed(const KURL& url) const
730 // We allow one level of self-reference because some sites depend on that,
731 // but we don't allow more than one.
732 bool foundSelfReference = false;
733 for (const Frame* frame = this; frame; frame = frame->tree().parent()) {
734 if (!frame->isLocalFrame())
735 continue;
736 if (equalIgnoringFragmentIdentifier(toLocalFrame(frame)->document()->url(), url)) {
737 if (foundSelfReference)
738 return false;
739 foundSelfReference = true;
742 return true;
745 bool LocalFrame::shouldReuseDefaultView(const KURL& url) const
747 return loader().stateMachine()->isDisplayingInitialEmptyDocument() && document()->isSecureTransitionTo(url);
750 void LocalFrame::removeSpellingMarkersUnderWords(const Vector<String>& words)
752 spellChecker().removeSpellingMarkersUnderWords(words);
755 static ScrollResult scrollAreaOnBothAxes(const FloatSize& delta, ScrollableArea& view)
757 ScrollResultOneDimensional scrolledHorizontal = view.userScroll(ScrollLeft, ScrollByPrecisePixel, delta.width());
758 ScrollResultOneDimensional scrolledVertical = view.userScroll(ScrollUp, ScrollByPrecisePixel, delta.height());
759 return ScrollResult(scrolledHorizontal.didScroll, scrolledVertical.didScroll, scrolledHorizontal.unusedScrollDelta, scrolledVertical.unusedScrollDelta);
762 // Returns true if a scroll occurred.
763 ScrollResult LocalFrame::applyScrollDelta(const FloatSize& delta, bool isScrollBegin)
765 if (isScrollBegin)
766 host()->topControls().scrollBegin();
768 if (!view() || delta.isZero())
769 return ScrollResult(false, false, delta.width(), delta.height());
771 FloatSize remainingDelta = delta;
773 // If this is main frame, allow top controls to scroll first.
774 if (shouldScrollTopControls(delta))
775 remainingDelta = host()->topControls().scrollBy(remainingDelta);
777 if (remainingDelta.isZero())
778 return ScrollResult(delta.width(), delta.height(), 0.0f, 0.0f);
780 ScrollResult result = scrollAreaOnBothAxes(remainingDelta, *view()->scrollableArea());
781 result.didScrollX = result.didScrollX || (remainingDelta.width() != delta.width());
782 result.didScrollY = result.didScrollY || (remainingDelta.height() != delta.height());
784 return result;
787 bool LocalFrame::shouldScrollTopControls(const FloatSize& delta) const
789 if (!isMainFrame())
790 return false;
792 // Always give the delta to the top controls if the scroll is in
793 // the direction to show the top controls. If it's in the
794 // direction to hide the top controls, only give the delta to the
795 // top controls when the frame can scroll.
796 DoublePoint maximumScrollPosition =
797 host()->visualViewport().maximumScrollPositionDouble() +
798 toDoubleSize(view()->maximumScrollPositionDouble());
799 DoublePoint scrollPosition = host()->visualViewport()
800 .visibleRectInDocument().location();
801 return delta.height() > 0 || scrollPosition.y() < maximumScrollPosition.y();
804 #if ENABLE(OILPAN)
805 void LocalFrame::registerPluginElement(HTMLPlugInElement* plugin)
807 m_pluginElements.add(plugin);
810 void LocalFrame::unregisterPluginElement(HTMLPlugInElement* plugin)
812 ASSERT(m_pluginElements.contains(plugin));
813 m_pluginElements.remove(plugin);
816 void LocalFrame::clearWeakMembers(Visitor* visitor)
818 Vector<HTMLPlugInElement*> deadPlugins;
819 for (const auto& pluginElement : m_pluginElements) {
820 if (!Heap::isHeapObjectAlive(pluginElement)) {
821 pluginElement->shouldDisposePlugin();
822 deadPlugins.append(pluginElement);
825 for (unsigned i = 0; i < deadPlugins.size(); ++i)
826 m_pluginElements.remove(deadPlugins[i]);
828 #endif
830 String LocalFrame::localLayerTreeAsText(unsigned flags) const
832 if (!contentLayoutObject())
833 return String();
835 return contentLayoutObject()->compositor()->layerTreeAsText(static_cast<LayerTreeFlags>(flags));
838 inline LocalFrame::LocalFrame(FrameLoaderClient* client, FrameHost* host, FrameOwner* owner)
839 : Frame(client, host, owner)
840 , m_loader(this)
841 , m_navigationScheduler(this)
842 , m_script(ScriptController::create(this))
843 , m_editor(Editor::create(*this))
844 , m_spellChecker(SpellChecker::create(*this))
845 , m_selection(FrameSelection::create(this))
846 , m_eventHandler(adoptPtrWillBeNoop(new EventHandler(this)))
847 , m_console(FrameConsole::create(*this))
848 , m_inputMethodController(InputMethodController::create(*this))
849 , m_pageZoomFactor(parentPageZoomFactor(this))
850 , m_textZoomFactor(parentTextZoomFactor(this))
851 , m_inViewSourceMode(false)
853 if (isLocalRoot())
854 m_instrumentingAgents = InstrumentingAgents::create();
855 else
856 m_instrumentingAgents = localFrameRoot()->m_instrumentingAgents;
859 DEFINE_WEAK_IDENTIFIER_MAP(LocalFrame);
861 } // namespace blink