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/Frame.h"
33 #include "RuntimeEnabledFeatures.h"
34 #include "bindings/v8/ScriptController.h"
35 #include "core/dom/DocumentType.h"
36 #include "core/dom/WheelController.h"
37 #include "core/editing/Editor.h"
38 #include "core/editing/FrameSelection.h"
39 #include "core/editing/InputMethodController.h"
40 #include "core/editing/SpellChecker.h"
41 #include "core/editing/htmlediting.h"
42 #include "core/editing/markup.h"
43 #include "core/events/Event.h"
44 #include "core/fetch/ResourceFetcher.h"
45 #include "core/frame/DOMWindow.h"
46 #include "core/frame/FrameDestructionObserver.h"
47 #include "core/frame/FrameHost.h"
48 #include "core/frame/FrameView.h"
49 #include "core/frame/Settings.h"
50 #include "core/html/HTMLFrameElementBase.h"
51 #include "core/inspector/InspectorInstrumentation.h"
52 #include "core/loader/EmptyClients.h"
53 #include "core/loader/FrameLoaderClient.h"
54 #include "core/page/Chrome.h"
55 #include "core/page/ChromeClient.h"
56 #include "core/page/EventHandler.h"
57 #include "core/page/FocusController.h"
58 #include "core/page/Page.h"
59 #include "core/page/scrolling/ScrollingCoordinator.h"
60 #include "core/rendering/HitTestResult.h"
61 #include "core/rendering/RenderLayer.h"
62 #include "core/rendering/RenderLayerCompositor.h"
63 #include "core/rendering/RenderPart.h"
64 #include "core/rendering/RenderView.h"
65 #include "core/svg/SVGDocument.h"
66 #include "platform/DragImage.h"
67 #include "platform/graphics/GraphicsContext.h"
68 #include "platform/graphics/ImageBuffer.h"
69 #include "public/platform/WebLayer.h"
70 #include "wtf/PassOwnPtr.h"
71 #include "wtf/RefCountedLeakCounter.h"
72 #include "wtf/StdLibExtras.h"
78 using namespace HTMLNames;
80 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, frameCounter, ("Frame"));
82 static inline float parentPageZoomFactor(Frame* frame)
84 Frame* parent = frame->tree().parent();
87 return parent->pageZoomFactor();
90 static inline float parentTextZoomFactor(Frame* frame)
92 Frame* parent = frame->tree().parent();
95 return parent->textZoomFactor();
98 inline Frame::Frame(PassRefPtr<FrameInit> frameInit)
99 : m_host(frameInit->frameHost())
101 , m_loader(this, frameInit->frameLoaderClient())
102 , m_navigationScheduler(this)
103 , m_script(adoptPtr(new ScriptController(this)))
104 , m_editor(Editor::create(*this))
105 , m_spellChecker(SpellChecker::create(*this))
106 , m_selection(adoptPtr(new FrameSelection(this)))
107 , m_eventHandler(adoptPtr(new EventHandler(this)))
108 , m_inputMethodController(InputMethodController::create(*this))
109 , m_frameInit(frameInit)
110 , m_pageZoomFactor(parentPageZoomFactor(this))
111 , m_textZoomFactor(parentTextZoomFactor(this))
113 , m_inViewSourceMode(false)
114 , m_remotePlatformLayer(0)
118 if (ownerElement()) {
119 page()->incrementSubframeCount();
120 ownerElement()->setContentFrame(*this);
124 frameCounter.increment();
128 PassRefPtr<Frame> Frame::create(PassRefPtr<FrameInit> frameInit)
130 RefPtr<Frame> frame = adoptRef(new Frame(frameInit));
131 if (!frame->ownerElement())
132 frame->page()->setMainFrame(frame);
133 InspectorInstrumentation::frameAttachedToParent(frame.get());
134 return frame.release();
143 // FIXME: We should not be doing all this work inside the destructor
146 frameCounter.decrement();
149 disconnectOwnerElement();
151 HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
152 for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
153 (*it)->frameDestroyed();
156 bool Frame::inScope(TreeScope* scope) const
159 Document* doc = document();
162 HTMLFrameOwnerElement* owner = doc->ownerElement();
165 return owner->treeScope() == scope;
168 void Frame::addDestructionObserver(FrameDestructionObserver* observer)
170 m_destructionObservers.add(observer);
173 void Frame::removeDestructionObserver(FrameDestructionObserver* observer)
175 m_destructionObservers.remove(observer);
178 void Frame::setView(PassRefPtr<FrameView> view)
180 // We the custom scroll bars as early as possible to prevent m_doc->detach()
181 // from messing with the view such that its scroll bars won't be torn down.
182 // FIXME: We should revisit this.
184 m_view->prepareForDetach();
186 // Prepare for destruction now, so any unload event handlers get run and the DOMWindow is
187 // notified. If we wait until the view is destroyed, then things won't be hooked up enough for
188 // these calls to work.
189 if (!view && document() && document()->isActive()) {
190 // FIXME: We don't call willRemove here. Why is that OK?
191 document()->prepareForDestruction();
194 eventHandler().clear();
198 if (m_view && isMainFrame())
199 m_view->setVisibleContentScaleFactor(page()->pageScaleFactor());
202 void Frame::sendOrientationChangeEvent(int orientation)
204 if (!RuntimeEnabledFeatures::orientationEventEnabled())
207 m_orientation = orientation;
208 if (DOMWindow* window = domWindow())
209 window->dispatchEvent(Event::create(EventTypeNames::orientationchange));
212 FrameHost* Frame::host() const
217 Page* Frame::page() const
220 return &m_host->page();
224 Settings* Frame::settings() const
227 return &m_host->settings();
231 void Frame::setPrinting(bool printing, const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkRatio)
233 // In setting printing, we should not validate resources already cached for the document.
234 // See https://bugs.webkit.org/show_bug.cgi?id=43704
235 ResourceCacheValidationSuppressor validationSuppressor(document()->fetcher());
237 document()->setPrinting(printing);
238 view()->adjustMediaTypeForPrinting(printing);
240 document()->styleResolverChanged(RecalcStyleImmediately);
241 if (shouldUsePrintingLayout()) {
242 view()->forceLayoutForPagination(pageSize, originalPageSize, maximumShrinkRatio);
244 view()->forceLayout();
245 view()->adjustViewSize();
248 // Subframes of the one we're printing don't lay out to the page size.
249 for (RefPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling())
250 child->setPrinting(printing, FloatSize(), FloatSize(), 0);
253 bool Frame::shouldUsePrintingLayout() const
255 // Only top frame being printed should be fit to page size.
256 // Subframes should be constrained by parents only.
257 return document()->printing() && (!tree().parent() || !tree().parent()->document()->printing());
260 FloatSize Frame::resizePageRectsKeepingRatio(const FloatSize& originalSize, const FloatSize& expectedSize)
262 FloatSize resultSize;
263 if (!contentRenderer())
266 if (contentRenderer()->style()->isHorizontalWritingMode()) {
267 ASSERT(fabs(originalSize.width()) > numeric_limits<float>::epsilon());
268 float ratio = originalSize.height() / originalSize.width();
269 resultSize.setWidth(floorf(expectedSize.width()));
270 resultSize.setHeight(floorf(resultSize.width() * ratio));
272 ASSERT(fabs(originalSize.height()) > numeric_limits<float>::epsilon());
273 float ratio = originalSize.width() / originalSize.height();
274 resultSize.setHeight(floorf(expectedSize.height()));
275 resultSize.setWidth(floorf(resultSize.height() * ratio));
280 void Frame::setDOMWindow(PassRefPtr<DOMWindow> domWindow)
282 InspectorInstrumentation::frameWindowDiscarded(this, m_domWindow.get());
284 m_domWindow->reset();
286 script().clearWindowShell();
287 m_domWindow = domWindow;
290 static ChromeClient& emptyChromeClient()
292 DEFINE_STATIC_LOCAL(EmptyChromeClient, client, ());
296 ChromeClient& Frame::chromeClient() const
298 if (Page* page = this->page())
299 return page->chrome().client();
300 return emptyChromeClient();
303 Document* Frame::document() const
305 return m_domWindow ? m_domWindow->document() : 0;
308 RenderView* Frame::contentRenderer() const
310 return document() ? document()->renderView() : 0;
313 RenderPart* Frame::ownerRenderer() const
317 RenderObject* object = ownerElement()->renderer();
320 // FIXME: If <object> is ever fixed to disassociate itself from frames
321 // that it has started but canceled, then this can turn into an ASSERT
322 // since ownerElement() would be 0 when the load is canceled.
323 // https://bugs.webkit.org/show_bug.cgi?id=18585
324 if (!object->isRenderPart())
326 return toRenderPart(object);
329 void Frame::didChangeVisibilityState()
332 document()->didChangeVisibilityState();
334 Vector<RefPtr<Frame> > childFrames;
335 for (Frame* child = tree().firstChild(); child; child = child->tree().nextSibling())
336 childFrames.append(child);
338 for (size_t i = 0; i < childFrames.size(); ++i)
339 childFrames[i]->didChangeVisibilityState();
342 void Frame::willDetachFrameHost()
344 // We should never be detatching the page during a Layout.
345 RELEASE_ASSERT(!m_view || !m_view->isInPerformLayout());
347 if (Frame* parent = tree().parent())
348 parent->loader().checkLoadComplete();
350 HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
351 for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
352 (*it)->willDetachFrameHost();
354 // FIXME: Page should take care of updating focus/scrolling instead of Frame.
355 // FIXME: It's unclear as to why this is called more than once, but it is,
356 // so page() could be NULL.
357 if (page() && page()->focusController().focusedFrame() == this)
358 page()->focusController().setFocusedFrame(0);
360 if (page() && page()->scrollingCoordinator() && m_view)
361 page()->scrollingCoordinator()->willDestroyScrollableArea(m_view.get());
363 script().clearScriptObjects();
366 void Frame::detachFromFrameHost()
368 // We should never be detatching the page during a Layout.
369 RELEASE_ASSERT(!m_view || !m_view->isInPerformLayout());
373 void Frame::disconnectOwnerElement()
375 if (ownerElement()) {
376 if (Document* doc = document())
377 doc->topDocument()->clearAXObjectCache();
378 ownerElement()->clearContentFrame();
380 page()->decrementSubframeCount();
382 m_frameInit->setOwnerElement(0);
385 bool Frame::isMainFrame() const
387 Page* page = this->page();
388 return page && this == page->mainFrame();
391 String Frame::documentTypeString() const
393 if (DocumentType* doctype = document()->doctype())
394 return createMarkup(doctype);
399 String Frame::selectedText() const
401 return selection().selectedText();
404 String Frame::selectedTextForClipboard() const
406 return selection().selectedTextForClipboard();
409 VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint)
411 HitTestResult result = eventHandler().hitTestResultAtPoint(framePoint);
412 Node* node = result.innerNonSharedNode();
414 return VisiblePosition();
415 RenderObject* renderer = node->renderer();
417 return VisiblePosition();
418 VisiblePosition visiblePos = VisiblePosition(renderer->positionForPoint(result.localPoint()));
419 if (visiblePos.isNull())
420 visiblePos = firstPositionInOrBeforeNode(node);
424 Document* Frame::documentAtPoint(const IntPoint& point)
429 IntPoint pt = view()->windowToContents(point);
430 HitTestResult result = HitTestResult(pt);
432 if (contentRenderer())
433 result = eventHandler().hitTestResultAtPoint(pt, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
434 return result.innerNode() ? &result.innerNode()->document() : 0;
437 PassRefPtr<Range> Frame::rangeForPoint(const IntPoint& framePoint)
439 VisiblePosition position = visiblePositionForPoint(framePoint);
440 if (position.isNull())
443 VisiblePosition previous = position.previous();
444 if (previous.isNotNull()) {
445 RefPtr<Range> previousCharacterRange = makeRange(previous, position);
446 LayoutRect rect = editor().firstRectForRange(previousCharacterRange.get());
447 if (rect.contains(framePoint))
448 return previousCharacterRange.release();
451 VisiblePosition next = position.next();
452 if (RefPtr<Range> nextCharacterRange = makeRange(position, next)) {
453 LayoutRect rect = editor().firstRectForRange(nextCharacterRange.get());
454 if (rect.contains(framePoint))
455 return nextCharacterRange.release();
461 void Frame::createView(const IntSize& viewportSize, const Color& backgroundColor, bool transparent,
462 ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
463 ScrollbarMode verticalScrollbarMode, bool verticalLock)
468 bool isMainFrame = this->isMainFrame();
470 if (isMainFrame && view())
471 view()->setParentVisible(false);
475 RefPtr<FrameView> frameView;
477 frameView = FrameView::create(this, viewportSize);
479 // The layout size is set by WebViewImpl to support @viewport
480 frameView->setLayoutSizeFixedToFrameSize(false);
482 frameView = FrameView::create(this);
484 frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
488 if (backgroundColor.alpha())
489 frameView->updateBackgroundRecursively(backgroundColor, transparent);
492 frameView->setParentVisible(true);
495 ownerRenderer()->setWidget(frameView);
497 if (HTMLFrameOwnerElement* owner = ownerElement())
498 view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
502 void Frame::countObjectsNeedingLayout(unsigned& needsLayoutObjects, unsigned& totalObjects, bool& isPartial)
504 RenderObject* root = view()->layoutRoot();
508 root = contentRenderer();
511 needsLayoutObjects = 0;
514 for (RenderObject* o = root; o; o = o->nextInPreOrder(root)) {
516 if (o->needsLayout())
517 ++needsLayoutObjects;
521 String Frame::layerTreeAsText(unsigned flags) const
523 document()->updateLayout();
525 if (!contentRenderer())
528 return contentRenderer()->compositor()->layerTreeAsText(static_cast<LayerTreeFlags>(flags));
531 String Frame::trackedRepaintRectsAsText() const
535 return m_view->trackedRepaintRectsAsText();
538 void Frame::setPageZoomFactor(float factor)
540 setPageAndTextZoomFactors(factor, m_textZoomFactor);
543 void Frame::setTextZoomFactor(float factor)
545 setPageAndTextZoomFactors(m_pageZoomFactor, factor);
548 void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
550 if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
553 Page* page = this->page();
557 Document* document = this->document();
561 // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
562 // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
563 if (document->isSVGDocument()) {
564 if (!toSVGDocument(document)->zoomAndPanEnabled())
568 if (m_pageZoomFactor != pageZoomFactor) {
569 if (FrameView* view = this->view()) {
570 // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
571 LayoutPoint scrollPosition = view->scrollPosition();
572 float percentDifference = (pageZoomFactor / m_pageZoomFactor);
573 view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
577 m_pageZoomFactor = pageZoomFactor;
578 m_textZoomFactor = textZoomFactor;
580 for (RefPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling())
581 child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
583 document->setNeedsStyleRecalc(SubtreeStyleChange);
584 document->updateLayoutIgnorePendingStylesheets();
587 void Frame::deviceOrPageScaleFactorChanged()
589 document()->mediaQueryAffectingValueChanged();
590 for (RefPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling())
591 child->deviceOrPageScaleFactorChanged();
594 void Frame::notifyChromeClientWheelEventHandlerCountChanged() const
596 // Ensure that this method is being called on the main frame of the page.
597 ASSERT(isMainFrame());
600 for (const Frame* frame = this; frame; frame = frame->tree().traverseNext()) {
601 if (frame->document())
602 count += WheelController::from(frame->document())->wheelEventHandlerCount();
605 m_host->chrome().client().numWheelEventHandlersChanged(count);
608 bool Frame::isURLAllowed(const KURL& url) const
610 // We allow one level of self-reference because some sites depend on that,
611 // but we don't allow more than one.
612 if (page()->subframeCount() >= Page::maxNumberOfFrames)
614 bool foundSelfReference = false;
615 for (const Frame* frame = this; frame; frame = frame->tree().parent()) {
616 if (equalIgnoringFragmentIdentifier(frame->document()->url(), url)) {
617 if (foundSelfReference)
619 foundSelfReference = true;
625 struct ScopedFramePaintingState {
626 ScopedFramePaintingState(Frame* frame, Node* node)
629 , paintBehavior(frame->view()->paintBehavior())
630 , backgroundColor(frame->view()->baseBackgroundColor())
632 ASSERT(!node || node->renderer());
634 node->renderer()->updateDragState(true);
637 ~ScopedFramePaintingState()
639 if (node && node->renderer())
640 node->renderer()->updateDragState(false);
641 frame->view()->setPaintBehavior(paintBehavior);
642 frame->view()->setBaseBackgroundColor(backgroundColor);
643 frame->view()->setNodeToDraw(0);
648 PaintBehavior paintBehavior;
649 Color backgroundColor;
652 PassOwnPtr<DragImage> Frame::nodeImage(Node* node)
654 if (!node->renderer())
657 const ScopedFramePaintingState state(this, node);
659 m_view->setPaintBehavior(state.paintBehavior | PaintBehaviorFlattenCompositingLayers);
661 // When generating the drag image for an element, ignore the document background.
662 m_view->setBaseBackgroundColor(Color::transparent);
663 document()->updateLayout();
664 m_view->setNodeToDraw(node); // Enable special sub-tree drawing mode.
666 // Document::updateLayout may have blown away the original RenderObject.
667 RenderObject* renderer = node->renderer();
671 LayoutRect topLevelRect;
672 IntRect paintingRect = pixelSnappedIntRect(renderer->paintingRootRect(topLevelRect));
674 ASSERT(document()->isActive());
675 float deviceScaleFactor = m_host->deviceScaleFactor();
676 paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
677 paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
679 OwnPtr<ImageBuffer> buffer = ImageBuffer::create(paintingRect.size());
682 buffer->context()->scale(FloatSize(deviceScaleFactor, deviceScaleFactor));
683 buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
684 buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
686 // https://code.google.com/p/chromium/issues/detail?id=343755
687 DisableCompositingQueryAsserts disabler;
688 m_view->paintContents(buffer->context(), paintingRect);
690 RefPtr<Image> image = buffer->copyImage();
691 return DragImage::create(image.get(), renderer->shouldRespectImageOrientation(), deviceScaleFactor);
694 PassOwnPtr<DragImage> Frame::dragImageForSelection()
696 if (!selection().isRange())
699 const ScopedFramePaintingState state(this, 0);
700 m_view->setPaintBehavior(PaintBehaviorSelectionOnly | PaintBehaviorFlattenCompositingLayers);
701 document()->updateLayout();
703 IntRect paintingRect = enclosingIntRect(selection().bounds());
705 ASSERT(document()->isActive());
706 float deviceScaleFactor = m_host->deviceScaleFactor();
707 paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
708 paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
710 OwnPtr<ImageBuffer> buffer = ImageBuffer::create(paintingRect.size());
713 buffer->context()->scale(FloatSize(deviceScaleFactor, deviceScaleFactor));
714 buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
715 buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
717 m_view->paintContents(buffer->context(), paintingRect);
719 RefPtr<Image> image = buffer->copyImage();
720 return DragImage::create(image.get(), DoNotRespectImageOrientation, deviceScaleFactor);
723 double Frame::devicePixelRatio() const
728 double ratio = m_host->deviceScaleFactor();
729 ratio *= pageZoomFactor();
733 } // namespace WebCore