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.
31 #include "core/frame/LocalFrame.h"
33 #include "bindings/core/v8/ScriptController.h"
34 #include "core/dom/DocumentType.h"
35 #include "core/editing/Editor.h"
36 #include "core/editing/FrameSelection.h"
37 #include "core/editing/InputMethodController.h"
38 #include "core/editing/SpellChecker.h"
39 #include "core/editing/htmlediting.h"
40 #include "core/editing/markup.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/FrameDestructionObserver.h"
46 #include "core/frame/FrameHost.h"
47 #include "core/frame/FrameView.h"
48 #include "core/frame/LocalDOMWindow.h"
49 #include "core/frame/Settings.h"
50 #include "core/html/HTMLFrameElementBase.h"
51 #include "core/inspector/InspectorInstrumentation.h"
52 #include "core/loader/FrameLoaderClient.h"
53 #include "core/page/Chrome.h"
54 #include "core/page/EventHandler.h"
55 #include "core/page/FocusController.h"
56 #include "core/page/Page.h"
57 #include "core/page/scrolling/ScrollingCoordinator.h"
58 #include "core/rendering/HitTestResult.h"
59 #include "core/rendering/RenderLayer.h"
60 #include "core/rendering/RenderView.h"
61 #include "core/rendering/compositing/RenderLayerCompositor.h"
62 #include "core/svg/SVGDocumentExtensions.h"
63 #include "platform/DragImage.h"
64 #include "platform/RuntimeEnabledFeatures.h"
65 #include "platform/graphics/GraphicsContext.h"
66 #include "platform/graphics/ImageBuffer.h"
67 #include "platform/text/TextStream.h"
68 #include "wtf/PassOwnPtr.h"
69 #include "wtf/StdLibExtras.h"
73 using namespace HTMLNames;
75 static inline float parentPageZoomFactor(LocalFrame* frame)
77 Frame* parent = frame->tree().parent();
78 if (!parent || !parent->isLocalFrame())
80 return toLocalFrame(parent)->pageZoomFactor();
83 static inline float parentTextZoomFactor(LocalFrame* frame)
85 Frame* parent = frame->tree().parent();
86 if (!parent || !parent->isLocalFrame())
88 return toLocalFrame(parent)->textZoomFactor();
91 inline LocalFrame::LocalFrame(FrameLoaderClient* client, FrameHost* host, FrameOwner* owner)
92 : Frame(client, host, owner)
94 , m_navigationScheduler(this)
95 , m_script(adoptPtr(new ScriptController(this)))
96 , m_editor(Editor::create(*this))
97 , m_spellChecker(SpellChecker::create(*this))
98 , m_selection(FrameSelection::create(this))
99 , m_eventHandler(adoptPtrWillBeNoop(new EventHandler(this)))
100 , m_console(FrameConsole::create(*this))
101 , m_inputMethodController(InputMethodController::create(*this))
102 , m_pageZoomFactor(parentPageZoomFactor(this))
103 , m_textZoomFactor(parentTextZoomFactor(this))
104 , m_inViewSourceMode(false)
108 PassRefPtr<LocalFrame> LocalFrame::create(FrameLoaderClient* client, FrameHost* host, FrameOwner* owner)
110 RefPtr<LocalFrame> frame = adoptRef(new LocalFrame(client, host, owner));
111 InspectorInstrumentation::frameAttachedToParent(frame.get());
112 return frame.release();
115 LocalFrame::~LocalFrame()
119 setDOMWindow(nullptr);
121 // FIXME: What to do here... some of this is redundant with ~Frame.
122 HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
123 for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
124 (*it)->frameDestroyed();
127 void LocalFrame::detach()
129 // A lot of the following steps can result in the current frame being
130 // detached, so protect a reference to it.
131 RefPtr<LocalFrame> protect(this);
132 m_loader.stopAllLoaders();
135 // stopAllLoaders() needs to be called after detachChildren(), because detachChildren()
136 // will trigger the unload event handlers of any child frames, and those event
137 // handlers might start a new subresource load in this frame.
138 m_loader.stopAllLoaders();
139 m_loader.detachFromParent();
142 bool LocalFrame::inScope(TreeScope* scope) const
145 Document* doc = document();
148 // FIXME: This check is broken in for OOPI.
149 HTMLFrameOwnerElement* owner = doc->ownerElement();
152 return owner->treeScope() == scope;
155 void LocalFrame::setView(PassRefPtr<FrameView> view)
157 // We the custom scroll bars as early as possible to prevent m_doc->detach()
158 // from messing with the view such that its scroll bars won't be torn down.
159 // FIXME: We should revisit this.
161 m_view->prepareForDetach();
163 // Prepare for destruction now, so any unload event handlers get run and the LocalDOMWindow is
164 // notified. If we wait until the view is destroyed, then things won't be hooked up enough for
165 // these calls to work.
166 if (!view && document() && document()->isActive()) {
167 // FIXME: We don't call willRemove here. Why is that OK?
168 document()->prepareForDestruction();
171 eventHandler().clear();
175 if (m_view && isMainFrame()) {
176 if (settings()->pinchVirtualViewportEnabled())
177 m_host->pinchViewport().mainFrameDidChangeSize();
179 m_view->setVisibleContentScaleFactor(page()->pageScaleFactor());
183 void LocalFrame::setPrinting(bool printing, const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkRatio)
185 // In setting printing, we should not validate resources already cached for the document.
186 // See https://bugs.webkit.org/show_bug.cgi?id=43704
187 ResourceCacheValidationSuppressor validationSuppressor(document()->fetcher());
189 document()->setPrinting(printing);
190 view()->adjustMediaTypeForPrinting(printing);
192 document()->styleResolverChanged();
193 if (shouldUsePrintingLayout()) {
194 view()->forceLayoutForPagination(pageSize, originalPageSize, maximumShrinkRatio);
196 view()->forceLayout();
197 view()->adjustViewSize();
200 // Subframes of the one we're printing don't lay out to the page size.
201 for (RefPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling()) {
202 if (child->isLocalFrame())
203 toLocalFrame(child.get())->setPrinting(printing, FloatSize(), FloatSize(), 0);
207 bool LocalFrame::shouldUsePrintingLayout() const
209 // Only top frame being printed should be fit to page size.
210 // Subframes should be constrained by parents only.
211 return document()->printing() && (!tree().parent() || !tree().parent()->isLocalFrame() || !toLocalFrame(tree().parent())->document()->printing());
214 FloatSize LocalFrame::resizePageRectsKeepingRatio(const FloatSize& originalSize, const FloatSize& expectedSize)
216 FloatSize resultSize;
217 if (!contentRenderer())
220 if (contentRenderer()->style()->isHorizontalWritingMode()) {
221 ASSERT(fabs(originalSize.width()) > std::numeric_limits<float>::epsilon());
222 float ratio = originalSize.height() / originalSize.width();
223 resultSize.setWidth(floorf(expectedSize.width()));
224 resultSize.setHeight(floorf(resultSize.width() * ratio));
226 ASSERT(fabs(originalSize.height()) > std::numeric_limits<float>::epsilon());
227 float ratio = originalSize.width() / originalSize.height();
228 resultSize.setHeight(floorf(expectedSize.height()));
229 resultSize.setWidth(floorf(resultSize.height() * ratio));
234 void LocalFrame::setDOMWindow(PassRefPtrWillBeRawPtr<LocalDOMWindow> domWindow)
236 InspectorInstrumentation::frameWindowDiscarded(this, m_domWindow.get());
238 script().clearWindowProxy();
239 Frame::setDOMWindow(domWindow);
242 void LocalFrame::didChangeVisibilityState()
245 document()->didChangeVisibilityState();
247 Vector<RefPtr<LocalFrame> > childFrames;
248 for (Frame* child = tree().firstChild(); child; child = child->tree().nextSibling()) {
249 if (child->isLocalFrame())
250 childFrames.append(toLocalFrame(child));
253 for (size_t i = 0; i < childFrames.size(); ++i)
254 childFrames[i]->didChangeVisibilityState();
257 void LocalFrame::addDestructionObserver(FrameDestructionObserver* observer)
259 m_destructionObservers.add(observer);
262 void LocalFrame::removeDestructionObserver(FrameDestructionObserver* observer)
264 m_destructionObservers.remove(observer);
267 void LocalFrame::willDetachFrameHost()
269 // We should never be detatching the page during a Layout.
270 RELEASE_ASSERT(!m_view || !m_view->isInPerformLayout());
272 Frame* parent = tree().parent();
273 if (parent && parent->isLocalFrame())
274 toLocalFrame(parent)->loader().checkLoadComplete();
276 HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
277 for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
278 (*it)->willDetachFrameHost();
280 // FIXME: Page should take care of updating focus/scrolling instead of Frame.
281 // FIXME: It's unclear as to why this is called more than once, but it is,
282 // so page() could be null.
283 if (page() && page()->focusController().focusedFrame() == this)
284 page()->focusController().setFocusedFrame(nullptr);
285 script().clearScriptObjects();
287 if (page() && page()->scrollingCoordinator() && m_view)
288 page()->scrollingCoordinator()->willDestroyScrollableArea(m_view.get());
291 void LocalFrame::detachFromFrameHost()
293 // We should never be detatching the page during a Layout.
294 RELEASE_ASSERT(!m_view || !m_view->isInPerformLayout());
298 String LocalFrame::documentTypeString() const
300 if (DocumentType* doctype = document()->doctype())
301 return createMarkup(doctype);
306 String LocalFrame::selectedText() const
308 return selection().selectedText();
311 String LocalFrame::selectedTextForClipboard() const
313 return selection().selectedTextForClipboard();
316 VisiblePosition LocalFrame::visiblePositionForPoint(const IntPoint& framePoint)
318 HitTestResult result = eventHandler().hitTestResultAtPoint(framePoint);
319 Node* node = result.innerNonSharedNode();
321 return VisiblePosition();
322 RenderObject* renderer = node->renderer();
324 return VisiblePosition();
325 VisiblePosition visiblePos = VisiblePosition(renderer->positionForPoint(result.localPoint()));
326 if (visiblePos.isNull())
327 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(node));
331 RenderView* LocalFrame::contentRenderer() const
333 return document() ? document()->renderView() : 0;
336 Document* LocalFrame::document() const
338 return m_domWindow ? m_domWindow->document() : 0;
341 Document* LocalFrame::documentAtPoint(const IntPoint& point)
346 IntPoint pt = view()->windowToContents(point);
347 HitTestResult result = HitTestResult(pt);
349 if (contentRenderer())
350 result = eventHandler().hitTestResultAtPoint(pt, HitTestRequest::ReadOnly | HitTestRequest::Active);
351 return result.innerNode() ? &result.innerNode()->document() : 0;
354 PassRefPtrWillBeRawPtr<Range> LocalFrame::rangeForPoint(const IntPoint& framePoint)
356 VisiblePosition position = visiblePositionForPoint(framePoint);
357 if (position.isNull())
360 VisiblePosition previous = position.previous();
361 if (previous.isNotNull()) {
362 RefPtrWillBeRawPtr<Range> previousCharacterRange = makeRange(previous, position);
363 LayoutRect rect = editor().firstRectForRange(previousCharacterRange.get());
364 if (rect.contains(framePoint))
365 return previousCharacterRange.release();
368 VisiblePosition next = position.next();
369 if (RefPtrWillBeRawPtr<Range> nextCharacterRange = makeRange(position, next)) {
370 LayoutRect rect = editor().firstRectForRange(nextCharacterRange.get());
371 if (rect.contains(framePoint))
372 return nextCharacterRange.release();
378 void LocalFrame::createView(const IntSize& viewportSize, const Color& backgroundColor, bool transparent,
379 ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
380 ScrollbarMode verticalScrollbarMode, bool verticalLock)
385 bool isLocalRoot = this->isLocalRoot();
387 if (isLocalRoot && view())
388 view()->setParentVisible(false);
392 RefPtr<FrameView> frameView;
394 frameView = FrameView::create(this, viewportSize);
396 // The layout size is set by WebViewImpl to support @viewport
397 frameView->setLayoutSizeFixedToFrameSize(false);
399 frameView = FrameView::create(this);
401 frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
405 frameView->updateBackgroundRecursively(backgroundColor, transparent);
408 frameView->setParentVisible(true);
410 // FIXME: Not clear what the right thing for OOPI is here.
411 if (ownerRenderer()) {
412 HTMLFrameOwnerElement* owner = deprecatedLocalOwner();
414 owner->setWidget(frameView);
417 if (HTMLFrameOwnerElement* owner = deprecatedLocalOwner())
418 view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
422 void LocalFrame::countObjectsNeedingLayout(unsigned& needsLayoutObjects, unsigned& totalObjects, bool& isPartial)
424 RenderObject* root = view()->layoutRoot();
428 root = contentRenderer();
431 needsLayoutObjects = 0;
434 for (RenderObject* o = root; o; o = o->nextInPreOrder(root)) {
436 if (o->needsLayout())
437 ++needsLayoutObjects;
441 String LocalFrame::layerTreeAsText(LayerTreeFlags flags) const
443 TextStream textStream;
444 textStream << localLayerTreeAsText(flags);
446 for (Frame* child = tree().firstChild(); child; child = child->tree().traverseNext(this)) {
447 if (!child->isLocalFrame())
449 String childLayerTree = toLocalFrame(child)->localLayerTreeAsText(flags);
450 if (!childLayerTree.length())
453 textStream << "\n\n--------\nFrame: '";
454 textStream << child->tree().uniqueName();
455 textStream << "'\n--------\n";
456 textStream << childLayerTree;
459 return textStream.release();
462 String LocalFrame::localLayerTreeAsText(unsigned flags) const
464 if (!contentRenderer())
467 return contentRenderer()->compositor()->layerTreeAsText(static_cast<LayerTreeFlags>(flags));
470 void LocalFrame::setPageZoomFactor(float factor)
472 setPageAndTextZoomFactors(factor, m_textZoomFactor);
475 void LocalFrame::setTextZoomFactor(float factor)
477 setPageAndTextZoomFactors(m_pageZoomFactor, factor);
480 void LocalFrame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
482 if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
485 Page* page = this->page();
489 Document* document = this->document();
493 // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
494 // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
495 if (document->isSVGDocument()) {
496 if (!document->accessSVGExtensions().zoomAndPanEnabled())
500 if (m_pageZoomFactor != pageZoomFactor) {
501 if (FrameView* view = this->view()) {
502 // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
503 LayoutPoint scrollPosition = view->scrollPosition();
504 float percentDifference = (pageZoomFactor / m_pageZoomFactor);
505 view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
509 m_pageZoomFactor = pageZoomFactor;
510 m_textZoomFactor = textZoomFactor;
512 for (RefPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling()) {
513 if (child->isLocalFrame())
514 toLocalFrame(child.get())->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
517 document->setNeedsStyleRecalc(SubtreeStyleChange);
518 document->updateLayoutIgnorePendingStylesheets();
521 void LocalFrame::deviceOrPageScaleFactorChanged()
523 document()->mediaQueryAffectingValueChanged();
524 for (RefPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling()) {
525 if (child->isLocalFrame())
526 toLocalFrame(child.get())->deviceOrPageScaleFactorChanged();
530 bool LocalFrame::isURLAllowed(const KURL& url) const
532 // We allow one level of self-reference because some sites depend on that,
533 // but we don't allow more than one.
534 if (page()->subframeCount() >= Page::maxNumberOfFrames)
536 bool foundSelfReference = false;
537 for (const Frame* frame = this; frame; frame = frame->tree().parent()) {
538 if (!frame->isLocalFrame())
540 if (equalIgnoringFragmentIdentifier(toLocalFrame(frame)->document()->url(), url)) {
541 if (foundSelfReference)
543 foundSelfReference = true;
549 struct ScopedFramePaintingState {
550 ScopedFramePaintingState(LocalFrame* frame, Node* node)
553 , paintBehavior(frame->view()->paintBehavior())
555 ASSERT(!node || node->renderer());
557 node->renderer()->updateDragState(true);
560 ~ScopedFramePaintingState()
562 if (node && node->renderer())
563 node->renderer()->updateDragState(false);
564 frame->view()->setPaintBehavior(paintBehavior);
565 frame->view()->setNodeToDraw(0);
570 PaintBehavior paintBehavior;
573 PassOwnPtr<DragImage> LocalFrame::nodeImage(Node& node)
575 if (!node.renderer())
578 const ScopedFramePaintingState state(this, &node);
580 m_view->updateLayoutAndStyleForPainting();
582 m_view->setPaintBehavior(state.paintBehavior | PaintBehaviorFlattenCompositingLayers);
584 m_view->setNodeToDraw(&node); // Enable special sub-tree drawing mode.
586 // Document::updateLayout may have blown away the original RenderObject.
587 RenderObject* renderer = node.renderer();
591 LayoutRect topLevelRect;
592 IntRect paintingRect = pixelSnappedIntRect(renderer->paintingRootRect(topLevelRect));
594 ASSERT(document()->isActive());
595 float deviceScaleFactor = m_host->deviceScaleFactor();
596 paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
597 paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
599 OwnPtr<ImageBuffer> buffer = ImageBuffer::create(paintingRect.size());
602 buffer->context()->scale(deviceScaleFactor, deviceScaleFactor);
603 buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
604 buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
606 m_view->paintContents(buffer->context(), paintingRect);
608 RefPtr<Image> image = buffer->copyImage();
609 return DragImage::create(image.get(), renderer->shouldRespectImageOrientation(), deviceScaleFactor);
612 PassOwnPtr<DragImage> LocalFrame::dragImageForSelection()
614 if (!selection().isRange())
617 const ScopedFramePaintingState state(this, 0);
618 m_view->setPaintBehavior(PaintBehaviorSelectionOnly | PaintBehaviorFlattenCompositingLayers);
619 m_view->updateLayoutAndStyleForPainting();
621 IntRect paintingRect = enclosingIntRect(selection().bounds());
623 ASSERT(document()->isActive());
624 float deviceScaleFactor = m_host->deviceScaleFactor();
625 paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
626 paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
628 OwnPtr<ImageBuffer> buffer = ImageBuffer::create(paintingRect.size());
631 buffer->context()->scale(deviceScaleFactor, deviceScaleFactor);
632 buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
633 buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
635 m_view->paintContents(buffer->context(), paintingRect);
637 RefPtr<Image> image = buffer->copyImage();
638 return DragImage::create(image.get(), DoNotRespectImageOrientation, deviceScaleFactor);
641 double LocalFrame::devicePixelRatio() const
646 double ratio = m_host->deviceScaleFactor();
647 ratio *= pageZoomFactor();
651 void LocalFrame::disconnectOwnerElement()
654 if (Document* doc = document())
655 doc->topDocument().clearAXObjectCache();
657 Frame::disconnectOwnerElement();
660 LocalFrame* LocalFrame::localFrameRoot()
662 LocalFrame* curFrame = this;
663 while (curFrame && curFrame->tree().parent() && curFrame->tree().parent()->isLocalFrame())
664 curFrame = toLocalFrame(curFrame->tree().parent());