/* * Copyright (C) 1998, 1999 Torben Weis * 1999 Lars Knoll * 1999 Antti Koivisto * 2000 Simon Hausmann * 2000 Stefan Schimanski <1Stein@gmx.de> * 2001 George Staikos * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. * Copyright (C) 2005 Alexey Proskuryakov * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * Copyright (C) 2008 Eric Seidel * Copyright (C) 2008 Google Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "config.h" #include "core/frame/LocalFrame.h" #include "bindings/core/v8/ScriptController.h" #include "core/editing/Editor.h" #include "core/editing/FrameSelection.h" #include "core/editing/InputMethodController.h" #include "core/editing/SpellChecker.h" #include "core/editing/htmlediting.h" #include "core/editing/markup.h" #include "core/events/Event.h" #include "core/fetch/ResourceFetcher.h" #include "core/frame/EventHandlerRegistry.h" #include "core/frame/FrameConsole.h" #include "core/frame/FrameDestructionObserver.h" #include "core/frame/FrameHost.h" #include "core/frame/FrameView.h" #include "core/frame/LocalDOMWindow.h" #include "core/frame/Settings.h" #include "core/inspector/ConsoleMessageStorage.h" #include "core/loader/FrameLoaderClient.h" #include "core/loader/MojoLoader.h" #include "core/page/Chrome.h" #include "core/page/EventHandler.h" #include "core/page/FocusController.h" #include "core/page/Page.h" #include "core/page/scrolling/ScrollingCoordinator.h" #include "core/rendering/HitTestResult.h" #include "core/rendering/RenderLayer.h" #include "core/rendering/RenderView.h" #include "core/rendering/compositing/RenderLayerCompositor.h" #include "platform/RuntimeEnabledFeatures.h" #include "platform/graphics/GraphicsContext.h" #include "platform/graphics/ImageBuffer.h" #include "platform/text/TextStream.h" #include "wtf/PassOwnPtr.h" #include "wtf/StdLibExtras.h" namespace blink { inline LocalFrame::LocalFrame(FrameLoaderClient* client, FrameHost* host) : Frame(client, host) , m_deprecatedLoader(this) , m_mojoLoader(adoptPtr(new MojoLoader(*this))) , m_script(adoptPtr(new ScriptController(this))) , m_editor(Editor::create(*this)) , m_spellChecker(SpellChecker::create(*this)) , m_selection(FrameSelection::create(this)) , m_eventHandler(adoptPtr(new EventHandler(this))) , m_console(FrameConsole::create(*this)) , m_inputMethodController(InputMethodController::create(*this)) , m_pageZoomFactor(1) , m_textZoomFactor(1) { page()->setMainFrame(this); } PassRefPtr LocalFrame::create(FrameLoaderClient* client, FrameHost* host) { return adoptRef(new LocalFrame(client, host)); } LocalFrame::~LocalFrame() { setView(nullptr); m_deprecatedLoader.clear(); setDOMWindow(nullptr); // FIXME: What to do here... some of this is redundant with ~Frame. HashSet::iterator stop = m_destructionObservers.end(); for (HashSet::iterator it = m_destructionObservers.begin(); it != stop; ++it) (*it)->frameDestroyed(); } FrameLoaderClient* LocalFrame::loaderClient() const { return static_cast(client()); } FetchContext& LocalFrame::fetchContext() const { return m_deprecatedLoader.fetchContext(); } void LocalFrame::detach() { // A lot of the following steps can result in the current frame being // detached, so protect a reference to it. RefPtr protect(this); m_deprecatedLoader.stopAllLoaders(); m_deprecatedLoader.closeURL(); detachChildren(); // stopAllLoaders() needs to be called after detachChildren(), because detachChildren() // will trigger the unload event handlers of any child frames, and those event // handlers might start a new subresource load in this frame. m_deprecatedLoader.stopAllLoaders(); setView(nullptr); willDetachFrameHost(); // Finish all cleanup work that might require talking to the embedder. // Notify ScriptController that the frame is closing, since its cleanup ends up calling // back to FrameLoaderClient via WindowProxy. script().clearForClose(); // After this, we must no longer talk to the client since this clears // its owning reference back to our owning LocalFrame. loaderClient()->detachedFromParent(); clearClient(); detachFromFrameHost(); } void LocalFrame::setView(PassRefPtr view) { // We the custom scroll bars as early as possible to prevent m_doc->detach() // from messing with the view such that its scroll bars won't be torn down. // FIXME: We should revisit this. if (m_view) m_view->prepareForDetach(); // Prepare for destruction now, so any unload event handlers get run and the LocalDOMWindow is // notified. If we wait until the view is destroyed, then things won't be hooked up enough for // these calls to work. if (!view && document() && document()->isActive()) { // FIXME: We don't call willRemove here. Why is that OK? document()->prepareForDestruction(); } eventHandler().clear(); m_view = view; } FloatSize LocalFrame::resizePageRectsKeepingRatio(const FloatSize& originalSize, const FloatSize& expectedSize) { FloatSize resultSize; if (!contentRenderer()) return FloatSize(); if (contentRenderer()->style()->isHorizontalWritingMode()) { ASSERT(fabs(originalSize.width()) > std::numeric_limits::epsilon()); float ratio = originalSize.height() / originalSize.width(); resultSize.setWidth(floorf(expectedSize.width())); resultSize.setHeight(floorf(resultSize.width() * ratio)); } else { ASSERT(fabs(originalSize.height()) > std::numeric_limits::epsilon()); float ratio = originalSize.width() / originalSize.height(); resultSize.setHeight(floorf(expectedSize.height())); resultSize.setWidth(floorf(resultSize.height() * ratio)); } return resultSize; } void LocalFrame::setDOMWindow(PassRefPtr domWindow) { if (m_domWindow) { console().messageStorage()->frameWindowDiscarded(m_domWindow.get()); } if (domWindow) script().clearWindowProxy(); Frame::setDOMWindow(domWindow); } void LocalFrame::didChangeVisibilityState() { if (document()) document()->didChangeVisibilityState(); } void LocalFrame::addDestructionObserver(FrameDestructionObserver* observer) { m_destructionObservers.add(observer); } void LocalFrame::removeDestructionObserver(FrameDestructionObserver* observer) { m_destructionObservers.remove(observer); } void LocalFrame::willDetachFrameHost() { // We should never be detatching the page during a Layout. RELEASE_ASSERT(!m_view || !m_view->isInPerformLayout()); HashSet::iterator stop = m_destructionObservers.end(); for (HashSet::iterator it = m_destructionObservers.begin(); it != stop; ++it) (*it)->willDetachFrameHost(); // FIXME: Page should take care of updating focus/scrolling instead of Frame. // FIXME: It's unclear as to why this is called more than once, but it is, // so page() could be null. if (page() && page()->focusController().focusedFrame() == this) page()->focusController().setFocusedFrame(nullptr); } void LocalFrame::detachFromFrameHost() { // We should never be detatching the page during a Layout. RELEASE_ASSERT(!m_view || !m_view->isInPerformLayout()); m_host = 0; } String LocalFrame::selectedText() const { return selection().selectedText(); } String LocalFrame::selectedTextForClipboard() const { return selection().selectedTextForClipboard(); } VisiblePosition LocalFrame::visiblePositionForPoint(const IntPoint& framePoint) { HitTestResult result = eventHandler().hitTestResultAtPoint(framePoint); Node* node = result.innerNonSharedNode(); if (!node) return VisiblePosition(); RenderObject* renderer = node->renderer(); if (!renderer) return VisiblePosition(); VisiblePosition visiblePos = VisiblePosition(renderer->positionForPoint(result.localPoint())); if (visiblePos.isNull()) visiblePos = VisiblePosition(firstPositionInOrBeforeNode(node)); return visiblePos; } RenderView* LocalFrame::contentRenderer() const { return document() ? document()->renderView() : 0; } Document* LocalFrame::document() const { return m_domWindow ? m_domWindow->document() : 0; } Document* LocalFrame::documentAtPoint(const IntPoint& point) { if (!view()) return 0; IntPoint pt = view()->windowToContents(point); HitTestResult result = HitTestResult(pt); if (contentRenderer()) result = eventHandler().hitTestResultAtPoint(pt, HitTestRequest::ReadOnly | HitTestRequest::Active); return result.innerNode() ? &result.innerNode()->document() : 0; } PassRefPtr LocalFrame::rangeForPoint(const IntPoint& framePoint) { VisiblePosition position = visiblePositionForPoint(framePoint); if (position.isNull()) return nullptr; VisiblePosition previous = position.previous(); if (previous.isNotNull()) { RefPtr previousCharacterRange = makeRange(previous, position); LayoutRect rect = editor().firstRectForRange(previousCharacterRange.get()); if (rect.contains(framePoint)) return previousCharacterRange.release(); } VisiblePosition next = position.next(); if (RefPtr nextCharacterRange = makeRange(position, next)) { LayoutRect rect = editor().firstRectForRange(nextCharacterRange.get()); if (rect.contains(framePoint)) return nextCharacterRange.release(); } return nullptr; } void LocalFrame::createView(const IntSize& viewportSize, const Color& backgroundColor, bool transparent, ScrollbarMode horizontalScrollbarMode, bool horizontalLock, ScrollbarMode verticalScrollbarMode, bool verticalLock) { ASSERT(this); ASSERT(page()); if (view()) view()->setParentVisible(false); setView(nullptr); RefPtr frameView; frameView = FrameView::create(this, viewportSize); // The layout size is set by WebViewImpl to support @viewport frameView->setLayoutSizeFixedToFrameSize(false); setView(frameView); frameView->updateBackgroundRecursively(backgroundColor, transparent); frameView->setParentVisible(true); } void LocalFrame::countObjectsNeedingLayout(unsigned& needsLayoutObjects, unsigned& totalObjects, bool& isPartial) { RenderObject* root = view()->layoutRoot(); isPartial = true; if (!root) { isPartial = false; root = contentRenderer(); } needsLayoutObjects = 0; totalObjects = 0; for (RenderObject* o = root; o; o = o->nextInPreOrder(root)) { ++totalObjects; if (o->needsLayout()) ++needsLayoutObjects; } } String LocalFrame::layerTreeAsText(LayerTreeFlags flags) const { TextStream textStream; textStream << localLayerTreeAsText(flags); return textStream.release(); } String LocalFrame::localLayerTreeAsText(unsigned flags) const { if (!contentRenderer()) return String(); return contentRenderer()->compositor()->layerTreeAsText(static_cast(flags)); } void LocalFrame::setPageZoomFactor(float factor) { setPageAndTextZoomFactors(factor, m_textZoomFactor); } void LocalFrame::setTextZoomFactor(float factor) { setPageAndTextZoomFactors(m_pageZoomFactor, factor); } void LocalFrame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor) { if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor) return; Page* page = this->page(); if (!page) return; Document* document = this->document(); if (!document) return; m_pageZoomFactor = pageZoomFactor; m_textZoomFactor = textZoomFactor; document->setNeedsStyleRecalc(SubtreeStyleChange); document->updateLayoutIgnorePendingStylesheets(); } void LocalFrame::deviceOrPageScaleFactorChanged() { document()->mediaQueryAffectingValueChanged(); } void LocalFrame::removeSpellingMarkersUnderWords(const Vector& words) { spellChecker().removeSpellingMarkersUnderWords(words); } struct ScopedFramePaintingState { ScopedFramePaintingState(LocalFrame* frame) : frame(frame) , paintBehavior(frame->view()->paintBehavior()) { } ~ScopedFramePaintingState() { frame->view()->setPaintBehavior(paintBehavior); frame->view()->setNodeToDraw(0); } LocalFrame* frame; PaintBehavior paintBehavior; }; double LocalFrame::devicePixelRatio() const { if (!m_host) return 0; double ratio = m_host->deviceScaleFactor(); ratio *= pageZoomFactor(); return ratio; } } // namespace blink