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

Side by Side Diff: trunk/Source/web/TextFinder.cpp

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

Powered by Google App Engine
This is Rietveld 408576698