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 "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/FrameConsole.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/FrameLoaderClient.h"
53 #include "core/page/Chrome.h"
54 #include "core/page/EventHandler.h"
55 #include "core/page/FocusController.h"
56 #include "core/page/scrolling/ScrollingCoordinator.h"
57 #include "core/rendering/HitTestResult.h"
58 #include "core/rendering/RenderLayer.h"
59 #include "core/rendering/RenderView.h"
60 #include "core/rendering/compositing/RenderLayerCompositor.h"
61 #include "core/svg/SVGDocumentExtensions.h"
62 #include "platform/DragImage.h"
63 #include "platform/graphics/GraphicsContext.h"
64 #include "platform/graphics/ImageBuffer.h"
65 #include "wtf/PassOwnPtr.h"
66 #include "wtf/StdLibExtras.h"
72 using namespace HTMLNames;
74 static inline float parentPageZoomFactor(LocalFrame* frame)
76 LocalFrame* parent = frame->tree().parent();
79 return parent->pageZoomFactor();
82 static inline float parentTextZoomFactor(LocalFrame* frame)
84 LocalFrame* parent = frame->tree().parent();
87 return parent->textZoomFactor();
90 inline LocalFrame::LocalFrame(FrameLoaderClient* client, FrameHost* host, HTMLFrameOwnerElement* ownerElement)
91 : Frame(host, ownerElement)
93 , m_loader(this, client)
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(adoptPtr(new FrameSelection(this)))
99 , m_eventHandler(adoptPtr(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, HTMLFrameOwnerElement* ownerElement)
110 RefPtr<LocalFrame> frame = adoptRef(new LocalFrame(client, host, ownerElement));
111 if (!frame->ownerElement())
112 frame->page()->setMainFrame(frame);
113 InspectorInstrumentation::frameAttachedToParent(frame.get());
114 return frame.release();
117 LocalFrame::~LocalFrame()
121 setDOMWindow(nullptr);
124 bool LocalFrame::inScope(TreeScope* scope) const
127 Document* doc = document();
130 HTMLFrameOwnerElement* owner = doc->ownerElement();
133 return owner->treeScope() == scope;
136 void LocalFrame::setView(PassRefPtr<FrameView> view)
138 // We the custom scroll bars as early as possible to prevent m_doc->detach()
139 // from messing with the view such that its scroll bars won't be torn down.
140 // FIXME: We should revisit this.
142 m_view->prepareForDetach();
144 // Prepare for destruction now, so any unload event handlers get run and the DOMWindow is
145 // notified. If we wait until the view is destroyed, then things won't be hooked up enough for
146 // these calls to work.
147 if (!view && document() && document()->isActive()) {
148 // FIXME: We don't call willRemove here. Why is that OK?
149 document()->prepareForDestruction();
152 eventHandler().clear();
156 if (m_view && isMainFrame()) {
157 if (settings()->pinchVirtualViewportEnabled())
158 m_host->pinchViewport().mainFrameDidChangeSize();
160 m_view->setVisibleContentScaleFactor(page()->pageScaleFactor());
164 void LocalFrame::sendOrientationChangeEvent()
166 if (!RuntimeEnabledFeatures::orientationEventEnabled())
169 if (DOMWindow* window = domWindow())
170 window->dispatchEvent(Event::create(EventTypeNames::orientationchange));
173 void LocalFrame::setPrinting(bool printing, const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkRatio)
175 // In setting printing, we should not validate resources already cached for the document.
176 // See https://bugs.webkit.org/show_bug.cgi?id=43704
177 ResourceCacheValidationSuppressor validationSuppressor(document()->fetcher());
179 document()->setPrinting(printing);
180 view()->adjustMediaTypeForPrinting(printing);
182 document()->styleResolverChanged(RecalcStyleImmediately);
183 if (shouldUsePrintingLayout()) {
184 view()->forceLayoutForPagination(pageSize, originalPageSize, maximumShrinkRatio);
186 view()->forceLayout();
187 view()->adjustViewSize();
190 // Subframes of the one we're printing don't lay out to the page size.
191 for (RefPtr<LocalFrame> child = tree().firstChild(); child; child = child->tree().nextSibling())
192 child->setPrinting(printing, FloatSize(), FloatSize(), 0);
195 bool LocalFrame::shouldUsePrintingLayout() const
197 // Only top frame being printed should be fit to page size.
198 // Subframes should be constrained by parents only.
199 return document()->printing() && (!tree().parent() || !tree().parent()->document()->printing());
202 FloatSize LocalFrame::resizePageRectsKeepingRatio(const FloatSize& originalSize, const FloatSize& expectedSize)
204 FloatSize resultSize;
205 if (!contentRenderer())
208 if (contentRenderer()->style()->isHorizontalWritingMode()) {
209 ASSERT(fabs(originalSize.width()) > numeric_limits<float>::epsilon());
210 float ratio = originalSize.height() / originalSize.width();
211 resultSize.setWidth(floorf(expectedSize.width()));
212 resultSize.setHeight(floorf(resultSize.width() * ratio));
214 ASSERT(fabs(originalSize.height()) > numeric_limits<float>::epsilon());
215 float ratio = originalSize.width() / originalSize.height();
216 resultSize.setHeight(floorf(expectedSize.height()));
217 resultSize.setWidth(floorf(resultSize.height() * ratio));
222 void LocalFrame::setDOMWindow(PassRefPtrWillBeRawPtr<DOMWindow> domWindow)
224 InspectorInstrumentation::frameWindowDiscarded(this, m_domWindow.get());
226 script().clearWindowShell();
227 Frame::setDOMWindow(domWindow);
230 void LocalFrame::didChangeVisibilityState()
233 document()->didChangeVisibilityState();
235 Vector<RefPtr<LocalFrame> > childFrames;
236 for (LocalFrame* child = tree().firstChild(); child; child = child->tree().nextSibling())
237 childFrames.append(child);
239 for (size_t i = 0; i < childFrames.size(); ++i)
240 childFrames[i]->didChangeVisibilityState();
243 void LocalFrame::willDetachFrameHost()
245 // We should never be detatching the page during a Layout.
246 RELEASE_ASSERT(!m_view || !m_view->isInPerformLayout());
248 if (LocalFrame* parent = tree().parent())
249 parent->loader().checkLoadComplete();
251 Frame::willDetachFrameHost();
252 script().clearScriptObjects();
254 if (page() && page()->scrollingCoordinator() && m_view)
255 page()->scrollingCoordinator()->willDestroyScrollableArea(m_view.get());
258 void LocalFrame::detachFromFrameHost()
260 // We should never be detatching the page during a Layout.
261 RELEASE_ASSERT(!m_view || !m_view->isInPerformLayout());
262 Frame::detachFromFrameHost();
265 String LocalFrame::documentTypeString() const
267 if (DocumentType* doctype = document()->doctype())
268 return createMarkup(doctype);
273 String LocalFrame::selectedText() const
275 return selection().selectedText();
278 String LocalFrame::selectedTextForClipboard() const
280 return selection().selectedTextForClipboard();
283 VisiblePosition LocalFrame::visiblePositionForPoint(const IntPoint& framePoint)
285 HitTestResult result = eventHandler().hitTestResultAtPoint(framePoint);
286 Node* node = result.innerNonSharedNode();
288 return VisiblePosition();
289 RenderObject* renderer = node->renderer();
291 return VisiblePosition();
292 VisiblePosition visiblePos = VisiblePosition(renderer->positionForPoint(result.localPoint()));
293 if (visiblePos.isNull())
294 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(node));
298 RenderView* LocalFrame::contentRenderer() const
300 return document() ? document()->renderView() : 0;
303 Document* LocalFrame::document() const
305 return m_domWindow ? m_domWindow->document() : 0;
308 Document* LocalFrame::documentAtPoint(const IntPoint& point)
313 IntPoint pt = view()->windowToContents(point);
314 HitTestResult result = HitTestResult(pt);
316 if (contentRenderer())
317 result = eventHandler().hitTestResultAtPoint(pt, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
318 return result.innerNode() ? &result.innerNode()->document() : 0;
321 PassRefPtrWillBeRawPtr<Range> LocalFrame::rangeForPoint(const IntPoint& framePoint)
323 VisiblePosition position = visiblePositionForPoint(framePoint);
324 if (position.isNull())
327 VisiblePosition previous = position.previous();
328 if (previous.isNotNull()) {
329 RefPtrWillBeRawPtr<Range> previousCharacterRange = makeRange(previous, position);
330 LayoutRect rect = editor().firstRectForRange(previousCharacterRange.get());
331 if (rect.contains(framePoint))
332 return previousCharacterRange.release();
335 VisiblePosition next = position.next();
336 if (RefPtrWillBeRawPtr<Range> nextCharacterRange = makeRange(position, next)) {
337 LayoutRect rect = editor().firstRectForRange(nextCharacterRange.get());
338 if (rect.contains(framePoint))
339 return nextCharacterRange.release();
345 void LocalFrame::createView(const IntSize& viewportSize, const Color& backgroundColor, bool transparent,
346 ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
347 ScrollbarMode verticalScrollbarMode, bool verticalLock)
352 bool isMainFrame = this->isMainFrame();
354 if (isMainFrame && view())
355 view()->setParentVisible(false);
359 RefPtr<FrameView> frameView;
361 frameView = FrameView::create(this, viewportSize);
363 // The layout size is set by WebViewImpl to support @viewport
364 frameView->setLayoutSizeFixedToFrameSize(false);
366 frameView = FrameView::create(this);
368 frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
372 if (backgroundColor.alpha())
373 frameView->updateBackgroundRecursively(backgroundColor, transparent);
376 frameView->setParentVisible(true);
378 if (ownerRenderer()) {
379 HTMLFrameOwnerElement* owner = ownerElement();
381 owner->setWidget(frameView);
384 if (HTMLFrameOwnerElement* owner = ownerElement())
385 view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
389 void LocalFrame::countObjectsNeedingLayout(unsigned& needsLayoutObjects, unsigned& totalObjects, bool& isPartial)
391 RenderObject* root = view()->layoutRoot();
395 root = contentRenderer();
398 needsLayoutObjects = 0;
401 for (RenderObject* o = root; o; o = o->nextInPreOrder(root)) {
403 if (o->needsLayout())
404 ++needsLayoutObjects;
408 String LocalFrame::layerTreeAsText(unsigned flags) const
410 if (!contentRenderer())
413 return contentRenderer()->compositor()->layerTreeAsText(static_cast<LayerTreeFlags>(flags));
416 String LocalFrame::trackedRepaintRectsAsText() const
420 return m_view->trackedRepaintRectsAsText();
423 void LocalFrame::setPageZoomFactor(float factor)
425 setPageAndTextZoomFactors(factor, m_textZoomFactor);
428 void LocalFrame::setTextZoomFactor(float factor)
430 setPageAndTextZoomFactors(m_pageZoomFactor, factor);
433 void LocalFrame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
435 if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
438 Page* page = this->page();
442 Document* document = this->document();
446 // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
447 // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
448 if (document->isSVGDocument()) {
449 if (!document->accessSVGExtensions().zoomAndPanEnabled())
453 if (m_pageZoomFactor != pageZoomFactor) {
454 if (FrameView* view = this->view()) {
455 // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
456 LayoutPoint scrollPosition = view->scrollPosition();
457 float percentDifference = (pageZoomFactor / m_pageZoomFactor);
458 view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
462 m_pageZoomFactor = pageZoomFactor;
463 m_textZoomFactor = textZoomFactor;
465 for (RefPtr<LocalFrame> child = tree().firstChild(); child; child = child->tree().nextSibling())
466 child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
468 document->setNeedsStyleRecalc(SubtreeStyleChange);
469 document->updateLayoutIgnorePendingStylesheets();
472 void LocalFrame::deviceOrPageScaleFactorChanged()
474 document()->mediaQueryAffectingValueChanged();
475 for (RefPtr<LocalFrame> child = tree().firstChild(); child; child = child->tree().nextSibling())
476 child->deviceOrPageScaleFactorChanged();
479 void LocalFrame::notifyChromeClientWheelEventHandlerCountChanged() const
481 // Ensure that this method is being called on the main frame of the page.
482 ASSERT(isMainFrame());
485 for (const LocalFrame* frame = this; frame; frame = frame->tree().traverseNext()) {
486 if (frame->document())
487 count += WheelController::from(*frame->document())->wheelEventHandlerCount();
490 m_host->chrome().client().numWheelEventHandlersChanged(count);
493 bool LocalFrame::isURLAllowed(const KURL& url) const
495 // We allow one level of self-reference because some sites depend on that,
496 // but we don't allow more than one.
497 if (page()->subframeCount() >= Page::maxNumberOfFrames)
499 bool foundSelfReference = false;
500 for (const LocalFrame* frame = this; frame; frame = frame->tree().parent()) {
501 if (equalIgnoringFragmentIdentifier(frame->document()->url(), url)) {
502 if (foundSelfReference)
504 foundSelfReference = true;
510 struct ScopedFramePaintingState {
511 ScopedFramePaintingState(LocalFrame* frame, Node* node)
514 , paintBehavior(frame->view()->paintBehavior())
516 ASSERT(!node || node->renderer());
518 node->renderer()->updateDragState(true);
521 ~ScopedFramePaintingState()
523 if (node && node->renderer())
524 node->renderer()->updateDragState(false);
525 frame->view()->setPaintBehavior(paintBehavior);
526 frame->view()->setNodeToDraw(0);
531 PaintBehavior paintBehavior;
534 PassOwnPtr<DragImage> LocalFrame::nodeImage(Node& node)
536 if (!node.renderer())
539 const ScopedFramePaintingState state(this, &node);
541 m_view->updateLayoutAndStyleForPainting();
543 m_view->setPaintBehavior(state.paintBehavior | PaintBehaviorFlattenCompositingLayers);
545 m_view->setNodeToDraw(&node); // Enable special sub-tree drawing mode.
547 // Document::updateLayout may have blown away the original RenderObject.
548 RenderObject* renderer = node.renderer();
552 LayoutRect topLevelRect;
553 IntRect paintingRect = pixelSnappedIntRect(renderer->paintingRootRect(topLevelRect));
555 ASSERT(document()->isActive());
556 float deviceScaleFactor = m_host->deviceScaleFactor();
557 paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
558 paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
560 OwnPtr<ImageBuffer> buffer = ImageBuffer::create(paintingRect.size());
563 buffer->context()->scale(FloatSize(deviceScaleFactor, deviceScaleFactor));
564 buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
565 buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
567 m_view->paintContents(buffer->context(), paintingRect);
569 RefPtr<Image> image = buffer->copyImage();
570 return DragImage::create(image.get(), renderer->shouldRespectImageOrientation(), deviceScaleFactor);
573 PassOwnPtr<DragImage> LocalFrame::dragImageForSelection()
575 if (!selection().isRange())
578 const ScopedFramePaintingState state(this, 0);
579 m_view->setPaintBehavior(PaintBehaviorSelectionOnly | PaintBehaviorFlattenCompositingLayers);
580 document()->updateLayout();
582 IntRect paintingRect = enclosingIntRect(selection().bounds());
584 ASSERT(document()->isActive());
585 float deviceScaleFactor = m_host->deviceScaleFactor();
586 paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
587 paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
589 OwnPtr<ImageBuffer> buffer = ImageBuffer::create(paintingRect.size());
592 buffer->context()->scale(FloatSize(deviceScaleFactor, deviceScaleFactor));
593 buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
594 buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
596 m_view->paintContents(buffer->context(), paintingRect);
598 RefPtr<Image> image = buffer->copyImage();
599 return DragImage::create(image.get(), DoNotRespectImageOrientation, deviceScaleFactor);
602 double LocalFrame::devicePixelRatio() const
607 double ratio = m_host->deviceScaleFactor();
608 ratio *= pageZoomFactor();
612 void LocalFrame::disconnectOwnerElement()
614 if (ownerElement()) {
615 if (Document* doc = document())
616 doc->topDocument().clearAXObjectCache();
618 Frame::disconnectOwnerElement();
621 LocalFrame* LocalFrame::localFrameRoot()
623 LocalFrame* curFrame = this;
624 while (curFrame && curFrame->tree().parent() && curFrame->tree().parent()->isLocalFrame())
625 curFrame = curFrame->tree().parent();
630 } // namespace WebCore