Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(254)

Side by Side Diff: Source/WebKit/chromium/src/WebFrameImpl.cpp

Issue 18615009: Start moving Source/WebKit to Source/web (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Moar includes Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/WebKit/chromium/src/WebFrameImpl.h ('k') | Source/web/WebFrameImpl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "public/platform/Platform.h"
75 #include "public/platform/WebFileSystem.h"
76 #include "public/platform/WebFileSystemType.h"
77 #include "public/platform/WebFloatPoint.h"
78 #include "public/platform/WebFloatRect.h"
79 #include "public/platform/WebPoint.h"
80 #include "public/platform/WebRect.h"
81 #include "public/platform/WebSize.h"
82 #include "public/platform/WebURLError.h"
83 #include "public/platform/WebVector.h"
84 #include "wtf/CurrentTime.h"
85 #include "wtf/HashMap.h"
86 #include <algorithm>
87 #include "AssociatedURLLoader.h"
88 #include "AsyncFileSystemChromium.h"
89 #include "DOMUtilitiesPrivate.h"
90 #include "EventListenerWrapper.h"
91 #include "FindInPageCoordinates.h"
92 #include "HTMLNames.h"
93 #include "PageOverlay.h"
94 #include "V8DOMFileSystem.h"
95 #include "V8DirectoryEntry.h"
96 #include "V8FileEntry.h"
97 #include "WebConsoleMessage.h"
98 #include "WebDOMEvent.h"
99 #include "WebDOMEventListener.h"
100 #include "WebDataSourceImpl.h"
101 #include "WebDevToolsAgentPrivate.h"
102 #include "WebDocument.h"
103 #include "WebFindOptions.h"
104 #include "WebFormElement.h"
105 #include "WebFrameClient.h"
106 #include "WebHistoryItem.h"
107 #include "WebIconURL.h"
108 #include "WebInputElement.h"
109 #include "WebNode.h"
110 #include "WebPerformance.h"
111 #include "WebPlugin.h"
112 #include "WebPluginContainerImpl.h"
113 #include "WebPrintParams.h"
114 #include "WebRange.h"
115 #include "WebScriptSource.h"
116 #include "WebSecurityOrigin.h"
117 #include "WebSerializedScriptValue.h"
118 #include "WebViewImpl.h"
119 #include "bindings/v8/DOMWrapperWorld.h"
120 #include "bindings/v8/ScriptController.h"
121 #include "bindings/v8/ScriptSourceCode.h"
122 #include "bindings/v8/ScriptValue.h"
123 #include "bindings/v8/V8GCController.h"
124 #include "core/dom/Document.h"
125 #include "core/dom/DocumentMarker.h"
126 #include "core/dom/DocumentMarkerController.h"
127 #include "core/dom/IconURL.h"
128 #include "core/dom/MessagePort.h"
129 #include "core/dom/Node.h"
130 #include "core/dom/NodeTraversal.h"
131 #include "core/dom/UserGestureIndicator.h"
132 #include "core/dom/default/chromium/PlatformMessagePortChannelChromium.h"
133 #include "core/dom/shadow/ShadowRoot.h"
134 #include "core/editing/Editor.h"
135 #include "core/editing/FrameSelection.h"
136 #include "core/editing/SpellChecker.h"
137 #include "core/editing/TextAffinity.h"
138 #include "core/editing/TextIterator.h"
139 #include "core/editing/htmlediting.h"
140 #include "core/editing/markup.h"
141 #include "core/history/BackForwardController.h"
142 #include "core/history/HistoryItem.h"
143 #include "core/html/HTMLCollection.h"
144 #include "core/html/HTMLFormElement.h"
145 #include "core/html/HTMLFrameOwnerElement.h"
146 #include "core/html/HTMLHeadElement.h"
147 #include "core/html/HTMLInputElement.h"
148 #include "core/html/HTMLLinkElement.h"
149 #include "core/html/PluginDocument.h"
150 #include "core/inspector/InspectorController.h"
151 #include "core/inspector/ScriptCallStack.h"
152 #include "core/loader/DocumentLoader.h"
153 #include "core/loader/FormState.h"
154 #include "core/loader/FrameLoadRequest.h"
155 #include "core/loader/FrameLoader.h"
156 #include "core/loader/IconController.h"
157 #include "core/loader/SubstituteData.h"
158 #include "core/page/Chrome.h"
159 #include "core/page/Console.h"
160 #include "core/page/DOMWindow.h"
161 #include "core/page/EventHandler.h"
162 #include "core/page/FocusController.h"
163 #include "core/page/FrameTree.h"
164 #include "core/page/FrameView.h"
165 #include "core/page/Page.h"
166 #include "core/page/Performance.h"
167 #include "core/page/PrintContext.h"
168 #include "core/page/Settings.h"
169 #include "core/platform/AsyncFileSystem.h"
170 #include "core/platform/ScrollTypes.h"
171 #include "core/platform/ScrollbarTheme.h"
172 #include "core/platform/chromium/ClipboardUtilitiesChromium.h"
173 #include "core/platform/chromium/TraceEvent.h"
174 #include "core/platform/graphics/FontCache.h"
175 #include "core/platform/graphics/GraphicsContext.h"
176 #include "core/platform/graphics/GraphicsLayerClient.h"
177 #include "core/platform/graphics/skia/SkiaUtils.h"
178 #include "core/platform/network/ResourceHandle.h"
179 #include "core/platform/network/ResourceRequest.h"
180 #include "core/rendering/HitTestResult.h"
181 #include "core/rendering/RenderBox.h"
182 #include "core/rendering/RenderFrame.h"
183 #include "core/rendering/RenderLayer.h"
184 #include "core/rendering/RenderObject.h"
185 #include "core/rendering/RenderTreeAsText.h"
186 #include "core/rendering/RenderView.h"
187 #include "core/rendering/style/StyleInheritedData.h"
188 #include "core/xml/XPathResult.h"
189 #include "modules/filesystem/DOMFileSystem.h"
190 #include "modules/filesystem/DirectoryEntry.h"
191 #include "modules/filesystem/FileEntry.h"
192 #include "modules/filesystem/FileSystemType.h"
193 #include "weborigin/KURL.h"
194 #include "weborigin/SchemeRegistry.h"
195 #include "weborigin/SecurityPolicy.h"
196
197 using namespace WebCore;
198
199 namespace WebKit {
200
201 static int frameCount = 0;
202
203 // Key for a StatsCounter tracking how many WebFrames are active.
204 static const char* const webFrameActiveCount = "WebFrameActiveCount";
205
206 // Backend for contentAsPlainText, this is a recursive function that gets
207 // the text for the current frame and all of its subframes. It will append
208 // the text of each frame in turn to the |output| up to |maxChars| length.
209 //
210 // The |frame| must be non-null.
211 //
212 // FIXME: We should use StringBuilder rather than Vector<UChar>.
213 static void frameContentAsPlainText(size_t maxChars, Frame* frame, Vector<UChar> * output)
214 {
215 Document* document = frame->document();
216 if (!document)
217 return;
218
219 if (!frame->view())
220 return;
221
222 // TextIterator iterates over the visual representation of the DOM. As such,
223 // it requires you to do a layout before using it (otherwise it'll crash).
224 if (frame->view()->needsLayout())
225 frame->view()->layout();
226
227 // Select the document body.
228 RefPtr<Range> range(document->createRange());
229 ExceptionCode exception = 0;
230 range->selectNodeContents(document->body(), exception);
231
232 if (!exception) {
233 // The text iterator will walk nodes giving us text. This is similar to
234 // the plainText() function in core/editing/TextIterator.h, but we imple ment the maximum
235 // size and also copy the results directly into a wstring, avoiding the
236 // string conversion.
237 for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
238 const UChar* chars = it.characters();
239 if (!chars) {
240 if (it.length()) {
241 // It appears from crash reports that an iterator can get in to a state
242 // where the character count is nonempty but the character p ointer is
243 // null. advance()ing it will then just add that many to the null
244 // pointer which won't be caught in a null check but will cr ash.
245 //
246 // A null pointer and 0 length is common for some nodes.
247 //
248 // IF YOU CATCH THIS IN A DEBUGGER please let brettw know. W e don't
249 // currently understand the conditions for this to occur. Id eally, the
250 // iterators would never get into the condition so we should fix them
251 // if we can.
252 ASSERT_NOT_REACHED();
253 break;
254 }
255
256 // Just got a null node, we can forge ahead!
257 continue;
258 }
259 size_t toAppend =
260 std::min(static_cast<size_t>(it.length()), maxChars - output->si ze());
261 output->append(chars, toAppend);
262 if (output->size() >= maxChars)
263 return; // Filled up the buffer.
264 }
265 }
266
267 // The separator between frames when the frames are converted to plain text.
268 const UChar frameSeparator[] = { '\n', '\n' };
269 const size_t frameSeparatorLen = 2;
270
271 // Recursively walk the children.
272 FrameTree* frameTree = frame->tree();
273 for (Frame* curChild = frameTree->firstChild(); curChild; curChild = curChil d->tree()->nextSibling()) {
274 // Ignore the text of non-visible frames.
275 RenderView* contentRenderer = curChild->contentRenderer();
276 RenderPart* ownerRenderer = curChild->ownerRenderer();
277 if (!contentRenderer || !contentRenderer->width() || !contentRenderer->h eight()
278 || (contentRenderer->x() + contentRenderer->width() <= 0) || (conten tRenderer->y() + contentRenderer->height() <= 0)
279 || (ownerRenderer && ownerRenderer->style() && ownerRenderer->style( )->visibility() != VISIBLE)) {
280 continue;
281 }
282
283 // Make sure the frame separator won't fill up the buffer, and give up i f
284 // it will. The danger is if the separator will make the buffer longer t han
285 // maxChars. This will cause the computation above:
286 // maxChars - output->size()
287 // to be a negative number which will crash when the subframe is added.
288 if (output->size() >= maxChars - frameSeparatorLen)
289 return;
290
291 output->append(frameSeparator, frameSeparatorLen);
292 frameContentAsPlainText(maxChars, curChild, output);
293 if (output->size() >= maxChars)
294 return; // Filled up the buffer.
295 }
296 }
297
298 static long long generateFrameIdentifier()
299 {
300 static long long next = 0;
301 return ++next;
302 }
303
304 WebPluginContainerImpl* WebFrameImpl::pluginContainerFromFrame(Frame* frame)
305 {
306 if (!frame)
307 return 0;
308 if (!frame->document() || !frame->document()->isPluginDocument())
309 return 0;
310 PluginDocument* pluginDocument = static_cast<PluginDocument*>(frame->documen t());
311 return static_cast<WebPluginContainerImpl *>(pluginDocument->pluginWidget()) ;
312 }
313
314 WebPluginContainerImpl* WebFrameImpl::pluginContainerFromNode(WebCore::Frame* fr ame, const WebNode& node)
315 {
316 WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame);
317 if (pluginContainer)
318 return pluginContainer;
319 return static_cast<WebPluginContainerImpl*>(node.pluginContainer());
320 }
321
322 // Simple class to override some of PrintContext behavior. Some of the methods
323 // made virtual so that they can be overridden by ChromePluginPrintContext.
324 class ChromePrintContext : public PrintContext {
325 WTF_MAKE_NONCOPYABLE(ChromePrintContext);
326 public:
327 ChromePrintContext(Frame* frame)
328 : PrintContext(frame)
329 , m_printedPageWidth(0)
330 {
331 }
332
333 virtual ~ChromePrintContext() { }
334
335 virtual void begin(float width, float height)
336 {
337 ASSERT(!m_printedPageWidth);
338 m_printedPageWidth = width;
339 PrintContext::begin(m_printedPageWidth, height);
340 }
341
342 virtual void end()
343 {
344 PrintContext::end();
345 }
346
347 virtual float getPageShrink(int pageNumber) const
348 {
349 IntRect pageRect = m_pageRects[pageNumber];
350 return m_printedPageWidth / pageRect.width();
351 }
352
353 // Spools the printed page, a subrect of frame(). Skip the scale step.
354 // NativeTheme doesn't play well with scaling. Scaling is done browser side
355 // instead. Returns the scale to be applied.
356 // On Linux, we don't have the problem with NativeTheme, hence we let WebKit
357 // do the scaling and ignore the return value.
358 virtual float spoolPage(GraphicsContext& context, int pageNumber)
359 {
360 IntRect pageRect = m_pageRects[pageNumber];
361 float scale = m_printedPageWidth / pageRect.width();
362
363 context.save();
364 #if OS(UNIX) && !OS(DARWIN)
365 context.scale(WebCore::FloatSize(scale, scale));
366 #endif
367 context.translate(static_cast<float>(-pageRect.x()), static_cast<float>( -pageRect.y()));
368 context.clip(pageRect);
369 frame()->view()->paintContents(&context, pageRect);
370 if (context.supportsURLFragments())
371 outputLinkedDestinations(context, frame()->document(), pageRect);
372 context.restore();
373 return scale;
374 }
375
376 void spoolAllPagesWithBoundaries(GraphicsContext& graphicsContext, const Flo atSize& pageSizeInPixels)
377 {
378 if (!frame()->document() || !frame()->view() || !frame()->document()->re nderer())
379 return;
380
381 frame()->document()->updateLayout();
382
383 float pageHeight;
384 computePageRects(FloatRect(FloatPoint(0, 0), pageSizeInPixels), 0, 0, 1, pageHeight);
385
386 const float pageWidth = pageSizeInPixels.width();
387 size_t numPages = pageRects().size();
388 int totalHeight = numPages * (pageSizeInPixels.height() + 1) - 1;
389
390 // Fill the whole background by white.
391 graphicsContext.setFillColor(Color::white);
392 graphicsContext.fillRect(FloatRect(0, 0, pageWidth, totalHeight));
393
394 graphicsContext.save();
395
396 int currentHeight = 0;
397 for (size_t pageIndex = 0; pageIndex < numPages; pageIndex++) {
398 // Draw a line for a page boundary if this isn't the first page.
399 if (pageIndex > 0) {
400 graphicsContext.save();
401 graphicsContext.setStrokeColor(Color(0, 0, 255));
402 graphicsContext.setFillColor(Color(0, 0, 255));
403 graphicsContext.drawLine(IntPoint(0, currentHeight), IntPoint(pa geWidth, currentHeight));
404 graphicsContext.restore();
405 }
406
407 graphicsContext.save();
408
409 graphicsContext.translate(0, currentHeight);
410 #if !OS(UNIX) || OS(DARWIN)
411 // Account for the disabling of scaling in spoolPage. In the context
412 // of spoolAllPagesWithBoundaries the scale HAS NOT been pre-applied .
413 float scale = getPageShrink(pageIndex);
414 graphicsContext.scale(WebCore::FloatSize(scale, scale));
415 #endif
416 spoolPage(graphicsContext, pageIndex);
417 graphicsContext.restore();
418
419 currentHeight += pageSizeInPixels.height() + 1;
420 }
421
422 graphicsContext.restore();
423 }
424
425 virtual void computePageRects(const FloatRect& printRect, float headerHeight , float footerHeight, float userScaleFactor, float& outPageHeight)
426 {
427 PrintContext::computePageRects(printRect, headerHeight, footerHeight, us erScaleFactor, outPageHeight);
428 }
429
430 virtual int pageCount() const
431 {
432 return PrintContext::pageCount();
433 }
434
435 virtual bool shouldUseBrowserOverlays() const
436 {
437 return true;
438 }
439
440 private:
441 // Set when printing.
442 float m_printedPageWidth;
443 };
444
445 // Simple class to override some of PrintContext behavior. This is used when
446 // the frame hosts a plugin that supports custom printing. In this case, we
447 // want to delegate all printing related calls to the plugin.
448 class ChromePluginPrintContext : public ChromePrintContext {
449 public:
450 ChromePluginPrintContext(Frame* frame, WebPluginContainerImpl* plugin, const WebPrintParams& printParams)
451 : ChromePrintContext(frame), m_plugin(plugin), m_pageCount(0), m_printPa rams(printParams)
452 {
453 }
454
455 virtual ~ChromePluginPrintContext() { }
456
457 virtual void begin(float width, float height)
458 {
459 }
460
461 virtual void end()
462 {
463 m_plugin->printEnd();
464 }
465
466 virtual float getPageShrink(int pageNumber) const
467 {
468 // We don't shrink the page (maybe we should ask the widget ??)
469 return 1.0;
470 }
471
472 virtual void computePageRects(const FloatRect& printRect, float headerHeight , float footerHeight, float userScaleFactor, float& outPageHeight)
473 {
474 m_printParams.printContentArea = IntRect(printRect);
475 m_pageCount = m_plugin->printBegin(m_printParams);
476 }
477
478 virtual int pageCount() const
479 {
480 return m_pageCount;
481 }
482
483 // Spools the printed page, a subrect of frame(). Skip the scale step.
484 // NativeTheme doesn't play well with scaling. Scaling is done browser side
485 // instead. Returns the scale to be applied.
486 virtual float spoolPage(GraphicsContext& context, int pageNumber)
487 {
488 m_plugin->printPage(pageNumber, &context);
489 return 1.0;
490 }
491
492 virtual bool shouldUseBrowserOverlays() const
493 {
494 return false;
495 }
496
497 private:
498 // Set when printing.
499 WebPluginContainerImpl* m_plugin;
500 int m_pageCount;
501 WebPrintParams m_printParams;
502
503 };
504
505 static WebDataSource* DataSourceForDocLoader(DocumentLoader* loader)
506 {
507 return loader ? WebDataSourceImpl::fromDocumentLoader(loader) : 0;
508 }
509
510 WebFrameImpl::FindMatch::FindMatch(PassRefPtr<Range> range, int ordinal)
511 : m_range(range)
512 , m_ordinal(ordinal)
513 {
514 }
515
516 class WebFrameImpl::DeferredScopeStringMatches {
517 public:
518 DeferredScopeStringMatches(WebFrameImpl* webFrame, int identifier, const Web String& searchText, const WebFindOptions& options, bool reset)
519 : m_timer(this, &DeferredScopeStringMatches::doTimeout)
520 , m_webFrame(webFrame)
521 , m_identifier(identifier)
522 , m_searchText(searchText)
523 , m_options(options)
524 , m_reset(reset)
525 {
526 m_timer.startOneShot(0.0);
527 }
528
529 private:
530 void doTimeout(Timer<DeferredScopeStringMatches>*)
531 {
532 m_webFrame->callScopeStringMatches(this, m_identifier, m_searchText, m_o ptions, m_reset);
533 }
534
535 Timer<DeferredScopeStringMatches> m_timer;
536 RefPtr<WebFrameImpl> m_webFrame;
537 int m_identifier;
538 WebString m_searchText;
539 WebFindOptions m_options;
540 bool m_reset;
541 };
542
543 // WebFrame -------------------------------------------------------------------
544
545 int WebFrame::instanceCount()
546 {
547 return frameCount;
548 }
549
550 WebFrame* WebFrame::frameForCurrentContext()
551 {
552 v8::Handle<v8::Context> context = v8::Context::GetCurrent();
553 if (context.IsEmpty())
554 return 0;
555 return frameForContext(context);
556 }
557
558 WebFrame* WebFrame::frameForContext(v8::Handle<v8::Context> context)
559 {
560 return WebFrameImpl::fromFrame(toFrameIfNotDetached(context));
561 }
562
563 WebFrame* WebFrame::fromFrameOwnerElement(const WebElement& element)
564 {
565 return WebFrameImpl::fromFrameOwnerElement(PassRefPtr<Element>(element).get( ));
566 }
567
568 WebString WebFrameImpl::uniqueName() const
569 {
570 return frame()->tree()->uniqueName();
571 }
572
573 WebString WebFrameImpl::assignedName() const
574 {
575 return frame()->tree()->name();
576 }
577
578 void WebFrameImpl::setName(const WebString& name)
579 {
580 frame()->tree()->setName(name);
581 }
582
583 long long WebFrameImpl::identifier() const
584 {
585 return m_identifier;
586 }
587
588 WebVector<WebIconURL> WebFrameImpl::iconURLs(int iconTypesMask) const
589 {
590 // The URL to the icon may be in the header. As such, only
591 // ask the loader for the icon if it's finished loading.
592 if (frame()->loader()->state() == FrameStateComplete)
593 return frame()->loader()->icon()->urlsForTypes(iconTypesMask);
594 return WebVector<WebIconURL>();
595 }
596
597 WebSize WebFrameImpl::scrollOffset() const
598 {
599 FrameView* view = frameView();
600 if (!view)
601 return WebSize();
602 return view->scrollOffset();
603 }
604
605 WebSize WebFrameImpl::minimumScrollOffset() const
606 {
607 FrameView* view = frameView();
608 if (!view)
609 return WebSize();
610 return toIntSize(view->minimumScrollPosition());
611 }
612
613 WebSize WebFrameImpl::maximumScrollOffset() const
614 {
615 FrameView* view = frameView();
616 if (!view)
617 return WebSize();
618 return toIntSize(view->maximumScrollPosition());
619 }
620
621 void WebFrameImpl::setScrollOffset(const WebSize& offset)
622 {
623 if (FrameView* view = frameView())
624 view->setScrollOffset(IntPoint(offset.width, offset.height));
625 }
626
627 WebSize WebFrameImpl::contentsSize() const
628 {
629 return frame()->view()->contentsSize();
630 }
631
632 bool WebFrameImpl::hasVisibleContent() const
633 {
634 return frame()->view()->visibleWidth() > 0 && frame()->view()->visibleHeight () > 0;
635 }
636
637 WebRect WebFrameImpl::visibleContentRect() const
638 {
639 return frame()->view()->visibleContentRect();
640 }
641
642 bool WebFrameImpl::hasHorizontalScrollbar() const
643 {
644 return frame() && frame()->view() && frame()->view()->horizontalScrollbar();
645 }
646
647 bool WebFrameImpl::hasVerticalScrollbar() const
648 {
649 return frame() && frame()->view() && frame()->view()->verticalScrollbar();
650 }
651
652 WebView* WebFrameImpl::view() const
653 {
654 return viewImpl();
655 }
656
657 WebFrame* WebFrameImpl::opener() const
658 {
659 if (!frame())
660 return 0;
661 return fromFrame(frame()->loader()->opener());
662 }
663
664 void WebFrameImpl::setOpener(const WebFrame* webFrame)
665 {
666 frame()->loader()->setOpener(webFrame ? static_cast<const WebFrameImpl*>(web Frame)->frame() : 0);
667 }
668
669 WebFrame* WebFrameImpl::parent() const
670 {
671 if (!frame())
672 return 0;
673 return fromFrame(frame()->tree()->parent());
674 }
675
676 WebFrame* WebFrameImpl::top() const
677 {
678 if (!frame())
679 return 0;
680 return fromFrame(frame()->tree()->top());
681 }
682
683 WebFrame* WebFrameImpl::firstChild() const
684 {
685 if (!frame())
686 return 0;
687 return fromFrame(frame()->tree()->firstChild());
688 }
689
690 WebFrame* WebFrameImpl::lastChild() const
691 {
692 if (!frame())
693 return 0;
694 return fromFrame(frame()->tree()->lastChild());
695 }
696
697 WebFrame* WebFrameImpl::nextSibling() const
698 {
699 if (!frame())
700 return 0;
701 return fromFrame(frame()->tree()->nextSibling());
702 }
703
704 WebFrame* WebFrameImpl::previousSibling() const
705 {
706 if (!frame())
707 return 0;
708 return fromFrame(frame()->tree()->previousSibling());
709 }
710
711 WebFrame* WebFrameImpl::traverseNext(bool wrap) const
712 {
713 if (!frame())
714 return 0;
715 return fromFrame(frame()->tree()->traverseNextWithWrap(wrap));
716 }
717
718 WebFrame* WebFrameImpl::traversePrevious(bool wrap) const
719 {
720 if (!frame())
721 return 0;
722 return fromFrame(frame()->tree()->traversePreviousWithWrap(wrap));
723 }
724
725 WebFrame* WebFrameImpl::findChildByName(const WebString& name) const
726 {
727 if (!frame())
728 return 0;
729 return fromFrame(frame()->tree()->child(name));
730 }
731
732 WebFrame* WebFrameImpl::findChildByExpression(const WebString& xpath) const
733 {
734 if (xpath.isEmpty())
735 return 0;
736
737 Document* document = frame()->document();
738
739 ExceptionCode ec = 0;
740 RefPtr<XPathResult> xpathResult = document->evaluate(xpath, document, 0, XPa thResult::ORDERED_NODE_ITERATOR_TYPE, 0, ec);
741 if (!xpathResult)
742 return 0;
743
744 Node* node = xpathResult->iterateNext(ec);
745 if (!node || !node->isFrameOwnerElement())
746 return 0;
747 HTMLFrameOwnerElement* frameElement = toFrameOwnerElement(node);
748 return fromFrame(frameElement->contentFrame());
749 }
750
751 WebDocument WebFrameImpl::document() const
752 {
753 if (!frame() || !frame()->document())
754 return WebDocument();
755 return WebDocument(frame()->document());
756 }
757
758 WebPerformance WebFrameImpl::performance() const
759 {
760 if (!frame())
761 return WebPerformance();
762 return WebPerformance(frame()->document()->domWindow()->performance());
763 }
764
765 NPObject* WebFrameImpl::windowObject() const
766 {
767 if (!frame())
768 return 0;
769 return frame()->script()->windowScriptNPObject();
770 }
771
772 void WebFrameImpl::bindToWindowObject(const WebString& name, NPObject* object)
773 {
774 if (!frame() || !frame()->script()->canExecuteScripts(NotAboutToExecuteScrip t))
775 return;
776 frame()->script()->bindToWindowObject(frame(), String(name), object);
777 }
778
779 void WebFrameImpl::executeScript(const WebScriptSource& source)
780 {
781 ASSERT(frame());
782 TextPosition position(OrdinalNumber::fromOneBasedInt(source.startLine), Ordi nalNumber::first());
783 frame()->script()->executeScript(ScriptSourceCode(source.code, source.url, p osition));
784 }
785
786 void WebFrameImpl::executeScriptInIsolatedWorld(int worldID, const WebScriptSour ce* sourcesIn, unsigned numSources, int extensionGroup)
787 {
788 ASSERT(frame());
789 ASSERT(worldID > 0);
790
791 Vector<ScriptSourceCode> sources;
792 for (unsigned i = 0; i < numSources; ++i) {
793 TextPosition position(OrdinalNumber::fromOneBasedInt(sourcesIn[i].startL ine), OrdinalNumber::first());
794 sources.append(ScriptSourceCode(sourcesIn[i].code, sourcesIn[i].url, pos ition));
795 }
796
797 frame()->script()->executeScriptInIsolatedWorld(worldID, sources, extensionG roup, 0);
798 }
799
800 void WebFrameImpl::setIsolatedWorldSecurityOrigin(int worldID, const WebSecurity Origin& securityOrigin)
801 {
802 ASSERT(frame());
803 DOMWrapperWorld::setIsolatedWorldSecurityOrigin(worldID, securityOrigin.get( ));
804 }
805
806 void WebFrameImpl::setIsolatedWorldContentSecurityPolicy(int worldID, const WebS tring& policy)
807 {
808 ASSERT(frame());
809 DOMWrapperWorld::setIsolatedWorldContentSecurityPolicy(worldID, policy);
810 }
811
812 void WebFrameImpl::addMessageToConsole(const WebConsoleMessage& message)
813 {
814 ASSERT(frame());
815
816 MessageLevel webCoreMessageLevel;
817 switch (message.level) {
818 case WebConsoleMessage::LevelDebug:
819 webCoreMessageLevel = DebugMessageLevel;
820 break;
821 case WebConsoleMessage::LevelLog:
822 webCoreMessageLevel = LogMessageLevel;
823 break;
824 case WebConsoleMessage::LevelWarning:
825 webCoreMessageLevel = WarningMessageLevel;
826 break;
827 case WebConsoleMessage::LevelError:
828 webCoreMessageLevel = ErrorMessageLevel;
829 break;
830 default:
831 ASSERT_NOT_REACHED();
832 return;
833 }
834
835 frame()->document()->addConsoleMessage(OtherMessageSource, webCoreMessageLev el, message.text);
836 }
837
838 void WebFrameImpl::collectGarbage()
839 {
840 if (!frame())
841 return;
842 if (!frame()->settings()->isScriptEnabled())
843 return;
844 V8GCController::collectGarbage(v8::Isolate::GetCurrent());
845 }
846
847 bool WebFrameImpl::checkIfRunInsecureContent(const WebURL& url) const
848 {
849 ASSERT(frame());
850 return frame()->loader()->mixedContentChecker()->canRunInsecureContent(frame ()->document()->securityOrigin(), url);
851 }
852
853 v8::Handle<v8::Value> WebFrameImpl::executeScriptAndReturnValue(const WebScriptS ource& source)
854 {
855 ASSERT(frame());
856
857 // FIXME: This fake user gesture is required to make a bunch of pyauto
858 // tests pass. If this isn't needed in non-test situations, we should
859 // consider removing this code and changing the tests.
860 // http://code.google.com/p/chromium/issues/detail?id=86397
861 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture);
862
863 TextPosition position(OrdinalNumber::fromOneBasedInt(source.startLine), Ordi nalNumber::first());
864 return frame()->script()->executeScript(ScriptSourceCode(source.code, source .url, position)).v8Value();
865 }
866
867 void WebFrameImpl::executeScriptInIsolatedWorld(int worldID, const WebScriptSour ce* sourcesIn, unsigned numSources, int extensionGroup, WebVector<v8::Local<v8:: Value> >* results)
868 {
869 ASSERT(frame());
870 ASSERT(worldID > 0);
871
872 Vector<ScriptSourceCode> sources;
873
874 for (unsigned i = 0; i < numSources; ++i) {
875 TextPosition position(OrdinalNumber::fromOneBasedInt(sourcesIn[i].startL ine), OrdinalNumber::first());
876 sources.append(ScriptSourceCode(sourcesIn[i].code, sourcesIn[i].url, pos ition));
877 }
878
879 if (results) {
880 Vector<ScriptValue> scriptResults;
881 frame()->script()->executeScriptInIsolatedWorld(worldID, sources, extens ionGroup, &scriptResults);
882 WebVector<v8::Local<v8::Value> > v8Results(scriptResults.size());
883 for (unsigned i = 0; i < scriptResults.size(); i++)
884 v8Results[i] = v8::Local<v8::Value>::New(scriptResults[i].v8Value()) ;
885 results->swap(v8Results);
886 } else
887 frame()->script()->executeScriptInIsolatedWorld(worldID, sources, extens ionGroup, 0);
888 }
889
890 v8::Handle<v8::Value> WebFrameImpl::callFunctionEvenIfScriptDisabled(v8::Handle< v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8 ::Value> argv[])
891 {
892 ASSERT(frame());
893 return frame()->script()->callFunctionEvenIfScriptDisabled(function, receive r, argc, argv).v8Value();
894 }
895
896 v8::Local<v8::Context> WebFrameImpl::mainWorldScriptContext() const
897 {
898 if (!frame())
899 return v8::Local<v8::Context>();
900 return ScriptController::mainWorldContext(frame());
901 }
902
903 v8::Handle<v8::Value> WebFrameImpl::createFileSystem(WebFileSystemType type, con st WebString& name, const WebString& path)
904 {
905 ASSERT(frame());
906 return toV8(DOMFileSystem::create(frame()->document(), name, static_cast<Web Core::FileSystemType>(type), KURL(ParsedURLString, path.utf8().data()), AsyncFil eSystemChromium::create()), v8::Handle<v8::Object>(), frame()->script()->current WorldContext()->GetIsolate());
907 }
908
909 v8::Handle<v8::Value> WebFrameImpl::createSerializableFileSystem(WebFileSystemTy pe type, const WebString& name, const WebString& path)
910 {
911 ASSERT(frame());
912 RefPtr<DOMFileSystem> fileSystem = DOMFileSystem::create(frame()->document() , name, static_cast<WebCore::FileSystemType>(type), KURL(ParsedURLString, path.u tf8().data()), AsyncFileSystemChromium::create());
913 fileSystem->makeClonable();
914 return toV8(fileSystem.release(), v8::Handle<v8::Object>(), frame()->script( )->currentWorldContext()->GetIsolate());
915 }
916
917 v8::Handle<v8::Value> WebFrameImpl::createFileEntry(WebFileSystemType type, cons t WebString& fileSystemName, const WebString& fileSystemPath, const WebString& f ilePath, bool isDirectory)
918 {
919 ASSERT(frame());
920
921 RefPtr<DOMFileSystemBase> fileSystem = DOMFileSystem::create(frame()->docume nt(), fileSystemName, static_cast<WebCore::FileSystemType>(type), KURL(ParsedURL String, fileSystemPath.utf8().data()), AsyncFileSystemChromium::create());
922 if (isDirectory)
923 return toV8(DirectoryEntry::create(fileSystem, filePath), v8::Handle<v8: :Object>(), frame()->script()->currentWorldContext()->GetIsolate());
924 return toV8(FileEntry::create(fileSystem, filePath), v8::Handle<v8::Object>( ), frame()->script()->currentWorldContext()->GetIsolate());
925 }
926
927 void WebFrameImpl::reload(bool ignoreCache)
928 {
929 ASSERT(frame());
930 frame()->loader()->reload(ignoreCache);
931 }
932
933 void WebFrameImpl::reloadWithOverrideURL(const WebURL& overrideUrl, bool ignoreC ache)
934 {
935 ASSERT(frame());
936 frame()->loader()->reload(ignoreCache, overrideUrl);
937 }
938
939 void WebFrameImpl::loadRequest(const WebURLRequest& request)
940 {
941 ASSERT(frame());
942 ASSERT(!request.isNull());
943 const ResourceRequest& resourceRequest = request.toResourceRequest();
944
945 if (resourceRequest.url().protocolIs("javascript")) {
946 loadJavaScriptURL(resourceRequest.url());
947 return;
948 }
949
950 frame()->loader()->load(FrameLoadRequest(frame(), resourceRequest));
951 }
952
953 void WebFrameImpl::loadHistoryItem(const WebHistoryItem& item)
954 {
955 ASSERT(frame());
956 RefPtr<HistoryItem> historyItem = PassRefPtr<HistoryItem>(item);
957 ASSERT(historyItem);
958
959 frame()->loader()->prepareForHistoryNavigation();
960 RefPtr<HistoryItem> currentItem = frame()->loader()->history()->currentItem( );
961 m_inSameDocumentHistoryLoad = currentItem && currentItem->shouldDoSameDocume ntNavigationTo(historyItem.get());
962 frame()->page()->goToItem(historyItem.get());
963 m_inSameDocumentHistoryLoad = false;
964 }
965
966 void WebFrameImpl::loadData(const WebData& data, const WebString& mimeType, cons t WebString& textEncoding, const WebURL& baseURL, const WebURL& unreachableURL, bool replace)
967 {
968 ASSERT(frame());
969
970 // If we are loading substitute data to replace an existing load, then
971 // inherit all of the properties of that original request. This way,
972 // reload will re-attempt the original request. It is essential that
973 // we only do this when there is an unreachableURL since a non-empty
974 // unreachableURL informs FrameLoader::reload to load unreachableURL
975 // instead of the currently loaded URL.
976 ResourceRequest request;
977 if (replace && !unreachableURL.isEmpty())
978 request = frame()->loader()->originalRequest();
979 request.setURL(baseURL);
980
981 FrameLoadRequest frameRequest(frame(), request, SubstituteData(data, mimeTyp e, textEncoding, unreachableURL));
982 ASSERT(frameRequest.substituteData().isValid());
983 frame()->loader()->load(frameRequest);
984 if (replace) {
985 // Do this to force WebKit to treat the load as replacing the currently
986 // loaded page.
987 // FIXME: Can we use lock history instead?
988 frame()->loader()->setReplacing();
989 }
990 }
991
992 void WebFrameImpl::loadHTMLString(const WebData& data, const WebURL& baseURL, co nst WebURL& unreachableURL, bool replace)
993 {
994 ASSERT(frame());
995 loadData(data, WebString::fromUTF8("text/html"), WebString::fromUTF8("UTF-8" ), baseURL, unreachableURL, replace);
996 }
997
998 bool WebFrameImpl::isLoading() const
999 {
1000 if (!frame())
1001 return false;
1002 return frame()->loader()->isLoading();
1003 }
1004
1005 void WebFrameImpl::stopLoading()
1006 {
1007 if (!frame())
1008 return;
1009 // FIXME: Figure out what we should really do here. It seems like a bug
1010 // that FrameLoader::stopLoading doesn't call stopAllLoaders.
1011 frame()->loader()->stopAllLoaders();
1012 frame()->loader()->stopLoading(UnloadEventPolicyNone);
1013 }
1014
1015 WebDataSource* WebFrameImpl::provisionalDataSource() const
1016 {
1017 ASSERT(frame());
1018
1019 // We regard the policy document loader as still provisional.
1020 DocumentLoader* documentLoader = frame()->loader()->provisionalDocumentLoade r();
1021 if (!documentLoader)
1022 documentLoader = frame()->loader()->policyDocumentLoader();
1023
1024 return DataSourceForDocLoader(documentLoader);
1025 }
1026
1027 WebDataSource* WebFrameImpl::dataSource() const
1028 {
1029 ASSERT(frame());
1030 return DataSourceForDocLoader(frame()->loader()->documentLoader());
1031 }
1032
1033 WebHistoryItem WebFrameImpl::previousHistoryItem() const
1034 {
1035 ASSERT(frame());
1036 // We use the previous item here because documentState (filled-out forms)
1037 // only get saved to history when it becomes the previous item. The caller
1038 // is expected to query the history item after a navigation occurs, after
1039 // the desired history item has become the previous entry.
1040 return WebHistoryItem(frame()->loader()->history()->previousItem());
1041 }
1042
1043 WebHistoryItem WebFrameImpl::currentHistoryItem() const
1044 {
1045 ASSERT(frame());
1046
1047 // We're shutting down.
1048 if (!frame()->loader()->activeDocumentLoader())
1049 return WebHistoryItem();
1050
1051 // If we are still loading, then we don't want to clobber the current
1052 // history item as this could cause us to lose the scroll position and
1053 // document state. However, it is OK for new navigations.
1054 // FIXME: Can we make this a plain old getter, instead of worrying about
1055 // clobbering here?
1056 if (!m_inSameDocumentHistoryLoad && (frame()->loader()->loadType() == FrameL oadTypeStandard
1057 || !frame()->loader()->activeDocumentLoader()->isLoadingInAPISense()))
1058 frame()->loader()->history()->saveDocumentAndScrollState();
1059
1060 return WebHistoryItem(frame()->page()->backForward()->currentItem());
1061 }
1062
1063 void WebFrameImpl::enableViewSourceMode(bool enable)
1064 {
1065 if (frame())
1066 frame()->setInViewSourceMode(enable);
1067 }
1068
1069 bool WebFrameImpl::isViewSourceModeEnabled() const
1070 {
1071 if (!frame())
1072 return false;
1073 return frame()->inViewSourceMode();
1074 }
1075
1076 void WebFrameImpl::setReferrerForRequest(WebURLRequest& request, const WebURL& r eferrerURL)
1077 {
1078 String referrer = referrerURL.isEmpty() ? frame()->loader()->outgoingReferre r() : String(referrerURL.spec().utf16());
1079 referrer = SecurityPolicy::generateReferrerHeader(frame()->document()->refer rerPolicy(), request.url(), referrer);
1080 if (referrer.isEmpty())
1081 return;
1082 request.setHTTPHeaderField(WebString::fromUTF8("Referer"), referrer);
1083 }
1084
1085 void WebFrameImpl::dispatchWillSendRequest(WebURLRequest& request)
1086 {
1087 ResourceResponse response;
1088 frame()->loader()->client()->dispatchWillSendRequest(0, 0, request.toMutable ResourceRequest(), response);
1089 }
1090
1091 WebURLLoader* WebFrameImpl::createAssociatedURLLoader(const WebURLLoaderOptions& options)
1092 {
1093 return new AssociatedURLLoader(this, options);
1094 }
1095
1096 unsigned WebFrameImpl::unloadListenerCount() const
1097 {
1098 return frame()->document()->domWindow()->pendingUnloadEventListeners();
1099 }
1100
1101 bool WebFrameImpl::willSuppressOpenerInNewFrame() const
1102 {
1103 return frame()->loader()->suppressOpenerInNewFrame();
1104 }
1105
1106 void WebFrameImpl::replaceSelection(const WebString& text)
1107 {
1108 bool selectReplacement = false;
1109 bool smartReplace = true;
1110 frame()->editor()->replaceSelectionWithText(text, selectReplacement, smartRe place);
1111 }
1112
1113 void WebFrameImpl::insertText(const WebString& text)
1114 {
1115 if (frame()->editor()->hasComposition())
1116 frame()->editor()->confirmComposition(text);
1117 else
1118 frame()->editor()->insertText(text, 0);
1119 }
1120
1121 void WebFrameImpl::setMarkedText(const WebString& text, unsigned location, unsig ned length)
1122 {
1123 Vector<CompositionUnderline> decorations;
1124 frame()->editor()->setComposition(text, decorations, location, length);
1125 }
1126
1127 void WebFrameImpl::unmarkText()
1128 {
1129 frame()->editor()->cancelComposition();
1130 }
1131
1132 bool WebFrameImpl::hasMarkedText() const
1133 {
1134 return frame()->editor()->hasComposition();
1135 }
1136
1137 WebRange WebFrameImpl::markedRange() const
1138 {
1139 return frame()->editor()->compositionRange();
1140 }
1141
1142 bool WebFrameImpl::firstRectForCharacterRange(unsigned location, unsigned length , WebRect& rect) const
1143 {
1144 if ((location + length < location) && (location + length))
1145 length = 0;
1146
1147 RefPtr<Range> range = TextIterator::rangeFromLocationAndLength(frame()->sele ction()->rootEditableElementOrDocumentElement(), location, length);
1148 if (!range)
1149 return false;
1150 IntRect intRect = frame()->editor()->firstRectForRange(range.get());
1151 rect = WebRect(intRect);
1152 rect = frame()->view()->contentsToWindow(rect);
1153 return true;
1154 }
1155
1156 size_t WebFrameImpl::characterIndexForPoint(const WebPoint& webPoint) const
1157 {
1158 if (!frame())
1159 return notFound;
1160
1161 IntPoint point = frame()->view()->windowToContents(webPoint);
1162 HitTestResult result = frame()->eventHandler()->hitTestResultAtPoint(point, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShad owContent);
1163 RefPtr<Range> range = frame()->rangeForPoint(result.roundedPointInInnerNodeF rame());
1164 if (!range)
1165 return notFound;
1166
1167 size_t location, length;
1168 TextIterator::getLocationAndLengthFromRange(frame()->selection()->rootEditab leElementOrDocumentElement(), range.get(), location, length);
1169 return location;
1170 }
1171
1172 bool WebFrameImpl::executeCommand(const WebString& name, const WebNode& node)
1173 {
1174 ASSERT(frame());
1175
1176 if (name.length() <= 2)
1177 return false;
1178
1179 // Since we don't have NSControl, we will convert the format of command
1180 // string and call the function on Editor directly.
1181 String command = name;
1182
1183 // Make sure the first letter is upper case.
1184 command.replace(0, 1, command.substring(0, 1).upper());
1185
1186 // Remove the trailing ':' if existing.
1187 if (command[command.length() - 1] == UChar(':'))
1188 command = command.substring(0, command.length() - 1);
1189
1190 WebPluginContainerImpl* pluginContainer = pluginContainerFromNode(frame(), n ode);
1191 if (pluginContainer && pluginContainer->executeEditCommand(name))
1192 return true;
1193
1194 bool result = true;
1195
1196 // Specially handling commands that Editor::execCommand does not directly
1197 // support.
1198 if (command == "DeleteToEndOfParagraph") {
1199 if (!frame()->editor()->deleteWithDirection(DirectionForward, ParagraphB oundary, true, false))
1200 frame()->editor()->deleteWithDirection(DirectionForward, CharacterGr anularity, true, false);
1201 } else if (command == "Indent")
1202 frame()->editor()->indent();
1203 else if (command == "Outdent")
1204 frame()->editor()->outdent();
1205 else if (command == "DeleteBackward")
1206 result = frame()->editor()->command(AtomicString("BackwardDelete")).exec ute();
1207 else if (command == "DeleteForward")
1208 result = frame()->editor()->command(AtomicString("ForwardDelete")).execu te();
1209 else if (command == "AdvanceToNextMisspelling") {
1210 // Wee need to pass false here or else the currently selected word will never be skipped.
1211 frame()->editor()->advanceToNextMisspelling(false);
1212 } else if (command == "ToggleSpellPanel")
1213 frame()->editor()->showSpellingGuessPanel();
1214 else
1215 result = frame()->editor()->command(command).execute();
1216 return result;
1217 }
1218
1219 bool WebFrameImpl::executeCommand(const WebString& name, const WebString& value, const WebNode& node)
1220 {
1221 ASSERT(frame());
1222 String webName = name;
1223
1224 WebPluginContainerImpl* pluginContainer = pluginContainerFromNode(frame(), n ode);
1225 if (pluginContainer && pluginContainer->executeEditCommand(name, value))
1226 return true;
1227
1228 // moveToBeginningOfDocument and moveToEndfDocument are only handled by WebK it for editable nodes.
1229 if (!frame()->editor()->canEdit() && webName == "moveToBeginningOfDocument")
1230 return viewImpl()->propagateScroll(ScrollUp, ScrollByDocument);
1231
1232 if (!frame()->editor()->canEdit() && webName == "moveToEndOfDocument")
1233 return viewImpl()->propagateScroll(ScrollDown, ScrollByDocument);
1234
1235 return frame()->editor()->command(webName).execute(value);
1236 }
1237
1238 bool WebFrameImpl::isCommandEnabled(const WebString& name) const
1239 {
1240 ASSERT(frame());
1241 return frame()->editor()->command(name).isEnabled();
1242 }
1243
1244 void WebFrameImpl::enableContinuousSpellChecking(bool enable)
1245 {
1246 if (enable == isContinuousSpellCheckingEnabled())
1247 return;
1248 frame()->editor()->toggleContinuousSpellChecking();
1249 }
1250
1251 bool WebFrameImpl::isContinuousSpellCheckingEnabled() const
1252 {
1253 return frame()->editor()->isContinuousSpellCheckingEnabled();
1254 }
1255
1256 void WebFrameImpl::requestTextChecking(const WebElement& webElement)
1257 {
1258 if (webElement.isNull())
1259 return;
1260 RefPtr<Range> rangeToCheck = rangeOfContents(const_cast<Element*>(webElement .constUnwrap<Element>()));
1261 frame()->editor()->spellChecker()->requestCheckingFor(SpellCheckRequest::cre ate(TextCheckingTypeSpelling | TextCheckingTypeGrammar, TextCheckingProcessBatch , rangeToCheck, rangeToCheck));
1262 }
1263
1264 void WebFrameImpl::replaceMisspelledRange(const WebString& text)
1265 {
1266 // If this caret selection has two or more markers, this function replace th e range covered by the first marker with the specified word as Microsoft Word do es.
1267 if (pluginContainerFromFrame(frame()))
1268 return;
1269 RefPtr<Range> caretRange = frame()->selection()->toNormalizedRange();
1270 if (!caretRange)
1271 return;
1272 Vector<DocumentMarker*> markers = frame()->document()->markers()->markersInR ange(caretRange.get(), DocumentMarker::Spelling | DocumentMarker::Grammar);
1273 if (markers.size() < 1 || markers[0]->startOffset() >= markers[0]->endOffset ())
1274 return;
1275 RefPtr<Range> markerRange = Range::create(caretRange->ownerDocument(), caret Range->startContainer(), markers[0]->startOffset(), caretRange->endContainer(), markers[0]->endOffset());
1276 if (!markerRange)
1277 return;
1278 if (!frame()->selection()->shouldChangeSelection(markerRange.get()))
1279 return;
1280 frame()->selection()->setSelection(markerRange.get(), CharacterGranularity);
1281 frame()->editor()->replaceSelectionWithText(text, false, false);
1282 }
1283
1284 void WebFrameImpl::removeSpellingMarkers()
1285 {
1286 frame()->document()->markers()->removeMarkers(DocumentMarker::Spelling | Doc umentMarker::Grammar);
1287 }
1288
1289 bool WebFrameImpl::hasSelection() const
1290 {
1291 WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame());
1292 if (pluginContainer)
1293 return pluginContainer->plugin()->hasSelection();
1294
1295 // frame()->selection()->isNone() never returns true.
1296 return (frame()->selection()->start() != frame()->selection()->end());
1297 }
1298
1299 WebRange WebFrameImpl::selectionRange() const
1300 {
1301 return frame()->selection()->toNormalizedRange();
1302 }
1303
1304 WebString WebFrameImpl::selectionAsText() const
1305 {
1306 WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame());
1307 if (pluginContainer)
1308 return pluginContainer->plugin()->selectionAsText();
1309
1310 RefPtr<Range> range = frame()->selection()->toNormalizedRange();
1311 if (!range)
1312 return WebString();
1313
1314 String text = range->text();
1315 #if OS(WINDOWS)
1316 replaceNewlinesWithWindowsStyleNewlines(text);
1317 #endif
1318 replaceNBSPWithSpace(text);
1319 return text;
1320 }
1321
1322 WebString WebFrameImpl::selectionAsMarkup() const
1323 {
1324 WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame());
1325 if (pluginContainer)
1326 return pluginContainer->plugin()->selectionAsMarkup();
1327
1328 RefPtr<Range> range = frame()->selection()->toNormalizedRange();
1329 if (!range)
1330 return WebString();
1331
1332 return createMarkup(range.get(), 0, AnnotateForInterchange, false, ResolveNo nLocalURLs);
1333 }
1334
1335 void WebFrameImpl::selectWordAroundPosition(Frame* frame, VisiblePosition positi on)
1336 {
1337 VisibleSelection selection(position);
1338 selection.expandUsingGranularity(WordGranularity);
1339
1340 if (frame->selection()->shouldChangeSelection(selection)) {
1341 TextGranularity granularity = selection.isRange() ? WordGranularity : Ch aracterGranularity;
1342 frame->selection()->setSelection(selection, granularity);
1343 }
1344 }
1345
1346 bool WebFrameImpl::selectWordAroundCaret()
1347 {
1348 FrameSelection* selection = frame()->selection();
1349 ASSERT(!selection->isNone());
1350 if (selection->isNone() || selection->isRange())
1351 return false;
1352 selectWordAroundPosition(frame(), selection->selection().visibleStart());
1353 return true;
1354 }
1355
1356 void WebFrameImpl::selectRange(const WebPoint& base, const WebPoint& extent)
1357 {
1358 moveRangeSelection(base, extent);
1359 }
1360
1361 void WebFrameImpl::selectRange(const WebRange& webRange)
1362 {
1363 if (RefPtr<Range> range = static_cast<PassRefPtr<Range> >(webRange))
1364 frame()->selection()->setSelectedRange(range.get(), WebCore::VP_DEFAULT_ AFFINITY, false);
1365 }
1366
1367 void WebFrameImpl::moveCaretSelectionTowardsWindowPoint(const WebPoint& point)
1368 {
1369 moveCaretSelection(point);
1370 }
1371
1372 void WebFrameImpl::moveRangeSelection(const WebPoint& base, const WebPoint& exte nt)
1373 {
1374 FrameSelection* selection = frame()->selection();
1375 if (!selection)
1376 return;
1377
1378 VisiblePosition basePosition = visiblePositionForWindowPoint(base);
1379 VisiblePosition extentPosition = visiblePositionForWindowPoint(extent);
1380 VisibleSelection newSelection = VisibleSelection(basePosition, extentPositio n);
1381 if (frame()->selection()->shouldChangeSelection(newSelection))
1382 frame()->selection()->setSelection(newSelection, CharacterGranularity);
1383 }
1384
1385 void WebFrameImpl::moveCaretSelection(const WebPoint& point)
1386 {
1387 Element* editable = frame()->selection()->rootEditableElement();
1388 if (!editable)
1389 return;
1390
1391 VisiblePosition position = visiblePositionForWindowPoint(point);
1392 if (frame()->selection()->shouldChangeSelection(position))
1393 frame()->selection()->moveTo(position, UserTriggered);
1394 }
1395
1396 VisiblePosition WebFrameImpl::visiblePositionForWindowPoint(const WebPoint& poin t)
1397 {
1398 FloatPoint unscaledPoint(point);
1399 unscaledPoint.scale(1 / view()->pageScaleFactor(), 1 / view()->pageScaleFact or());
1400
1401 HitTestRequest request = HitTestRequest::Move | HitTestRequest::ReadOnly | H itTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::Disallo wShadowContent;
1402 HitTestResult result(frame()->view()->windowToContents(roundedIntPoint(unsca ledPoint)));
1403 frame()->document()->renderView()->layer()->hitTest(request, result);
1404
1405 Node* node = result.targetNode();
1406 if (!node)
1407 return VisiblePosition();
1408 return frame()->selection()->selection().visiblePositionRespectingEditingBou ndary(result.localPoint(), node);
1409 }
1410
1411 int WebFrameImpl::printBegin(const WebPrintParams& printParams, const WebNode& c onstrainToNode, bool* useBrowserOverlays)
1412 {
1413 ASSERT(!frame()->document()->isFrameSet());
1414 WebPluginContainerImpl* pluginContainer = 0;
1415 if (constrainToNode.isNull()) {
1416 // If this is a plugin document, check if the plugin supports its own
1417 // printing. If it does, we will delegate all printing to that.
1418 pluginContainer = pluginContainerFromFrame(frame());
1419 } else {
1420 // We only support printing plugin nodes for now.
1421 pluginContainer = static_cast<WebPluginContainerImpl*>(constrainToNode.p luginContainer());
1422 }
1423
1424 if (pluginContainer && pluginContainer->supportsPaginatedPrint())
1425 m_printContext = adoptPtr(new ChromePluginPrintContext(frame(), pluginCo ntainer, printParams));
1426 else
1427 m_printContext = adoptPtr(new ChromePrintContext(frame()));
1428
1429 FloatRect rect(0, 0, static_cast<float>(printParams.printContentArea.width), static_cast<float>(printParams.printContentArea.height));
1430 m_printContext->begin(rect.width(), rect.height());
1431 float pageHeight;
1432 // We ignore the overlays calculation for now since they are generated in th e
1433 // browser. pageHeight is actually an output parameter.
1434 m_printContext->computePageRects(rect, 0, 0, 1.0, pageHeight);
1435 if (useBrowserOverlays)
1436 *useBrowserOverlays = m_printContext->shouldUseBrowserOverlays();
1437
1438 return m_printContext->pageCount();
1439 }
1440
1441 float WebFrameImpl::getPrintPageShrink(int page)
1442 {
1443 ASSERT(m_printContext && page >= 0);
1444 return m_printContext->getPageShrink(page);
1445 }
1446
1447 float WebFrameImpl::printPage(int page, WebCanvas* canvas)
1448 {
1449 #if ENABLE(PRINTING)
1450 ASSERT(m_printContext && page >= 0 && frame() && frame()->document());
1451
1452 GraphicsContext graphicsContext(canvas);
1453 graphicsContext.setPrinting(true);
1454 return m_printContext->spoolPage(graphicsContext, page);
1455 #else
1456 return 0;
1457 #endif
1458 }
1459
1460 void WebFrameImpl::printEnd()
1461 {
1462 ASSERT(m_printContext);
1463 m_printContext->end();
1464 m_printContext.clear();
1465 }
1466
1467 bool WebFrameImpl::isPrintScalingDisabledForPlugin(const WebNode& node)
1468 {
1469 WebPluginContainerImpl* pluginContainer = node.isNull() ? pluginContainerFr omFrame(frame()) : static_cast<WebPluginContainerImpl*>(node.pluginContainer());
1470
1471 if (!pluginContainer || !pluginContainer->supportsPaginatedPrint())
1472 return false;
1473
1474 return pluginContainer->isPrintScalingDisabled();
1475 }
1476
1477 bool WebFrameImpl::hasCustomPageSizeStyle(int pageIndex)
1478 {
1479 return frame()->document()->styleForPage(pageIndex)->pageSizeType() != PAGE_ SIZE_AUTO;
1480 }
1481
1482 bool WebFrameImpl::isPageBoxVisible(int pageIndex)
1483 {
1484 return frame()->document()->isPageBoxVisible(pageIndex);
1485 }
1486
1487 void WebFrameImpl::pageSizeAndMarginsInPixels(int pageIndex, WebSize& pageSize, int& marginTop, int& marginRight, int& marginBottom, int& marginLeft)
1488 {
1489 IntSize size = pageSize;
1490 frame()->document()->pageSizeAndMarginsInPixels(pageIndex, size, marginTop, marginRight, marginBottom, marginLeft);
1491 pageSize = size;
1492 }
1493
1494 WebString WebFrameImpl::pageProperty(const WebString& propertyName, int pageInde x)
1495 {
1496 ASSERT(m_printContext);
1497 return m_printContext->pageProperty(frame(), propertyName.utf8().data(), pag eIndex);
1498 }
1499
1500 bool WebFrameImpl::find(int identifier, const WebString& searchText, const WebFi ndOptions& options, bool wrapWithinFrame, WebRect* selectionRect)
1501 {
1502 if (!frame() || !frame()->page())
1503 return false;
1504
1505 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
1506
1507 if (!options.findNext)
1508 frame()->page()->unmarkAllTextMatches();
1509 else
1510 setMarkerActive(m_activeMatch.get(), false);
1511
1512 if (m_activeMatch && m_activeMatch->ownerDocument() != frame()->document())
1513 m_activeMatch = 0;
1514
1515 // If the user has selected something since the last Find operation we want
1516 // to start from there. Otherwise, we start searching from where the last Fi nd
1517 // operation left off (either a Find or a FindNext operation).
1518 VisibleSelection selection(frame()->selection()->selection());
1519 bool activeSelection = !selection.isNone();
1520 if (activeSelection) {
1521 m_activeMatch = selection.firstRange().get();
1522 frame()->selection()->clear();
1523 }
1524
1525 ASSERT(frame() && frame()->view());
1526 const FindOptions findOptions = (options.forward ? 0 : Backwards)
1527 | (options.matchCase ? 0 : CaseInsensitive)
1528 | (wrapWithinFrame ? WrapAround : 0)
1529 | (!options.findNext ? StartInSelection : 0);
1530 m_activeMatch = frame()->editor()->findStringAndScrollToVisible(searchText, m_activeMatch.get(), findOptions);
1531
1532 if (!m_activeMatch) {
1533 // If we're finding next the next active match might not be in the curre nt frame.
1534 // In this case we don't want to clear the matches cache.
1535 if (!options.findNext)
1536 clearFindMatchesCache();
1537 invalidateArea(InvalidateAll);
1538 return false;
1539 }
1540
1541 #if OS(ANDROID)
1542 viewImpl()->zoomToFindInPageRect(frameView()->contentsToWindow(enclosingIntR ect(RenderObject::absoluteBoundingBoxRectForRange(m_activeMatch.get()))));
1543 #endif
1544
1545 setMarkerActive(m_activeMatch.get(), true);
1546 WebFrameImpl* oldActiveFrame = mainFrameImpl->m_currentActiveMatchFrame;
1547 mainFrameImpl->m_currentActiveMatchFrame = this;
1548
1549 // Make sure no node is focused. See http://crbug.com/38700.
1550 frame()->document()->setFocusedNode(0);
1551
1552 if (!options.findNext || activeSelection) {
1553 // This is either a Find operation or a Find-next from a new start point
1554 // due to a selection, so we set the flag to ask the scoping effort
1555 // to find the active rect for us and report it back to the UI.
1556 m_locatingActiveRect = true;
1557 } else {
1558 if (oldActiveFrame != this) {
1559 if (options.forward)
1560 m_activeMatchIndexInCurrentFrame = 0;
1561 else
1562 m_activeMatchIndexInCurrentFrame = m_lastMatchCount - 1;
1563 } else {
1564 if (options.forward)
1565 ++m_activeMatchIndexInCurrentFrame;
1566 else
1567 --m_activeMatchIndexInCurrentFrame;
1568
1569 if (m_activeMatchIndexInCurrentFrame + 1 > m_lastMatchCount)
1570 m_activeMatchIndexInCurrentFrame = 0;
1571 if (m_activeMatchIndexInCurrentFrame == -1)
1572 m_activeMatchIndexInCurrentFrame = m_lastMatchCount - 1;
1573 }
1574 if (selectionRect) {
1575 *selectionRect = frameView()->contentsToWindow(m_activeMatch->boundi ngBox());
1576 reportFindInPageSelection(*selectionRect, m_activeMatchIndexInCurren tFrame + 1, identifier);
1577 }
1578 }
1579
1580 return true;
1581 }
1582
1583 void WebFrameImpl::stopFinding(bool clearSelection)
1584 {
1585 if (!clearSelection)
1586 setFindEndstateFocusAndSelection();
1587 cancelPendingScopingEffort();
1588
1589 // Remove all markers for matches found and turn off the highlighting.
1590 frame()->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
1591 frame()->editor()->setMarkedTextMatchesAreHighlighted(false);
1592 clearFindMatchesCache();
1593
1594 // Let the frame know that we don't want tickmarks or highlighting anymore.
1595 invalidateArea(InvalidateAll);
1596 }
1597
1598 void WebFrameImpl::scopeStringMatches(int identifier, const WebString& searchTex t, const WebFindOptions& options, bool reset)
1599 {
1600 if (reset) {
1601 // This is a brand new search, so we need to reset everything.
1602 // Scoping is just about to begin.
1603 m_scopingInProgress = true;
1604
1605 // Need to keep the current identifier locally in order to finish the
1606 // request in case the frame is detached during the process.
1607 m_findRequestIdentifier = identifier;
1608
1609 // Clear highlighting for this frame.
1610 if (frame() && frame()->page() && frame()->editor()->markedTextMatchesAr eHighlighted())
1611 frame()->page()->unmarkAllTextMatches();
1612
1613 // Clear the tickmarks and results cache.
1614 clearFindMatchesCache();
1615
1616 // Clear the counters from last operation.
1617 m_lastMatchCount = 0;
1618 m_nextInvalidateAfter = 0;
1619
1620 m_resumeScopingFromRange = 0;
1621
1622 // The view might be null on detached frames.
1623 if (frame() && frame()->page())
1624 viewImpl()->mainFrameImpl()->m_framesScopingCount++;
1625
1626 // Now, defer scoping until later to allow find operation to finish quic kly.
1627 scopeStringMatchesSoon(identifier, searchText, options, false); // false means just reset, so don't do it again.
1628 return;
1629 }
1630
1631 if (!shouldScopeMatches(searchText)) {
1632 // Note that we want to defer the final update when resetting even if sh ouldScopeMatches returns false.
1633 // This is done in order to prevent sending a final message based only o n the results of the first frame
1634 // since m_framesScopingCount would be 0 as other frames have yet to res et.
1635 finishCurrentScopingEffort(identifier);
1636 return;
1637 }
1638
1639 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
1640 RefPtr<Range> searchRange(rangeOfContents(frame()->document()));
1641
1642 Node* originalEndContainer = searchRange->endContainer();
1643 int originalEndOffset = searchRange->endOffset();
1644
1645 ExceptionCode ec = 0, ec2 = 0;
1646 if (m_resumeScopingFromRange) {
1647 // This is a continuation of a scoping operation that timed out and didn 't
1648 // complete last time around, so we should start from where we left off.
1649 searchRange->setStart(m_resumeScopingFromRange->startContainer(),
1650 m_resumeScopingFromRange->startOffset(ec2) + 1,
1651 ec);
1652 if (ec || ec2) {
1653 if (ec2) // A non-zero |ec| happens when navigating during search.
1654 ASSERT_NOT_REACHED();
1655 return;
1656 }
1657 }
1658
1659 // This timeout controls how long we scope before releasing control. This
1660 // value does not prevent us from running for longer than this, but it is
1661 // periodically checked to see if we have exceeded our allocated time.
1662 const double maxScopingDuration = 0.1; // seconds
1663
1664 int matchCount = 0;
1665 bool timedOut = false;
1666 double startTime = currentTime();
1667 do {
1668 // Find next occurrence of the search string.
1669 // FIXME: (http://b/1088245) This WebKit operation may run for longer
1670 // than the timeout value, and is not interruptible as it is currently
1671 // written. We may need to rewrite it with interruptibility in mind, or
1672 // find an alternative.
1673 RefPtr<Range> resultRange(findPlainText(searchRange.get(),
1674 searchText,
1675 options.matchCase ? 0 : CaseInse nsitive));
1676 if (resultRange->collapsed(ec)) {
1677 if (!resultRange->startContainer()->isInShadowTree())
1678 break;
1679
1680 searchRange->setStartAfter(
1681 resultRange->startContainer()->deprecatedShadowAncestorNode(), e c);
1682 searchRange->setEnd(originalEndContainer, originalEndOffset, ec);
1683 continue;
1684 }
1685
1686 ++matchCount;
1687
1688 // Catch a special case where Find found something but doesn't know what
1689 // the bounding box for it is. In this case we set the first match we fi nd
1690 // as the active rect.
1691 IntRect resultBounds = resultRange->boundingBox();
1692 IntRect activeSelectionRect;
1693 if (m_locatingActiveRect) {
1694 activeSelectionRect = m_activeMatch.get() ?
1695 m_activeMatch->boundingBox() : resultBounds;
1696 }
1697
1698 // If the Find function found a match it will have stored where the
1699 // match was found in m_activeSelectionRect on the current frame. If we
1700 // find this rect during scoping it means we have found the active
1701 // tickmark.
1702 bool foundActiveMatch = false;
1703 if (m_locatingActiveRect && (activeSelectionRect == resultBounds)) {
1704 // We have found the active tickmark frame.
1705 mainFrameImpl->m_currentActiveMatchFrame = this;
1706 foundActiveMatch = true;
1707 // We also know which tickmark is active now.
1708 m_activeMatchIndexInCurrentFrame = matchCount - 1;
1709 // To stop looking for the active tickmark, we set this flag.
1710 m_locatingActiveRect = false;
1711
1712 // Notify browser of new location for the selected rectangle.
1713 reportFindInPageSelection(
1714 frameView()->contentsToWindow(resultBounds),
1715 m_activeMatchIndexInCurrentFrame + 1,
1716 identifier);
1717 }
1718
1719 addMarker(resultRange.get(), foundActiveMatch);
1720
1721 m_findMatchesCache.append(FindMatch(resultRange.get(), m_lastMatchCount + matchCount));
1722
1723 // Set the new start for the search range to be the end of the previous
1724 // result range. There is no need to use a VisiblePosition here,
1725 // since findPlainText will use a TextIterator to go over the visible
1726 // text nodes.
1727 searchRange->setStart(resultRange->endContainer(ec), resultRange->endOff set(ec), ec);
1728
1729 Node* shadowTreeRoot = searchRange->shadowRoot();
1730 if (searchRange->collapsed(ec) && shadowTreeRoot)
1731 searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount() , ec);
1732
1733 m_resumeScopingFromRange = resultRange;
1734 timedOut = (currentTime() - startTime) >= maxScopingDuration;
1735 } while (!timedOut);
1736
1737 // Remember what we search for last time, so we can skip searching if more
1738 // letters are added to the search string (and last outcome was 0).
1739 m_lastSearchString = searchText;
1740
1741 if (matchCount > 0) {
1742 frame()->editor()->setMarkedTextMatchesAreHighlighted(true);
1743
1744 m_lastMatchCount += matchCount;
1745
1746 // Let the mainframe know how much we found during this pass.
1747 mainFrameImpl->increaseMatchCount(matchCount, identifier);
1748 }
1749
1750 if (timedOut) {
1751 // If we found anything during this pass, we should redraw. However, we
1752 // don't want to spam too much if the page is extremely long, so if we
1753 // reach a certain point we start throttling the redraw requests.
1754 if (matchCount > 0)
1755 invalidateIfNecessary();
1756
1757 // Scoping effort ran out of time, lets ask for another time-slice.
1758 scopeStringMatchesSoon(
1759 identifier,
1760 searchText,
1761 options,
1762 false); // don't reset.
1763 return; // Done for now, resume work later.
1764 }
1765
1766 finishCurrentScopingEffort(identifier);
1767 }
1768
1769 void WebFrameImpl::flushCurrentScopingEffort(int identifier)
1770 {
1771 if (!frame() || !frame()->page())
1772 return;
1773
1774 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
1775
1776 // This frame has no further scoping left, so it is done. Other frames might ,
1777 // of course, continue to scope matches.
1778 mainFrameImpl->m_framesScopingCount--;
1779
1780 // If this is the last frame to finish scoping we need to trigger the final
1781 // update to be sent.
1782 if (!mainFrameImpl->m_framesScopingCount)
1783 mainFrameImpl->increaseMatchCount(0, identifier);
1784 }
1785
1786 void WebFrameImpl::finishCurrentScopingEffort(int identifier)
1787 {
1788 flushCurrentScopingEffort(identifier);
1789
1790 m_scopingInProgress = false;
1791 m_lastFindRequestCompletedWithNoMatches = !m_lastMatchCount;
1792
1793 // This frame is done, so show any scrollbar tickmarks we haven't drawn yet.
1794 invalidateArea(InvalidateScrollbar);
1795 }
1796
1797 void WebFrameImpl::cancelPendingScopingEffort()
1798 {
1799 deleteAllValues(m_deferredScopingWork);
1800 m_deferredScopingWork.clear();
1801
1802 m_activeMatchIndexInCurrentFrame = -1;
1803
1804 // Last request didn't complete.
1805 if (m_scopingInProgress)
1806 m_lastFindRequestCompletedWithNoMatches = false;
1807
1808 m_scopingInProgress = false;
1809 }
1810
1811 void WebFrameImpl::increaseMatchCount(int count, int identifier)
1812 {
1813 // This function should only be called on the mainframe.
1814 ASSERT(!parent());
1815
1816 if (count)
1817 ++m_findMatchMarkersVersion;
1818
1819 m_totalMatchCount += count;
1820
1821 // Update the UI with the latest findings.
1822 if (client())
1823 client()->reportFindInPageMatchCount(identifier, m_totalMatchCount, !m_f ramesScopingCount);
1824 }
1825
1826 void WebFrameImpl::reportFindInPageSelection(const WebRect& selectionRect, int a ctiveMatchOrdinal, int identifier)
1827 {
1828 // Update the UI with the latest selection rect.
1829 if (client())
1830 client()->reportFindInPageSelection(identifier, ordinalOfFirstMatchForFr ame(this) + activeMatchOrdinal, selectionRect);
1831 }
1832
1833 void WebFrameImpl::resetMatchCount()
1834 {
1835 if (m_totalMatchCount > 0)
1836 ++m_findMatchMarkersVersion;
1837
1838 m_totalMatchCount = 0;
1839 m_framesScopingCount = 0;
1840 }
1841
1842 void WebFrameImpl::sendOrientationChangeEvent(int orientation)
1843 {
1844 #if ENABLE(ORIENTATION_EVENTS)
1845 if (frame())
1846 frame()->sendOrientationChangeEvent(orientation);
1847 #endif
1848 }
1849
1850 void WebFrameImpl::dispatchMessageEventWithOriginCheck(const WebSecurityOrigin& intendedTargetOrigin, const WebDOMEvent& event)
1851 {
1852 ASSERT(!event.isNull());
1853 frame()->document()->domWindow()->dispatchMessageEventWithOriginCheck(intend edTargetOrigin.get(), event, 0);
1854 }
1855
1856 int WebFrameImpl::findMatchMarkersVersion() const
1857 {
1858 ASSERT(!parent());
1859 return m_findMatchMarkersVersion;
1860 }
1861
1862 void WebFrameImpl::clearFindMatchesCache()
1863 {
1864 if (!m_findMatchesCache.isEmpty())
1865 viewImpl()->mainFrameImpl()->m_findMatchMarkersVersion++;
1866
1867 m_findMatchesCache.clear();
1868 m_findMatchRectsAreValid = false;
1869 }
1870
1871 bool WebFrameImpl::isActiveMatchFrameValid() const
1872 {
1873 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
1874 WebFrameImpl* activeMatchFrame = mainFrameImpl->activeMatchFrame();
1875 return activeMatchFrame && activeMatchFrame->m_activeMatch && activeMatchFra me->frame()->tree()->isDescendantOf(mainFrameImpl->frame());
1876 }
1877
1878 void WebFrameImpl::updateFindMatchRects()
1879 {
1880 IntSize currentContentsSize = contentsSize();
1881 if (m_contentsSizeForCurrentFindMatchRects != currentContentsSize) {
1882 m_contentsSizeForCurrentFindMatchRects = currentContentsSize;
1883 m_findMatchRectsAreValid = false;
1884 }
1885
1886 size_t deadMatches = 0;
1887 for (Vector<FindMatch>::iterator it = m_findMatchesCache.begin(); it != m_fi ndMatchesCache.end(); ++it) {
1888 if (!it->m_range->boundaryPointsValid() || !it->m_range->startContainer( )->inDocument())
1889 it->m_rect = FloatRect();
1890 else if (!m_findMatchRectsAreValid)
1891 it->m_rect = findInPageRectFromRange(it->m_range.get());
1892
1893 if (it->m_rect.isEmpty())
1894 ++deadMatches;
1895 }
1896
1897 // Remove any invalid matches from the cache.
1898 if (deadMatches) {
1899 Vector<FindMatch> filteredMatches;
1900 filteredMatches.reserveCapacity(m_findMatchesCache.size() - deadMatches) ;
1901
1902 for (Vector<FindMatch>::const_iterator it = m_findMatchesCache.begin(); it != m_findMatchesCache.end(); ++it)
1903 if (!it->m_rect.isEmpty())
1904 filteredMatches.append(*it);
1905
1906 m_findMatchesCache.swap(filteredMatches);
1907 }
1908
1909 // Invalidate the rects in child frames. Will be updated later during traver sal.
1910 if (!m_findMatchRectsAreValid)
1911 for (WebFrame* child = firstChild(); child; child = child->nextSibling() )
1912 static_cast<WebFrameImpl*>(child)->m_findMatchRectsAreValid = false;
1913
1914 m_findMatchRectsAreValid = true;
1915 }
1916
1917 WebFloatRect WebFrameImpl::activeFindMatchRect()
1918 {
1919 ASSERT(!parent());
1920
1921 if (!isActiveMatchFrameValid())
1922 return WebFloatRect();
1923
1924 return WebFloatRect(findInPageRectFromRange(m_currentActiveMatchFrame->m_act iveMatch.get()));
1925 }
1926
1927 void WebFrameImpl::findMatchRects(WebVector<WebFloatRect>& outputRects)
1928 {
1929 ASSERT(!parent());
1930
1931 Vector<WebFloatRect> matchRects;
1932 for (WebFrameImpl* frame = this; frame; frame = static_cast<WebFrameImpl*>(f rame->traverseNext(false)))
1933 frame->appendFindMatchRects(matchRects);
1934
1935 outputRects = matchRects;
1936 }
1937
1938 void WebFrameImpl::appendFindMatchRects(Vector<WebFloatRect>& frameRects)
1939 {
1940 updateFindMatchRects();
1941 frameRects.reserveCapacity(frameRects.size() + m_findMatchesCache.size());
1942 for (Vector<FindMatch>::const_iterator it = m_findMatchesCache.begin(); it ! = m_findMatchesCache.end(); ++it) {
1943 ASSERT(!it->m_rect.isEmpty());
1944 frameRects.append(it->m_rect);
1945 }
1946 }
1947
1948 int WebFrameImpl::selectNearestFindMatch(const WebFloatPoint& point, WebRect* se lectionRect)
1949 {
1950 ASSERT(!parent());
1951
1952 WebFrameImpl* bestFrame = 0;
1953 int indexInBestFrame = -1;
1954 float distanceInBestFrame = FLT_MAX;
1955
1956 for (WebFrameImpl* frame = this; frame; frame = static_cast<WebFrameImpl*>(f rame->traverseNext(false))) {
1957 float distanceInFrame;
1958 int indexInFrame = frame->nearestFindMatch(point, distanceInFrame);
1959 if (distanceInFrame < distanceInBestFrame) {
1960 bestFrame = frame;
1961 indexInBestFrame = indexInFrame;
1962 distanceInBestFrame = distanceInFrame;
1963 }
1964 }
1965
1966 if (indexInBestFrame != -1)
1967 return bestFrame->selectFindMatch(static_cast<unsigned>(indexInBestFrame ), selectionRect);
1968
1969 return -1;
1970 }
1971
1972 int WebFrameImpl::nearestFindMatch(const FloatPoint& point, float& distanceSquar ed)
1973 {
1974 updateFindMatchRects();
1975
1976 int nearest = -1;
1977 distanceSquared = FLT_MAX;
1978 for (size_t i = 0; i < m_findMatchesCache.size(); ++i) {
1979 ASSERT(!m_findMatchesCache[i].m_rect.isEmpty());
1980 FloatSize offset = point - m_findMatchesCache[i].m_rect.center();
1981 float width = offset.width();
1982 float height = offset.height();
1983 float currentDistanceSquared = width * width + height * height;
1984 if (currentDistanceSquared < distanceSquared) {
1985 nearest = i;
1986 distanceSquared = currentDistanceSquared;
1987 }
1988 }
1989 return nearest;
1990 }
1991
1992 int WebFrameImpl::selectFindMatch(unsigned index, WebRect* selectionRect)
1993 {
1994 ASSERT_WITH_SECURITY_IMPLICATION(index < m_findMatchesCache.size());
1995
1996 RefPtr<Range> range = m_findMatchesCache[index].m_range;
1997 if (!range->boundaryPointsValid() || !range->startContainer()->inDocument())
1998 return -1;
1999
2000 // Check if the match is already selected.
2001 WebFrameImpl* activeMatchFrame = viewImpl()->mainFrameImpl()->m_currentActiv eMatchFrame;
2002 if (this != activeMatchFrame || !m_activeMatch || !areRangesEqual(m_activeMa tch.get(), range.get())) {
2003 if (isActiveMatchFrameValid())
2004 activeMatchFrame->setMarkerActive(activeMatchFrame->m_activeMatch.ge t(), false);
2005
2006 m_activeMatchIndexInCurrentFrame = m_findMatchesCache[index].m_ordinal - 1;
2007
2008 // Set this frame as the active frame (the one with the active highlight ).
2009 viewImpl()->mainFrameImpl()->m_currentActiveMatchFrame = this;
2010 viewImpl()->setFocusedFrame(this);
2011
2012 m_activeMatch = range.release();
2013 setMarkerActive(m_activeMatch.get(), true);
2014
2015 // Clear any user selection, to make sure Find Next continues on from th e match we just activated.
2016 frame()->selection()->clear();
2017
2018 // Make sure no node is focused. See http://crbug.com/38700.
2019 frame()->document()->setFocusedNode(0);
2020 }
2021
2022 IntRect activeMatchRect;
2023 IntRect activeMatchBoundingBox = enclosingIntRect(RenderObject::absoluteBoun dingBoxRectForRange(m_activeMatch.get()));
2024
2025 if (!activeMatchBoundingBox.isEmpty()) {
2026 if (m_activeMatch->firstNode() && m_activeMatch->firstNode()->renderer() )
2027 m_activeMatch->firstNode()->renderer()->scrollRectToVisible(activeMa tchBoundingBox,
2028 ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::align CenterIfNeeded);
2029
2030 // Zoom to the active match.
2031 activeMatchRect = frameView()->contentsToWindow(activeMatchBoundingBox);
2032 viewImpl()->zoomToFindInPageRect(activeMatchRect);
2033 }
2034
2035 if (selectionRect)
2036 *selectionRect = activeMatchRect;
2037
2038 return ordinalOfFirstMatchForFrame(this) + m_activeMatchIndexInCurrentFrame + 1;
2039 }
2040
2041 WebString WebFrameImpl::contentAsText(size_t maxChars) const
2042 {
2043 if (!frame())
2044 return WebString();
2045 Vector<UChar> text;
2046 frameContentAsPlainText(maxChars, frame(), &text);
2047 return String::adopt(text);
2048 }
2049
2050 WebString WebFrameImpl::contentAsMarkup() const
2051 {
2052 if (!frame())
2053 return WebString();
2054 return createFullMarkup(frame()->document());
2055 }
2056
2057 WebString WebFrameImpl::renderTreeAsText(RenderAsTextControls toShow) const
2058 {
2059 RenderAsTextBehavior behavior = RenderAsTextBehaviorNormal;
2060
2061 if (toShow & RenderAsTextDebug)
2062 behavior |= RenderAsTextShowCompositedLayers | RenderAsTextShowAddresses | RenderAsTextShowIDAndClass | RenderAsTextShowLayerNesting;
2063
2064 if (toShow & RenderAsTextPrinting)
2065 behavior |= RenderAsTextPrintingMode;
2066
2067 return externalRepresentation(frame(), behavior);
2068 }
2069
2070 WebString WebFrameImpl::markerTextForListItem(const WebElement& webElement) cons t
2071 {
2072 return WebCore::markerTextForListItem(const_cast<Element*>(webElement.constU nwrap<Element>()));
2073 }
2074
2075 void WebFrameImpl::printPagesWithBoundaries(WebCanvas* canvas, const WebSize& pa geSizeInPixels)
2076 {
2077 ASSERT(m_printContext);
2078
2079 GraphicsContext graphicsContext(canvas);
2080 graphicsContext.setPrinting(true);
2081
2082 m_printContext->spoolAllPagesWithBoundaries(graphicsContext, FloatSize(pageS izeInPixels.width, pageSizeInPixels.height));
2083 }
2084
2085 WebRect WebFrameImpl::selectionBoundsRect() const
2086 {
2087 return hasSelection() ? WebRect(IntRect(frame()->selection()->bounds(false)) ) : WebRect();
2088 }
2089
2090 bool WebFrameImpl::selectionStartHasSpellingMarkerFor(int from, int length) cons t
2091 {
2092 if (!frame())
2093 return false;
2094 return frame()->editor()->selectionStartHasMarkerFor(DocumentMarker::Spellin g, from, length);
2095 }
2096
2097 WebString WebFrameImpl::layerTreeAsText(bool showDebugInfo) const
2098 {
2099 if (!frame())
2100 return WebString();
2101
2102 return WebString(frame()->layerTreeAsText(showDebugInfo ? LayerTreeIncludesD ebugInfo : LayerTreeNormal));
2103 }
2104
2105 // WebFrameImpl public ---------------------------------------------------------
2106
2107 PassRefPtr<WebFrameImpl> WebFrameImpl::create(WebFrameClient* client)
2108 {
2109 return adoptRef(new WebFrameImpl(client));
2110 }
2111
2112 WebFrameImpl::WebFrameImpl(WebFrameClient* client)
2113 : FrameDestructionObserver(0)
2114 , m_frameLoaderClient(this)
2115 , m_client(client)
2116 , m_currentActiveMatchFrame(0)
2117 , m_activeMatchIndexInCurrentFrame(-1)
2118 , m_locatingActiveRect(false)
2119 , m_resumeScopingFromRange(0)
2120 , m_lastMatchCount(-1)
2121 , m_totalMatchCount(-1)
2122 , m_framesScopingCount(-1)
2123 , m_findRequestIdentifier(-1)
2124 , m_scopingInProgress(false)
2125 , m_lastFindRequestCompletedWithNoMatches(false)
2126 , m_nextInvalidateAfter(0)
2127 , m_findMatchMarkersVersion(0)
2128 , m_findMatchRectsAreValid(false)
2129 , m_identifier(generateFrameIdentifier())
2130 , m_inSameDocumentHistoryLoad(false)
2131 {
2132 WebKit::Platform::current()->incrementStatsCounter(webFrameActiveCount);
2133 frameCount++;
2134 }
2135
2136 WebFrameImpl::~WebFrameImpl()
2137 {
2138 WebKit::Platform::current()->decrementStatsCounter(webFrameActiveCount);
2139 frameCount--;
2140
2141 cancelPendingScopingEffort();
2142 }
2143
2144 void WebFrameImpl::setWebCoreFrame(WebCore::Frame* frame)
2145 {
2146 ASSERT(frame);
2147 observeFrame(frame);
2148 }
2149
2150 void WebFrameImpl::initializeAsMainFrame(WebCore::Page* page)
2151 {
2152 RefPtr<Frame> mainFrame = Frame::create(page, 0, &m_frameLoaderClient);
2153 setWebCoreFrame(mainFrame.get());
2154
2155 // Add reference on behalf of FrameLoader. See comments in
2156 // WebFrameLoaderClient::frameLoaderDestroyed for more info.
2157 ref();
2158
2159 // We must call init() after m_frame is assigned because it is referenced
2160 // during init().
2161 frame()->init();
2162 }
2163
2164 PassRefPtr<Frame> WebFrameImpl::createChildFrame(const FrameLoadRequest& request , HTMLFrameOwnerElement* ownerElement)
2165 {
2166 RefPtr<WebFrameImpl> webframe(adoptRef(new WebFrameImpl(m_client)));
2167
2168 // Add an extra ref on behalf of the Frame/FrameLoader, which references the
2169 // WebFrame via the FrameLoaderClient interface. See the comment at the top
2170 // of this file for more info.
2171 webframe->ref();
2172
2173 RefPtr<Frame> childFrame = Frame::create(frame()->page(), ownerElement, &web frame->m_frameLoaderClient);
2174 webframe->setWebCoreFrame(childFrame.get());
2175
2176 childFrame->tree()->setName(request.frameName());
2177
2178 frame()->tree()->appendChild(childFrame);
2179
2180 // Frame::init() can trigger onload event in the parent frame,
2181 // which may detach this frame and trigger a null-pointer access
2182 // in FrameTree::removeChild. Move init() after appendChild call
2183 // so that webframe->mFrame is in the tree before triggering
2184 // onload event handler.
2185 // Because the event handler may set webframe->mFrame to null,
2186 // it is necessary to check the value after calling init() and
2187 // return without loading URL.
2188 // (b:791612)
2189 childFrame->init(); // create an empty document
2190 if (!childFrame->tree()->parent())
2191 return 0;
2192
2193 frame()->loader()->loadURLIntoChildFrame(request.resourceRequest(), childFra me.get());
2194
2195 // A synchronous navigation (about:blank) would have already processed
2196 // onload, so it is possible for the frame to have already been destroyed by
2197 // script in the page.
2198 if (!childFrame->tree()->parent())
2199 return 0;
2200
2201 if (m_client)
2202 m_client->didCreateFrame(this, webframe.get());
2203
2204 return childFrame.release();
2205 }
2206
2207 void WebFrameImpl::didChangeContentsSize(const IntSize& size)
2208 {
2209 // This is only possible on the main frame.
2210 if (m_totalMatchCount > 0) {
2211 ASSERT(!parent());
2212 ++m_findMatchMarkersVersion;
2213 }
2214 }
2215
2216 void WebFrameImpl::createFrameView()
2217 {
2218 TRACE_EVENT0("webkit", "WebFrameImpl::createFrameView");
2219
2220 ASSERT(frame()); // If frame() doesn't exist, we probably didn't init proper ly.
2221
2222 WebViewImpl* webView = viewImpl();
2223 bool isMainFrame = webView->mainFrameImpl()->frame() == frame();
2224 if (isMainFrame)
2225 webView->suppressInvalidations(true);
2226
2227 frame()->createView(webView->size(), Color::white, webView->isTransparent(), webView->fixedLayoutSize(), isMainFrame ? webView->isFixedLayoutModeEnabled() : 0);
2228 if (webView->shouldAutoResize() && isMainFrame)
2229 frame()->view()->enableAutoSizeMode(true, webView->minAutoSize(), webVie w->maxAutoSize());
2230
2231 if (isMainFrame)
2232 webView->suppressInvalidations(false);
2233
2234 if (isMainFrame && webView->devToolsAgentPrivate())
2235 webView->devToolsAgentPrivate()->mainFrameViewCreated(this);
2236 }
2237
2238 WebFrameImpl* WebFrameImpl::fromFrame(Frame* frame)
2239 {
2240 if (!frame)
2241 return 0;
2242 return static_cast<FrameLoaderClientImpl*>(frame->loader()->client())->webFr ame();
2243 }
2244
2245 WebFrameImpl* WebFrameImpl::fromFrameOwnerElement(Element* element)
2246 {
2247 // FIXME: Why do we check specifically for <iframe> and <frame> here? Why ca n't we get the WebFrameImpl from an <object> element, for example.
2248 if (!element || !element->isFrameOwnerElement() || (!element->hasTagName(HTM LNames::iframeTag) && !element->hasTagName(HTMLNames::frameTag)))
2249 return 0;
2250 HTMLFrameOwnerElement* frameElement = toFrameOwnerElement(element);
2251 return fromFrame(frameElement->contentFrame());
2252 }
2253
2254 WebViewImpl* WebFrameImpl::viewImpl() const
2255 {
2256 if (!frame())
2257 return 0;
2258 return WebViewImpl::fromPage(frame()->page());
2259 }
2260
2261 WebDataSourceImpl* WebFrameImpl::dataSourceImpl() const
2262 {
2263 return static_cast<WebDataSourceImpl*>(dataSource());
2264 }
2265
2266 WebDataSourceImpl* WebFrameImpl::provisionalDataSourceImpl() const
2267 {
2268 return static_cast<WebDataSourceImpl*>(provisionalDataSource());
2269 }
2270
2271 void WebFrameImpl::setFindEndstateFocusAndSelection()
2272 {
2273 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
2274
2275 if (this == mainFrameImpl->activeMatchFrame() && m_activeMatch.get()) {
2276 // If the user has set the selection since the match was found, we
2277 // don't focus anything.
2278 VisibleSelection selection(frame()->selection()->selection());
2279 if (!selection.isNone())
2280 return;
2281
2282 // Try to find the first focusable node up the chain, which will, for
2283 // example, focus links if we have found text within the link.
2284 Node* node = m_activeMatch->firstNode();
2285 if (node && node->isInShadowTree()) {
2286 Node* host = node->deprecatedShadowAncestorNode();
2287 if (host->hasTagName(HTMLNames::inputTag) || host->hasTagName(HTMLNa mes::textareaTag))
2288 node = host;
2289 }
2290 while (node && !node->isFocusable() && node != frame()->document())
2291 node = node->parentNode();
2292
2293 if (node && node != frame()->document()) {
2294 // Found a focusable parent node. Set the active match as the
2295 // selection and focus to the focusable node.
2296 frame()->selection()->setSelection(m_activeMatch.get());
2297 frame()->document()->setFocusedNode(node);
2298 return;
2299 }
2300
2301 // Iterate over all the nodes in the range until we find a focusable nod e.
2302 // This, for example, sets focus to the first link if you search for
2303 // text and text that is within one or more links.
2304 node = m_activeMatch->firstNode();
2305 while (node && node != m_activeMatch->pastLastNode()) {
2306 if (node->isFocusable()) {
2307 frame()->document()->setFocusedNode(node);
2308 return;
2309 }
2310 node = NodeTraversal::next(node);
2311 }
2312
2313 // No node related to the active match was focusable, so set the
2314 // active match as the selection (so that when you end the Find session,
2315 // you'll have the last thing you found highlighted) and make sure that
2316 // we have nothing focused (otherwise you might have text selected but
2317 // a link focused, which is weird).
2318 frame()->selection()->setSelection(m_activeMatch.get());
2319 frame()->document()->setFocusedNode(0);
2320
2321 // Finally clear the active match, for two reasons:
2322 // We just finished the find 'session' and we don't want future (potenti ally
2323 // unrelated) find 'sessions' operations to start at the same place.
2324 // The WebFrameImpl could get reused and the m_activeMatch could end up pointing
2325 // to a document that is no longer valid. Keeping an invalid reference a round
2326 // is just asking for trouble.
2327 m_activeMatch = 0;
2328 }
2329 }
2330
2331 void WebFrameImpl::didFail(const ResourceError& error, bool wasProvisional)
2332 {
2333 if (!client())
2334 return;
2335 WebURLError webError = error;
2336 if (wasProvisional)
2337 client()->didFailProvisionalLoad(this, webError);
2338 else
2339 client()->didFailLoad(this, webError);
2340 }
2341
2342 void WebFrameImpl::setCanHaveScrollbars(bool canHaveScrollbars)
2343 {
2344 frame()->view()->setCanHaveScrollbars(canHaveScrollbars);
2345 }
2346
2347 void WebFrameImpl::invalidateArea(AreaToInvalidate area)
2348 {
2349 ASSERT(frame() && frame()->view());
2350 FrameView* view = frame()->view();
2351
2352 if ((area & InvalidateAll) == InvalidateAll)
2353 view->invalidateRect(view->frameRect());
2354 else {
2355 if ((area & InvalidateContentArea) == InvalidateContentArea) {
2356 IntRect contentArea(
2357 view->x(), view->y(), view->visibleWidth(), view->visibleHeight( ));
2358 IntRect frameRect = view->frameRect();
2359 contentArea.move(-frameRect.x(), -frameRect.y());
2360 view->invalidateRect(contentArea);
2361 }
2362 }
2363
2364 if ((area & InvalidateScrollbar) == InvalidateScrollbar) {
2365 // Invalidate the vertical scroll bar region for the view.
2366 Scrollbar* scrollbar = view->verticalScrollbar();
2367 if (scrollbar)
2368 scrollbar->invalidate();
2369 }
2370 }
2371
2372 void WebFrameImpl::addMarker(Range* range, bool activeMatch)
2373 {
2374 frame()->document()->markers()->addTextMatchMarker(range, activeMatch);
2375 }
2376
2377 void WebFrameImpl::setMarkerActive(Range* range, bool active)
2378 {
2379 WebCore::ExceptionCode ec;
2380 if (!range || range->collapsed(ec))
2381 return;
2382 frame()->document()->markers()->setMarkersActive(range, active);
2383 }
2384
2385 int WebFrameImpl::ordinalOfFirstMatchForFrame(WebFrameImpl* frame) const
2386 {
2387 int ordinal = 0;
2388 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
2389 // Iterate from the main frame up to (but not including) |frame| and
2390 // add up the number of matches found so far.
2391 for (WebFrameImpl* it = mainFrameImpl; it != frame; it = static_cast<WebFram eImpl*>(it->traverseNext(true))) {
2392 if (it->m_lastMatchCount > 0)
2393 ordinal += it->m_lastMatchCount;
2394 }
2395 return ordinal;
2396 }
2397
2398 bool WebFrameImpl::shouldScopeMatches(const String& searchText)
2399 {
2400 // Don't scope if we can't find a frame or a view.
2401 // The user may have closed the tab/application, so abort.
2402 // Also ignore detached frames, as many find operations report to the main f rame.
2403 if (!frame() || !frame()->view() || !frame()->page() || !hasVisibleContent() )
2404 return false;
2405
2406 ASSERT(frame()->document() && frame()->view());
2407
2408 // If the frame completed the scoping operation and found 0 matches the last
2409 // time it was searched, then we don't have to search it again if the user i s
2410 // just adding to the search string or sending the same search string again.
2411 if (m_lastFindRequestCompletedWithNoMatches && !m_lastSearchString.isEmpty() ) {
2412 // Check to see if the search string prefixes match.
2413 String previousSearchPrefix =
2414 searchText.substring(0, m_lastSearchString.length());
2415
2416 if (previousSearchPrefix == m_lastSearchString)
2417 return false; // Don't search this frame, it will be fruitless.
2418 }
2419
2420 return true;
2421 }
2422
2423 void WebFrameImpl::scopeStringMatchesSoon(int identifier, const WebString& searc hText, const WebFindOptions& options, bool reset)
2424 {
2425 m_deferredScopingWork.append(new DeferredScopeStringMatches(this, identifier , searchText, options, reset));
2426 }
2427
2428 void WebFrameImpl::callScopeStringMatches(DeferredScopeStringMatches* caller, in t identifier, const WebString& searchText, const WebFindOptions& options, bool r eset)
2429 {
2430 m_deferredScopingWork.remove(m_deferredScopingWork.find(caller));
2431 scopeStringMatches(identifier, searchText, options, reset);
2432
2433 // This needs to happen last since searchText is passed by reference.
2434 delete caller;
2435 }
2436
2437 void WebFrameImpl::invalidateIfNecessary()
2438 {
2439 if (m_lastMatchCount <= m_nextInvalidateAfter)
2440 return;
2441
2442 // FIXME: (http://b/1088165) Optimize the drawing of the tickmarks and
2443 // remove this. This calculation sets a milestone for when next to
2444 // invalidate the scrollbar and the content area. We do this so that we
2445 // don't spend too much time drawing the scrollbar over and over again.
2446 // Basically, up until the first 500 matches there is no throttle.
2447 // After the first 500 matches, we set set the milestone further and
2448 // further out (750, 1125, 1688, 2K, 3K).
2449 static const int startSlowingDownAfter = 500;
2450 static const int slowdown = 750;
2451
2452 int i = m_lastMatchCount / startSlowingDownAfter;
2453 m_nextInvalidateAfter += i * slowdown;
2454 invalidateArea(InvalidateScrollbar);
2455 }
2456
2457 void WebFrameImpl::loadJavaScriptURL(const KURL& url)
2458 {
2459 // This is copied from ScriptController::executeScriptIfJavaScriptURL.
2460 // Unfortunately, we cannot just use that method since it is private, and
2461 // it also doesn't quite behave as we require it to for bookmarklets. The
2462 // key difference is that we need to suppress loading the string result
2463 // from evaluating the JS URL if executing the JS URL resulted in a
2464 // location change. We also allow a JS URL to be loaded even if scripts on
2465 // the page are otherwise disabled.
2466
2467 if (!frame()->document() || !frame()->page())
2468 return;
2469
2470 RefPtr<Document> ownerDocument(frame()->document());
2471
2472 // Protect privileged pages against bookmarklets and other javascript manipu lations.
2473 if (SchemeRegistry::shouldTreatURLSchemeAsNotAllowingJavascriptURLs(frame()- >document()->url().protocol()))
2474 return;
2475
2476 String script = decodeURLEscapeSequences(url.string().substring(strlen("java script:")));
2477 ScriptValue result = frame()->script()->executeScript(script, true);
2478
2479 String scriptResult;
2480 if (!result.getString(scriptResult))
2481 return;
2482
2483 if (!frame()->navigationScheduler()->locationChangePending())
2484 frame()->document()->loader()->replaceDocument(scriptResult, ownerDocume nt.get());
2485 }
2486
2487 void WebFrameImpl::willDetachPage()
2488 {
2489 if (!frame() || !frame()->page())
2490 return;
2491
2492 // Do not expect string scoping results from any frames that got detached
2493 // in the middle of the operation.
2494 if (m_scopingInProgress) {
2495
2496 // There is a possibility that the frame being detached was the only
2497 // pending one. We need to make sure final replies can be sent.
2498 flushCurrentScopingEffort(m_findRequestIdentifier);
2499
2500 cancelPendingScopingEffort();
2501 }
2502 }
2503
2504 } // namespace WebKit
OLDNEW
« no previous file with comments | « Source/WebKit/chromium/src/WebFrameImpl.h ('k') | Source/web/WebFrameImpl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698