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

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

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

Powered by Google App Engine
This is Rietveld 408576698