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

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

Powered by Google App Engine
This is Rietveld 408576698