Home | History | Annotate | Download | only in page
      1 /*
      2  * Copyright (C) 1998, 1999 Torben Weis <weis (at) kde.org>
      3  *                     1999 Lars Knoll <knoll (at) kde.org>
      4  *                     1999 Antti Koivisto <koivisto (at) kde.org>
      5  *                     2000 Simon Hausmann <hausmann (at) kde.org>
      6  *                     2000 Stefan Schimanski <1Stein (at) gmx.de>
      7  *                     2001 George Staikos <staikos (at) 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 (at) nypop.com>
     10  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
     11  * Copyright (C) 2008 Eric Seidel <eric (at) webkit.org>
     12  *
     13  * This library is free software; you can redistribute it and/or
     14  * modify it under the terms of the GNU Library General Public
     15  * License as published by the Free Software Foundation; either
     16  * version 2 of the License, or (at your option) any later version.
     17  *
     18  * This library is distributed in the hope that it will be useful,
     19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     21  * Library General Public License for more details.
     22  *
     23  * You should have received a copy of the GNU Library General Public License
     24  * along with this library; see the file COPYING.LIB.  If not, write to
     25  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     26  * Boston, MA 02110-1301, USA.
     27  */
     28 
     29 #include "config.h"
     30 #include "Frame.h"
     31 
     32 #include "ApplyStyleCommand.h"
     33 #include "CSSComputedStyleDeclaration.h"
     34 #include "CSSMutableStyleDeclaration.h"
     35 #include "CSSProperty.h"
     36 #include "CSSPropertyNames.h"
     37 #include "CachedCSSStyleSheet.h"
     38 #include "Chrome.h"
     39 #include "ChromeClient.h"
     40 #include "DOMWindow.h"
     41 #include "CachedResourceLoader.h"
     42 #include "DocumentType.h"
     43 #include "EditingText.h"
     44 #include "EditorClient.h"
     45 #include "EventNames.h"
     46 #include "FloatQuad.h"
     47 #include "FocusController.h"
     48 #include "FrameLoader.h"
     49 #include "FrameLoaderClient.h"
     50 #include "FrameView.h"
     51 #include "GraphicsContext.h"
     52 #include "GraphicsLayer.h"
     53 #include "HTMLDocument.h"
     54 #include "HTMLFormControlElement.h"
     55 #include "HTMLFormElement.h"
     56 #include "HTMLFrameElementBase.h"
     57 #include "HTMLNames.h"
     58 #include "HTMLTableCellElement.h"
     59 #include "HitTestResult.h"
     60 #include "Logging.h"
     61 #include "MediaFeatureNames.h"
     62 #include "Navigator.h"
     63 #include "NodeList.h"
     64 #include "Page.h"
     65 #include "PageGroup.h"
     66 #include "RegularExpression.h"
     67 #include "RenderLayer.h"
     68 #include "RenderPart.h"
     69 #include "RenderTableCell.h"
     70 #include "RenderTextControl.h"
     71 #include "RenderTheme.h"
     72 #include "RenderView.h"
     73 #include "ScriptController.h"
     74 #include "ScriptSourceCode.h"
     75 #include "ScriptValue.h"
     76 #include "Settings.h"
     77 #include "TextIterator.h"
     78 #include "TextResourceDecoder.h"
     79 #include "UserContentURLPattern.h"
     80 #include "UserTypingGestureIndicator.h"
     81 #include "XMLNSNames.h"
     82 #include "XMLNames.h"
     83 #include "htmlediting.h"
     84 #include "markup.h"
     85 #include "npruntime_impl.h"
     86 #include "visible_units.h"
     87 #include <wtf/RefCountedLeakCounter.h>
     88 #include <wtf/StdLibExtras.h>
     89 
     90 #if USE(ACCELERATED_COMPOSITING)
     91 #include "RenderLayerCompositor.h"
     92 #endif
     93 
     94 #if USE(JSC)
     95 #include "JSDOMWindowShell.h"
     96 #include "runtime_root.h"
     97 #endif
     98 
     99 #include "MathMLNames.h"
    100 #include "SVGNames.h"
    101 #include "XLinkNames.h"
    102 
    103 #if ENABLE(SVG)
    104 #include "SVGDocument.h"
    105 #include "SVGDocumentExtensions.h"
    106 #endif
    107 
    108 #if ENABLE(TILED_BACKING_STORE)
    109 #include "TiledBackingStore.h"
    110 #endif
    111 
    112 #if ENABLE(WML)
    113 #include "WMLNames.h"
    114 #endif
    115 
    116 #if PLATFORM(ANDROID)
    117 #include "WebViewCore.h"
    118 #endif
    119 
    120 using namespace std;
    121 
    122 namespace WebCore {
    123 
    124 using namespace HTMLNames;
    125 
    126 #ifndef NDEBUG
    127 static WTF::RefCountedLeakCounter frameCounter("Frame");
    128 #endif
    129 
    130 static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
    131 {
    132     if (!ownerElement)
    133         return 0;
    134     return ownerElement->document()->frame();
    135 }
    136 
    137 static inline float parentPageZoomFactor(Frame* frame)
    138 {
    139     Frame* parent = frame->tree()->parent();
    140     if (!parent)
    141         return 1;
    142     return parent->pageZoomFactor();
    143 }
    144 
    145 static inline float parentTextZoomFactor(Frame* frame)
    146 {
    147     Frame* parent = frame->tree()->parent();
    148     if (!parent)
    149         return 1;
    150     return parent->textZoomFactor();
    151 }
    152 
    153 inline Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient)
    154     : m_page(page)
    155     , m_treeNode(this, parentFromOwnerElement(ownerElement))
    156     , m_loader(this, frameLoaderClient)
    157     , m_navigationScheduler(this)
    158     , m_ownerElement(ownerElement)
    159     , m_script(this)
    160     , m_editor(this)
    161     , m_selectionController(this)
    162     , m_eventHandler(this)
    163     , m_animationController(this)
    164     , m_lifeSupportTimer(this, &Frame::lifeSupportTimerFired)
    165     , m_pageZoomFactor(parentPageZoomFactor(this))
    166     , m_textZoomFactor(parentTextZoomFactor(this))
    167     , m_pageScaleFactor(1)
    168 #if ENABLE(ORIENTATION_EVENTS)
    169     , m_orientation(0)
    170 #endif
    171     , m_inViewSourceMode(false)
    172     , m_isDisconnected(false)
    173     , m_excludeFromTextSearch(false)
    174 #if PLATFORM(ANDROID)
    175     // Temporary hack for http://b/5188895
    176     , m_isDocumentUpToDate(true)
    177 #endif
    178 {
    179     ASSERT(page);
    180     AtomicString::init();
    181     HTMLNames::init();
    182     QualifiedName::init();
    183     MediaFeatureNames::init();
    184     SVGNames::init();
    185     XLinkNames::init();
    186     MathMLNames::init();
    187     XMLNSNames::init();
    188     XMLNames::init();
    189 
    190 #if ENABLE(WML)
    191     WMLNames::init();
    192 #endif
    193 
    194     if (!ownerElement) {
    195 #if ENABLE(TILED_BACKING_STORE)
    196         // Top level frame only for now.
    197         setTiledBackingStoreEnabled(page->settings()->tiledBackingStoreEnabled());
    198 #endif
    199     } else {
    200         page->incrementFrameCount();
    201 
    202         // Make sure we will not end up with two frames referencing the same owner element.
    203         Frame*& contentFrameSlot = ownerElement->m_contentFrame;
    204         ASSERT(!contentFrameSlot || contentFrameSlot->ownerElement() != ownerElement);
    205         contentFrameSlot = this;
    206     }
    207 
    208 #ifndef NDEBUG
    209     frameCounter.increment();
    210 #endif
    211 }
    212 
    213 PassRefPtr<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client)
    214 {
    215     RefPtr<Frame> frame = adoptRef(new Frame(page, ownerElement, client));
    216     if (!ownerElement)
    217         page->setMainFrame(frame);
    218     return frame.release();
    219 }
    220 
    221 Frame::~Frame()
    222 {
    223     setView(0);
    224     loader()->cancelAndClear();
    225 
    226     // FIXME: We should not be doing all this work inside the destructor
    227 
    228     ASSERT(!m_lifeSupportTimer.isActive());
    229 
    230 #ifndef NDEBUG
    231     frameCounter.decrement();
    232 #endif
    233 
    234     disconnectOwnerElement();
    235 
    236     if (m_domWindow)
    237         m_domWindow->disconnectFrame();
    238     script()->clearWindowShell();
    239 
    240     HashSet<DOMWindow*>::iterator end = m_liveFormerWindows.end();
    241     for (HashSet<DOMWindow*>::iterator it = m_liveFormerWindows.begin(); it != end; ++it)
    242         (*it)->disconnectFrame();
    243 
    244     HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
    245     for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
    246         (*it)->frameDestroyed();
    247 
    248     if (m_view) {
    249         m_view->hide();
    250         m_view->clearFrame();
    251     }
    252 
    253     ASSERT(!m_lifeSupportTimer.isActive());
    254 }
    255 
    256 void Frame::addDestructionObserver(FrameDestructionObserver* observer)
    257 {
    258     m_destructionObservers.add(observer);
    259 }
    260 
    261 void Frame::removeDestructionObserver(FrameDestructionObserver* observer)
    262 {
    263     m_destructionObservers.remove(observer);
    264 }
    265 
    266 void Frame::setView(PassRefPtr<FrameView> view)
    267 {
    268     // We the custom scroll bars as early as possible to prevent m_doc->detach()
    269     // from messing with the view such that its scroll bars won't be torn down.
    270     // FIXME: We should revisit this.
    271     if (m_view)
    272         m_view->detachCustomScrollbars();
    273 
    274     // Detach the document now, so any onUnload handlers get run - if
    275     // we wait until the view is destroyed, then things won't be
    276     // hooked up enough for some JavaScript calls to work.
    277     if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) {
    278         // FIXME: We don't call willRemove here. Why is that OK?
    279         m_doc->detach();
    280     }
    281 
    282     if (m_view)
    283         m_view->unscheduleRelayout();
    284 
    285     eventHandler()->clear();
    286 
    287     m_view = view;
    288 
    289     // Only one form submission is allowed per view of a part.
    290     // Since this part may be getting reused as a result of being
    291     // pulled from the back/forward cache, reset this flag.
    292     loader()->resetMultipleFormSubmissionProtection();
    293 
    294 #if ENABLE(TILED_BACKING_STORE)
    295     if (m_view && tiledBackingStore())
    296         m_view->setPaintsEntireContents(true);
    297 #endif
    298 }
    299 
    300 void Frame::setDocument(PassRefPtr<Document> newDoc)
    301 {
    302     ASSERT(!newDoc || newDoc->frame());
    303     if (m_doc && m_doc->attached() && !m_doc->inPageCache()) {
    304         // FIXME: We don't call willRemove here. Why is that OK?
    305         m_doc->detach();
    306     }
    307 
    308     m_doc = newDoc;
    309 #if PLATFORM(ANDROID)
    310     // Temporary hack for http://b/5188895
    311     m_isDocumentUpToDate = true;
    312 #endif
    313     selection()->updateSecureKeyboardEntryIfActive();
    314 
    315     if (m_doc && !m_doc->attached())
    316         m_doc->attach();
    317 
    318     // Update the cached 'document' property, which is now stale.
    319     m_script.updateDocument();
    320 
    321     if (m_page)
    322         m_page->updateViewportArguments();
    323 }
    324 
    325 #if ENABLE(ORIENTATION_EVENTS)
    326 void Frame::sendOrientationChangeEvent(int orientation)
    327 {
    328     m_orientation = orientation;
    329     if (Document* doc = document())
    330         doc->dispatchWindowEvent(Event::create(eventNames().orientationchangeEvent, false, false));
    331 }
    332 #endif // ENABLE(ORIENTATION_EVENTS)
    333 
    334 Settings* Frame::settings() const
    335 {
    336     return m_page ? m_page->settings() : 0;
    337 }
    338 
    339 static RegularExpression* createRegExpForLabels(const Vector<String>& labels)
    340 {
    341     // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being
    342     // the same across calls.  We can't do that.
    343 
    344     DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive));
    345     String pattern("(");
    346     unsigned int numLabels = labels.size();
    347     unsigned int i;
    348     for (i = 0; i < numLabels; i++) {
    349         String label = labels[i];
    350 
    351         bool startsWithWordChar = false;
    352         bool endsWithWordChar = false;
    353         if (label.length()) {
    354             startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0;
    355             endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0;
    356         }
    357 
    358         if (i)
    359             pattern.append("|");
    360         // Search for word boundaries only if label starts/ends with "word characters".
    361         // If we always searched for word boundaries, this wouldn't work for languages
    362         // such as Japanese.
    363         if (startsWithWordChar)
    364             pattern.append("\\b");
    365         pattern.append(label);
    366         if (endsWithWordChar)
    367             pattern.append("\\b");
    368     }
    369     pattern.append(")");
    370     return new RegularExpression(pattern, TextCaseInsensitive);
    371 }
    372 
    373 String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell, size_t* resultDistanceFromStartOfCell)
    374 {
    375     HTMLTableCellElement* aboveCell = cell->cellAbove();
    376     if (aboveCell) {
    377         // search within the above cell we found for a match
    378         size_t lengthSearched = 0;
    379         for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
    380             if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
    381                 // For each text chunk, run the regexp
    382                 String nodeString = n->nodeValue();
    383                 int pos = regExp->searchRev(nodeString);
    384                 if (pos >= 0) {
    385                     if (resultDistanceFromStartOfCell)
    386                         *resultDistanceFromStartOfCell = lengthSearched;
    387                     return nodeString.substring(pos, regExp->matchedLength());
    388                 }
    389                 lengthSearched += nodeString.length();
    390             }
    391         }
    392     }
    393 
    394     // Any reason in practice to search all cells in that are above cell?
    395     if (resultDistanceFromStartOfCell)
    396         *resultDistanceFromStartOfCell = notFound;
    397     return String();
    398 }
    399 
    400 String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove)
    401 {
    402     OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
    403     // We stop searching after we've seen this many chars
    404     const unsigned int charsSearchedThreshold = 500;
    405     // This is the absolute max we search.  We allow a little more slop than
    406     // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
    407     const unsigned int maxCharsSearched = 600;
    408     // If the starting element is within a table, the cell that contains it
    409     HTMLTableCellElement* startingTableCell = 0;
    410     bool searchedCellAbove = false;
    411 
    412     if (resultDistance)
    413         *resultDistance = notFound;
    414     if (resultIsInCellAbove)
    415         *resultIsInCellAbove = false;
    416 
    417     // walk backwards in the node tree, until another element, or form, or end of tree
    418     int unsigned lengthSearched = 0;
    419     Node* n;
    420     for (n = element->traversePreviousNode();
    421          n && lengthSearched < charsSearchedThreshold;
    422          n = n->traversePreviousNode())
    423     {
    424         if (n->hasTagName(formTag)
    425             || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()))
    426         {
    427             // We hit another form element or the start of the form - bail out
    428             break;
    429         } else if (n->hasTagName(tdTag) && !startingTableCell) {
    430             startingTableCell = static_cast<HTMLTableCellElement*>(n);
    431         } else if (n->hasTagName(trTag) && startingTableCell) {
    432             String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
    433             if (!result.isEmpty()) {
    434                 if (resultIsInCellAbove)
    435                     *resultIsInCellAbove = true;
    436                 return result;
    437             }
    438             searchedCellAbove = true;
    439         } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
    440             // For each text chunk, run the regexp
    441             String nodeString = n->nodeValue();
    442             // add 100 for slop, to make it more likely that we'll search whole nodes
    443             if (lengthSearched + nodeString.length() > maxCharsSearched)
    444                 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
    445             int pos = regExp->searchRev(nodeString);
    446             if (pos >= 0) {
    447                 if (resultDistance)
    448                     *resultDistance = lengthSearched;
    449                 return nodeString.substring(pos, regExp->matchedLength());
    450             }
    451             lengthSearched += nodeString.length();
    452         }
    453     }
    454 
    455     // If we started in a cell, but bailed because we found the start of the form or the
    456     // previous element, we still might need to search the row above us for a label.
    457     if (startingTableCell && !searchedCellAbove) {
    458          String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
    459         if (!result.isEmpty()) {
    460             if (resultIsInCellAbove)
    461                 *resultIsInCellAbove = true;
    462             return result;
    463         }
    464     }
    465     return String();
    466 }
    467 
    468 static String matchLabelsAgainstString(const Vector<String>& labels, const String& stringToMatch)
    469 {
    470     if (stringToMatch.isEmpty())
    471         return String();
    472 
    473     String mutableStringToMatch = stringToMatch;
    474 
    475     // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
    476     replace(mutableStringToMatch, RegularExpression("\\d", TextCaseSensitive), " ");
    477     mutableStringToMatch.replace('_', ' ');
    478 
    479     OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
    480     // Use the largest match we can find in the whole string
    481     int pos;
    482     int length;
    483     int bestPos = -1;
    484     int bestLength = -1;
    485     int start = 0;
    486     do {
    487         pos = regExp->match(mutableStringToMatch, start);
    488         if (pos != -1) {
    489             length = regExp->matchedLength();
    490             if (length >= bestLength) {
    491                 bestPos = pos;
    492                 bestLength = length;
    493             }
    494             start = pos + 1;
    495         }
    496     } while (pos != -1);
    497 
    498     if (bestPos != -1)
    499         return mutableStringToMatch.substring(bestPos, bestLength);
    500     return String();
    501 }
    502 
    503 String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element)
    504 {
    505     // Match against the name element, then against the id element if no match is found for the name element.
    506     // See 7538330 for one popular site that benefits from the id element check.
    507     // FIXME: This code is mirrored in FrameMac.mm. It would be nice to make the Mac code call the platform-agnostic
    508     // code, which would require converting the NSArray of NSStrings to a Vector of Strings somewhere along the way.
    509     String resultFromNameAttribute = matchLabelsAgainstString(labels, element->getAttribute(nameAttr));
    510     if (!resultFromNameAttribute.isEmpty())
    511         return resultFromNameAttribute;
    512 
    513     return matchLabelsAgainstString(labels, element->getAttribute(idAttr));
    514 }
    515 
    516 void Frame::setPrinting(bool printing, const FloatSize& pageSize, float maximumShrinkRatio, AdjustViewSizeOrNot shouldAdjustViewSize)
    517 {
    518     m_doc->setPrinting(printing);
    519     view()->adjustMediaTypeForPrinting(printing);
    520 
    521     m_doc->styleSelectorChanged(RecalcStyleImmediately);
    522     view()->forceLayoutForPagination(pageSize, maximumShrinkRatio, shouldAdjustViewSize);
    523 
    524     // Subframes of the one we're printing don't lay out to the page size.
    525     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
    526         child->setPrinting(printing, IntSize(), 0, shouldAdjustViewSize);
    527 }
    528 
    529 void Frame::injectUserScripts(UserScriptInjectionTime injectionTime)
    530 {
    531     if (!m_page)
    532         return;
    533 
    534     if (loader()->stateMachine()->creatingInitialEmptyDocument() && !settings()->shouldInjectUserScriptsInInitialEmptyDocument())
    535         return;
    536 
    537     // Walk the hashtable. Inject by world.
    538     const UserScriptMap* userScripts = m_page->group().userScripts();
    539     if (!userScripts)
    540         return;
    541     UserScriptMap::const_iterator end = userScripts->end();
    542     for (UserScriptMap::const_iterator it = userScripts->begin(); it != end; ++it)
    543         injectUserScriptsForWorld(it->first.get(), *it->second, injectionTime);
    544 }
    545 
    546 void Frame::injectUserScriptsForWorld(DOMWrapperWorld* world, const UserScriptVector& userScripts, UserScriptInjectionTime injectionTime)
    547 {
    548     if (userScripts.isEmpty())
    549         return;
    550 
    551     Document* doc = document();
    552     if (!doc)
    553         return;
    554 
    555     Vector<ScriptSourceCode> sourceCode;
    556     unsigned count = userScripts.size();
    557     for (unsigned i = 0; i < count; ++i) {
    558         UserScript* script = userScripts[i].get();
    559         if (script->injectedFrames() == InjectInTopFrameOnly && ownerElement())
    560             continue;
    561 
    562         if (script->injectionTime() == injectionTime && UserContentURLPattern::matchesPatterns(doc->url(), script->whitelist(), script->blacklist()))
    563             m_script.evaluateInWorld(ScriptSourceCode(script->source(), script->url()), world);
    564     }
    565 }
    566 
    567 #ifndef NDEBUG
    568 static HashSet<Frame*>& keepAliveSet()
    569 {
    570     DEFINE_STATIC_LOCAL(HashSet<Frame*>, staticKeepAliveSet, ());
    571     return staticKeepAliveSet;
    572 }
    573 #endif
    574 
    575 void Frame::keepAlive()
    576 {
    577     if (m_lifeSupportTimer.isActive())
    578         return;
    579 #ifndef NDEBUG
    580     keepAliveSet().add(this);
    581 #endif
    582     ref();
    583     m_lifeSupportTimer.startOneShot(0);
    584 }
    585 
    586 #ifndef NDEBUG
    587 void Frame::cancelAllKeepAlive()
    588 {
    589     HashSet<Frame*>::iterator end = keepAliveSet().end();
    590     for (HashSet<Frame*>::iterator it = keepAliveSet().begin(); it != end; ++it) {
    591         Frame* frame = *it;
    592         frame->m_lifeSupportTimer.stop();
    593         frame->deref();
    594     }
    595     keepAliveSet().clear();
    596 }
    597 #endif
    598 
    599 void Frame::lifeSupportTimerFired(Timer<Frame>*)
    600 {
    601 #ifndef NDEBUG
    602     keepAliveSet().remove(this);
    603 #endif
    604     deref();
    605 }
    606 
    607 void Frame::clearDOMWindow()
    608 {
    609     if (m_domWindow) {
    610         m_liveFormerWindows.add(m_domWindow.get());
    611         m_domWindow->clear();
    612     }
    613     m_domWindow = 0;
    614 }
    615 
    616 RenderView* Frame::contentRenderer() const
    617 {
    618     Document* doc = document();
    619     if (!doc)
    620         return 0;
    621     RenderObject* object = doc->renderer();
    622     if (!object)
    623         return 0;
    624     ASSERT(object->isRenderView());
    625     return toRenderView(object);
    626 }
    627 
    628 RenderPart* Frame::ownerRenderer() const
    629 {
    630     HTMLFrameOwnerElement* ownerElement = m_ownerElement;
    631     if (!ownerElement)
    632         return 0;
    633     RenderObject* object = ownerElement->renderer();
    634     if (!object)
    635         return 0;
    636     // FIXME: If <object> is ever fixed to disassociate itself from frames
    637     // that it has started but canceled, then this can turn into an ASSERT
    638     // since m_ownerElement would be 0 when the load is canceled.
    639     // https://bugs.webkit.org/show_bug.cgi?id=18585
    640     if (!object->isRenderPart())
    641         return 0;
    642     return toRenderPart(object);
    643 }
    644 
    645 Frame* Frame::frameForWidget(const Widget* widget)
    646 {
    647     ASSERT_ARG(widget, widget);
    648 
    649     if (RenderWidget* renderer = RenderWidget::find(widget))
    650         if (Node* node = renderer->node())
    651             return node->document()->frame();
    652 
    653     // Assume all widgets are either a FrameView or owned by a RenderWidget.
    654     // FIXME: That assumption is not right for scroll bars!
    655     ASSERT(widget->isFrameView());
    656     return static_cast<const FrameView*>(widget)->frame();
    657 }
    658 
    659 void Frame::clearTimers(FrameView *view, Document *document)
    660 {
    661     if (view) {
    662         view->unscheduleRelayout();
    663         if (view->frame()) {
    664             view->frame()->animation()->suspendAnimationsForDocument(document);
    665             view->frame()->eventHandler()->stopAutoscrollTimer();
    666         }
    667     }
    668 }
    669 
    670 void Frame::clearTimers()
    671 {
    672     clearTimers(m_view.get(), document());
    673 }
    674 
    675 void Frame::setDOMWindow(DOMWindow* domWindow)
    676 {
    677     if (m_domWindow) {
    678         m_liveFormerWindows.add(m_domWindow.get());
    679         m_domWindow->clear();
    680     }
    681     m_domWindow = domWindow;
    682 }
    683 
    684 DOMWindow* Frame::domWindow() const
    685 {
    686     if (!m_domWindow)
    687         m_domWindow = DOMWindow::create(const_cast<Frame*>(this));
    688 
    689     return m_domWindow.get();
    690 }
    691 
    692 void Frame::clearFormerDOMWindow(DOMWindow* window)
    693 {
    694     m_liveFormerWindows.remove(window);
    695 }
    696 
    697 void Frame::pageDestroyed()
    698 {
    699     if (Frame* parent = tree()->parent())
    700         parent->loader()->checkLoadComplete();
    701 
    702     if (m_domWindow) {
    703         m_domWindow->resetGeolocation();
    704         m_domWindow->pageDestroyed();
    705     }
    706 
    707     // FIXME: It's unclear as to why this is called more than once, but it is,
    708     // so page() could be NULL.
    709     if (page() && page()->focusController()->focusedFrame() == this)
    710         page()->focusController()->setFocusedFrame(0);
    711 
    712     script()->clearWindowShell();
    713     script()->clearScriptObjects();
    714     script()->updatePlatformScriptObjects();
    715 
    716     detachFromPage();
    717 }
    718 
    719 void Frame::disconnectOwnerElement()
    720 {
    721     if (m_ownerElement) {
    722         if (Document* doc = document())
    723             doc->clearAXObjectCache();
    724         m_ownerElement->m_contentFrame = 0;
    725         if (m_page)
    726             m_page->decrementFrameCount();
    727     }
    728     m_ownerElement = 0;
    729 }
    730 
    731 // The frame is moved in DOM, potentially to another page.
    732 void Frame::transferChildFrameToNewDocument()
    733 {
    734     ASSERT(m_ownerElement);
    735     Frame* newParent = m_ownerElement->document()->frame();
    736     ASSERT(newParent);
    737     bool didTransfer = false;
    738 
    739     // Switch page.
    740     Page* newPage = newParent->page();
    741     Page* oldPage = m_page;
    742     if (m_page != newPage) {
    743         if (m_page) {
    744             if (m_page->focusController()->focusedFrame() == this)
    745                 m_page->focusController()->setFocusedFrame(0);
    746 
    747              m_page->decrementFrameCount();
    748         }
    749 
    750         // FIXME: We should ideally allow existing Geolocation activities to continue
    751         // when the Geolocation's iframe is reparented.
    752         // See https://bugs.webkit.org/show_bug.cgi?id=55577
    753         // and https://bugs.webkit.org/show_bug.cgi?id=52877
    754         if (m_domWindow)
    755             m_domWindow->resetGeolocation();
    756 
    757         m_page = newPage;
    758 
    759         if (newPage)
    760             newPage->incrementFrameCount();
    761 
    762         didTransfer = true;
    763     }
    764 
    765     // Update the frame tree.
    766     didTransfer = newParent->tree()->transferChild(this) || didTransfer;
    767 
    768     // Avoid unnecessary calls to client and frame subtree if the frame ended
    769     // up on the same page and under the same parent frame.
    770     if (didTransfer) {
    771         // Let external clients update themselves.
    772         loader()->client()->didTransferChildFrameToNewDocument(oldPage);
    773 
    774         // Update resource tracking now that frame could be in a different page.
    775         if (oldPage != newPage)
    776             loader()->transferLoadingResourcesFromPage(oldPage);
    777 
    778         // Do the same for all the children.
    779         for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
    780             child->transferChildFrameToNewDocument();
    781     }
    782 }
    783 
    784 String Frame::documentTypeString() const
    785 {
    786     if (DocumentType* doctype = document()->doctype())
    787         return createMarkup(doctype);
    788 
    789     return String();
    790 }
    791 
    792 VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint)
    793 {
    794     HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, true);
    795     Node* node = result.innerNode();
    796     if (!node)
    797         return VisiblePosition();
    798     RenderObject* renderer = node->renderer();
    799     if (!renderer)
    800         return VisiblePosition();
    801     VisiblePosition visiblePos = renderer->positionForPoint(result.localPoint());
    802     if (visiblePos.isNull())
    803         visiblePos = firstPositionInOrBeforeNode(node);
    804     return visiblePos;
    805 }
    806 
    807 Document* Frame::documentAtPoint(const IntPoint& point)
    808 {
    809     if (!view())
    810         return 0;
    811 
    812     IntPoint pt = view()->windowToContents(point);
    813     HitTestResult result = HitTestResult(pt);
    814 
    815     if (contentRenderer())
    816         result = eventHandler()->hitTestResultAtPoint(pt, false);
    817     return result.innerNode() ? result.innerNode()->document() : 0;
    818 }
    819 
    820 PassRefPtr<Range> Frame::rangeForPoint(const IntPoint& framePoint)
    821 {
    822     VisiblePosition position = visiblePositionForPoint(framePoint);
    823     if (position.isNull())
    824         return 0;
    825 
    826     VisiblePosition previous = position.previous();
    827     if (previous.isNotNull()) {
    828         RefPtr<Range> previousCharacterRange = makeRange(previous, position);
    829         IntRect rect = editor()->firstRectForRange(previousCharacterRange.get());
    830         if (rect.contains(framePoint))
    831             return previousCharacterRange.release();
    832     }
    833 
    834     VisiblePosition next = position.next();
    835     if (next.isNotNull()) {
    836         RefPtr<Range> nextCharacterRange = makeRange(position, next);
    837         IntRect rect = editor()->firstRectForRange(nextCharacterRange.get());
    838         if (rect.contains(framePoint))
    839             return nextCharacterRange.release();
    840     }
    841 
    842     return 0;
    843 }
    844 
    845 void Frame::createView(const IntSize& viewportSize,
    846                        const Color& backgroundColor, bool transparent,
    847                        const IntSize& fixedLayoutSize, bool useFixedLayout,
    848                        ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
    849                        ScrollbarMode verticalScrollbarMode, bool verticalLock)
    850 {
    851     ASSERT(this);
    852     ASSERT(m_page);
    853 
    854     bool isMainFrame = this == m_page->mainFrame();
    855 
    856     if (isMainFrame && view())
    857         view()->setParentVisible(false);
    858 
    859     setView(0);
    860 
    861     RefPtr<FrameView> frameView;
    862     if (isMainFrame) {
    863         frameView = FrameView::create(this, viewportSize);
    864         frameView->setFixedLayoutSize(fixedLayoutSize);
    865         frameView->setUseFixedLayout(useFixedLayout);
    866     } else
    867         frameView = FrameView::create(this);
    868 
    869     frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
    870 
    871     setView(frameView);
    872 
    873     if (backgroundColor.isValid())
    874         frameView->updateBackgroundRecursively(backgroundColor, transparent);
    875 
    876     if (isMainFrame)
    877         frameView->setParentVisible(true);
    878 
    879     if (ownerRenderer())
    880         ownerRenderer()->setWidget(frameView);
    881 
    882     if (HTMLFrameOwnerElement* owner = ownerElement())
    883         view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
    884 }
    885 
    886 #if ENABLE(TILED_BACKING_STORE)
    887 void Frame::setTiledBackingStoreEnabled(bool enabled)
    888 {
    889     if (!enabled) {
    890         m_tiledBackingStore.clear();
    891         return;
    892     }
    893     if (m_tiledBackingStore)
    894         return;
    895     m_tiledBackingStore.set(new TiledBackingStore(this));
    896     if (m_view)
    897         m_view->setPaintsEntireContents(true);
    898 }
    899 
    900 void Frame::tiledBackingStorePaintBegin()
    901 {
    902     if (!m_view)
    903         return;
    904     m_view->updateLayoutAndStyleIfNeededRecursive();
    905     m_view->flushDeferredRepaints();
    906 }
    907 
    908 void Frame::tiledBackingStorePaint(GraphicsContext* context, const IntRect& rect)
    909 {
    910     if (!m_view)
    911         return;
    912     m_view->paintContents(context, rect);
    913 }
    914 
    915 void Frame::tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea)
    916 {
    917     if (!m_page || !m_view)
    918         return;
    919     unsigned size = paintedArea.size();
    920     // Request repaint from the system
    921     for (int n = 0; n < size; ++n)
    922         m_page->chrome()->invalidateContentsAndWindow(m_view->contentsToWindow(paintedArea[n]), false);
    923 }
    924 
    925 IntRect Frame::tiledBackingStoreContentsRect()
    926 {
    927     if (!m_view)
    928         return IntRect();
    929     return IntRect(IntPoint(), m_view->contentsSize());
    930 }
    931 
    932 IntRect Frame::tiledBackingStoreVisibleRect()
    933 {
    934     if (!m_page)
    935         return IntRect();
    936     return m_page->chrome()->client()->visibleRectForTiledBackingStore();
    937 }
    938 
    939 Color Frame::tiledBackingStoreBackgroundColor() const
    940 {
    941     if (!m_view)
    942         return Color();
    943     return m_view->baseBackgroundColor();
    944 }
    945 #endif
    946 
    947 String Frame::layerTreeAsText(bool showDebugInfo) const
    948 {
    949 #if USE(ACCELERATED_COMPOSITING)
    950     document()->updateLayout();
    951 
    952     if (!contentRenderer())
    953         return String();
    954 
    955     return contentRenderer()->compositor()->layerTreeAsText(showDebugInfo);
    956 #else
    957     return String();
    958 #endif
    959 }
    960 
    961 void Frame::setPageZoomFactor(float factor)
    962 {
    963     setPageAndTextZoomFactors(factor, m_textZoomFactor);
    964 }
    965 
    966 void Frame::setTextZoomFactor(float factor)
    967 {
    968     setPageAndTextZoomFactors(m_pageZoomFactor, factor);
    969 }
    970 
    971 void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
    972 {
    973     if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
    974         return;
    975 
    976     Page* page = this->page();
    977     if (!page)
    978         return;
    979 
    980     Document* document = this->document();
    981     if (!document)
    982         return;
    983 
    984     m_editor.dismissCorrectionPanelAsIgnored();
    985 
    986 #if ENABLE(SVG)
    987     // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
    988     // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
    989     if (document->isSVGDocument()) {
    990         if (!static_cast<SVGDocument*>(document)->zoomAndPanEnabled())
    991             return;
    992         if (document->renderer())
    993             document->renderer()->setNeedsLayout(true);
    994     }
    995 #endif
    996 
    997     if (m_pageZoomFactor != pageZoomFactor) {
    998         if (FrameView* view = this->view()) {
    999             // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
   1000             IntPoint scrollPosition = view->scrollPosition();
   1001             float percentDifference = (pageZoomFactor / m_pageZoomFactor);
   1002             view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
   1003         }
   1004     }
   1005 
   1006     m_pageZoomFactor = pageZoomFactor;
   1007     m_textZoomFactor = textZoomFactor;
   1008 
   1009     document->recalcStyle(Node::Force);
   1010 
   1011     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
   1012         child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
   1013 
   1014     if (FrameView* view = this->view()) {
   1015         if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
   1016             view->layout();
   1017     }
   1018 }
   1019 
   1020 #if USE(ACCELERATED_COMPOSITING)
   1021 void Frame::updateContentsScale(float scale)
   1022 {
   1023     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
   1024         child->updateContentsScale(scale);
   1025 
   1026     RenderView* root = contentRenderer();
   1027     if (root && root->compositor())
   1028         root->compositor()->updateContentsScale(scale);
   1029 }
   1030 #endif
   1031 
   1032 void Frame::scalePage(float scale, const IntPoint& origin)
   1033 {
   1034     Document* document = this->document();
   1035     if (!document)
   1036         return;
   1037 
   1038     if (scale != m_pageScaleFactor) {
   1039         m_pageScaleFactor = scale;
   1040 
   1041         if (document->renderer())
   1042             document->renderer()->setNeedsLayout(true);
   1043 
   1044         document->recalcStyle(Node::Force);
   1045 
   1046 #if USE(ACCELERATED_COMPOSITING)
   1047         updateContentsScale(scale);
   1048 #endif
   1049     }
   1050 
   1051     if (FrameView* view = this->view()) {
   1052         if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
   1053             view->layout();
   1054         view->setScrollPosition(origin);
   1055     }
   1056 }
   1057 
   1058 } // namespace WebCore
   1059