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 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 "BeforeUnloadEvent.h"
     34 #include "CSSComputedStyleDeclaration.h"
     35 #include "CSSMutableStyleDeclaration.h"
     36 #include "CSSProperty.h"
     37 #include "CSSPropertyNames.h"
     38 #include "CachedCSSStyleSheet.h"
     39 #include "Chrome.h"
     40 #include "DOMWindow.h"
     41 #include "DocLoader.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 "HTMLDocument.h"
     53 #include "HTMLFormControlElement.h"
     54 #include "HTMLFormElement.h"
     55 #include "HTMLFrameElementBase.h"
     56 #include "HTMLNames.h"
     57 #include "HTMLTableCellElement.h"
     58 #include "HitTestResult.h"
     59 #include "Logging.h"
     60 #include "MediaFeatureNames.h"
     61 #include "Navigator.h"
     62 #include "NodeList.h"
     63 #include "Page.h"
     64 #include "PageGroup.h"
     65 #include "RegularExpression.h"
     66 #include "RenderPart.h"
     67 #include "RenderTableCell.h"
     68 #include "RenderTextControl.h"
     69 #include "RenderTheme.h"
     70 #include "RenderView.h"
     71 #include "ScriptController.h"
     72 #include "ScriptSourceCode.h"
     73 #include "ScriptValue.h"
     74 #include "Settings.h"
     75 #include "TextIterator.h"
     76 #include "TextResourceDecoder.h"
     77 #include "UserContentURLPattern.h"
     78 #include "XMLNSNames.h"
     79 #include "XMLNames.h"
     80 #include "htmlediting.h"
     81 #include "markup.h"
     82 #include "npruntime_impl.h"
     83 #include "visible_units.h"
     84 #include <wtf/RefCountedLeakCounter.h>
     85 #include <wtf/StdLibExtras.h>
     86 
     87 #if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
     88 #import <Carbon/Carbon.h>
     89 #endif
     90 
     91 #if USE(JSC)
     92 #include "JSDOMWindowShell.h"
     93 #include "runtime_root.h"
     94 #endif
     95 
     96 #if ENABLE(SVG)
     97 #include "SVGDocument.h"
     98 #include "SVGDocumentExtensions.h"
     99 #include "SVGNames.h"
    100 #include "XLinkNames.h"
    101 #endif
    102 
    103 #if PLATFORM(ANDROID)
    104 #include "WebViewCore.h"
    105 #endif
    106 
    107 #if ENABLE(WML)
    108 #include "WMLNames.h"
    109 #endif
    110 
    111 #if ENABLE(MATHML)
    112 #include "MathMLNames.h"
    113 #endif
    114 
    115 using namespace std;
    116 
    117 namespace WebCore {
    118 
    119 using namespace HTMLNames;
    120 
    121 #ifndef NDEBUG
    122 static WTF::RefCountedLeakCounter frameCounter("Frame");
    123 #endif
    124 
    125 static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
    126 {
    127     if (!ownerElement)
    128         return 0;
    129     return ownerElement->document()->frame();
    130 }
    131 
    132 Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient)
    133     : m_page(page)
    134     , m_treeNode(this, parentFromOwnerElement(ownerElement))
    135     , m_loader(this, frameLoaderClient)
    136     , m_redirectScheduler(this)
    137     , m_ownerElement(ownerElement)
    138     , m_script(this)
    139     , m_selectionGranularity(CharacterGranularity)
    140     , m_selectionController(this)
    141     , m_editor(this)
    142     , m_eventHandler(this)
    143     , m_animationController(this)
    144     , m_lifeSupportTimer(this, &Frame::lifeSupportTimerFired)
    145 #if ENABLE(ORIENTATION_EVENTS)
    146     , m_orientation(0)
    147 #endif
    148     , m_highlightTextMatches(false)
    149     , m_inViewSourceMode(false)
    150     , m_needsReapplyStyles(false)
    151     , m_isDisconnected(false)
    152     , m_excludeFromTextSearch(false)
    153 {
    154     Frame* parent = parentFromOwnerElement(ownerElement);
    155     m_zoomFactor = parent ? parent->m_zoomFactor : 1.0f;
    156 
    157     AtomicString::init();
    158     HTMLNames::init();
    159     QualifiedName::init();
    160     MediaFeatureNames::init();
    161 
    162 #if ENABLE(SVG)
    163     SVGNames::init();
    164     XLinkNames::init();
    165 #endif
    166 
    167 #if ENABLE(WML)
    168     WMLNames::init();
    169 #endif
    170 
    171 #if ENABLE(MATHML)
    172     MathMLNames::init();
    173 #endif
    174 
    175     XMLNSNames::init();
    176     XMLNames::init();
    177 
    178     if (!ownerElement)
    179         page->setMainFrame(this);
    180     else {
    181         page->incrementFrameCount();
    182         // Make sure we will not end up with two frames referencing the same owner element.
    183         ASSERT((!(ownerElement->m_contentFrame)) || (ownerElement->m_contentFrame->ownerElement() != ownerElement));
    184         ownerElement->m_contentFrame = this;
    185     }
    186 
    187 #ifndef NDEBUG
    188     frameCounter.increment();
    189 #endif
    190 }
    191 
    192 Frame::~Frame()
    193 {
    194     setView(0);
    195     loader()->cancelAndClear();
    196 
    197     // FIXME: We should not be doing all this work inside the destructor
    198 
    199     ASSERT(!m_lifeSupportTimer.isActive());
    200 
    201 #ifndef NDEBUG
    202     frameCounter.decrement();
    203 #endif
    204 
    205     disconnectOwnerElement();
    206 
    207     if (m_domWindow)
    208         m_domWindow->disconnectFrame();
    209     script()->clearWindowShell();
    210 
    211     HashSet<DOMWindow*>::iterator end = m_liveFormerWindows.end();
    212     for (HashSet<DOMWindow*>::iterator it = m_liveFormerWindows.begin(); it != end; ++it)
    213         (*it)->disconnectFrame();
    214 
    215     if (m_view) {
    216         m_view->hide();
    217         m_view->clearFrame();
    218     }
    219 
    220     ASSERT(!m_lifeSupportTimer.isActive());
    221 }
    222 
    223 void Frame::init()
    224 {
    225     m_loader.init();
    226 }
    227 
    228 FrameLoader* Frame::loader() const
    229 {
    230     return &m_loader;
    231 }
    232 
    233 RedirectScheduler* Frame::redirectScheduler() const
    234 {
    235     return &m_redirectScheduler;
    236 }
    237 
    238 FrameView* Frame::view() const
    239 {
    240     return m_view.get();
    241 }
    242 
    243 void Frame::setView(PassRefPtr<FrameView> view)
    244 {
    245     // We the custom scroll bars as early as possible to prevent m_doc->detach()
    246     // from messing with the view such that its scroll bars won't be torn down.
    247     // FIXME: We should revisit this.
    248     if (m_view)
    249         m_view->detachCustomScrollbars();
    250 
    251     // Detach the document now, so any onUnload handlers get run - if
    252     // we wait until the view is destroyed, then things won't be
    253     // hooked up enough for some JavaScript calls to work.
    254     if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) {
    255         // FIXME: We don't call willRemove here. Why is that OK?
    256         m_doc->detach();
    257         if (m_view)
    258             m_view->unscheduleRelayout();
    259     }
    260     eventHandler()->clear();
    261 
    262     m_view = view;
    263 
    264     // Only one form submission is allowed per view of a part.
    265     // Since this part may be getting reused as a result of being
    266     // pulled from the back/forward cache, reset this flag.
    267     loader()->resetMultipleFormSubmissionProtection();
    268 }
    269 
    270 ScriptController* Frame::script()
    271 {
    272     return &m_script;
    273 }
    274 
    275 Document* Frame::document() const
    276 {
    277     return m_doc.get();
    278 }
    279 
    280 void Frame::setDocument(PassRefPtr<Document> newDoc)
    281 {
    282     if (m_doc && m_doc->attached() && !m_doc->inPageCache()) {
    283         // FIXME: We don't call willRemove here. Why is that OK?
    284         m_doc->detach();
    285     }
    286 
    287     m_doc = newDoc;
    288     if (m_doc && selection()->isFocusedAndActive())
    289         setUseSecureKeyboardEntry(m_doc->useSecureKeyboardEntryWhenActive());
    290 
    291     if (m_doc && !m_doc->attached())
    292         m_doc->attach();
    293 
    294     // Update the cached 'document' property, which is now stale.
    295     m_script.updateDocument();
    296 }
    297 
    298 #if ENABLE(ORIENTATION_EVENTS)
    299 void Frame::sendOrientationChangeEvent(int orientation)
    300 {
    301     m_orientation = orientation;
    302     if (Document* doc = document())
    303         doc->dispatchWindowEvent(Event::create(eventNames().orientationchangeEvent, false, false));
    304 }
    305 #endif // ENABLE(ORIENTATION_EVENTS)
    306 
    307 Settings* Frame::settings() const
    308 {
    309     return m_page ? m_page->settings() : 0;
    310 }
    311 
    312 String Frame::selectedText() const
    313 {
    314     return plainText(selection()->toNormalizedRange().get());
    315 }
    316 
    317 IntRect Frame::firstRectForRange(Range* range) const
    318 {
    319     int extraWidthToEndOfLine = 0;
    320     ExceptionCode ec = 0;
    321     ASSERT(range->startContainer(ec));
    322     ASSERT(range->endContainer(ec));
    323 
    324     InlineBox* startInlineBox;
    325     int startCaretOffset;
    326     range->startPosition().getInlineBoxAndOffset(DOWNSTREAM, startInlineBox, startCaretOffset);
    327 
    328     RenderObject* startRenderer = range->startContainer(ec)->renderer();
    329     IntRect startCaretRect = startRenderer->localCaretRect(startInlineBox, startCaretOffset, &extraWidthToEndOfLine);
    330     if (startCaretRect != IntRect())
    331         startCaretRect = startRenderer->localToAbsoluteQuad(FloatRect(startCaretRect)).enclosingBoundingBox();
    332 
    333     InlineBox* endInlineBox;
    334     int endCaretOffset;
    335     range->endPosition().getInlineBoxAndOffset(UPSTREAM, endInlineBox, endCaretOffset);
    336 
    337     RenderObject* endRenderer = range->endContainer(ec)->renderer();
    338     IntRect endCaretRect = endRenderer->localCaretRect(endInlineBox, endCaretOffset);
    339     if (endCaretRect != IntRect())
    340         endCaretRect = endRenderer->localToAbsoluteQuad(FloatRect(endCaretRect)).enclosingBoundingBox();
    341 
    342     if (startCaretRect.y() == endCaretRect.y()) {
    343         // start and end are on the same line
    344         return IntRect(min(startCaretRect.x(), endCaretRect.x()),
    345                        startCaretRect.y(),
    346                        abs(endCaretRect.x() - startCaretRect.x()),
    347                        max(startCaretRect.height(), endCaretRect.height()));
    348     }
    349 
    350     // start and end aren't on the same line, so go from start to the end of its line
    351     return IntRect(startCaretRect.x(),
    352                    startCaretRect.y(),
    353                    startCaretRect.width() + extraWidthToEndOfLine,
    354                    startCaretRect.height());
    355 }
    356 
    357 SelectionController* Frame::selection() const
    358 {
    359     return &m_selectionController;
    360 }
    361 
    362 Editor* Frame::editor() const
    363 {
    364     return &m_editor;
    365 }
    366 
    367 TextGranularity Frame::selectionGranularity() const
    368 {
    369     return m_selectionGranularity;
    370 }
    371 
    372 void Frame::setSelectionGranularity(TextGranularity granularity)
    373 {
    374     m_selectionGranularity = granularity;
    375 }
    376 
    377 SelectionController* Frame::dragCaretController() const
    378 {
    379     return m_page->dragCaretController();
    380 }
    381 
    382 
    383 AnimationController* Frame::animation() const
    384 {
    385     return &m_animationController;
    386 }
    387 
    388 static RegularExpression* createRegExpForLabels(const Vector<String>& labels)
    389 {
    390     // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being
    391     // the same across calls.  We can't do that.
    392 
    393     DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive));
    394     String pattern("(");
    395     unsigned int numLabels = labels.size();
    396     unsigned int i;
    397     for (i = 0; i < numLabels; i++) {
    398         String label = labels[i];
    399 
    400         bool startsWithWordChar = false;
    401         bool endsWithWordChar = false;
    402         if (label.length()) {
    403             startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0;
    404             endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0;
    405         }
    406 
    407         if (i)
    408             pattern.append("|");
    409         // Search for word boundaries only if label starts/ends with "word characters".
    410         // If we always searched for word boundaries, this wouldn't work for languages
    411         // such as Japanese.
    412         if (startsWithWordChar)
    413             pattern.append("\\b");
    414         pattern.append(label);
    415         if (endsWithWordChar)
    416             pattern.append("\\b");
    417     }
    418     pattern.append(")");
    419     return new RegularExpression(pattern, TextCaseInsensitive);
    420 }
    421 
    422 String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell, size_t* resultDistanceFromStartOfCell)
    423 {
    424     RenderObject* cellRenderer = cell->renderer();
    425 
    426     if (cellRenderer && cellRenderer->isTableCell()) {
    427         RenderTableCell* tableCellRenderer = toRenderTableCell(cellRenderer);
    428         RenderTableCell* cellAboveRenderer = tableCellRenderer->table()->cellAbove(tableCellRenderer);
    429 
    430         if (cellAboveRenderer) {
    431             HTMLTableCellElement* aboveCell =
    432                 static_cast<HTMLTableCellElement*>(cellAboveRenderer->node());
    433 
    434             if (aboveCell) {
    435                 // search within the above cell we found for a match
    436                 size_t lengthSearched = 0;
    437                 for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
    438                     if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
    439                         // For each text chunk, run the regexp
    440                         String nodeString = n->nodeValue();
    441                         int pos = regExp->searchRev(nodeString);
    442                         if (pos >= 0) {
    443                             if (resultDistanceFromStartOfCell)
    444                                 *resultDistanceFromStartOfCell = lengthSearched;
    445                             return nodeString.substring(pos, regExp->matchedLength());
    446                         }
    447                         lengthSearched += nodeString.length();
    448                     }
    449                 }
    450             }
    451         }
    452     }
    453     // Any reason in practice to search all cells in that are above cell?
    454     if (resultDistanceFromStartOfCell)
    455         *resultDistanceFromStartOfCell = notFound;
    456     return String();
    457 }
    458 
    459 String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove)
    460 {
    461     OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
    462     // We stop searching after we've seen this many chars
    463     const unsigned int charsSearchedThreshold = 500;
    464     // This is the absolute max we search.  We allow a little more slop than
    465     // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
    466     const unsigned int maxCharsSearched = 600;
    467     // If the starting element is within a table, the cell that contains it
    468     HTMLTableCellElement* startingTableCell = 0;
    469     bool searchedCellAbove = false;
    470 
    471     if (resultDistance)
    472         *resultDistance = notFound;
    473     if (resultIsInCellAbove)
    474         *resultIsInCellAbove = false;
    475 
    476     // walk backwards in the node tree, until another element, or form, or end of tree
    477     int unsigned lengthSearched = 0;
    478     Node* n;
    479     for (n = element->traversePreviousNode();
    480          n && lengthSearched < charsSearchedThreshold;
    481          n = n->traversePreviousNode())
    482     {
    483         if (n->hasTagName(formTag)
    484             || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()))
    485         {
    486             // We hit another form element or the start of the form - bail out
    487             break;
    488         } else if (n->hasTagName(tdTag) && !startingTableCell) {
    489             startingTableCell = static_cast<HTMLTableCellElement*>(n);
    490         } else if (n->hasTagName(trTag) && startingTableCell) {
    491             String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
    492             if (!result.isEmpty()) {
    493                 if (resultIsInCellAbove)
    494                     *resultIsInCellAbove = true;
    495                 return result;
    496             }
    497             searchedCellAbove = true;
    498         } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
    499             // For each text chunk, run the regexp
    500             String nodeString = n->nodeValue();
    501             // add 100 for slop, to make it more likely that we'll search whole nodes
    502             if (lengthSearched + nodeString.length() > maxCharsSearched)
    503                 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
    504             int pos = regExp->searchRev(nodeString);
    505             if (pos >= 0) {
    506                 if (resultDistance)
    507                     *resultDistance = lengthSearched;
    508                 return nodeString.substring(pos, regExp->matchedLength());
    509             }
    510             lengthSearched += nodeString.length();
    511         }
    512     }
    513 
    514     // If we started in a cell, but bailed because we found the start of the form or the
    515     // previous element, we still might need to search the row above us for a label.
    516     if (startingTableCell && !searchedCellAbove) {
    517          String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
    518         if (!result.isEmpty()) {
    519             if (resultIsInCellAbove)
    520                 *resultIsInCellAbove = true;
    521             return result;
    522         }
    523     }
    524     return String();
    525 }
    526 
    527 static String matchLabelsAgainstString(const Vector<String>& labels, const String& stringToMatch)
    528 {
    529     if (stringToMatch.isEmpty())
    530         return String();
    531 
    532     String mutableStringToMatch = stringToMatch;
    533 
    534     // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
    535     replace(mutableStringToMatch, RegularExpression("\\d", TextCaseSensitive), " ");
    536     mutableStringToMatch.replace('_', ' ');
    537 
    538     OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
    539     // Use the largest match we can find in the whole string
    540     int pos;
    541     int length;
    542     int bestPos = -1;
    543     int bestLength = -1;
    544     int start = 0;
    545     do {
    546         pos = regExp->match(mutableStringToMatch, start);
    547         if (pos != -1) {
    548             length = regExp->matchedLength();
    549             if (length >= bestLength) {
    550                 bestPos = pos;
    551                 bestLength = length;
    552             }
    553             start = pos + 1;
    554         }
    555     } while (pos != -1);
    556 
    557     if (bestPos != -1)
    558         return mutableStringToMatch.substring(bestPos, bestLength);
    559     return String();
    560 }
    561 
    562 String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element)
    563 {
    564     // Match against the name element, then against the id element if no match is found for the name element.
    565     // See 7538330 for one popular site that benefits from the id element check.
    566     // FIXME: This code is mirrored in FrameMac.mm. It would be nice to make the Mac code call the platform-agnostic
    567     // code, which would require converting the NSArray of NSStrings to a Vector of Strings somewhere along the way.
    568     String resultFromNameAttribute = matchLabelsAgainstString(labels, element->getAttribute(nameAttr));
    569     if (!resultFromNameAttribute.isEmpty())
    570         return resultFromNameAttribute;
    571 
    572     return matchLabelsAgainstString(labels, element->getAttribute(idAttr));
    573 }
    574 
    575 const VisibleSelection& Frame::mark() const
    576 {
    577     return m_mark;
    578 }
    579 
    580 void Frame::setMark(const VisibleSelection& s)
    581 {
    582     ASSERT(!s.base().node() || s.base().node()->document() == document());
    583     ASSERT(!s.extent().node() || s.extent().node()->document() == document());
    584     ASSERT(!s.start().node() || s.start().node()->document() == document());
    585     ASSERT(!s.end().node() || s.end().node()->document() == document());
    586 
    587     m_mark = s;
    588 }
    589 
    590 void Frame::notifyRendererOfSelectionChange(bool userTriggered)
    591 {
    592     RenderObject* renderer = 0;
    593     if (selection()->rootEditableElement())
    594         renderer = selection()->rootEditableElement()->shadowAncestorNode()->renderer();
    595 
    596     // If the current selection is in a textfield or textarea, notify the renderer that the selection has changed
    597     if (renderer && renderer->isTextControl())
    598         toRenderTextControl(renderer)->selectionChanged(userTriggered);
    599 }
    600 
    601 // Helper function that tells whether a particular node is an element that has an entire
    602 // Frame and FrameView, a <frame>, <iframe>, or <object>.
    603 static bool isFrameElement(const Node *n)
    604 {
    605     if (!n)
    606         return false;
    607     RenderObject *renderer = n->renderer();
    608     if (!renderer || !renderer->isWidget())
    609         return false;
    610     Widget* widget = toRenderWidget(renderer)->widget();
    611     return widget && widget->isFrameView();
    612 }
    613 
    614 void Frame::setFocusedNodeIfNeeded()
    615 {
    616     if (selection()->isNone() || !selection()->isFocused())
    617         return;
    618 
    619     bool caretBrowsing = settings() && settings()->caretBrowsingEnabled();
    620     if (caretBrowsing) {
    621         Node* anchor = enclosingAnchorElement(selection()->base());
    622         if (anchor) {
    623             page()->focusController()->setFocusedNode(anchor, this);
    624             return;
    625         }
    626     }
    627 
    628     Node* target = selection()->rootEditableElement();
    629     if (target) {
    630         RenderObject* renderer = target->renderer();
    631 
    632         // Walk up the render tree to search for a node to focus.
    633         // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
    634         while (renderer) {
    635             // We don't want to set focus on a subframe when selecting in a parent frame,
    636             // so add the !isFrameElement check here. There's probably a better way to make this
    637             // work in the long term, but this is the safest fix at this time.
    638             if (target && target->isMouseFocusable() && !isFrameElement(target)) {
    639                 page()->focusController()->setFocusedNode(target, this);
    640                 return;
    641             }
    642             renderer = renderer->parent();
    643             if (renderer)
    644                 target = renderer->node();
    645         }
    646         document()->setFocusedNode(0);
    647     }
    648 
    649     if (caretBrowsing)
    650         page()->focusController()->setFocusedNode(0, this);
    651 }
    652 
    653 void Frame::paintDragCaret(GraphicsContext* p, int tx, int ty, const IntRect& clipRect) const
    654 {
    655 #if ENABLE(TEXT_CARET)
    656     SelectionController* dragCaretController = m_page->dragCaretController();
    657     ASSERT(dragCaretController->selection().isCaret());
    658     if (dragCaretController->selection().start().node()->document()->frame() == this)
    659         dragCaretController->paintCaret(p, tx, ty, clipRect);
    660 #endif
    661 }
    662 
    663 float Frame::zoomFactor() const
    664 {
    665     return m_zoomFactor;
    666 }
    667 
    668 bool Frame::isZoomFactorTextOnly() const
    669 {
    670     return m_page->settings()->zoomsTextOnly();
    671 }
    672 
    673 bool Frame::shouldApplyTextZoom() const
    674 {
    675     if (m_zoomFactor == 1.0f || !isZoomFactorTextOnly())
    676         return false;
    677 #if ENABLE(SVG)
    678     if (m_doc->isSVGDocument())
    679         return false;
    680 #endif
    681     return true;
    682 }
    683 
    684 bool Frame::shouldApplyPageZoom() const
    685 {
    686     if (m_zoomFactor == 1.0f || isZoomFactorTextOnly())
    687         return false;
    688 #if ENABLE(SVG)
    689     if (m_doc->isSVGDocument())
    690         return false;
    691 #endif
    692     return true;
    693 }
    694 
    695 void Frame::setZoomFactor(float percent, bool isTextOnly)
    696 {
    697     if (m_zoomFactor == percent && isZoomFactorTextOnly() == isTextOnly)
    698         return;
    699 
    700 #if ENABLE(SVG)
    701     // SVG doesn't care if the zoom factor is text only.  It will always apply a
    702     // zoom to the whole SVG.
    703     if (m_doc->isSVGDocument()) {
    704         if (!static_cast<SVGDocument*>(m_doc.get())->zoomAndPanEnabled())
    705             return;
    706         m_zoomFactor = percent;
    707         m_page->settings()->setZoomsTextOnly(true); // We do this to avoid doing any scaling of CSS pixels, since the SVG has its own notion of zoom.
    708         if (m_doc->renderer())
    709             m_doc->renderer()->repaint();
    710         return;
    711     }
    712 #endif
    713 
    714     if (!isTextOnly) {
    715         // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
    716         IntPoint scrollPosition = view()->scrollPosition();
    717         float percentDifference = (percent / m_zoomFactor);
    718         view()->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
    719     }
    720 
    721     m_zoomFactor = percent;
    722     m_page->settings()->setZoomsTextOnly(isTextOnly);
    723 
    724     m_doc->recalcStyle(Node::Force);
    725 
    726     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
    727         child->setZoomFactor(m_zoomFactor, isTextOnly);
    728 
    729     if (m_doc->renderer() && m_doc->renderer()->needsLayout() && view()->didFirstLayout())
    730         view()->layout();
    731 }
    732 
    733 void Frame::setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize)
    734 {
    735     m_doc->setPrinting(printing);
    736     view()->setMediaType(printing ? "print" : "screen");
    737     m_doc->updateStyleSelector();
    738     view()->forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth, adjustViewSize);
    739 
    740     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
    741         child->setPrinting(printing, minPageWidth, maxPageWidth, adjustViewSize);
    742 }
    743 
    744 void Frame::setJSStatusBarText(const String& text)
    745 {
    746     ASSERT(m_doc); // Client calls shouldn't be made when the frame is in inconsistent state.
    747     m_kjsStatusBarText = text;
    748     if (m_page)
    749         m_page->chrome()->setStatusbarText(this, m_kjsStatusBarText);
    750 }
    751 
    752 void Frame::setJSDefaultStatusBarText(const String& text)
    753 {
    754     ASSERT(m_doc); // Client calls shouldn't be made when the frame is in inconsistent state.
    755     m_kjsDefaultStatusBarText = text;
    756     if (m_page)
    757         m_page->chrome()->setStatusbarText(this, m_kjsDefaultStatusBarText);
    758 }
    759 
    760 String Frame::jsStatusBarText() const
    761 {
    762     return m_kjsStatusBarText;
    763 }
    764 
    765 String Frame::jsDefaultStatusBarText() const
    766 {
    767     return m_kjsDefaultStatusBarText;
    768 }
    769 
    770 void Frame::setNeedsReapplyStyles()
    771 {
    772     // When the frame is not showing web content, it doesn't make sense to apply styles.
    773     // If we tried, we'd end up doing things with the document, but the document, if one
    774     // exists, is not currently shown and should be in the page cache.
    775     if (!m_loader.client()->hasHTMLView())
    776         return;
    777 
    778     if (m_needsReapplyStyles)
    779         return;
    780 
    781     m_needsReapplyStyles = true;
    782 
    783     // FrameView's "layout" timer includes reapplyStyles, so despite its
    784     // name, it's what we want to call here.
    785     if (view())
    786         view()->scheduleRelayout();
    787 }
    788 
    789 bool Frame::needsReapplyStyles() const
    790 {
    791     return m_needsReapplyStyles;
    792 }
    793 
    794 void Frame::reapplyStyles()
    795 {
    796     m_needsReapplyStyles = false;
    797 
    798     // FIXME: This call doesn't really make sense in a function called reapplyStyles.
    799     // We should probably eventually move it into its own function.
    800     m_doc->docLoader()->setAutoLoadImages(m_page && m_page->settings()->loadsImagesAutomatically());
    801 
    802     // FIXME: It's not entirely clear why the following is needed.
    803     // The document automatically does this as required when you set the style sheet.
    804     // But we had problems when this code was removed. Details are in
    805     // <http://bugs.webkit.org/show_bug.cgi?id=8079>.
    806     m_doc->updateStyleSelector();
    807 }
    808 
    809 void Frame::injectUserScripts(UserScriptInjectionTime injectionTime)
    810 {
    811     if (!m_page)
    812         return;
    813 
    814     // Walk the hashtable. Inject by world.
    815     const UserScriptMap* userScripts = m_page->group().userScripts();
    816     if (!userScripts)
    817         return;
    818     UserScriptMap::const_iterator end = userScripts->end();
    819     for (UserScriptMap::const_iterator it = userScripts->begin(); it != end; ++it)
    820         injectUserScriptsForWorld(it->first.get(), *it->second, injectionTime);
    821 }
    822 
    823 void Frame::injectUserScriptsForWorld(DOMWrapperWorld* world, const UserScriptVector& userScripts, UserScriptInjectionTime injectionTime)
    824 {
    825     if (userScripts.isEmpty())
    826         return;
    827 
    828     Document* doc = document();
    829     if (!doc)
    830         return;
    831 
    832     Vector<ScriptSourceCode> sourceCode;
    833     unsigned count = userScripts.size();
    834     for (unsigned i = 0; i < count; ++i) {
    835         UserScript* script = userScripts[i].get();
    836         if (script->injectionTime() == injectionTime && UserContentURLPattern::matchesPatterns(doc->url(), script->whitelist(), script->blacklist()))
    837             m_script.evaluateInWorld(ScriptSourceCode(script->source(), script->url()), world);
    838     }
    839 }
    840 
    841 bool Frame::shouldChangeSelection(const VisibleSelection& newSelection) const
    842 {
    843     return shouldChangeSelection(selection()->selection(), newSelection, newSelection.affinity(), false);
    844 }
    845 
    846 bool Frame::shouldChangeSelection(const VisibleSelection& oldSelection, const VisibleSelection& newSelection, EAffinity affinity, bool stillSelecting) const
    847 {
    848     return editor()->client()->shouldChangeSelectedRange(oldSelection.toNormalizedRange().get(), newSelection.toNormalizedRange().get(),
    849                                                          affinity, stillSelecting);
    850 }
    851 
    852 bool Frame::shouldDeleteSelection(const VisibleSelection& selection) const
    853 {
    854     return editor()->client()->shouldDeleteRange(selection.toNormalizedRange().get());
    855 }
    856 
    857 bool Frame::isContentEditable() const
    858 {
    859     if (m_editor.clientIsEditable())
    860         return true;
    861     return m_doc->inDesignMode();
    862 }
    863 
    864 #if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
    865 const short enableRomanKeyboardsOnly = -23;
    866 #endif
    867 void Frame::setUseSecureKeyboardEntry(bool enable)
    868 {
    869 #if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
    870     if (enable == IsSecureEventInputEnabled())
    871         return;
    872     if (enable) {
    873         EnableSecureEventInput();
    874 #ifdef BUILDING_ON_TIGER
    875         KeyScript(enableRomanKeyboardsOnly);
    876 #else
    877         // WebKit substitutes nil for input context when in password field, which corresponds to null TSMDocument. So, there is
    878         // no need to call TSMGetActiveDocument(), which may return an incorrect result when selection hasn't been yet updated
    879         // after focusing a node.
    880         CFArrayRef inputSources = TISCreateASCIICapableInputSourceList();
    881         TSMSetDocumentProperty(0, kTSMDocumentEnabledInputSourcesPropertyTag, sizeof(CFArrayRef), &inputSources);
    882         CFRelease(inputSources);
    883 #endif
    884     } else {
    885         DisableSecureEventInput();
    886 #ifdef BUILDING_ON_TIGER
    887         KeyScript(smKeyEnableKybds);
    888 #else
    889         TSMRemoveDocumentProperty(0, kTSMDocumentEnabledInputSourcesPropertyTag);
    890 #endif
    891     }
    892 #endif
    893 }
    894 
    895 void Frame::updateSecureKeyboardEntryIfActive()
    896 {
    897     if (selection()->isFocusedAndActive())
    898         setUseSecureKeyboardEntry(m_doc->useSecureKeyboardEntryWhenActive());
    899 }
    900 
    901 CSSMutableStyleDeclaration *Frame::typingStyle() const
    902 {
    903     return m_typingStyle.get();
    904 }
    905 
    906 void Frame::setTypingStyle(CSSMutableStyleDeclaration *style)
    907 {
    908     m_typingStyle = style;
    909 }
    910 
    911 void Frame::clearTypingStyle()
    912 {
    913     m_typingStyle = 0;
    914 }
    915 
    916 void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction editingAction)
    917 {
    918     if (!style || !style->length()) {
    919         clearTypingStyle();
    920         return;
    921     }
    922 
    923     // Calculate the current typing style.
    924     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
    925     if (typingStyle()) {
    926         typingStyle()->merge(mutableStyle.get());
    927         mutableStyle = typingStyle();
    928     }
    929 
    930     RefPtr<CSSValue> unicodeBidi;
    931     RefPtr<CSSValue> direction;
    932     if (editingAction == EditActionSetWritingDirection) {
    933         unicodeBidi = mutableStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
    934         direction = mutableStyle->getPropertyCSSValue(CSSPropertyDirection);
    935     }
    936 
    937     Node* node = selection()->selection().visibleStart().deepEquivalent().node();
    938     computedStyle(node)->diff(mutableStyle.get());
    939 
    940     if (editingAction == EditActionSetWritingDirection && unicodeBidi) {
    941         ASSERT(unicodeBidi->isPrimitiveValue());
    942         mutableStyle->setProperty(CSSPropertyUnicodeBidi, static_cast<CSSPrimitiveValue*>(unicodeBidi.get())->getIdent());
    943         if (direction) {
    944             ASSERT(direction->isPrimitiveValue());
    945             mutableStyle->setProperty(CSSPropertyDirection, static_cast<CSSPrimitiveValue*>(direction.get())->getIdent());
    946         }
    947     }
    948 
    949     // Handle block styles, substracting these from the typing style.
    950     RefPtr<CSSMutableStyleDeclaration> blockStyle = mutableStyle->copyBlockProperties();
    951     blockStyle->diff(mutableStyle.get());
    952     if (blockStyle->length() > 0)
    953         applyCommand(ApplyStyleCommand::create(document(), blockStyle.get(), editingAction));
    954 
    955     // Set the remaining style as the typing style.
    956     m_typingStyle = mutableStyle.release();
    957 }
    958 
    959 String Frame::selectionStartStylePropertyValue(int stylePropertyID) const
    960 {
    961     Node *nodeToRemove;
    962     RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
    963     if (!selectionStyle)
    964         return String();
    965 
    966     String value = selectionStyle->getPropertyValue(stylePropertyID);
    967 
    968     if (nodeToRemove) {
    969         ExceptionCode ec = 0;
    970         nodeToRemove->remove(ec);
    971         ASSERT(!ec);
    972     }
    973 
    974     return value;
    975 }
    976 
    977 PassRefPtr<CSSComputedStyleDeclaration> Frame::selectionComputedStyle(Node*& nodeToRemove) const
    978 {
    979     nodeToRemove = 0;
    980 
    981     if (selection()->isNone())
    982         return 0;
    983 
    984     RefPtr<Range> range(selection()->toNormalizedRange());
    985     Position pos = range->editingStartPosition();
    986 
    987     Element *elem = pos.element();
    988     if (!elem)
    989         return 0;
    990 
    991     RefPtr<Element> styleElement = elem;
    992     ExceptionCode ec = 0;
    993 
    994     if (m_typingStyle) {
    995         styleElement = document()->createElement(spanTag, false);
    996 
    997         styleElement->setAttribute(styleAttr, m_typingStyle->cssText().impl(), ec);
    998         ASSERT(!ec);
    999 
   1000         styleElement->appendChild(document()->createEditingTextNode(""), ec);
   1001         ASSERT(!ec);
   1002 
   1003         if (elem->renderer() && elem->renderer()->canHaveChildren()) {
   1004             elem->appendChild(styleElement, ec);
   1005         } else {
   1006             Node *parent = elem->parent();
   1007             Node *next = elem->nextSibling();
   1008 
   1009             if (next)
   1010                 parent->insertBefore(styleElement, next, ec);
   1011             else
   1012                 parent->appendChild(styleElement, ec);
   1013         }
   1014         ASSERT(!ec);
   1015 
   1016         nodeToRemove = styleElement.get();
   1017     }
   1018 
   1019     return computedStyle(styleElement.release());
   1020 }
   1021 
   1022 void Frame::textFieldDidBeginEditing(Element* e)
   1023 {
   1024     if (editor()->client())
   1025         editor()->client()->textFieldDidBeginEditing(e);
   1026 }
   1027 
   1028 void Frame::textFieldDidEndEditing(Element* e)
   1029 {
   1030     if (editor()->client())
   1031         editor()->client()->textFieldDidEndEditing(e);
   1032 }
   1033 
   1034 void Frame::textDidChangeInTextField(Element* e)
   1035 {
   1036     if (editor()->client())
   1037         editor()->client()->textDidChangeInTextField(e);
   1038 }
   1039 
   1040 bool Frame::doTextFieldCommandFromEvent(Element* e, KeyboardEvent* ke)
   1041 {
   1042     if (editor()->client())
   1043         return editor()->client()->doTextFieldCommandFromEvent(e, ke);
   1044 
   1045     return false;
   1046 }
   1047 
   1048 void Frame::textWillBeDeletedInTextField(Element* input)
   1049 {
   1050     if (editor()->client())
   1051         editor()->client()->textWillBeDeletedInTextField(input);
   1052 }
   1053 
   1054 void Frame::textDidChangeInTextArea(Element* e)
   1055 {
   1056     if (editor()->client())
   1057         editor()->client()->textDidChangeInTextArea(e);
   1058 }
   1059 
   1060 void Frame::applyEditingStyleToBodyElement() const
   1061 {
   1062     RefPtr<NodeList> list = m_doc->getElementsByTagName("body");
   1063     unsigned len = list->length();
   1064     for (unsigned i = 0; i < len; i++)
   1065         applyEditingStyleToElement(static_cast<Element*>(list->item(i)));
   1066 }
   1067 
   1068 void Frame::removeEditingStyleFromBodyElement() const
   1069 {
   1070     RefPtr<NodeList> list = m_doc->getElementsByTagName("body");
   1071     unsigned len = list->length();
   1072     for (unsigned i = 0; i < len; i++)
   1073         removeEditingStyleFromElement(static_cast<Element*>(list->item(i)));
   1074 }
   1075 
   1076 void Frame::applyEditingStyleToElement(Element* element) const
   1077 {
   1078     if (!element)
   1079         return;
   1080 
   1081     CSSStyleDeclaration* style = element->style();
   1082     ASSERT(style);
   1083 
   1084     ExceptionCode ec = 0;
   1085     style->setProperty(CSSPropertyWordWrap, "break-word", false, ec);
   1086     ASSERT(!ec);
   1087     style->setProperty(CSSPropertyWebkitNbspMode, "space", false, ec);
   1088     ASSERT(!ec);
   1089     style->setProperty(CSSPropertyWebkitLineBreak, "after-white-space", false, ec);
   1090     ASSERT(!ec);
   1091 }
   1092 
   1093 void Frame::removeEditingStyleFromElement(Element*) const
   1094 {
   1095 }
   1096 
   1097 #ifndef NDEBUG
   1098 static HashSet<Frame*>& keepAliveSet()
   1099 {
   1100     DEFINE_STATIC_LOCAL(HashSet<Frame*>, staticKeepAliveSet, ());
   1101     return staticKeepAliveSet;
   1102 }
   1103 #endif
   1104 
   1105 void Frame::keepAlive()
   1106 {
   1107     if (m_lifeSupportTimer.isActive())
   1108         return;
   1109 #ifndef NDEBUG
   1110     keepAliveSet().add(this);
   1111 #endif
   1112     ref();
   1113     m_lifeSupportTimer.startOneShot(0);
   1114 }
   1115 
   1116 #ifndef NDEBUG
   1117 void Frame::cancelAllKeepAlive()
   1118 {
   1119     HashSet<Frame*>::iterator end = keepAliveSet().end();
   1120     for (HashSet<Frame*>::iterator it = keepAliveSet().begin(); it != end; ++it) {
   1121         Frame* frame = *it;
   1122         frame->m_lifeSupportTimer.stop();
   1123         frame->deref();
   1124     }
   1125     keepAliveSet().clear();
   1126 }
   1127 #endif
   1128 
   1129 void Frame::lifeSupportTimerFired(Timer<Frame>*)
   1130 {
   1131 #ifndef NDEBUG
   1132     keepAliveSet().remove(this);
   1133 #endif
   1134     deref();
   1135 }
   1136 
   1137 void Frame::clearDOMWindow()
   1138 {
   1139     if (m_domWindow) {
   1140         m_liveFormerWindows.add(m_domWindow.get());
   1141         m_domWindow->clear();
   1142     }
   1143     m_domWindow = 0;
   1144 }
   1145 
   1146 RenderView* Frame::contentRenderer() const
   1147 {
   1148     Document* doc = document();
   1149     if (!doc)
   1150         return 0;
   1151     RenderObject* object = doc->renderer();
   1152     if (!object)
   1153         return 0;
   1154     ASSERT(object->isRenderView());
   1155     return toRenderView(object);
   1156 }
   1157 
   1158 HTMLFrameOwnerElement* Frame::ownerElement() const
   1159 {
   1160     return m_ownerElement;
   1161 }
   1162 
   1163 RenderPart* Frame::ownerRenderer() const
   1164 {
   1165     HTMLFrameOwnerElement* ownerElement = m_ownerElement;
   1166     if (!ownerElement)
   1167         return 0;
   1168     RenderObject* object = ownerElement->renderer();
   1169     if (!object)
   1170         return 0;
   1171     // FIXME: If <object> is ever fixed to disassociate itself from frames
   1172     // that it has started but canceled, then this can turn into an ASSERT
   1173     // since m_ownerElement would be 0 when the load is canceled.
   1174     // https://bugs.webkit.org/show_bug.cgi?id=18585
   1175     if (!object->isRenderPart())
   1176         return 0;
   1177     return toRenderPart(object);
   1178 }
   1179 
   1180 bool Frame::isDisconnected() const
   1181 {
   1182     return m_isDisconnected;
   1183 }
   1184 
   1185 void Frame::setIsDisconnected(bool isDisconnected)
   1186 {
   1187     m_isDisconnected = isDisconnected;
   1188 }
   1189 
   1190 bool Frame::excludeFromTextSearch() const
   1191 {
   1192     return m_excludeFromTextSearch;
   1193 }
   1194 
   1195 void Frame::setExcludeFromTextSearch(bool exclude)
   1196 {
   1197     m_excludeFromTextSearch = exclude;
   1198 }
   1199 
   1200 // returns FloatRect because going through IntRect would truncate any floats
   1201 FloatRect Frame::selectionBounds(bool clipToVisibleContent) const
   1202 {
   1203     RenderView* root = contentRenderer();
   1204     FrameView* view = m_view.get();
   1205     if (!root || !view)
   1206         return IntRect();
   1207 
   1208     IntRect selectionRect = root->selectionBounds(clipToVisibleContent);
   1209     return clipToVisibleContent ? intersection(selectionRect, view->visibleContentRect()) : selectionRect;
   1210 }
   1211 
   1212 void Frame::selectionTextRects(Vector<FloatRect>& rects, SelectionRectRespectTransforms respectTransforms, bool clipToVisibleContent) const
   1213 {
   1214     RenderView* root = contentRenderer();
   1215     if (!root)
   1216         return;
   1217 
   1218     RefPtr<Range> selectedRange = selection()->toNormalizedRange();
   1219 
   1220     FloatRect visibleContentRect = m_view->visibleContentRect();
   1221 
   1222     // FIMXE: we are appending empty rects to the list for those that fall outside visibleContentRect.
   1223     // We may not want to do that.
   1224     if (respectTransforms) {
   1225         Vector<FloatQuad> quads;
   1226         selectedRange->textQuads(quads, true);
   1227 
   1228         unsigned size = quads.size();
   1229         for (unsigned i = 0; i < size; ++i) {
   1230             IntRect currRect = quads[i].enclosingBoundingBox();
   1231             if (clipToVisibleContent)
   1232                 rects.append(intersection(currRect, visibleContentRect));
   1233             else
   1234                 rects.append(currRect);
   1235         }
   1236     } else {
   1237         Vector<IntRect> intRects;
   1238         selectedRange->textRects(intRects, true);
   1239 
   1240         unsigned size = intRects.size();
   1241         for (unsigned i = 0; i < size; ++i) {
   1242             if (clipToVisibleContent)
   1243                 rects.append(intersection(intRects[i], visibleContentRect));
   1244             else
   1245                 rects.append(intRects[i]);
   1246         }
   1247     }
   1248 }
   1249 
   1250 // Scans logically forward from "start", including any child frames
   1251 static HTMLFormElement *scanForForm(Node *start)
   1252 {
   1253     Node *n;
   1254     for (n = start; n; n = n->traverseNextNode()) {
   1255         if (n->hasTagName(formTag))
   1256             return static_cast<HTMLFormElement*>(n);
   1257         else if (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement())
   1258             return static_cast<HTMLFormControlElement*>(n)->form();
   1259         else if (n->hasTagName(frameTag) || n->hasTagName(iframeTag)) {
   1260             Node *childDoc = static_cast<HTMLFrameElementBase*>(n)->contentDocument();
   1261             if (HTMLFormElement *frameResult = scanForForm(childDoc))
   1262                 return frameResult;
   1263         }
   1264     }
   1265     return 0;
   1266 }
   1267 
   1268 // We look for either the form containing the current focus, or for one immediately after it
   1269 HTMLFormElement *Frame::currentForm() const
   1270 {
   1271     // start looking either at the active (first responder) node, or where the selection is
   1272     Node *start = m_doc ? m_doc->focusedNode() : 0;
   1273     if (!start)
   1274         start = selection()->start().node();
   1275 
   1276     // try walking up the node tree to find a form element
   1277     Node *n;
   1278     for (n = start; n; n = n->parentNode()) {
   1279         if (n->hasTagName(formTag))
   1280             return static_cast<HTMLFormElement*>(n);
   1281         else if (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement())
   1282             return static_cast<HTMLFormControlElement*>(n)->form();
   1283     }
   1284 
   1285     // try walking forward in the node tree to find a form element
   1286     return start ? scanForForm(start) : 0;
   1287 }
   1288 
   1289 void Frame::revealSelection(const ScrollAlignment& alignment, bool revealExtent)
   1290 {
   1291     IntRect rect;
   1292 
   1293     switch (selection()->selectionType()) {
   1294     case VisibleSelection::NoSelection:
   1295         return;
   1296     case VisibleSelection::CaretSelection:
   1297         rect = selection()->absoluteCaretBounds();
   1298         break;
   1299     case VisibleSelection::RangeSelection:
   1300         rect = revealExtent ? VisiblePosition(selection()->extent()).absoluteCaretBounds() : enclosingIntRect(selectionBounds(false));
   1301         break;
   1302     }
   1303 
   1304     Position start = selection()->start();
   1305     ASSERT(start.node());
   1306     if (start.node() && start.node()->renderer()) {
   1307         // FIXME: This code only handles scrolling the startContainer's layer, but
   1308         // the selection rect could intersect more than just that.
   1309         // See <rdar://problem/4799899>.
   1310         if (RenderLayer* layer = start.node()->renderer()->enclosingLayer())
   1311             layer->scrollRectToVisible(rect, false, alignment, alignment);
   1312     }
   1313 }
   1314 
   1315 Frame* Frame::frameForWidget(const Widget* widget)
   1316 {
   1317     ASSERT_ARG(widget, widget);
   1318 
   1319     if (RenderWidget* renderer = RenderWidget::find(widget))
   1320         if (Node* node = renderer->node())
   1321             return node->document()->frame();
   1322 
   1323     // Assume all widgets are either a FrameView or owned by a RenderWidget.
   1324     // FIXME: That assumption is not right for scroll bars!
   1325     ASSERT(widget->isFrameView());
   1326     return static_cast<const FrameView*>(widget)->frame();
   1327 }
   1328 
   1329 void Frame::clearTimers(FrameView *view, Document *document)
   1330 {
   1331     if (view) {
   1332         view->unscheduleRelayout();
   1333         if (view->frame()) {
   1334             view->frame()->animation()->suspendAnimations(document);
   1335             view->frame()->eventHandler()->stopAutoscrollTimer();
   1336         }
   1337     }
   1338 }
   1339 
   1340 void Frame::clearTimers()
   1341 {
   1342     clearTimers(m_view.get(), document());
   1343 }
   1344 
   1345 RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const
   1346 {
   1347     nodeToRemove = 0;
   1348 
   1349     if (selection()->isNone())
   1350         return 0;
   1351 
   1352     Position pos = selection()->selection().visibleStart().deepEquivalent();
   1353     if (!pos.isCandidate())
   1354         return 0;
   1355     Node *node = pos.node();
   1356     if (!node)
   1357         return 0;
   1358 
   1359     if (!m_typingStyle)
   1360         return node->renderer()->style();
   1361 
   1362     RefPtr<Element> styleElement = document()->createElement(spanTag, false);
   1363 
   1364     ExceptionCode ec = 0;
   1365     String styleText = m_typingStyle->cssText() + " display: inline";
   1366     styleElement->setAttribute(styleAttr, styleText.impl(), ec);
   1367     ASSERT(!ec);
   1368 
   1369     styleElement->appendChild(document()->createEditingTextNode(""), ec);
   1370     ASSERT(!ec);
   1371 
   1372     node->parentNode()->appendChild(styleElement, ec);
   1373     ASSERT(!ec);
   1374 
   1375     nodeToRemove = styleElement.get();
   1376     return styleElement->renderer() ? styleElement->renderer()->style() : 0;
   1377 }
   1378 
   1379 void Frame::setSelectionFromNone()
   1380 {
   1381     // Put a caret inside the body if the entire frame is editable (either the
   1382     // entire WebView is editable or designMode is on for this document).
   1383     Document *doc = document();
   1384     bool caretBrowsing = settings() && settings()->caretBrowsingEnabled();
   1385     if (!selection()->isNone() || !(isContentEditable() || caretBrowsing))
   1386         return;
   1387 
   1388     Node* node = doc->documentElement();
   1389     while (node && !node->hasTagName(bodyTag))
   1390         node = node->traverseNextNode();
   1391     if (node)
   1392         selection()->setSelection(VisibleSelection(Position(node, 0), DOWNSTREAM));
   1393 }
   1394 
   1395 bool Frame::inViewSourceMode() const
   1396 {
   1397     return m_inViewSourceMode;
   1398 }
   1399 
   1400 void Frame::setInViewSourceMode(bool mode)
   1401 {
   1402     m_inViewSourceMode = mode;
   1403 }
   1404 
   1405 // Searches from the beginning of the document if nothing is selected.
   1406 bool Frame::findString(const String& target, bool forward, bool caseFlag, bool wrapFlag, bool startInSelection)
   1407 {
   1408     if (target.isEmpty())
   1409         return false;
   1410 
   1411     if (excludeFromTextSearch())
   1412         return false;
   1413 
   1414     // Start from an edge of the selection, if there's a selection that's not in shadow content. Which edge
   1415     // is used depends on whether we're searching forward or backward, and whether startInSelection is set.
   1416     RefPtr<Range> searchRange(rangeOfContents(document()));
   1417     VisibleSelection selection = this->selection()->selection();
   1418 
   1419     if (forward)
   1420         setStart(searchRange.get(), startInSelection ? selection.visibleStart() : selection.visibleEnd());
   1421     else
   1422         setEnd(searchRange.get(), startInSelection ? selection.visibleEnd() : selection.visibleStart());
   1423 
   1424     Node* shadowTreeRoot = selection.shadowTreeRootNode();
   1425     if (shadowTreeRoot) {
   1426         ExceptionCode ec = 0;
   1427         if (forward)
   1428             searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
   1429         else
   1430             searchRange->setStart(shadowTreeRoot, 0, ec);
   1431     }
   1432 
   1433     RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, forward, caseFlag));
   1434     // If we started in the selection and the found range exactly matches the existing selection, find again.
   1435     // Build a selection with the found range to remove collapsed whitespace.
   1436     // Compare ranges instead of selection objects to ignore the way that the current selection was made.
   1437     if (startInSelection && *VisibleSelection(resultRange.get()).toNormalizedRange() == *selection.toNormalizedRange()) {
   1438         searchRange = rangeOfContents(document());
   1439         if (forward)
   1440             setStart(searchRange.get(), selection.visibleEnd());
   1441         else
   1442             setEnd(searchRange.get(), selection.visibleStart());
   1443 
   1444         if (shadowTreeRoot) {
   1445             ExceptionCode ec = 0;
   1446             if (forward)
   1447                 searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
   1448             else
   1449                 searchRange->setStart(shadowTreeRoot, 0, ec);
   1450         }
   1451 
   1452         resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
   1453     }
   1454 
   1455     ExceptionCode exception = 0;
   1456 
   1457     // If nothing was found in the shadow tree, search in main content following the shadow tree.
   1458     if (resultRange->collapsed(exception) && shadowTreeRoot) {
   1459         searchRange = rangeOfContents(document());
   1460         if (forward)
   1461             searchRange->setStartAfter(shadowTreeRoot->shadowParentNode(), exception);
   1462         else
   1463             searchRange->setEndBefore(shadowTreeRoot->shadowParentNode(), exception);
   1464 
   1465         resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
   1466     }
   1467 
   1468     if (!editor()->insideVisibleArea(resultRange.get())) {
   1469         resultRange = editor()->nextVisibleRange(resultRange.get(), target, forward, caseFlag, wrapFlag);
   1470         if (!resultRange)
   1471             return false;
   1472     }
   1473 
   1474     // If we didn't find anything and we're wrapping, search again in the entire document (this will
   1475     // redundantly re-search the area already searched in some cases).
   1476     if (resultRange->collapsed(exception) && wrapFlag) {
   1477         searchRange = rangeOfContents(document());
   1478         resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
   1479         // We used to return false here if we ended up with the same range that we started with
   1480         // (e.g., the selection was already the only instance of this text). But we decided that
   1481         // this should be a success case instead, so we'll just fall through in that case.
   1482     }
   1483 
   1484     if (resultRange->collapsed(exception))
   1485         return false;
   1486 
   1487     this->selection()->setSelection(VisibleSelection(resultRange.get(), DOWNSTREAM));
   1488     revealSelection();
   1489     return true;
   1490 }
   1491 
   1492 unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsigned limit)
   1493 {
   1494     if (target.isEmpty())
   1495         return 0;
   1496 
   1497     RefPtr<Range> searchRange(rangeOfContents(document()));
   1498 
   1499     ExceptionCode exception = 0;
   1500     unsigned matchCount = 0;
   1501     do {
   1502         RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, caseFlag));
   1503         if (resultRange->collapsed(exception)) {
   1504             if (!resultRange->startContainer()->isInShadowTree())
   1505                 break;
   1506 
   1507             searchRange = rangeOfContents(document());
   1508             searchRange->setStartAfter(resultRange->startContainer()->shadowAncestorNode(), exception);
   1509             continue;
   1510         }
   1511 
   1512         // Only treat the result as a match if it is visible
   1513         if (editor()->insideVisibleArea(resultRange.get())) {
   1514             ++matchCount;
   1515             document()->addMarker(resultRange.get(), DocumentMarker::TextMatch);
   1516         }
   1517 
   1518         // Stop looking if we hit the specified limit. A limit of 0 means no limit.
   1519         if (limit > 0 && matchCount >= limit)
   1520             break;
   1521 
   1522         // Set the new start for the search range to be the end of the previous
   1523         // result range. There is no need to use a VisiblePosition here,
   1524         // since findPlainText will use a TextIterator to go over the visible
   1525         // text nodes.
   1526         searchRange->setStart(resultRange->endContainer(exception), resultRange->endOffset(exception), exception);
   1527 
   1528         Node* shadowTreeRoot = searchRange->shadowTreeRootNode();
   1529         if (searchRange->collapsed(exception) && shadowTreeRoot)
   1530             searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), exception);
   1531     } while (true);
   1532 
   1533     // Do a "fake" paint in order to execute the code that computes the rendered rect for
   1534     // each text match.
   1535     Document* doc = document();
   1536     if (m_view && contentRenderer()) {
   1537         doc->updateLayout(); // Ensure layout is up to date.
   1538         IntRect visibleRect = m_view->visibleContentRect();
   1539         if (!visibleRect.isEmpty()) {
   1540             GraphicsContext context((PlatformGraphicsContext*)0);
   1541             context.setPaintingDisabled(true);
   1542             m_view->paintContents(&context, visibleRect);
   1543         }
   1544     }
   1545 
   1546     return matchCount;
   1547 }
   1548 
   1549 bool Frame::markedTextMatchesAreHighlighted() const
   1550 {
   1551     return m_highlightTextMatches;
   1552 }
   1553 
   1554 void Frame::setMarkedTextMatchesAreHighlighted(bool flag)
   1555 {
   1556     if (flag == m_highlightTextMatches)
   1557         return;
   1558 
   1559     m_highlightTextMatches = flag;
   1560     document()->repaintMarkers(DocumentMarker::TextMatch);
   1561 }
   1562 
   1563 FrameTree* Frame::tree() const
   1564 {
   1565     return &m_treeNode;
   1566 }
   1567 
   1568 void Frame::setDOMWindow(DOMWindow* domWindow)
   1569 {
   1570     if (m_domWindow) {
   1571         m_liveFormerWindows.add(m_domWindow.get());
   1572         m_domWindow->clear();
   1573     }
   1574     m_domWindow = domWindow;
   1575 }
   1576 
   1577 DOMWindow* Frame::domWindow() const
   1578 {
   1579     if (!m_domWindow)
   1580         m_domWindow = DOMWindow::create(const_cast<Frame*>(this));
   1581 
   1582     return m_domWindow.get();
   1583 }
   1584 
   1585 void Frame::clearFormerDOMWindow(DOMWindow* window)
   1586 {
   1587     m_liveFormerWindows.remove(window);
   1588 }
   1589 
   1590 Page* Frame::page() const
   1591 {
   1592     return m_page;
   1593 }
   1594 
   1595 void Frame::detachFromPage()
   1596 {
   1597     m_page = 0;
   1598 }
   1599 
   1600 EventHandler* Frame::eventHandler() const
   1601 {
   1602     return &m_eventHandler;
   1603 }
   1604 
   1605 void Frame::pageDestroyed()
   1606 {
   1607     if (Frame* parent = tree()->parent())
   1608         parent->loader()->checkLoadComplete();
   1609 
   1610     // FIXME: It's unclear as to why this is called more than once, but it is,
   1611     // so page() could be NULL.
   1612     if (page() && page()->focusController()->focusedFrame() == this)
   1613         page()->focusController()->setFocusedFrame(0);
   1614 
   1615     script()->clearWindowShell();
   1616     script()->clearScriptObjects();
   1617     script()->updatePlatformScriptObjects();
   1618 
   1619     detachFromPage();
   1620 }
   1621 
   1622 void Frame::disconnectOwnerElement()
   1623 {
   1624     if (m_ownerElement) {
   1625         if (Document* doc = document())
   1626             doc->clearAXObjectCache();
   1627         m_ownerElement->m_contentFrame = 0;
   1628         if (m_page)
   1629             m_page->decrementFrameCount();
   1630     }
   1631     m_ownerElement = 0;
   1632 }
   1633 
   1634 String Frame::documentTypeString() const
   1635 {
   1636     if (DocumentType* doctype = document()->doctype())
   1637         return createMarkup(doctype);
   1638 
   1639     return String();
   1640 }
   1641 
   1642 void Frame::focusWindow()
   1643 {
   1644     if (!page())
   1645         return;
   1646 
   1647     // If we're a top level window, bring the window to the front.
   1648     if (!tree()->parent())
   1649 #ifdef ANDROID_USER_GESTURE
   1650         // FrameLoader::isProcessingUserGesture() will be false when a
   1651         // different frame tries to focus this frame through javascript.
   1652         page()->chrome()->focus(m_loader.isProcessingUserGesture());
   1653 #else
   1654         page()->chrome()->focus();
   1655 #endif
   1656 
   1657     eventHandler()->focusDocumentView();
   1658 }
   1659 
   1660 void Frame::unfocusWindow()
   1661 {
   1662     if (!page())
   1663         return;
   1664 
   1665     // If we're a top level window, deactivate the window.
   1666     if (!tree()->parent())
   1667         page()->chrome()->unfocus();
   1668 }
   1669 
   1670 bool Frame::shouldClose()
   1671 {
   1672     Chrome* chrome = page() ? page()->chrome() : 0;
   1673     if (!chrome || !chrome->canRunBeforeUnloadConfirmPanel())
   1674         return true;
   1675 
   1676     if (!m_domWindow)
   1677         return true;
   1678 
   1679     RefPtr<Document> doc = document();
   1680     HTMLElement* body = doc->body();
   1681     if (!body)
   1682         return true;
   1683 
   1684     RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create();
   1685     m_domWindow->dispatchEvent(beforeUnloadEvent.get(), m_domWindow->document());
   1686 
   1687     if (!beforeUnloadEvent->defaultPrevented())
   1688         doc->defaultEventHandler(beforeUnloadEvent.get());
   1689     if (beforeUnloadEvent->result().isNull())
   1690         return true;
   1691 
   1692     String text = doc->displayStringModifiedByEncoding(beforeUnloadEvent->result());
   1693     return chrome->runBeforeUnloadConfirmPanel(text, this);
   1694 }
   1695 
   1696 void Frame::scheduleClose()
   1697 {
   1698     if (!shouldClose())
   1699         return;
   1700 
   1701     Chrome* chrome = page() ? page()->chrome() : 0;
   1702     if (chrome)
   1703         chrome->closeWindowSoon();
   1704 }
   1705 
   1706 void Frame::respondToChangedSelection(const VisibleSelection& oldSelection, bool closeTyping)
   1707 {
   1708     bool isContinuousSpellCheckingEnabled = editor()->isContinuousSpellCheckingEnabled();
   1709     bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled && editor()->isGrammarCheckingEnabled();
   1710     if (isContinuousSpellCheckingEnabled) {
   1711         VisibleSelection newAdjacentWords;
   1712         VisibleSelection newSelectedSentence;
   1713         bool caretBrowsing = settings() && settings()->caretBrowsingEnabled();
   1714         if (selection()->selection().isContentEditable() || caretBrowsing) {
   1715             VisiblePosition newStart(selection()->selection().visibleStart());
   1716             newAdjacentWords = VisibleSelection(startOfWord(newStart, LeftWordIfOnBoundary), endOfWord(newStart, RightWordIfOnBoundary));
   1717             if (isContinuousGrammarCheckingEnabled)
   1718                 newSelectedSentence = VisibleSelection(startOfSentence(newStart), endOfSentence(newStart));
   1719         }
   1720 
   1721         // When typing we check spelling elsewhere, so don't redo it here.
   1722         // If this is a change in selection resulting from a delete operation,
   1723         // oldSelection may no longer be in the document.
   1724         if (closeTyping && oldSelection.isContentEditable() && oldSelection.start().node() && oldSelection.start().node()->inDocument()) {
   1725             VisiblePosition oldStart(oldSelection.visibleStart());
   1726             VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));
   1727             if (oldAdjacentWords != newAdjacentWords) {
   1728                 if (isContinuousGrammarCheckingEnabled) {
   1729                     VisibleSelection oldSelectedSentence = VisibleSelection(startOfSentence(oldStart), endOfSentence(oldStart));
   1730                     editor()->markMisspellingsAndBadGrammar(oldAdjacentWords, oldSelectedSentence != newSelectedSentence, oldSelectedSentence);
   1731                 } else
   1732                     editor()->markMisspellingsAndBadGrammar(oldAdjacentWords, false, oldAdjacentWords);
   1733             }
   1734         }
   1735 
   1736         // This only erases markers that are in the first unit (word or sentence) of the selection.
   1737         // Perhaps peculiar, but it matches AppKit.
   1738         if (RefPtr<Range> wordRange = newAdjacentWords.toNormalizedRange())
   1739             document()->removeMarkers(wordRange.get(), DocumentMarker::Spelling);
   1740         if (RefPtr<Range> sentenceRange = newSelectedSentence.toNormalizedRange())
   1741             document()->removeMarkers(sentenceRange.get(), DocumentMarker::Grammar);
   1742     }
   1743 
   1744     // When continuous spell checking is off, existing markers disappear after the selection changes.
   1745     if (!isContinuousSpellCheckingEnabled)
   1746         document()->removeMarkers(DocumentMarker::Spelling);
   1747     if (!isContinuousGrammarCheckingEnabled)
   1748         document()->removeMarkers(DocumentMarker::Grammar);
   1749 
   1750     editor()->respondToChangedSelection(oldSelection);
   1751 }
   1752 
   1753 VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint)
   1754 {
   1755     HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, true);
   1756     Node* node = result.innerNode();
   1757     if (!node)
   1758         return VisiblePosition();
   1759     RenderObject* renderer = node->renderer();
   1760     if (!renderer)
   1761         return VisiblePosition();
   1762     VisiblePosition visiblePos = renderer->positionForPoint(result.localPoint());
   1763     if (visiblePos.isNull())
   1764         visiblePos = VisiblePosition(Position(node, 0));
   1765     return visiblePos;
   1766 }
   1767 
   1768 Document* Frame::documentAtPoint(const IntPoint& point)
   1769 {
   1770     if (!view())
   1771         return 0;
   1772 
   1773     IntPoint pt = view()->windowToContents(point);
   1774     HitTestResult result = HitTestResult(pt);
   1775 
   1776     if (contentRenderer())
   1777         result = eventHandler()->hitTestResultAtPoint(pt, false);
   1778     return result.innerNode() ? result.innerNode()->document() : 0;
   1779 }
   1780 
   1781 void Frame::createView(const IntSize& viewportSize,
   1782                        const Color& backgroundColor, bool transparent,
   1783                        const IntSize& fixedLayoutSize, bool useFixedLayout,
   1784                        ScrollbarMode horizontalScrollbarMode, ScrollbarMode verticalScrollbarMode)
   1785 {
   1786     ASSERT(this);
   1787     ASSERT(m_page);
   1788 
   1789     bool isMainFrame = this == m_page->mainFrame();
   1790 
   1791     if (isMainFrame && view())
   1792         view()->setParentVisible(false);
   1793 
   1794     setView(0);
   1795 
   1796     RefPtr<FrameView> frameView;
   1797     if (isMainFrame) {
   1798         frameView = FrameView::create(this, viewportSize);
   1799         frameView->setFixedLayoutSize(fixedLayoutSize);
   1800         frameView->setUseFixedLayout(useFixedLayout);
   1801     } else
   1802         frameView = FrameView::create(this);
   1803 
   1804     frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode);
   1805 
   1806     setView(frameView);
   1807 
   1808     if (backgroundColor.isValid())
   1809         frameView->updateBackgroundRecursively(backgroundColor, transparent);
   1810 
   1811     if (isMainFrame)
   1812         frameView->setParentVisible(true);
   1813 
   1814     if (ownerRenderer())
   1815         ownerRenderer()->setWidget(frameView);
   1816 
   1817     if (HTMLFrameOwnerElement* owner = ownerElement())
   1818         view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
   1819 }
   1820 
   1821 } // namespace WebCore
   1822