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

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

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