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