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

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

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

Powered by Google App Engine
This is Rietveld 408576698