Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2009 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 // How ownership works
     32 // -------------------
     33 //
     34 // Big oh represents a refcounted relationship: owner O--- ownee
     35 //
     36 // WebView (for the toplevel frame only)
     37 //    O
     38 //    |
     39 //   Page O------- Frame (m_mainFrame) O-------O FrameView
     40 //                   ||
     41 //                   ||
     42 //               FrameLoader O-------- WebFrame (via FrameLoaderClient)
     43 //
     44 // FrameLoader and Frame are formerly one object that was split apart because
     45 // it got too big. They basically have the same lifetime, hence the double line.
     46 //
     47 // WebFrame is refcounted and has one ref on behalf of the FrameLoader/Frame.
     48 // This is not a normal reference counted pointer because that would require
     49 // changing WebKit code that we don't control. Instead, it is created with this
     50 // ref initially and it is removed when the FrameLoader is getting destroyed.
     51 //
     52 // WebFrames are created in two places, first in WebViewImpl when the root
     53 // frame is created, and second in WebFrame::CreateChildFrame when sub-frames
     54 // are created. WebKit will hook up this object to the FrameLoader/Frame
     55 // and the refcount will be correct.
     56 //
     57 // How frames are destroyed
     58 // ------------------------
     59 //
     60 // The main frame is never destroyed and is re-used. The FrameLoader is re-used
     61 // and a reference to the main frame is kept by the Page.
     62 //
     63 // When frame content is replaced, all subframes are destroyed. This happens
     64 // in FrameLoader::detachFromParent for each subframe.
     65 //
     66 // Frame going away causes the FrameLoader to get deleted. In FrameLoader's
     67 // destructor, it notifies its client with frameLoaderDestroyed. This calls
     68 // WebFrame::Closing and then derefs the WebFrame and will cause it to be
     69 // deleted (unless an external someone is also holding a reference).
     70 
     71 #include "config.h"
     72 #include "WebFrameImpl.h"
     73 
     74 #include "Chrome.h"
     75 #include "ChromiumBridge.h"
     76 #include "ClipboardUtilitiesChromium.h"
     77 #include "Console.h"
     78 #include "Document.h"
     79 #include "DocumentFragment.h" // Only needed for ReplaceSelectionCommand.h :(
     80 #include "DocumentLoader.h"
     81 #include "DocumentMarker.h"
     82 #include "DOMUtilitiesPrivate.h"
     83 #include "DOMWindow.h"
     84 #include "Editor.h"
     85 #include "EventHandler.h"
     86 #include "FormState.h"
     87 #include "FrameLoader.h"
     88 #include "FrameLoadRequest.h"
     89 #include "FrameTree.h"
     90 #include "FrameView.h"
     91 #include "GraphicsContext.h"
     92 #include "HistoryItem.h"
     93 #include "HTMLCollection.h"
     94 #include "HTMLFormElement.h"
     95 #include "HTMLFrameOwnerElement.h"
     96 #include "HTMLHeadElement.h"
     97 #include "HTMLInputElement.h"
     98 #include "HTMLLinkElement.h"
     99 #include "HTMLNames.h"
    100 #include "InspectorController.h"
    101 #include "markup.h"
    102 #include "Page.h"
    103 #include "PlatformContextSkia.h"
    104 #include "PrintContext.h"
    105 #include "RenderFrame.h"
    106 #include "RenderTreeAsText.h"
    107 #include "RenderView.h"
    108 #include "RenderWidget.h"
    109 #include "ReplaceSelectionCommand.h"
    110 #include "ResourceHandle.h"
    111 #include "ResourceRequest.h"
    112 #include "ScriptController.h"
    113 #include "ScriptSourceCode.h"
    114 #include "ScriptValue.h"
    115 #include "ScrollbarTheme.h"
    116 #include "ScrollTypes.h"
    117 #include "SelectionController.h"
    118 #include "Settings.h"
    119 #include "SkiaUtils.h"
    120 #include "SubstituteData.h"
    121 #include "TextAffinity.h"
    122 #include "TextIterator.h"
    123 #include "WebAnimationControllerImpl.h"
    124 #include "WebConsoleMessage.h"
    125 #include "WebDataSourceImpl.h"
    126 #include "WebDocument.h"
    127 #include "WebFindOptions.h"
    128 #include "WebFormElement.h"
    129 #include "WebFrameClient.h"
    130 #include "WebHistoryItem.h"
    131 #include "WebInputElement.h"
    132 #include "WebPasswordAutocompleteListener.h"
    133 #include "WebRange.h"
    134 #include "WebRect.h"
    135 #include "WebScriptSource.h"
    136 #include "WebSecurityOrigin.h"
    137 #include "WebSize.h"
    138 #include "WebURLError.h"
    139 #include "WebVector.h"
    140 #include "WebViewImpl.h"
    141 #include "XPathResult.h"
    142 
    143 #include <algorithm>
    144 #include <wtf/CurrentTime.h>
    145 
    146 
    147 #if OS(DARWIN)
    148 #include "LocalCurrentGraphicsContext.h"
    149 #endif
    150 
    151 #if OS(LINUX)
    152 #include <gdk/gdk.h>
    153 #endif
    154 
    155 using namespace WebCore;
    156 
    157 namespace WebKit {
    158 
    159 static int frameCount = 0;
    160 
    161 // Key for a StatsCounter tracking how many WebFrames are active.
    162 static const char* const webFrameActiveCount = "WebFrameActiveCount";
    163 
    164 static const char* const osdType = "application/opensearchdescription+xml";
    165 static const char* const osdRel = "search";
    166 
    167 // Backend for contentAsPlainText, this is a recursive function that gets
    168 // the text for the current frame and all of its subframes. It will append
    169 // the text of each frame in turn to the |output| up to |maxChars| length.
    170 //
    171 // The |frame| must be non-null.
    172 static void frameContentAsPlainText(size_t maxChars, Frame* frame,
    173                                     Vector<UChar>* output)
    174 {
    175     Document* doc = frame->document();
    176     if (!doc)
    177         return;
    178 
    179     if (!frame->view())
    180         return;
    181 
    182     // TextIterator iterates over the visual representation of the DOM. As such,
    183     // it requires you to do a layout before using it (otherwise it'll crash).
    184     if (frame->view()->needsLayout())
    185         frame->view()->layout();
    186 
    187     // Select the document body.
    188     RefPtr<Range> range(doc->createRange());
    189     ExceptionCode exception = 0;
    190     range->selectNodeContents(doc->body(), exception);
    191 
    192     if (!exception) {
    193         // The text iterator will walk nodes giving us text. This is similar to
    194         // the plainText() function in TextIterator.h, but we implement the maximum
    195         // size and also copy the results directly into a wstring, avoiding the
    196         // string conversion.
    197         for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
    198             const UChar* chars = it.characters();
    199             if (!chars) {
    200                 if (it.length()) {
    201                     // It appears from crash reports that an iterator can get into a state
    202                     // where the character count is nonempty but the character pointer is
    203                     // null. advance()ing it will then just add that many to the null
    204                     // pointer which won't be caught in a null check but will crash.
    205                     //
    206                     // A null pointer and 0 length is common for some nodes.
    207                     //
    208                     // IF YOU CATCH THIS IN A DEBUGGER please let brettw know. We don't
    209                     // currently understand the conditions for this to occur. Ideally, the
    210                     // iterators would never get into the condition so we should fix them
    211                     // if we can.
    212                     ASSERT_NOT_REACHED();
    213                     break;
    214                 }
    215 
    216                 // Just got a null node, we can forge ahead!
    217                 continue;
    218             }
    219             size_t toAppend =
    220                 std::min(static_cast<size_t>(it.length()), maxChars - output->size());
    221             output->append(chars, toAppend);
    222             if (output->size() >= maxChars)
    223                 return; // Filled up the buffer.
    224         }
    225     }
    226 
    227     // The separator between frames when the frames are converted to plain text.
    228     const UChar frameSeparator[] = { '\n', '\n' };
    229     const size_t frameSeparatorLen = 2;
    230 
    231     // Recursively walk the children.
    232     FrameTree* frameTree = frame->tree();
    233     for (Frame* curChild = frameTree->firstChild(); curChild; curChild = curChild->tree()->nextSibling()) {
    234         // Make sure the frame separator won't fill up the buffer, and give up if
    235         // it will. The danger is if the separator will make the buffer longer than
    236         // maxChars. This will cause the computation above:
    237         //   maxChars - output->size()
    238         // to be a negative number which will crash when the subframe is added.
    239         if (output->size() >= maxChars - frameSeparatorLen)
    240             return;
    241 
    242         output->append(frameSeparator, frameSeparatorLen);
    243         frameContentAsPlainText(maxChars, curChild, output);
    244         if (output->size() >= maxChars)
    245             return; // Filled up the buffer.
    246     }
    247 }
    248 
    249 // Simple class to override some of PrintContext behavior.
    250 class ChromePrintContext : public PrintContext, public Noncopyable {
    251 public:
    252     ChromePrintContext(Frame* frame)
    253         : PrintContext(frame)
    254         , m_printedPageWidth(0)
    255     {
    256     }
    257 
    258     void begin(float width)
    259     {
    260         ASSERT(!m_printedPageWidth);
    261         m_printedPageWidth = width;
    262         PrintContext::begin(m_printedPageWidth);
    263     }
    264 
    265     float getPageShrink(int pageNumber) const
    266     {
    267         IntRect pageRect = m_pageRects[pageNumber];
    268         return m_printedPageWidth / pageRect.width();
    269     }
    270 
    271     // Spools the printed page, a subrect of m_frame.  Skip the scale step.
    272     // NativeTheme doesn't play well with scaling. Scaling is done browser side
    273     // instead.  Returns the scale to be applied.
    274     float spoolPage(GraphicsContext& ctx, int pageNumber)
    275     {
    276         IntRect pageRect = m_pageRects[pageNumber];
    277         float scale = m_printedPageWidth / pageRect.width();
    278 
    279         ctx.save();
    280         ctx.translate(static_cast<float>(-pageRect.x()),
    281                       static_cast<float>(-pageRect.y()));
    282         ctx.clip(pageRect);
    283         m_frame->view()->paintContents(&ctx, pageRect);
    284         ctx.restore();
    285         return scale;
    286     }
    287 
    288 private:
    289     // Set when printing.
    290     float m_printedPageWidth;
    291 };
    292 
    293 static WebDataSource* DataSourceForDocLoader(DocumentLoader* loader)
    294 {
    295     return loader ? WebDataSourceImpl::fromDocumentLoader(loader) : 0;
    296 }
    297 
    298 
    299 // WebFrame -------------------------------------------------------------------
    300 
    301 class WebFrameImpl::DeferredScopeStringMatches {
    302 public:
    303     DeferredScopeStringMatches(WebFrameImpl* webFrame,
    304                                int identifier,
    305                                const WebString& searchText,
    306                                const WebFindOptions& options,
    307                                bool reset)
    308         : m_timer(this, &DeferredScopeStringMatches::doTimeout)
    309         , m_webFrame(webFrame)
    310         , m_identifier(identifier)
    311         , m_searchText(searchText)
    312         , m_options(options)
    313         , m_reset(reset)
    314     {
    315         m_timer.startOneShot(0.0);
    316     }
    317 
    318 private:
    319     void doTimeout(Timer<DeferredScopeStringMatches>*)
    320     {
    321         m_webFrame->callScopeStringMatches(
    322             this, m_identifier, m_searchText, m_options, m_reset);
    323     }
    324 
    325     Timer<DeferredScopeStringMatches> m_timer;
    326     RefPtr<WebFrameImpl> m_webFrame;
    327     int m_identifier;
    328     WebString m_searchText;
    329     WebFindOptions m_options;
    330     bool m_reset;
    331 };
    332 
    333 
    334 // WebFrame -------------------------------------------------------------------
    335 
    336 int WebFrame::instanceCount()
    337 {
    338     return frameCount;
    339 }
    340 
    341 WebFrame* WebFrame::frameForEnteredContext()
    342 {
    343     Frame* frame =
    344         ScriptController::retrieveFrameForEnteredContext();
    345     return WebFrameImpl::fromFrame(frame);
    346 }
    347 
    348 WebFrame* WebFrame::frameForCurrentContext()
    349 {
    350     Frame* frame =
    351         ScriptController::retrieveFrameForCurrentContext();
    352     return WebFrameImpl::fromFrame(frame);
    353 }
    354 
    355 WebFrame* WebFrame::fromFrameOwnerElement(const WebElement& element)
    356 {
    357     return WebFrameImpl::fromFrameOwnerElement(
    358         PassRefPtr<Element>(element).get());
    359 }
    360 
    361 WebString WebFrameImpl::name() const
    362 {
    363     return m_frame->tree()->name();
    364 }
    365 
    366 void WebFrameImpl::clearName()
    367 {
    368     m_frame->tree()->clearName();
    369 }
    370 
    371 WebURL WebFrameImpl::url() const
    372 {
    373     const WebDataSource* ds = dataSource();
    374     if (!ds)
    375         return WebURL();
    376     return ds->request().url();
    377 }
    378 
    379 WebURL WebFrameImpl::favIconURL() const
    380 {
    381     FrameLoader* frameLoader = m_frame->loader();
    382     // The URL to the favicon may be in the header. As such, only
    383     // ask the loader for the favicon if it's finished loading.
    384     if (frameLoader->state() == FrameStateComplete) {
    385         const KURL& url = frameLoader->iconURL();
    386         if (!url.isEmpty())
    387             return url;
    388     }
    389     return WebURL();
    390 }
    391 
    392 WebURL WebFrameImpl::openSearchDescriptionURL() const
    393 {
    394     FrameLoader* frameLoader = m_frame->loader();
    395     if (frameLoader->state() == FrameStateComplete
    396         && m_frame->document() && m_frame->document()->head()
    397         && !m_frame->tree()->parent()) {
    398         HTMLHeadElement* head = m_frame->document()->head();
    399         if (head) {
    400             RefPtr<HTMLCollection> children = head->children();
    401             for (Node* child = children->firstItem(); child; child = children->nextItem()) {
    402                 HTMLLinkElement* linkElement = toHTMLLinkElement(child);
    403                 if (linkElement
    404                     && linkElement->type() == osdType
    405                     && linkElement->rel() == osdRel
    406                     && !linkElement->href().isEmpty())
    407                     return linkElement->href();
    408             }
    409         }
    410     }
    411     return WebURL();
    412 }
    413 
    414 WebString WebFrameImpl::encoding() const
    415 {
    416     return frame()->loader()->encoding();
    417 }
    418 
    419 WebSize WebFrameImpl::scrollOffset() const
    420 {
    421     FrameView* view = frameView();
    422     if (view)
    423         return view->scrollOffset();
    424 
    425     return WebSize();
    426 }
    427 
    428 WebSize WebFrameImpl::contentsSize() const
    429 {
    430     return frame()->view()->contentsSize();
    431 }
    432 
    433 int WebFrameImpl::contentsPreferredWidth() const
    434 {
    435     if (m_frame->document() && m_frame->document()->renderView())
    436         return m_frame->document()->renderView()->minPrefWidth();
    437     return 0;
    438 }
    439 
    440 int WebFrameImpl::documentElementScrollHeight() const
    441 {
    442     if (m_frame->document() && m_frame->document()->documentElement())
    443         return m_frame->document()->documentElement()->scrollHeight();
    444     return 0;
    445 }
    446 
    447 bool WebFrameImpl::hasVisibleContent() const
    448 {
    449     return frame()->view()->visibleWidth() > 0 && frame()->view()->visibleHeight() > 0;
    450 }
    451 
    452 WebView* WebFrameImpl::view() const
    453 {
    454     return viewImpl();
    455 }
    456 
    457 WebFrame* WebFrameImpl::opener() const
    458 {
    459     Frame* opener = 0;
    460     if (m_frame)
    461         opener = m_frame->loader()->opener();
    462     return fromFrame(opener);
    463 }
    464 
    465 WebFrame* WebFrameImpl::parent() const
    466 {
    467     Frame* parent = 0;
    468     if (m_frame)
    469         parent = m_frame->tree()->parent();
    470     return fromFrame(parent);
    471 }
    472 
    473 WebFrame* WebFrameImpl::top() const
    474 {
    475     if (m_frame)
    476         return fromFrame(m_frame->tree()->top());
    477 
    478     return 0;
    479 }
    480 
    481 WebFrame* WebFrameImpl::firstChild() const
    482 {
    483     return fromFrame(frame()->tree()->firstChild());
    484 }
    485 
    486 WebFrame* WebFrameImpl::lastChild() const
    487 {
    488     return fromFrame(frame()->tree()->lastChild());
    489 }
    490 
    491 WebFrame* WebFrameImpl::nextSibling() const
    492 {
    493     return fromFrame(frame()->tree()->nextSibling());
    494 }
    495 
    496 WebFrame* WebFrameImpl::previousSibling() const
    497 {
    498     return fromFrame(frame()->tree()->previousSibling());
    499 }
    500 
    501 WebFrame* WebFrameImpl::traverseNext(bool wrap) const
    502 {
    503     return fromFrame(frame()->tree()->traverseNextWithWrap(wrap));
    504 }
    505 
    506 WebFrame* WebFrameImpl::traversePrevious(bool wrap) const
    507 {
    508     return fromFrame(frame()->tree()->traversePreviousWithWrap(wrap));
    509 }
    510 
    511 WebFrame* WebFrameImpl::findChildByName(const WebString& name) const
    512 {
    513     return fromFrame(frame()->tree()->child(name));
    514 }
    515 
    516 WebFrame* WebFrameImpl::findChildByExpression(const WebString& xpath) const
    517 {
    518     if (xpath.isEmpty())
    519         return 0;
    520 
    521     Document* document = m_frame->document();
    522 
    523     ExceptionCode ec = 0;
    524     PassRefPtr<XPathResult> xpathResult =
    525         document->evaluate(xpath,
    526         document,
    527         0, // namespace
    528         XPathResult::ORDERED_NODE_ITERATOR_TYPE,
    529         0, // XPathResult object
    530         ec);
    531     if (!xpathResult.get())
    532         return 0;
    533 
    534     Node* node = xpathResult->iterateNext(ec);
    535 
    536     if (!node || !node->isFrameOwnerElement())
    537         return 0;
    538     HTMLFrameOwnerElement* frameElement =
    539         static_cast<HTMLFrameOwnerElement*>(node);
    540     return fromFrame(frameElement->contentFrame());
    541 }
    542 
    543 WebDocument WebFrameImpl::document() const
    544 {
    545     if (!m_frame || !m_frame->document())
    546         return WebDocument();
    547     return WebDocument(m_frame->document());
    548 }
    549 
    550 void WebFrameImpl::forms(WebVector<WebFormElement>& results) const
    551 {
    552     if (!m_frame)
    553         return;
    554 
    555     RefPtr<HTMLCollection> forms = m_frame->document()->forms();
    556     size_t formCount = forms->length();
    557 
    558     WebVector<WebFormElement> temp(formCount);
    559     for (size_t i = 0; i < formCount; ++i) {
    560         Node* node = forms->item(i);
    561         // Strange but true, sometimes item can be 0.
    562         if (node)
    563             temp[i] = static_cast<HTMLFormElement*>(node);
    564     }
    565     results.swap(temp);
    566 }
    567 
    568 WebAnimationController* WebFrameImpl::animationController()
    569 {
    570     return &m_animationController;
    571 }
    572 
    573 WebSecurityOrigin WebFrameImpl::securityOrigin() const
    574 {
    575     if (!m_frame || !m_frame->document())
    576         return WebSecurityOrigin();
    577 
    578     return WebSecurityOrigin(m_frame->document()->securityOrigin());
    579 }
    580 
    581 void WebFrameImpl::grantUniversalAccess()
    582 {
    583     ASSERT(m_frame && m_frame->document());
    584     if (m_frame && m_frame->document())
    585         m_frame->document()->securityOrigin()->grantUniversalAccess();
    586 }
    587 
    588 NPObject* WebFrameImpl::windowObject() const
    589 {
    590     if (!m_frame)
    591         return 0;
    592 
    593     return m_frame->script()->windowScriptNPObject();
    594 }
    595 
    596 void WebFrameImpl::bindToWindowObject(const WebString& name, NPObject* object)
    597 {
    598     ASSERT(m_frame);
    599     if (!m_frame || !m_frame->script()->canExecuteScripts())
    600         return;
    601 
    602     String key = name;
    603 #if USE(V8)
    604     m_frame->script()->bindToWindowObject(m_frame, key, object);
    605 #else
    606     notImplemented();
    607 #endif
    608 }
    609 
    610 void WebFrameImpl::executeScript(const WebScriptSource& source)
    611 {
    612     m_frame->script()->executeScript(
    613         ScriptSourceCode(source.code, source.url, source.startLine));
    614 }
    615 
    616 void WebFrameImpl::executeScriptInIsolatedWorld(
    617     int worldId, const WebScriptSource* sourcesIn, unsigned numSources,
    618     int extensionGroup)
    619 {
    620     Vector<ScriptSourceCode> sources;
    621 
    622     for (unsigned i = 0; i < numSources; ++i) {
    623         sources.append(ScriptSourceCode(
    624             sourcesIn[i].code, sourcesIn[i].url, sourcesIn[i].startLine));
    625     }
    626 
    627     m_frame->script()->evaluateInIsolatedWorld(worldId, sources, extensionGroup);
    628 }
    629 
    630 void WebFrameImpl::addMessageToConsole(const WebConsoleMessage& message)
    631 {
    632     ASSERT(frame());
    633 
    634     MessageLevel webCoreMessageLevel;
    635     switch (message.level) {
    636     case WebConsoleMessage::LevelTip:
    637         webCoreMessageLevel = TipMessageLevel;
    638         break;
    639     case WebConsoleMessage::LevelLog:
    640         webCoreMessageLevel = LogMessageLevel;
    641         break;
    642     case WebConsoleMessage::LevelWarning:
    643         webCoreMessageLevel = WarningMessageLevel;
    644         break;
    645     case WebConsoleMessage::LevelError:
    646         webCoreMessageLevel = ErrorMessageLevel;
    647         break;
    648     default:
    649         ASSERT_NOT_REACHED();
    650         return;
    651     }
    652 
    653     frame()->domWindow()->console()->addMessage(
    654         OtherMessageSource, LogMessageType, webCoreMessageLevel, message.text,
    655         1, String());
    656 }
    657 
    658 void WebFrameImpl::collectGarbage()
    659 {
    660     if (!m_frame)
    661         return;
    662     if (!m_frame->settings()->isJavaScriptEnabled())
    663         return;
    664     // FIXME: Move this to the ScriptController and make it JS neutral.
    665 #if USE(V8)
    666     m_frame->script()->collectGarbage();
    667 #else
    668     notImplemented();
    669 #endif
    670 }
    671 
    672 #if USE(V8)
    673 // Returns the V8 context for this frame, or an empty handle if there is none.
    674 v8::Local<v8::Context> WebFrameImpl::mainWorldScriptContext() const
    675 {
    676     if (!m_frame)
    677         return v8::Local<v8::Context>();
    678 
    679     return V8Proxy::mainWorldContext(m_frame);
    680 }
    681 #endif
    682 
    683 bool WebFrameImpl::insertStyleText(
    684     const WebString& css, const WebString& id) {
    685     Document* document = frame()->document();
    686     if (!document)
    687         return false;
    688     Element* documentElement = document->documentElement();
    689     if (!documentElement)
    690         return false;
    691 
    692     ExceptionCode err = 0;
    693 
    694     if (!id.isEmpty()) {
    695         Element* oldElement = document->getElementById(id);
    696         if (oldElement) {
    697             Node* parent = oldElement->parent();
    698             if (!parent)
    699                 return false;
    700             parent->removeChild(oldElement, err);
    701         }
    702     }
    703 
    704     RefPtr<Element> stylesheet = document->createElement(
    705         HTMLNames::styleTag, false);
    706     if (!id.isEmpty())
    707         stylesheet->setAttribute(HTMLNames::idAttr, id);
    708     stylesheet->setTextContent(css, err);
    709     ASSERT(!err);
    710     Node* first = documentElement->firstChild();
    711     bool success = documentElement->insertBefore(stylesheet, first, err);
    712     ASSERT(success);
    713     return success;
    714 }
    715 
    716 void WebFrameImpl::reload()
    717 {
    718     m_frame->loader()->history()->saveDocumentAndScrollState();
    719 
    720     stopLoading();  // Make sure existing activity stops.
    721     m_frame->loader()->reload();
    722 }
    723 
    724 void WebFrameImpl::loadRequest(const WebURLRequest& request)
    725 {
    726     ASSERT(!request.isNull());
    727     const ResourceRequest& resourceRequest = request.toResourceRequest();
    728 
    729     if (resourceRequest.url().protocolIs("javascript")) {
    730         loadJavaScriptURL(resourceRequest.url());
    731         return;
    732     }
    733 
    734     stopLoading();  // Make sure existing activity stops.
    735     m_frame->loader()->load(resourceRequest, false);
    736 }
    737 
    738 void WebFrameImpl::loadHistoryItem(const WebHistoryItem& item)
    739 {
    740     RefPtr<HistoryItem> historyItem = PassRefPtr<HistoryItem>(item);
    741     ASSERT(historyItem.get());
    742 
    743     stopLoading();  // Make sure existing activity stops.
    744 
    745     // If there is no currentItem, which happens when we are navigating in
    746     // session history after a crash, we need to manufacture one otherwise WebKit
    747     // hoarks. This is probably the wrong thing to do, but it seems to work.
    748     RefPtr<HistoryItem> currentItem = m_frame->loader()->history()->currentItem();
    749     if (!currentItem) {
    750         currentItem = HistoryItem::create();
    751         currentItem->setLastVisitWasFailure(true);
    752         m_frame->loader()->history()->setCurrentItem(currentItem.get());
    753         viewImpl()->setCurrentHistoryItem(currentItem.get());
    754     }
    755 
    756     m_frame->loader()->history()->goToItem(
    757         historyItem.get(), FrameLoadTypeIndexedBackForward);
    758 }
    759 
    760 void WebFrameImpl::loadData(const WebData& data,
    761                             const WebString& mimeType,
    762                             const WebString& textEncoding,
    763                             const WebURL& baseURL,
    764                             const WebURL& unreachableURL,
    765                             bool replace)
    766 {
    767     SubstituteData substData(data, mimeType, textEncoding, unreachableURL);
    768     ASSERT(substData.isValid());
    769 
    770     // If we are loading substitute data to replace an existing load, then
    771     // inherit all of the properties of that original request.  This way,
    772     // reload will re-attempt the original request.  It is essential that
    773     // we only do this when there is an unreachableURL since a non-empty
    774     // unreachableURL informs FrameLoader::reload to load unreachableURL
    775     // instead of the currently loaded URL.
    776     ResourceRequest request;
    777     if (replace && !unreachableURL.isEmpty())
    778         request = m_frame->loader()->originalRequest();
    779     request.setURL(baseURL);
    780 
    781     stopLoading();  // Make sure existing activity stops.
    782 
    783     m_frame->loader()->load(request, substData, false);
    784     if (replace) {
    785         // Do this to force WebKit to treat the load as replacing the currently
    786         // loaded page.
    787         m_frame->loader()->setReplacing();
    788     }
    789 }
    790 
    791 void WebFrameImpl::loadHTMLString(const WebData& data,
    792                                   const WebURL& baseURL,
    793                                   const WebURL& unreachableURL,
    794                                   bool replace)
    795 {
    796     loadData(data,
    797              WebString::fromUTF8("text/html"),
    798              WebString::fromUTF8("UTF-8"),
    799              baseURL,
    800              unreachableURL,
    801              replace);
    802 }
    803 
    804 bool WebFrameImpl::isLoading() const
    805 {
    806     if (!m_frame)
    807         return false;
    808     return m_frame->loader()->isLoading();
    809 }
    810 
    811 void WebFrameImpl::stopLoading()
    812 {
    813     if (!m_frame)
    814       return;
    815 
    816     // FIXME: Figure out what we should really do here.  It seems like a bug
    817     // that FrameLoader::stopLoading doesn't call stopAllLoaders.
    818     m_frame->loader()->stopAllLoaders();
    819     m_frame->loader()->stopLoading(UnloadEventPolicyNone);
    820 }
    821 
    822 WebDataSource* WebFrameImpl::provisionalDataSource() const
    823 {
    824     FrameLoader* frameLoader = m_frame->loader();
    825 
    826     // We regard the policy document loader as still provisional.
    827     DocumentLoader* docLoader = frameLoader->provisionalDocumentLoader();
    828     if (!docLoader)
    829         docLoader = frameLoader->policyDocumentLoader();
    830 
    831     return DataSourceForDocLoader(docLoader);
    832 }
    833 
    834 WebDataSource* WebFrameImpl::dataSource() const
    835 {
    836     return DataSourceForDocLoader(m_frame->loader()->documentLoader());
    837 }
    838 
    839 WebHistoryItem WebFrameImpl::previousHistoryItem() const
    840 {
    841     // We use the previous item here because documentState (filled-out forms)
    842     // only get saved to history when it becomes the previous item.  The caller
    843     // is expected to query the history item after a navigation occurs, after
    844     // the desired history item has become the previous entry.
    845     return WebHistoryItem(viewImpl()->previousHistoryItem());
    846 }
    847 
    848 WebHistoryItem WebFrameImpl::currentHistoryItem() const
    849 {
    850     m_frame->loader()->history()->saveDocumentAndScrollState();
    851 
    852     return WebHistoryItem(m_frame->page()->backForwardList()->currentItem());
    853 }
    854 
    855 void WebFrameImpl::enableViewSourceMode(bool enable)
    856 {
    857     if (m_frame)
    858         m_frame->setInViewSourceMode(enable);
    859 }
    860 
    861 bool WebFrameImpl::isViewSourceModeEnabled() const
    862 {
    863     if (m_frame)
    864         return m_frame->inViewSourceMode();
    865 
    866     return false;
    867 }
    868 
    869 void WebFrameImpl::setReferrerForRequest(
    870     WebURLRequest& request, const WebURL& referrerURL) {
    871     String referrer;
    872     if (referrerURL.isEmpty())
    873         referrer = m_frame->loader()->outgoingReferrer();
    874     else
    875         referrer = referrerURL.spec().utf16();
    876     if (SecurityOrigin::shouldHideReferrer(request.url(), referrer))
    877         return;
    878     request.setHTTPHeaderField(WebString::fromUTF8("Referer"), referrer);
    879 }
    880 
    881 void WebFrameImpl::dispatchWillSendRequest(WebURLRequest& request)
    882 {
    883     ResourceResponse response;
    884     m_frame->loader()->client()->dispatchWillSendRequest(
    885         0, 0, request.toMutableResourceRequest(), response);
    886 }
    887 
    888 void WebFrameImpl::commitDocumentData(const char* data, size_t dataLen)
    889 {
    890     DocumentLoader* documentLoader = m_frame->loader()->documentLoader();
    891 
    892     // Set the text encoding.  This calls begin() for us.  It is safe to call
    893     // this multiple times (Mac does: page/mac/WebCoreFrameBridge.mm).
    894     bool userChosen = true;
    895     String encoding = documentLoader->overrideEncoding();
    896     if (encoding.isNull()) {
    897         userChosen = false;
    898         encoding = documentLoader->response().textEncodingName();
    899     }
    900     m_frame->loader()->setEncoding(encoding, userChosen);
    901 
    902     // NOTE: mac only does this if there is a document
    903     m_frame->loader()->addData(data, dataLen);
    904 }
    905 
    906 unsigned WebFrameImpl::unloadListenerCount() const
    907 {
    908     return frame()->domWindow()->pendingUnloadEventListeners();
    909 }
    910 
    911 bool WebFrameImpl::isProcessingUserGesture() const
    912 {
    913     return frame()->loader()->isProcessingUserGesture();
    914 }
    915 
    916 bool WebFrameImpl::willSuppressOpenerInNewFrame() const
    917 {
    918     return frame()->loader()->suppressOpenerInNewFrame();
    919 }
    920 
    921 void WebFrameImpl::replaceSelection(const WebString& text)
    922 {
    923     RefPtr<DocumentFragment> fragment = createFragmentFromText(
    924         frame()->selection()->toNormalizedRange().get(), text);
    925     applyCommand(ReplaceSelectionCommand::create(
    926         frame()->document(), fragment.get(), false, true, true));
    927 }
    928 
    929 void WebFrameImpl::insertText(const WebString& text)
    930 {
    931     frame()->editor()->insertText(text, 0);
    932 }
    933 
    934 void WebFrameImpl::setMarkedText(
    935     const WebString& text, unsigned location, unsigned length)
    936 {
    937     Editor* editor = frame()->editor();
    938 
    939     editor->confirmComposition(text);
    940 
    941     Vector<CompositionUnderline> decorations;
    942     editor->setComposition(text, decorations, location, length);
    943 }
    944 
    945 void WebFrameImpl::unmarkText()
    946 {
    947     frame()->editor()->confirmCompositionWithoutDisturbingSelection();
    948 }
    949 
    950 bool WebFrameImpl::hasMarkedText() const
    951 {
    952     return frame()->editor()->hasComposition();
    953 }
    954 
    955 WebRange WebFrameImpl::markedRange() const
    956 {
    957     return frame()->editor()->compositionRange();
    958 }
    959 
    960 bool WebFrameImpl::executeCommand(const WebString& name)
    961 {
    962     ASSERT(frame());
    963 
    964     if (name.length() <= 2)
    965         return false;
    966 
    967     // Since we don't have NSControl, we will convert the format of command
    968     // string and call the function on Editor directly.
    969     String command = name;
    970 
    971     // Make sure the first letter is upper case.
    972     command.replace(0, 1, command.substring(0, 1).upper());
    973 
    974     // Remove the trailing ':' if existing.
    975     if (command[command.length() - 1] == UChar(':'))
    976         command = command.substring(0, command.length() - 1);
    977 
    978     bool rv = true;
    979 
    980     // Specially handling commands that Editor::execCommand does not directly
    981     // support.
    982     if (command == "DeleteToEndOfParagraph") {
    983         Editor* editor = frame()->editor();
    984         if (!editor->deleteWithDirection(SelectionController::FORWARD,
    985                                          ParagraphBoundary,
    986                                          true,
    987                                          false)) {
    988             editor->deleteWithDirection(SelectionController::FORWARD,
    989                                         CharacterGranularity,
    990                                         true,
    991                                         false);
    992         }
    993     } else if (command == "Indent")
    994         frame()->editor()->indent();
    995     else if (command == "Outdent")
    996         frame()->editor()->outdent();
    997     else if (command == "DeleteBackward")
    998         rv = frame()->editor()->command(AtomicString("BackwardDelete")).execute();
    999     else if (command == "DeleteForward")
   1000         rv = frame()->editor()->command(AtomicString("ForwardDelete")).execute();
   1001     else if (command == "AdvanceToNextMisspelling") {
   1002         // False must be passed here, or the currently selected word will never be
   1003         // skipped.
   1004         frame()->editor()->advanceToNextMisspelling(false);
   1005     } else if (command == "ToggleSpellPanel")
   1006         frame()->editor()->showSpellingGuessPanel();
   1007     else
   1008         rv = frame()->editor()->command(command).execute();
   1009     return rv;
   1010 }
   1011 
   1012 bool WebFrameImpl::executeCommand(const WebString& name, const WebString& value)
   1013 {
   1014     ASSERT(frame());
   1015     String webName = name;
   1016 
   1017     // moveToBeginningOfDocument and moveToEndfDocument are only handled by WebKit
   1018     // for editable nodes.
   1019     if (!frame()->editor()->canEdit() && webName == "moveToBeginningOfDocument")
   1020         return viewImpl()->propagateScroll(ScrollUp, ScrollByDocument);
   1021 
   1022     if (!frame()->editor()->canEdit() && webName == "moveToEndOfDocument")
   1023         return viewImpl()->propagateScroll(ScrollDown, ScrollByDocument);
   1024 
   1025     return frame()->editor()->command(webName).execute(value);
   1026 }
   1027 
   1028 bool WebFrameImpl::isCommandEnabled(const WebString& name) const
   1029 {
   1030     ASSERT(frame());
   1031     return frame()->editor()->command(name).isEnabled();
   1032 }
   1033 
   1034 void WebFrameImpl::enableContinuousSpellChecking(bool enable)
   1035 {
   1036     if (enable == isContinuousSpellCheckingEnabled())
   1037         return;
   1038     frame()->editor()->toggleContinuousSpellChecking();
   1039 }
   1040 
   1041 bool WebFrameImpl::isContinuousSpellCheckingEnabled() const
   1042 {
   1043     return frame()->editor()->isContinuousSpellCheckingEnabled();
   1044 }
   1045 
   1046 bool WebFrameImpl::hasSelection() const
   1047 {
   1048     // frame()->selection()->isNone() never returns true.
   1049     return (frame()->selection()->start() != frame()->selection()->end());
   1050 }
   1051 
   1052 WebRange WebFrameImpl::selectionRange() const
   1053 {
   1054     return frame()->selection()->toNormalizedRange();
   1055 }
   1056 
   1057 WebString WebFrameImpl::selectionAsText() const
   1058 {
   1059     RefPtr<Range> range = frame()->selection()->toNormalizedRange();
   1060     if (!range.get())
   1061         return WebString();
   1062 
   1063     String text = range->text();
   1064 #if OS(WINDOWS)
   1065     replaceNewlinesWithWindowsStyleNewlines(text);
   1066 #endif
   1067     replaceNBSPWithSpace(text);
   1068     return text;
   1069 }
   1070 
   1071 WebString WebFrameImpl::selectionAsMarkup() const
   1072 {
   1073     RefPtr<Range> range = frame()->selection()->toNormalizedRange();
   1074     if (!range.get())
   1075         return WebString();
   1076 
   1077     return createMarkup(range.get(), 0);
   1078 }
   1079 
   1080 void WebFrameImpl::selectWordAroundPosition(Frame* frame, VisiblePosition pos)
   1081 {
   1082     VisibleSelection selection(pos);
   1083     selection.expandUsingGranularity(WordGranularity);
   1084 
   1085     if (selection.isRange())
   1086         frame->setSelectionGranularity(WordGranularity);
   1087 
   1088     if (frame->shouldChangeSelection(selection))
   1089         frame->selection()->setSelection(selection);
   1090 }
   1091 
   1092 bool WebFrameImpl::selectWordAroundCaret()
   1093 {
   1094     SelectionController* controller = frame()->selection();
   1095     ASSERT(!controller->isNone());
   1096     if (controller->isNone() || controller->isRange())
   1097         return false;
   1098     selectWordAroundPosition(frame(), controller->selection().visibleStart());
   1099     return true;
   1100 }
   1101 
   1102 int WebFrameImpl::printBegin(const WebSize& pageSize)
   1103 {
   1104     ASSERT(!frame()->document()->isFrameSet());
   1105 
   1106     m_printContext.set(new ChromePrintContext(frame()));
   1107     FloatRect rect(0, 0, static_cast<float>(pageSize.width),
   1108                          static_cast<float>(pageSize.height));
   1109     m_printContext->begin(rect.width());
   1110     float pageHeight;
   1111     // We ignore the overlays calculation for now since they are generated in the
   1112     // browser. pageHeight is actually an output parameter.
   1113     m_printContext->computePageRects(rect, 0, 0, 1.0, pageHeight);
   1114     return m_printContext->pageCount();
   1115 }
   1116 
   1117 float WebFrameImpl::getPrintPageShrink(int page)
   1118 {
   1119     // Ensure correct state.
   1120     if (!m_printContext.get() || page < 0) {
   1121         ASSERT_NOT_REACHED();
   1122         return 0;
   1123     }
   1124 
   1125     return m_printContext->getPageShrink(page);
   1126 }
   1127 
   1128 float WebFrameImpl::printPage(int page, WebCanvas* canvas)
   1129 {
   1130     // Ensure correct state.
   1131     if (!m_printContext.get() || page < 0 || !frame() || !frame()->document()) {
   1132         ASSERT_NOT_REACHED();
   1133         return 0;
   1134     }
   1135 
   1136 #if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD)
   1137     PlatformContextSkia context(canvas);
   1138     GraphicsContext spool(&context);
   1139 #elif OS(DARWIN)
   1140     GraphicsContext spool(canvas);
   1141     LocalCurrentGraphicsContext localContext(&spool);
   1142 #endif
   1143 
   1144     return m_printContext->spoolPage(spool, page);
   1145 }
   1146 
   1147 void WebFrameImpl::printEnd()
   1148 {
   1149     ASSERT(m_printContext.get());
   1150     if (m_printContext.get())
   1151         m_printContext->end();
   1152     m_printContext.clear();
   1153 }
   1154 
   1155 bool WebFrameImpl::find(int identifier,
   1156                         const WebString& searchText,
   1157                         const WebFindOptions& options,
   1158                         bool wrapWithinFrame,
   1159                         WebRect* selectionRect)
   1160 {
   1161     WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
   1162 
   1163     if (!options.findNext)
   1164         frame()->page()->unmarkAllTextMatches();
   1165     else
   1166         setMarkerActive(m_activeMatch.get(), false);  // Active match is changing.
   1167 
   1168     // Starts the search from the current selection.
   1169     bool startInSelection = true;
   1170 
   1171     // If the user has selected something since the last Find operation we want
   1172     // to start from there. Otherwise, we start searching from where the last Find
   1173     // operation left off (either a Find or a FindNext operation).
   1174     VisibleSelection selection(frame()->selection()->selection());
   1175     bool activeSelection = !selection.isNone();
   1176     if (!activeSelection && m_activeMatch) {
   1177         selection = VisibleSelection(m_activeMatch.get());
   1178         frame()->selection()->setSelection(selection);
   1179     }
   1180 
   1181     ASSERT(frame() && frame()->view());
   1182     bool found = frame()->findString(
   1183         searchText, options.forward, options.matchCase, wrapWithinFrame,
   1184         startInSelection);
   1185     if (found) {
   1186         // Store which frame was active. This will come in handy later when we
   1187         // change the active match ordinal below.
   1188         WebFrameImpl* oldActiveFrame = mainFrameImpl->m_activeMatchFrame;
   1189         // Set this frame as the active frame (the one with the active highlight).
   1190         mainFrameImpl->m_activeMatchFrame = this;
   1191 
   1192         // We found something, so we can now query the selection for its position.
   1193         VisibleSelection newSelection(frame()->selection()->selection());
   1194         IntRect currSelectionRect;
   1195 
   1196         // If we thought we found something, but it couldn't be selected (perhaps
   1197         // because it was marked -webkit-user-select: none), we can't set it to
   1198         // be active but we still continue searching. This matches Safari's
   1199         // behavior, including some oddities when selectable and un-selectable text
   1200         // are mixed on a page: see https://bugs.webkit.org/show_bug.cgi?id=19127.
   1201         if (newSelection.isNone() || (newSelection.start() == newSelection.end()))
   1202             m_activeMatch = 0;
   1203         else {
   1204             m_activeMatch = newSelection.toNormalizedRange();
   1205             currSelectionRect = m_activeMatch->boundingBox();
   1206             setMarkerActive(m_activeMatch.get(), true);  // Active.
   1207             // WebKit draws the highlighting for all matches.
   1208             executeCommand(WebString::fromUTF8("Unselect"));
   1209         }
   1210 
   1211         if (!options.findNext || activeSelection) {
   1212             // This is either a Find operation or a Find-next from a new start point
   1213             // due to a selection, so we set the flag to ask the scoping effort
   1214             // to find the active rect for us so we can update the ordinal (n of m).
   1215             m_locatingActiveRect = true;
   1216         } else {
   1217             if (oldActiveFrame != this) {
   1218                 // If the active frame has changed it means that we have a multi-frame
   1219                 // page and we just switch to searching in a new frame. Then we just
   1220                 // want to reset the index.
   1221                 if (options.forward)
   1222                     m_activeMatchIndex = 0;
   1223                 else
   1224                     m_activeMatchIndex = m_lastMatchCount - 1;
   1225             } else {
   1226                 // We are still the active frame, so increment (or decrement) the
   1227                 // |m_activeMatchIndex|, wrapping if needed (on single frame pages).
   1228                 options.forward ? ++m_activeMatchIndex : --m_activeMatchIndex;
   1229                 if (m_activeMatchIndex + 1 > m_lastMatchCount)
   1230                     m_activeMatchIndex = 0;
   1231                 if (m_activeMatchIndex == -1)
   1232                     m_activeMatchIndex = m_lastMatchCount - 1;
   1233             }
   1234             if (selectionRect) {
   1235                 WebRect rect = frame()->view()->convertToContainingWindow(currSelectionRect);
   1236                 rect.x -= frameView()->scrollOffset().width();
   1237                 rect.y -= frameView()->scrollOffset().height();
   1238                 *selectionRect = rect;
   1239 
   1240                 reportFindInPageSelection(rect, m_activeMatchIndex + 1, identifier);
   1241             }
   1242         }
   1243     } else {
   1244         // Nothing was found in this frame.
   1245         m_activeMatch = 0;
   1246 
   1247         // Erase all previous tickmarks and highlighting.
   1248         invalidateArea(InvalidateAll);
   1249     }
   1250 
   1251     return found;
   1252 }
   1253 
   1254 void WebFrameImpl::stopFinding(bool clearSelection)
   1255 {
   1256     if (!clearSelection)
   1257         setFindEndstateFocusAndSelection();
   1258     cancelPendingScopingEffort();
   1259 
   1260     // Remove all markers for matches found and turn off the highlighting.
   1261     frame()->document()->removeMarkers(DocumentMarker::TextMatch);
   1262     frame()->setMarkedTextMatchesAreHighlighted(false);
   1263 
   1264     // Let the frame know that we don't want tickmarks or highlighting anymore.
   1265     invalidateArea(InvalidateAll);
   1266 }
   1267 
   1268 void WebFrameImpl::scopeStringMatches(int identifier,
   1269                                       const WebString& searchText,
   1270                                       const WebFindOptions& options,
   1271                                       bool reset)
   1272 {
   1273     if (!shouldScopeMatches(searchText))
   1274         return;
   1275 
   1276     WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
   1277 
   1278     if (reset) {
   1279         // This is a brand new search, so we need to reset everything.
   1280         // Scoping is just about to begin.
   1281         m_scopingComplete = false;
   1282         // Clear highlighting for this frame.
   1283         if (frame()->markedTextMatchesAreHighlighted())
   1284             frame()->page()->unmarkAllTextMatches();
   1285         // Clear the counters from last operation.
   1286         m_lastMatchCount = 0;
   1287         m_nextInvalidateAfter = 0;
   1288 
   1289         m_resumeScopingFromRange = 0;
   1290 
   1291         mainFrameImpl->m_framesScopingCount++;
   1292 
   1293         // Now, defer scoping until later to allow find operation to finish quickly.
   1294         scopeStringMatchesSoon(
   1295             identifier,
   1296             searchText,
   1297             options,
   1298             false);  // false=we just reset, so don't do it again.
   1299         return;
   1300     }
   1301 
   1302     RefPtr<Range> searchRange(rangeOfContents(frame()->document()));
   1303 
   1304     ExceptionCode ec = 0, ec2 = 0;
   1305     if (m_resumeScopingFromRange.get()) {
   1306         // This is a continuation of a scoping operation that timed out and didn't
   1307         // complete last time around, so we should start from where we left off.
   1308         searchRange->setStart(m_resumeScopingFromRange->startContainer(),
   1309                               m_resumeScopingFromRange->startOffset(ec2) + 1,
   1310                               ec);
   1311         if (ec || ec2) {
   1312             if (ec2)  // A non-zero |ec| happens when navigating during search.
   1313                 ASSERT_NOT_REACHED();
   1314             return;
   1315         }
   1316     }
   1317 
   1318     // This timeout controls how long we scope before releasing control.  This
   1319     // value does not prevent us from running for longer than this, but it is
   1320     // periodically checked to see if we have exceeded our allocated time.
   1321     const double maxScopingDuration = 0.1;  // seconds
   1322 
   1323     int matchCount = 0;
   1324     bool timedOut = false;
   1325     double startTime = currentTime();
   1326     do {
   1327         // Find next occurrence of the search string.
   1328         // FIXME: (http://b/1088245) This WebKit operation may run for longer
   1329         // than the timeout value, and is not interruptible as it is currently
   1330         // written. We may need to rewrite it with interruptibility in mind, or
   1331         // find an alternative.
   1332         RefPtr<Range> resultRange(findPlainText(searchRange.get(),
   1333                                                 searchText,
   1334                                                 true,
   1335                                                 options.matchCase));
   1336         if (resultRange->collapsed(ec)) {
   1337             if (!resultRange->startContainer()->isInShadowTree())
   1338                 break;
   1339 
   1340             searchRange = rangeOfContents(frame()->document());
   1341             searchRange->setStartAfter(
   1342                 resultRange->startContainer()->shadowAncestorNode(), ec);
   1343             continue;
   1344         }
   1345 
   1346         // A non-collapsed result range can in some funky whitespace cases still not
   1347         // advance the range's start position (4509328). Break to avoid infinite
   1348         // loop. (This function is based on the implementation of
   1349         // Frame::markAllMatchesForText, which is where this safeguard comes from).
   1350         VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
   1351         if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
   1352             break;
   1353 
   1354         // Only treat the result as a match if it is visible
   1355         if (frame()->editor()->insideVisibleArea(resultRange.get())) {
   1356             ++matchCount;
   1357 
   1358             setStart(searchRange.get(), newStart);
   1359             Node* shadowTreeRoot = searchRange->shadowTreeRootNode();
   1360             if (searchRange->collapsed(ec) && shadowTreeRoot)
   1361                 searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
   1362 
   1363             // Catch a special case where Find found something but doesn't know what
   1364             // the bounding box for it is. In this case we set the first match we find
   1365             // as the active rect.
   1366             IntRect resultBounds = resultRange->boundingBox();
   1367             IntRect activeSelectionRect;
   1368             if (m_locatingActiveRect) {
   1369                 activeSelectionRect = m_activeMatch.get() ?
   1370                     m_activeMatch->boundingBox() : resultBounds;
   1371             }
   1372 
   1373             // If the Find function found a match it will have stored where the
   1374             // match was found in m_activeSelectionRect on the current frame. If we
   1375             // find this rect during scoping it means we have found the active
   1376             // tickmark.
   1377             bool foundActiveMatch = false;
   1378             if (m_locatingActiveRect && (activeSelectionRect == resultBounds)) {
   1379                 // We have found the active tickmark frame.
   1380                 mainFrameImpl->m_activeMatchFrame = this;
   1381                 foundActiveMatch = true;
   1382                 // We also know which tickmark is active now.
   1383                 m_activeMatchIndex = matchCount - 1;
   1384                 // To stop looking for the active tickmark, we set this flag.
   1385                 m_locatingActiveRect = false;
   1386 
   1387                 // Notify browser of new location for the selected rectangle.
   1388                 resultBounds.move(-frameView()->scrollOffset().width(),
   1389                                   -frameView()->scrollOffset().height());
   1390                 reportFindInPageSelection(
   1391                     frame()->view()->convertToContainingWindow(resultBounds),
   1392                     m_activeMatchIndex + 1,
   1393                     identifier);
   1394             }
   1395 
   1396             addMarker(resultRange.get(), foundActiveMatch);
   1397         }
   1398 
   1399         m_resumeScopingFromRange = resultRange;
   1400         timedOut = (currentTime() - startTime) >= maxScopingDuration;
   1401     } while (!timedOut);
   1402 
   1403     // Remember what we search for last time, so we can skip searching if more
   1404     // letters are added to the search string (and last outcome was 0).
   1405     m_lastSearchString = searchText;
   1406 
   1407     if (matchCount > 0) {
   1408         frame()->setMarkedTextMatchesAreHighlighted(true);
   1409 
   1410         m_lastMatchCount += matchCount;
   1411 
   1412         // Let the mainframe know how much we found during this pass.
   1413         mainFrameImpl->increaseMatchCount(matchCount, identifier);
   1414     }
   1415 
   1416     if (timedOut) {
   1417         // If we found anything during this pass, we should redraw. However, we
   1418         // don't want to spam too much if the page is extremely long, so if we
   1419         // reach a certain point we start throttling the redraw requests.
   1420         if (matchCount > 0)
   1421             invalidateIfNecessary();
   1422 
   1423         // Scoping effort ran out of time, lets ask for another time-slice.
   1424         scopeStringMatchesSoon(
   1425             identifier,
   1426             searchText,
   1427             options,
   1428             false);  // don't reset.
   1429         return;  // Done for now, resume work later.
   1430     }
   1431 
   1432     // This frame has no further scoping left, so it is done. Other frames might,
   1433     // of course, continue to scope matches.
   1434     m_scopingComplete = true;
   1435     mainFrameImpl->m_framesScopingCount--;
   1436 
   1437     // If this is the last frame to finish scoping we need to trigger the final
   1438     // update to be sent.
   1439     if (!mainFrameImpl->m_framesScopingCount)
   1440         mainFrameImpl->increaseMatchCount(0, identifier);
   1441 
   1442     // This frame is done, so show any scrollbar tickmarks we haven't drawn yet.
   1443     invalidateArea(InvalidateScrollbar);
   1444 }
   1445 
   1446 void WebFrameImpl::cancelPendingScopingEffort()
   1447 {
   1448     deleteAllValues(m_deferredScopingWork);
   1449     m_deferredScopingWork.clear();
   1450 
   1451     m_activeMatchIndex = -1;
   1452 }
   1453 
   1454 void WebFrameImpl::increaseMatchCount(int count, int identifier)
   1455 {
   1456     // This function should only be called on the mainframe.
   1457     ASSERT(!parent());
   1458 
   1459     m_totalMatchCount += count;
   1460 
   1461     // Update the UI with the latest findings.
   1462     if (client())
   1463         client()->reportFindInPageMatchCount(identifier, m_totalMatchCount, !m_framesScopingCount);
   1464 }
   1465 
   1466 void WebFrameImpl::reportFindInPageSelection(const WebRect& selectionRect,
   1467                                              int activeMatchOrdinal,
   1468                                              int identifier)
   1469 {
   1470     // Update the UI with the latest selection rect.
   1471     if (client())
   1472         client()->reportFindInPageSelection(identifier, ordinalOfFirstMatchForFrame(this) + activeMatchOrdinal, selectionRect);
   1473 }
   1474 
   1475 void WebFrameImpl::resetMatchCount()
   1476 {
   1477     m_totalMatchCount = 0;
   1478     m_framesScopingCount = 0;
   1479 }
   1480 
   1481 WebURL WebFrameImpl::completeURL(const WebString& url) const
   1482 {
   1483     if (!m_frame || !m_frame->document())
   1484         return WebURL();
   1485 
   1486     return m_frame->document()->completeURL(url);
   1487 }
   1488 
   1489 WebString WebFrameImpl::contentAsText(size_t maxChars) const
   1490 {
   1491     if (!m_frame)
   1492         return WebString();
   1493 
   1494     Vector<UChar> text;
   1495     frameContentAsPlainText(maxChars, m_frame, &text);
   1496     return String::adopt(text);
   1497 }
   1498 
   1499 WebString WebFrameImpl::contentAsMarkup() const
   1500 {
   1501     return createFullMarkup(m_frame->document());
   1502 }
   1503 
   1504 WebString WebFrameImpl::renderTreeAsText() const
   1505 {
   1506     return externalRepresentation(m_frame);
   1507 }
   1508 
   1509 WebString WebFrameImpl::counterValueForElementById(const WebString& id) const
   1510 {
   1511     if (!m_frame)
   1512         return WebString();
   1513 
   1514     Element* element = m_frame->document()->getElementById(id);
   1515     if (!element)
   1516         return WebString();
   1517 
   1518     return counterValueForElement(element);
   1519 }
   1520 
   1521 int WebFrameImpl::pageNumberForElementById(const WebString& id,
   1522                                            float pageWidthInPixels,
   1523                                            float pageHeightInPixels) const
   1524 {
   1525     if (!m_frame)
   1526         return -1;
   1527 
   1528     Element* element = m_frame->document()->getElementById(id);
   1529     if (!element)
   1530         return -1;
   1531 
   1532     FloatSize pageSize(pageWidthInPixels, pageHeightInPixels);
   1533     return PrintContext::pageNumberForElement(element, pageSize);
   1534 }
   1535 
   1536 // WebFrameImpl public ---------------------------------------------------------
   1537 
   1538 PassRefPtr<WebFrameImpl> WebFrameImpl::create(WebFrameClient* client)
   1539 {
   1540     return adoptRef(new WebFrameImpl(client));
   1541 }
   1542 
   1543 WebFrameImpl::WebFrameImpl(WebFrameClient* client)
   1544     : m_frameLoaderClient(this)
   1545     , m_client(client)
   1546     , m_activeMatchFrame(0)
   1547     , m_activeMatchIndex(-1)
   1548     , m_locatingActiveRect(false)
   1549     , m_resumeScopingFromRange(0)
   1550     , m_lastMatchCount(-1)
   1551     , m_totalMatchCount(-1)
   1552     , m_framesScopingCount(-1)
   1553     , m_scopingComplete(false)
   1554     , m_nextInvalidateAfter(0)
   1555     , m_animationController(this)
   1556 {
   1557     ChromiumBridge::incrementStatsCounter(webFrameActiveCount);
   1558     frameCount++;
   1559 }
   1560 
   1561 WebFrameImpl::~WebFrameImpl()
   1562 {
   1563     ChromiumBridge::decrementStatsCounter(webFrameActiveCount);
   1564     frameCount--;
   1565 
   1566     cancelPendingScopingEffort();
   1567     clearPasswordListeners();
   1568 }
   1569 
   1570 void WebFrameImpl::initializeAsMainFrame(WebViewImpl* webViewImpl)
   1571 {
   1572     RefPtr<Frame> frame = Frame::create(webViewImpl->page(), 0, &m_frameLoaderClient);
   1573     m_frame = frame.get();
   1574 
   1575     // Add reference on behalf of FrameLoader.  See comments in
   1576     // WebFrameLoaderClient::frameLoaderDestroyed for more info.
   1577     ref();
   1578 
   1579     // We must call init() after m_frame is assigned because it is referenced
   1580     // during init().
   1581     m_frame->init();
   1582 }
   1583 
   1584 PassRefPtr<Frame> WebFrameImpl::createChildFrame(
   1585     const FrameLoadRequest& request, HTMLFrameOwnerElement* ownerElement)
   1586 {
   1587     RefPtr<WebFrameImpl> webframe(adoptRef(new WebFrameImpl(m_client)));
   1588 
   1589     // Add an extra ref on behalf of the Frame/FrameLoader, which references the
   1590     // WebFrame via the FrameLoaderClient interface. See the comment at the top
   1591     // of this file for more info.
   1592     webframe->ref();
   1593 
   1594     RefPtr<Frame> childFrame = Frame::create(
   1595         m_frame->page(), ownerElement, &webframe->m_frameLoaderClient);
   1596     webframe->m_frame = childFrame.get();
   1597 
   1598     childFrame->tree()->setName(request.frameName());
   1599 
   1600     m_frame->tree()->appendChild(childFrame);
   1601 
   1602     // Frame::init() can trigger onload event in the parent frame,
   1603     // which may detach this frame and trigger a null-pointer access
   1604     // in FrameTree::removeChild. Move init() after appendChild call
   1605     // so that webframe->mFrame is in the tree before triggering
   1606     // onload event handler.
   1607     // Because the event handler may set webframe->mFrame to null,
   1608     // it is necessary to check the value after calling init() and
   1609     // return without loading URL.
   1610     // (b:791612)
   1611     childFrame->init();      // create an empty document
   1612     if (!childFrame->tree()->parent())
   1613         return 0;
   1614 
   1615     m_frame->loader()->loadURLIntoChildFrame(
   1616         request.resourceRequest().url(),
   1617         request.resourceRequest().httpReferrer(),
   1618         childFrame.get());
   1619 
   1620     // A synchronous navigation (about:blank) would have already processed
   1621     // onload, so it is possible for the frame to have already been destroyed by
   1622     // script in the page.
   1623     if (!childFrame->tree()->parent())
   1624         return 0;
   1625 
   1626     return childFrame.release();
   1627 }
   1628 
   1629 void WebFrameImpl::layout()
   1630 {
   1631     // layout this frame
   1632     FrameView* view = m_frame->view();
   1633     if (view)
   1634         view->layoutIfNeededRecursive();
   1635 }
   1636 
   1637 void WebFrameImpl::paint(WebCanvas* canvas, const WebRect& rect)
   1638 {
   1639     if (rect.isEmpty())
   1640         return;
   1641     IntRect dirtyRect(rect);
   1642 #if WEBKIT_USING_CG
   1643     GraphicsContext gc(canvas);
   1644     LocalCurrentGraphicsContext localContext(&gc);
   1645 #elif WEBKIT_USING_SKIA
   1646     PlatformContextSkia context(canvas);
   1647 
   1648     // PlatformGraphicsContext is actually a pointer to PlatformContextSkia
   1649     GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context));
   1650 #else
   1651     notImplemented();
   1652 #endif
   1653     gc.save();
   1654     if (m_frame->document() && frameView()) {
   1655         gc.clip(dirtyRect);
   1656         frameView()->paint(&gc, dirtyRect);
   1657         m_frame->page()->inspectorController()->drawNodeHighlight(gc);
   1658     } else
   1659         gc.fillRect(dirtyRect, Color::white, DeviceColorSpace);
   1660     gc.restore();
   1661 }
   1662 
   1663 void WebFrameImpl::createFrameView()
   1664 {
   1665     ASSERT(m_frame); // If m_frame doesn't exist, we probably didn't init properly.
   1666 
   1667     Page* page = m_frame->page();
   1668     ASSERT(page);
   1669     ASSERT(page->mainFrame());
   1670 
   1671     bool isMainFrame = m_frame == page->mainFrame();
   1672     if (isMainFrame && m_frame->view())
   1673         m_frame->view()->setParentVisible(false);
   1674 
   1675     m_frame->setView(0);
   1676 
   1677     WebViewImpl* webView = viewImpl();
   1678 
   1679     RefPtr<FrameView> view;
   1680     if (isMainFrame)
   1681         view = FrameView::create(m_frame, webView->size());
   1682     else
   1683         view = FrameView::create(m_frame);
   1684 
   1685     m_frame->setView(view);
   1686 
   1687     if (webView->isTransparent())
   1688         view->setTransparent(true);
   1689 
   1690     // FIXME: The Mac code has a comment about this possibly being unnecessary.
   1691     // See installInFrame in WebCoreFrameBridge.mm
   1692     if (m_frame->ownerRenderer())
   1693         m_frame->ownerRenderer()->setWidget(view.get());
   1694 
   1695     if (HTMLFrameOwnerElement* owner = m_frame->ownerElement())
   1696         view->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
   1697 
   1698     if (isMainFrame)
   1699         view->setParentVisible(true);
   1700 }
   1701 
   1702 WebFrameImpl* WebFrameImpl::fromFrame(Frame* frame)
   1703 {
   1704     if (!frame)
   1705         return 0;
   1706 
   1707     return static_cast<FrameLoaderClientImpl*>(frame->loader()->client())->webFrame();
   1708 }
   1709 
   1710 WebFrameImpl* WebFrameImpl::fromFrameOwnerElement(Element* element)
   1711 {
   1712     if (!element
   1713         || !element->isFrameOwnerElement()
   1714         || (!element->hasTagName(HTMLNames::iframeTag)
   1715             && !element->hasTagName(HTMLNames::frameTag)))
   1716         return 0;
   1717 
   1718     HTMLFrameOwnerElement* frameElement =
   1719         static_cast<HTMLFrameOwnerElement*>(element);
   1720     return fromFrame(frameElement->contentFrame());
   1721 }
   1722 
   1723 WebViewImpl* WebFrameImpl::viewImpl() const
   1724 {
   1725     if (!m_frame)
   1726         return 0;
   1727 
   1728     return WebViewImpl::fromPage(m_frame->page());
   1729 }
   1730 
   1731 WebDataSourceImpl* WebFrameImpl::dataSourceImpl() const
   1732 {
   1733     return static_cast<WebDataSourceImpl*>(dataSource());
   1734 }
   1735 
   1736 WebDataSourceImpl* WebFrameImpl::provisionalDataSourceImpl() const
   1737 {
   1738     return static_cast<WebDataSourceImpl*>(provisionalDataSource());
   1739 }
   1740 
   1741 void WebFrameImpl::setFindEndstateFocusAndSelection()
   1742 {
   1743     WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
   1744 
   1745     if (this == mainFrameImpl->activeMatchFrame() && m_activeMatch.get()) {
   1746         // If the user has set the selection since the match was found, we
   1747         // don't focus anything.
   1748         VisibleSelection selection(frame()->selection()->selection());
   1749         if (!selection.isNone())
   1750             return;
   1751 
   1752         // Try to find the first focusable node up the chain, which will, for
   1753         // example, focus links if we have found text within the link.
   1754         Node* node = m_activeMatch->firstNode();
   1755         while (node && !node->isFocusable() && node != frame()->document())
   1756             node = node->parent();
   1757 
   1758         if (node && node != frame()->document()) {
   1759             // Found a focusable parent node. Set focus to it.
   1760             frame()->document()->setFocusedNode(node);
   1761             return;
   1762         }
   1763 
   1764         // Iterate over all the nodes in the range until we find a focusable node.
   1765         // This, for example, sets focus to the first link if you search for
   1766         // text and text that is within one or more links.
   1767         node = m_activeMatch->firstNode();
   1768         while (node && node != m_activeMatch->pastLastNode()) {
   1769             if (node->isFocusable()) {
   1770                 frame()->document()->setFocusedNode(node);
   1771                 return;
   1772             }
   1773             node = node->traverseNextNode();
   1774         }
   1775 
   1776         // No node related to the active match was focusable, so set the
   1777         // active match as the selection (so that when you end the Find session,
   1778         // you'll have the last thing you found highlighted) and make sure that
   1779         // we have nothing focused (otherwise you might have text selected but
   1780         // a link focused, which is weird).
   1781         frame()->selection()->setSelection(m_activeMatch.get());
   1782         frame()->document()->setFocusedNode(0);
   1783     }
   1784 }
   1785 
   1786 void WebFrameImpl::didFail(const ResourceError& error, bool wasProvisional)
   1787 {
   1788     if (!client())
   1789         return;
   1790     WebURLError webError = error;
   1791     if (wasProvisional)
   1792         client()->didFailProvisionalLoad(this, webError);
   1793     else
   1794         client()->didFailLoad(this, webError);
   1795 }
   1796 
   1797 void WebFrameImpl::setAllowsScrolling(bool flag)
   1798 {
   1799     m_frame->view()->setCanHaveScrollbars(flag);
   1800 }
   1801 
   1802 void WebFrameImpl::registerPasswordListener(
   1803     WebInputElement inputElement,
   1804     WebPasswordAutocompleteListener* listener)
   1805 {
   1806     RefPtr<HTMLInputElement> element = inputElement.operator PassRefPtr<HTMLInputElement>();
   1807     ASSERT(m_passwordListeners.find(element) == m_passwordListeners.end());
   1808     m_passwordListeners.set(element, listener);
   1809 }
   1810 
   1811 WebPasswordAutocompleteListener* WebFrameImpl::getPasswordListener(
   1812     HTMLInputElement* inputElement)
   1813 {
   1814     return m_passwordListeners.get(RefPtr<HTMLInputElement>(inputElement));
   1815 }
   1816 
   1817 // WebFrameImpl private --------------------------------------------------------
   1818 
   1819 void WebFrameImpl::closing()
   1820 {
   1821     m_frame = 0;
   1822 }
   1823 
   1824 void WebFrameImpl::invalidateArea(AreaToInvalidate area)
   1825 {
   1826     ASSERT(frame() && frame()->view());
   1827     FrameView* view = frame()->view();
   1828 
   1829     if ((area & InvalidateAll) == InvalidateAll)
   1830         view->invalidateRect(view->frameRect());
   1831     else {
   1832         if ((area & InvalidateContentArea) == InvalidateContentArea) {
   1833             IntRect contentArea(
   1834                 view->x(), view->y(), view->visibleWidth(), view->visibleHeight());
   1835             view->invalidateRect(contentArea);
   1836         }
   1837 
   1838         if ((area & InvalidateScrollbar) == InvalidateScrollbar) {
   1839             // Invalidate the vertical scroll bar region for the view.
   1840             IntRect scrollBarVert(
   1841                 view->x() + view->visibleWidth(), view->y(),
   1842                 ScrollbarTheme::nativeTheme()->scrollbarThickness(),
   1843                 view->visibleHeight());
   1844             view->invalidateRect(scrollBarVert);
   1845         }
   1846     }
   1847 }
   1848 
   1849 void WebFrameImpl::addMarker(Range* range, bool activeMatch)
   1850 {
   1851     // Use a TextIterator to visit the potentially multiple nodes the range
   1852     // covers.
   1853     TextIterator markedText(range);
   1854     for (; !markedText.atEnd(); markedText.advance()) {
   1855         RefPtr<Range> textPiece = markedText.range();
   1856         int exception = 0;
   1857 
   1858         DocumentMarker marker = {
   1859             DocumentMarker::TextMatch,
   1860             textPiece->startOffset(exception),
   1861             textPiece->endOffset(exception),
   1862             "",
   1863             activeMatch
   1864         };
   1865 
   1866         if (marker.endOffset > marker.startOffset) {
   1867             // Find the node to add a marker to and add it.
   1868             Node* node = textPiece->startContainer(exception);
   1869             frame()->document()->addMarker(node, marker);
   1870 
   1871             // Rendered rects for markers in WebKit are not populated until each time
   1872             // the markers are painted. However, we need it to happen sooner, because
   1873             // the whole purpose of tickmarks on the scrollbar is to show where
   1874             // matches off-screen are (that haven't been painted yet).
   1875             Vector<DocumentMarker> markers = frame()->document()->markersForNode(node);
   1876             frame()->document()->setRenderedRectForMarker(
   1877                 textPiece->startContainer(exception),
   1878                 markers[markers.size() - 1],
   1879                 range->boundingBox());
   1880         }
   1881     }
   1882 }
   1883 
   1884 void WebFrameImpl::setMarkerActive(Range* range, bool active)
   1885 {
   1886     if (!range)
   1887         return;
   1888 
   1889     frame()->document()->setMarkersActive(range, active);
   1890 }
   1891 
   1892 int WebFrameImpl::ordinalOfFirstMatchForFrame(WebFrameImpl* frame) const
   1893 {
   1894     int ordinal = 0;
   1895     WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
   1896     // Iterate from the main frame up to (but not including) |frame| and
   1897     // add up the number of matches found so far.
   1898     for (WebFrameImpl* it = mainFrameImpl;
   1899          it != frame;
   1900          it = static_cast<WebFrameImpl*>(it->traverseNext(true))) {
   1901         if (it->m_lastMatchCount > 0)
   1902             ordinal += it->m_lastMatchCount;
   1903     }
   1904     return ordinal;
   1905 }
   1906 
   1907 bool WebFrameImpl::shouldScopeMatches(const String& searchText)
   1908 {
   1909     // Don't scope if we can't find a frame or if the frame is not visible.
   1910     // The user may have closed the tab/application, so abort.
   1911     if (!frame() || !hasVisibleContent())
   1912         return false;
   1913 
   1914     ASSERT(frame()->document() && frame()->view());
   1915 
   1916     // If the frame completed the scoping operation and found 0 matches the last
   1917     // time it was searched, then we don't have to search it again if the user is
   1918     // just adding to the search string or sending the same search string again.
   1919     if (m_scopingComplete && !m_lastSearchString.isEmpty() && !m_lastMatchCount) {
   1920         // Check to see if the search string prefixes match.
   1921         String previousSearchPrefix =
   1922             searchText.substring(0, m_lastSearchString.length());
   1923 
   1924         if (previousSearchPrefix == m_lastSearchString)
   1925             return false;  // Don't search this frame, it will be fruitless.
   1926     }
   1927 
   1928     return true;
   1929 }
   1930 
   1931 void WebFrameImpl::scopeStringMatchesSoon(int identifier, const WebString& searchText,
   1932                                           const WebFindOptions& options, bool reset)
   1933 {
   1934     m_deferredScopingWork.append(new DeferredScopeStringMatches(
   1935         this, identifier, searchText, options, reset));
   1936 }
   1937 
   1938 void WebFrameImpl::callScopeStringMatches(DeferredScopeStringMatches* caller,
   1939                                           int identifier, const WebString& searchText,
   1940                                           const WebFindOptions& options, bool reset)
   1941 {
   1942     m_deferredScopingWork.remove(m_deferredScopingWork.find(caller));
   1943 
   1944     scopeStringMatches(identifier, searchText, options, reset);
   1945 
   1946     // This needs to happen last since searchText is passed by reference.
   1947     delete caller;
   1948 }
   1949 
   1950 void WebFrameImpl::invalidateIfNecessary()
   1951 {
   1952     if (m_lastMatchCount > m_nextInvalidateAfter) {
   1953         // FIXME: (http://b/1088165) Optimize the drawing of the tickmarks and
   1954         // remove this. This calculation sets a milestone for when next to
   1955         // invalidate the scrollbar and the content area. We do this so that we
   1956         // don't spend too much time drawing the scrollbar over and over again.
   1957         // Basically, up until the first 500 matches there is no throttle.
   1958         // After the first 500 matches, we set set the milestone further and
   1959         // further out (750, 1125, 1688, 2K, 3K).
   1960         static const int startSlowingDownAfter = 500;
   1961         static const int slowdown = 750;
   1962         int i = (m_lastMatchCount / startSlowingDownAfter);
   1963         m_nextInvalidateAfter += i * slowdown;
   1964 
   1965         invalidateArea(InvalidateScrollbar);
   1966     }
   1967 }
   1968 
   1969 void WebFrameImpl::clearPasswordListeners()
   1970 {
   1971     deleteAllValues(m_passwordListeners);
   1972     m_passwordListeners.clear();
   1973 }
   1974 
   1975 void WebFrameImpl::loadJavaScriptURL(const KURL& url)
   1976 {
   1977     // This is copied from FrameLoader::executeIfJavaScriptURL.  Unfortunately,
   1978     // we cannot just use that method since it is private, and it also doesn't
   1979     // quite behave as we require it to for bookmarklets.  The key difference is
   1980     // that we need to suppress loading the string result from evaluating the JS
   1981     // URL if executing the JS URL resulted in a location change.  We also allow
   1982     // a JS URL to be loaded even if scripts on the page are otherwise disabled.
   1983 
   1984     if (!m_frame->document() || !m_frame->page())
   1985         return;
   1986 
   1987     String script = decodeURLEscapeSequences(url.string().substring(strlen("javascript:")));
   1988     ScriptValue result = m_frame->script()->executeScript(script, true);
   1989 
   1990     String scriptResult;
   1991     if (!result.getString(scriptResult))
   1992         return;
   1993 
   1994     SecurityOrigin* securityOrigin = m_frame->document()->securityOrigin();
   1995 
   1996     if (!m_frame->redirectScheduler()->locationChangePending()) {
   1997         m_frame->loader()->stopAllLoaders();
   1998         m_frame->loader()->begin(m_frame->loader()->url(), true, securityOrigin);
   1999         m_frame->loader()->write(scriptResult);
   2000         m_frame->loader()->end();
   2001     }
   2002 }
   2003 
   2004 } // namespace WebKit
   2005