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