summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/page/Frame.cpp
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/page/Frame.cpp
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/page/Frame.cpp')
-rw-r--r--Source/WebCore/page/Frame.cpp1002
1 files changed, 1002 insertions, 0 deletions
diff --git a/Source/WebCore/page/Frame.cpp b/Source/WebCore/page/Frame.cpp
new file mode 100644
index 0000000..11a86c6
--- /dev/null
+++ b/Source/WebCore/page/Frame.cpp
@@ -0,0 +1,1002 @@
+/*
+ * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ * 1999 Lars Knoll <knoll@kde.org>
+ * 1999 Antti Koivisto <koivisto@kde.org>
+ * 2000 Simon Hausmann <hausmann@kde.org>
+ * 2000 Stefan Schimanski <1Stein@gmx.de>
+ * 2001 George Staikos <staikos@kde.org>
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com>
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ *
+ * 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 "Frame.h"
+
+#include "ApplyStyleCommand.h"
+#include "CSSComputedStyleDeclaration.h"
+#include "CSSMutableStyleDeclaration.h"
+#include "CSSProperty.h"
+#include "CSSPropertyNames.h"
+#include "CachedCSSStyleSheet.h"
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "DOMWindow.h"
+#include "CachedResourceLoader.h"
+#include "DocumentType.h"
+#include "EditingText.h"
+#include "EditorClient.h"
+#include "EventNames.h"
+#include "FloatQuad.h"
+#include "FocusController.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "GraphicsLayer.h"
+#include "HTMLDocument.h"
+#include "HTMLFormControlElement.h"
+#include "HTMLFormElement.h"
+#include "HTMLFrameElementBase.h"
+#include "HTMLNames.h"
+#include "HTMLTableCellElement.h"
+#include "HitTestResult.h"
+#include "Logging.h"
+#include "MediaFeatureNames.h"
+#include "Navigator.h"
+#include "NodeList.h"
+#include "Page.h"
+#include "PageGroup.h"
+#include "RegularExpression.h"
+#include "RenderLayer.h"
+#include "RenderPart.h"
+#include "RenderTableCell.h"
+#include "RenderTextControl.h"
+#include "RenderTheme.h"
+#include "RenderView.h"
+#include "ScriptController.h"
+#include "ScriptSourceCode.h"
+#include "Settings.h"
+#include "TextIterator.h"
+#include "TextResourceDecoder.h"
+#include "UserContentURLPattern.h"
+#include "UserTypingGestureIndicator.h"
+#include "XMLNSNames.h"
+#include "XMLNames.h"
+#include "htmlediting.h"
+#include "markup.h"
+#include "npruntime_impl.h"
+#include "visible_units.h"
+#include <wtf/RefCountedLeakCounter.h>
+#include <wtf/StdLibExtras.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "RenderLayerCompositor.h"
+#endif
+
+#if USE(JSC)
+#include "JSDOMWindowShell.h"
+#include "runtime_root.h"
+#endif
+
+#include "MathMLNames.h"
+#include "SVGNames.h"
+#include "XLinkNames.h"
+
+#if ENABLE(SVG)
+#include "SVGDocument.h"
+#include "SVGDocumentExtensions.h"
+#endif
+
+#if ENABLE(TILED_BACKING_STORE)
+#include "TiledBackingStore.h"
+#endif
+
+#if ENABLE(WML)
+#include "WMLNames.h"
+#endif
+
+#if PLATFORM(ANDROID)
+#include "WebViewCore.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+#ifndef NDEBUG
+static WTF::RefCountedLeakCounter frameCounter("Frame");
+#endif
+
+static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
+{
+ if (!ownerElement)
+ return 0;
+ return ownerElement->document()->frame();
+}
+
+static inline float parentPageZoomFactor(Frame* frame)
+{
+ Frame* parent = frame->tree()->parent();
+ if (!parent)
+ return 1;
+ return parent->pageZoomFactor();
+}
+
+static inline float parentTextZoomFactor(Frame* frame)
+{
+ Frame* parent = frame->tree()->parent();
+ if (!parent)
+ return 1;
+ return parent->textZoomFactor();
+}
+
+inline Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient)
+ : m_page(page)
+ , m_treeNode(this, parentFromOwnerElement(ownerElement))
+ , m_loader(this, frameLoaderClient)
+ , m_navigationScheduler(this)
+ , m_ownerElement(ownerElement)
+ , m_script(this)
+ , m_editor(this)
+ , m_selectionController(this)
+ , m_eventHandler(this)
+ , m_animationController(this)
+ , m_lifeSupportTimer(this, &Frame::lifeSupportTimerFired)
+ , m_pageZoomFactor(parentPageZoomFactor(this))
+ , m_textZoomFactor(parentTextZoomFactor(this))
+ , m_pageScaleFactor(1)
+#if ENABLE(ORIENTATION_EVENTS)
+ , m_orientation(0)
+#endif
+ , m_inViewSourceMode(false)
+ , m_isDisconnected(false)
+ , m_excludeFromTextSearch(false)
+{
+ ASSERT(page);
+ AtomicString::init();
+ HTMLNames::init();
+ QualifiedName::init();
+ MediaFeatureNames::init();
+ SVGNames::init();
+ XLinkNames::init();
+ MathMLNames::init();
+ XMLNSNames::init();
+ XMLNames::init();
+
+#if ENABLE(WML)
+ WMLNames::init();
+#endif
+
+ if (!ownerElement) {
+#if ENABLE(TILED_BACKING_STORE)
+ // Top level frame only for now.
+ setTiledBackingStoreEnabled(page->settings()->tiledBackingStoreEnabled());
+#endif
+ } else {
+ page->incrementFrameCount();
+
+ // Make sure we will not end up with two frames referencing the same owner element.
+ Frame*& contentFrameSlot = ownerElement->m_contentFrame;
+ ASSERT(!contentFrameSlot || contentFrameSlot->ownerElement() != ownerElement);
+ contentFrameSlot = this;
+ }
+
+#ifndef NDEBUG
+ frameCounter.increment();
+#endif
+}
+
+PassRefPtr<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client)
+{
+ RefPtr<Frame> frame = adoptRef(new Frame(page, ownerElement, client));
+ if (!ownerElement)
+ page->setMainFrame(frame);
+ return frame.release();
+}
+
+Frame::~Frame()
+{
+ setView(0);
+ loader()->cancelAndClear();
+
+ // FIXME: We should not be doing all this work inside the destructor
+
+ ASSERT(!m_lifeSupportTimer.isActive());
+
+#ifndef NDEBUG
+ frameCounter.decrement();
+#endif
+
+ disconnectOwnerElement();
+
+ if (m_domWindow)
+ m_domWindow->disconnectFrame();
+ script()->clearWindowShell();
+
+ HashSet<DOMWindow*>::iterator end = m_liveFormerWindows.end();
+ for (HashSet<DOMWindow*>::iterator it = m_liveFormerWindows.begin(); it != end; ++it)
+ (*it)->disconnectFrame();
+
+ HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
+ for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
+ (*it)->frameDestroyed();
+
+ if (m_view) {
+ m_view->hide();
+ m_view->clearFrame();
+ }
+
+ ASSERT(!m_lifeSupportTimer.isActive());
+}
+
+void Frame::addDestructionObserver(FrameDestructionObserver* observer)
+{
+ m_destructionObservers.add(observer);
+}
+
+void Frame::removeDestructionObserver(FrameDestructionObserver* observer)
+{
+ m_destructionObservers.remove(observer);
+}
+
+void Frame::setView(PassRefPtr<FrameView> 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->detachCustomScrollbars();
+
+ // Detach the document now, so any onUnload handlers get run - if
+ // we wait until the view is destroyed, then things won't be
+ // hooked up enough for some JavaScript calls to work.
+ if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) {
+ // FIXME: We don't call willRemove here. Why is that OK?
+ m_doc->detach();
+ }
+
+ if (m_view)
+ m_view->unscheduleRelayout();
+
+ eventHandler()->clear();
+
+ m_view = view;
+
+ // Only one form submission is allowed per view of a part.
+ // Since this part may be getting reused as a result of being
+ // pulled from the back/forward cache, reset this flag.
+ loader()->resetMultipleFormSubmissionProtection();
+
+#if ENABLE(TILED_BACKING_STORE)
+ if (m_view && tiledBackingStore())
+ m_view->setPaintsEntireContents(true);
+#endif
+}
+
+void Frame::setDocument(PassRefPtr<Document> newDoc)
+{
+ ASSERT(!newDoc || newDoc->frame());
+ if (m_doc && m_doc->attached() && !m_doc->inPageCache()) {
+ // FIXME: We don't call willRemove here. Why is that OK?
+ m_doc->detach();
+ }
+
+ m_doc = newDoc;
+ selection()->updateSecureKeyboardEntryIfActive();
+
+ if (m_doc && !m_doc->attached())
+ m_doc->attach();
+
+ // Update the cached 'document' property, which is now stale.
+ m_script.updateDocument();
+
+ if (m_page)
+ m_page->updateViewportArguments();
+}
+
+#if ENABLE(ORIENTATION_EVENTS)
+void Frame::sendOrientationChangeEvent(int orientation)
+{
+ m_orientation = orientation;
+ if (Document* doc = document())
+ doc->dispatchWindowEvent(Event::create(eventNames().orientationchangeEvent, false, false));
+}
+#endif // ENABLE(ORIENTATION_EVENTS)
+
+Settings* Frame::settings() const
+{
+ return m_page ? m_page->settings() : 0;
+}
+
+static RegularExpression* createRegExpForLabels(const Vector<String>& labels)
+{
+ // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being
+ // the same across calls. We can't do that.
+
+ DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive));
+ String pattern("(");
+ unsigned int numLabels = labels.size();
+ unsigned int i;
+ for (i = 0; i < numLabels; i++) {
+ String label = labels[i];
+
+ bool startsWithWordChar = false;
+ bool endsWithWordChar = false;
+ if (label.length()) {
+ startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0;
+ endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0;
+ }
+
+ if (i)
+ pattern.append("|");
+ // Search for word boundaries only if label starts/ends with "word characters".
+ // If we always searched for word boundaries, this wouldn't work for languages
+ // such as Japanese.
+ if (startsWithWordChar)
+ pattern.append("\\b");
+ pattern.append(label);
+ if (endsWithWordChar)
+ pattern.append("\\b");
+ }
+ pattern.append(")");
+ return new RegularExpression(pattern, TextCaseInsensitive);
+}
+
+String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell, size_t* resultDistanceFromStartOfCell)
+{
+ HTMLTableCellElement* aboveCell = cell->cellAbove();
+ if (aboveCell) {
+ // search within the above cell we found for a match
+ size_t lengthSearched = 0;
+ for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
+ if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
+ // For each text chunk, run the regexp
+ String nodeString = n->nodeValue();
+ int pos = regExp->searchRev(nodeString);
+ if (pos >= 0) {
+ if (resultDistanceFromStartOfCell)
+ *resultDistanceFromStartOfCell = lengthSearched;
+ return nodeString.substring(pos, regExp->matchedLength());
+ }
+ lengthSearched += nodeString.length();
+ }
+ }
+ }
+
+ // Any reason in practice to search all cells in that are above cell?
+ if (resultDistanceFromStartOfCell)
+ *resultDistanceFromStartOfCell = notFound;
+ return String();
+}
+
+String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove)
+{
+ OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
+ // We stop searching after we've seen this many chars
+ const unsigned int charsSearchedThreshold = 500;
+ // This is the absolute max we search. We allow a little more slop than
+ // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
+ const unsigned int maxCharsSearched = 600;
+ // If the starting element is within a table, the cell that contains it
+ HTMLTableCellElement* startingTableCell = 0;
+ bool searchedCellAbove = false;
+
+ if (resultDistance)
+ *resultDistance = notFound;
+ if (resultIsInCellAbove)
+ *resultIsInCellAbove = false;
+
+ // walk backwards in the node tree, until another element, or form, or end of tree
+ int unsigned lengthSearched = 0;
+ Node* n;
+ for (n = element->traversePreviousNode();
+ n && lengthSearched < charsSearchedThreshold;
+ n = n->traversePreviousNode())
+ {
+ if (n->hasTagName(formTag)
+ || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()))
+ {
+ // We hit another form element or the start of the form - bail out
+ break;
+ } else if (n->hasTagName(tdTag) && !startingTableCell) {
+ startingTableCell = static_cast<HTMLTableCellElement*>(n);
+ } else if (n->hasTagName(trTag) && startingTableCell) {
+ String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
+ if (!result.isEmpty()) {
+ if (resultIsInCellAbove)
+ *resultIsInCellAbove = true;
+ return result;
+ }
+ searchedCellAbove = true;
+ } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
+ // For each text chunk, run the regexp
+ String nodeString = n->nodeValue();
+ // add 100 for slop, to make it more likely that we'll search whole nodes
+ if (lengthSearched + nodeString.length() > maxCharsSearched)
+ nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
+ int pos = regExp->searchRev(nodeString);
+ if (pos >= 0) {
+ if (resultDistance)
+ *resultDistance = lengthSearched;
+ return nodeString.substring(pos, regExp->matchedLength());
+ }
+ lengthSearched += nodeString.length();
+ }
+ }
+
+ // If we started in a cell, but bailed because we found the start of the form or the
+ // previous element, we still might need to search the row above us for a label.
+ if (startingTableCell && !searchedCellAbove) {
+ String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
+ if (!result.isEmpty()) {
+ if (resultIsInCellAbove)
+ *resultIsInCellAbove = true;
+ return result;
+ }
+ }
+ return String();
+}
+
+static String matchLabelsAgainstString(const Vector<String>& labels, const String& stringToMatch)
+{
+ if (stringToMatch.isEmpty())
+ return String();
+
+ String mutableStringToMatch = stringToMatch;
+
+ // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
+ replace(mutableStringToMatch, RegularExpression("\\d", TextCaseSensitive), " ");
+ mutableStringToMatch.replace('_', ' ');
+
+ OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
+ // Use the largest match we can find in the whole string
+ int pos;
+ int length;
+ int bestPos = -1;
+ int bestLength = -1;
+ int start = 0;
+ do {
+ pos = regExp->match(mutableStringToMatch, start);
+ if (pos != -1) {
+ length = regExp->matchedLength();
+ if (length >= bestLength) {
+ bestPos = pos;
+ bestLength = length;
+ }
+ start = pos + 1;
+ }
+ } while (pos != -1);
+
+ if (bestPos != -1)
+ return mutableStringToMatch.substring(bestPos, bestLength);
+ return String();
+}
+
+String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element)
+{
+ // Match against the name element, then against the id element if no match is found for the name element.
+ // See 7538330 for one popular site that benefits from the id element check.
+ // FIXME: This code is mirrored in FrameMac.mm. It would be nice to make the Mac code call the platform-agnostic
+ // code, which would require converting the NSArray of NSStrings to a Vector of Strings somewhere along the way.
+ String resultFromNameAttribute = matchLabelsAgainstString(labels, element->getAttribute(nameAttr));
+ if (!resultFromNameAttribute.isEmpty())
+ return resultFromNameAttribute;
+
+ return matchLabelsAgainstString(labels, element->getAttribute(idAttr));
+}
+
+void Frame::setPrinting(bool printing, const FloatSize& pageSize, float maximumShrinkRatio, AdjustViewSizeOrNot shouldAdjustViewSize)
+{
+ m_doc->setPrinting(printing);
+ view()->adjustMediaTypeForPrinting(printing);
+
+ m_doc->styleSelectorChanged(RecalcStyleImmediately);
+ view()->forceLayoutForPagination(pageSize, maximumShrinkRatio, shouldAdjustViewSize);
+
+ // Subframes of the one we're printing don't lay out to the page size.
+ for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
+ child->setPrinting(printing, IntSize(), 0, shouldAdjustViewSize);
+}
+
+void Frame::injectUserScripts(UserScriptInjectionTime injectionTime)
+{
+ if (!m_page)
+ return;
+
+ if (loader()->stateMachine()->creatingInitialEmptyDocument())
+ return;
+
+ // Walk the hashtable. Inject by world.
+ const UserScriptMap* userScripts = m_page->group().userScripts();
+ if (!userScripts)
+ return;
+ UserScriptMap::const_iterator end = userScripts->end();
+ for (UserScriptMap::const_iterator it = userScripts->begin(); it != end; ++it)
+ injectUserScriptsForWorld(it->first.get(), *it->second, injectionTime);
+}
+
+void Frame::injectUserScriptsForWorld(DOMWrapperWorld* world, const UserScriptVector& userScripts, UserScriptInjectionTime injectionTime)
+{
+ if (userScripts.isEmpty())
+ return;
+
+ Document* doc = document();
+ if (!doc)
+ return;
+
+ Vector<ScriptSourceCode> sourceCode;
+ unsigned count = userScripts.size();
+ for (unsigned i = 0; i < count; ++i) {
+ UserScript* script = userScripts[i].get();
+ if (script->injectedFrames() == InjectInTopFrameOnly && ownerElement())
+ continue;
+
+ if (script->injectionTime() == injectionTime && UserContentURLPattern::matchesPatterns(doc->url(), script->whitelist(), script->blacklist()))
+ m_script.evaluateInWorld(ScriptSourceCode(script->source(), script->url()), world);
+ }
+}
+
+bool Frame::isContentEditable() const
+{
+ if (m_editor.clientIsEditable())
+ return true;
+ return m_doc->inDesignMode();
+}
+
+#ifndef NDEBUG
+static HashSet<Frame*>& keepAliveSet()
+{
+ DEFINE_STATIC_LOCAL(HashSet<Frame*>, staticKeepAliveSet, ());
+ return staticKeepAliveSet;
+}
+#endif
+
+void Frame::keepAlive()
+{
+ if (m_lifeSupportTimer.isActive())
+ return;
+#ifndef NDEBUG
+ keepAliveSet().add(this);
+#endif
+ ref();
+ m_lifeSupportTimer.startOneShot(0);
+}
+
+#ifndef NDEBUG
+void Frame::cancelAllKeepAlive()
+{
+ HashSet<Frame*>::iterator end = keepAliveSet().end();
+ for (HashSet<Frame*>::iterator it = keepAliveSet().begin(); it != end; ++it) {
+ Frame* frame = *it;
+ frame->m_lifeSupportTimer.stop();
+ frame->deref();
+ }
+ keepAliveSet().clear();
+}
+#endif
+
+void Frame::lifeSupportTimerFired(Timer<Frame>*)
+{
+#ifndef NDEBUG
+ keepAliveSet().remove(this);
+#endif
+ deref();
+}
+
+void Frame::clearDOMWindow()
+{
+ if (m_domWindow) {
+ m_liveFormerWindows.add(m_domWindow.get());
+ m_domWindow->clear();
+ }
+ m_domWindow = 0;
+}
+
+RenderView* Frame::contentRenderer() const
+{
+ Document* doc = document();
+ if (!doc)
+ return 0;
+ RenderObject* object = doc->renderer();
+ if (!object)
+ return 0;
+ ASSERT(object->isRenderView());
+ return toRenderView(object);
+}
+
+RenderPart* Frame::ownerRenderer() const
+{
+ HTMLFrameOwnerElement* ownerElement = m_ownerElement;
+ if (!ownerElement)
+ return 0;
+ RenderObject* object = ownerElement->renderer();
+ if (!object)
+ return 0;
+ // FIXME: If <object> is ever fixed to disassociate itself from frames
+ // that it has started but canceled, then this can turn into an ASSERT
+ // since m_ownerElement would be 0 when the load is canceled.
+ // https://bugs.webkit.org/show_bug.cgi?id=18585
+ if (!object->isRenderPart())
+ return 0;
+ return toRenderPart(object);
+}
+
+Frame* Frame::frameForWidget(const Widget* widget)
+{
+ ASSERT_ARG(widget, widget);
+
+ if (RenderWidget* renderer = RenderWidget::find(widget))
+ if (Node* node = renderer->node())
+ return node->document()->frame();
+
+ // Assume all widgets are either a FrameView or owned by a RenderWidget.
+ // FIXME: That assumption is not right for scroll bars!
+ ASSERT(widget->isFrameView());
+ return static_cast<const FrameView*>(widget)->frame();
+}
+
+void Frame::clearTimers(FrameView *view, Document *document)
+{
+ if (view) {
+ view->unscheduleRelayout();
+ if (view->frame()) {
+ view->frame()->animation()->suspendAnimationsForDocument(document);
+ view->frame()->eventHandler()->stopAutoscrollTimer();
+ }
+ }
+}
+
+void Frame::clearTimers()
+{
+ clearTimers(m_view.get(), document());
+}
+
+void Frame::setDOMWindow(DOMWindow* domWindow)
+{
+ if (m_domWindow) {
+ m_liveFormerWindows.add(m_domWindow.get());
+ m_domWindow->clear();
+ }
+ m_domWindow = domWindow;
+}
+
+DOMWindow* Frame::domWindow() const
+{
+ if (!m_domWindow)
+ m_domWindow = DOMWindow::create(const_cast<Frame*>(this));
+
+ return m_domWindow.get();
+}
+
+void Frame::clearFormerDOMWindow(DOMWindow* window)
+{
+ m_liveFormerWindows.remove(window);
+}
+
+void Frame::pageDestroyed()
+{
+ if (Frame* parent = tree()->parent())
+ parent->loader()->checkLoadComplete();
+
+ if (m_domWindow)
+ m_domWindow->pageDestroyed();
+
+ // 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(0);
+
+ script()->clearWindowShell();
+ script()->clearScriptObjects();
+ script()->updatePlatformScriptObjects();
+
+ detachFromPage();
+}
+
+void Frame::disconnectOwnerElement()
+{
+ if (m_ownerElement) {
+ if (Document* doc = document())
+ doc->clearAXObjectCache();
+ m_ownerElement->m_contentFrame = 0;
+ if (m_page)
+ m_page->decrementFrameCount();
+ }
+ m_ownerElement = 0;
+}
+
+// The frame is moved in DOM, potentially to another page.
+void Frame::transferChildFrameToNewDocument()
+{
+ ASSERT(m_ownerElement);
+ Frame* newParent = m_ownerElement->document()->frame();
+ ASSERT(newParent);
+ bool didTransfer = false;
+
+ // Switch page.
+ Page* newPage = newParent->page();
+ Page* oldPage = m_page;
+ if (m_page != newPage) {
+ if (m_page) {
+ if (m_page->focusController()->focusedFrame() == this)
+ m_page->focusController()->setFocusedFrame(0);
+
+ m_page->decrementFrameCount();
+ }
+
+ m_page = newPage;
+
+ if (newPage)
+ newPage->incrementFrameCount();
+
+ didTransfer = true;
+ }
+
+ // Update the frame tree.
+ didTransfer = newParent->tree()->transferChild(this) || didTransfer;
+
+ // Avoid unnecessary calls to client and frame subtree if the frame ended
+ // up on the same page and under the same parent frame.
+ if (didTransfer) {
+ // Let external clients update themselves.
+ loader()->client()->didTransferChildFrameToNewDocument(oldPage);
+
+ // Update resource tracking now that frame could be in a different page.
+ if (oldPage != newPage)
+ loader()->transferLoadingResourcesFromPage(oldPage);
+
+ // Do the same for all the children.
+ for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
+ child->transferChildFrameToNewDocument();
+ }
+}
+
+String Frame::documentTypeString() const
+{
+ if (DocumentType* doctype = document()->doctype())
+ return createMarkup(doctype);
+
+ return String();
+}
+
+VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint)
+{
+ HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, true);
+ Node* node = result.innerNode();
+ if (!node)
+ return VisiblePosition();
+ RenderObject* renderer = node->renderer();
+ if (!renderer)
+ return VisiblePosition();
+ VisiblePosition visiblePos = renderer->positionForPoint(result.localPoint());
+ if (visiblePos.isNull())
+ visiblePos = VisiblePosition(Position(node, 0));
+ return visiblePos;
+}
+
+Document* Frame::documentAtPoint(const IntPoint& point)
+{
+ if (!view())
+ return 0;
+
+ IntPoint pt = view()->windowToContents(point);
+ HitTestResult result = HitTestResult(pt);
+
+ if (contentRenderer())
+ result = eventHandler()->hitTestResultAtPoint(pt, false);
+ return result.innerNode() ? result.innerNode()->document() : 0;
+}
+
+void Frame::createView(const IntSize& viewportSize,
+ const Color& backgroundColor, bool transparent,
+ const IntSize& fixedLayoutSize, bool useFixedLayout,
+ ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
+ ScrollbarMode verticalScrollbarMode, bool verticalLock)
+{
+ ASSERT(this);
+ ASSERT(m_page);
+
+ bool isMainFrame = this == m_page->mainFrame();
+
+ if (isMainFrame && view())
+ view()->setParentVisible(false);
+
+ setView(0);
+
+ RefPtr<FrameView> frameView;
+ if (isMainFrame) {
+ frameView = FrameView::create(this, viewportSize);
+ frameView->setFixedLayoutSize(fixedLayoutSize);
+ frameView->setUseFixedLayout(useFixedLayout);
+ } else
+ frameView = FrameView::create(this);
+
+ frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
+
+ setView(frameView);
+
+ if (backgroundColor.isValid())
+ frameView->updateBackgroundRecursively(backgroundColor, transparent);
+
+ if (isMainFrame)
+ frameView->setParentVisible(true);
+
+ if (ownerRenderer())
+ ownerRenderer()->setWidget(frameView);
+
+ if (HTMLFrameOwnerElement* owner = ownerElement())
+ view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
+}
+
+#if ENABLE(TILED_BACKING_STORE)
+void Frame::setTiledBackingStoreEnabled(bool enabled)
+{
+ if (!enabled) {
+ m_tiledBackingStore.clear();
+ return;
+ }
+ if (m_tiledBackingStore)
+ return;
+ m_tiledBackingStore.set(new TiledBackingStore(this));
+ if (m_view)
+ m_view->setPaintsEntireContents(true);
+}
+
+void Frame::tiledBackingStorePaintBegin()
+{
+ if (!m_view)
+ return;
+ m_view->updateLayoutAndStyleIfNeededRecursive();
+ m_view->flushDeferredRepaints();
+}
+
+void Frame::tiledBackingStorePaint(GraphicsContext* context, const IntRect& rect)
+{
+ if (!m_view)
+ return;
+ m_view->paintContents(context, rect);
+}
+
+void Frame::tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea)
+{
+ if (!m_page || !m_view)
+ return;
+ unsigned size = paintedArea.size();
+ // Request repaint from the system
+ for (int n = 0; n < size; ++n)
+ m_page->chrome()->invalidateContentsAndWindow(m_view->contentsToWindow(paintedArea[n]), false);
+}
+
+IntRect Frame::tiledBackingStoreContentsRect()
+{
+ if (!m_view)
+ return IntRect();
+ return IntRect(IntPoint(), m_view->contentsSize());
+}
+
+IntRect Frame::tiledBackingStoreVisibleRect()
+{
+ if (!m_page)
+ return IntRect();
+ return m_page->chrome()->client()->visibleRectForTiledBackingStore();
+}
+
+Color Frame::tiledBackingStoreBackgroundColor() const
+{
+ if (!m_view)
+ return Color();
+ return m_view->baseBackgroundColor();
+}
+#endif
+
+String Frame::layerTreeAsText() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ document()->updateLayout();
+
+ if (!contentRenderer())
+ return String();
+
+ return contentRenderer()->compositor()->layerTreeAsText();
+#else
+ return String();
+#endif
+}
+
+void Frame::setPageZoomFactor(float factor)
+{
+ setPageAndTextZoomFactors(factor, m_textZoomFactor);
+}
+
+void Frame::setTextZoomFactor(float factor)
+{
+ setPageAndTextZoomFactors(m_pageZoomFactor, factor);
+}
+
+void Frame::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;
+
+#if ENABLE(SVG)
+ // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
+ // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
+ if (document->isSVGDocument()) {
+ if (!static_cast<SVGDocument*>(document)->zoomAndPanEnabled())
+ return;
+ if (document->renderer())
+ document->renderer()->setNeedsLayout(true);
+ }
+#endif
+
+ if (m_pageZoomFactor != pageZoomFactor) {
+ if (FrameView* view = this->view()) {
+ // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
+ IntPoint scrollPosition = view->scrollPosition();
+ float percentDifference = (pageZoomFactor / m_pageZoomFactor);
+ view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
+ }
+ }
+
+ m_pageZoomFactor = pageZoomFactor;
+ m_textZoomFactor = textZoomFactor;
+
+ document->recalcStyle(Node::Force);
+
+ for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
+ child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
+
+ if (FrameView* view = this->view()) {
+ if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
+ view->layout();
+ }
+}
+
+void Frame::scalePage(float scale, const IntPoint& origin)
+{
+ Document* document = this->document();
+ if (!document)
+ return;
+
+ m_pageScaleFactor = scale;
+
+ if (document->renderer())
+ document->renderer()->setNeedsLayout(true);
+
+ document->recalcStyle(Node::Force);
+
+ if (FrameView* view = this->view()) {
+ if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
+ view->layout();
+ view->setScrollPosition(origin);
+ }
+}
+
+} // namespace WebCore