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

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

Issue 1959183002: Multi-Process Find-in-Page. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Disabled tests on Android Release because of crbug.com/615291. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2009 Google Inc. All rights reserved. 2 * Copyright (C) 2009 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 const WebString m_searchText; 110 const WebString m_searchText;
111 const WebFindOptions m_options; 111 const WebFindOptions m_options;
112 const bool m_reset; 112 const bool m_reset;
113 }; 113 };
114 114
115 bool TextFinder::find(int identifier, const WebString& searchText, const WebFind Options& options, bool wrapWithinFrame, WebRect* selectionRect, bool* activeNow) 115 bool TextFinder::find(int identifier, const WebString& searchText, const WebFind Options& options, bool wrapWithinFrame, WebRect* selectionRect, bool* activeNow)
116 { 116 {
117 if (!ownerFrame().frame() || !ownerFrame().frame()->page()) 117 if (!ownerFrame().frame() || !ownerFrame().frame()->page())
118 return false; 118 return false;
119 119
120 WebLocalFrameImpl* mainFrameImpl = ownerFrame().viewImpl()->mainFrameImpl();
121
122 if (!options.findNext) 120 if (!options.findNext)
123 unmarkAllTextMatches(); 121 unmarkAllTextMatches();
124 else 122 else
125 setMarkerActive(m_activeMatch.get(), false); 123 setMarkerActive(m_activeMatch.get(), false);
126 124
127 if (m_activeMatch && &m_activeMatch->ownerDocument() != ownerFrame().frame() ->document()) 125 if (m_activeMatch && &m_activeMatch->ownerDocument() != ownerFrame().frame() ->document())
128 m_activeMatch = nullptr; 126 m_activeMatch = nullptr;
129 127
130 // If the user has selected something since the last Find operation we want 128 // If the user has selected something since the last Find operation we want
131 // to start from there. Otherwise, we start searching from where the last Fi nd 129 // to start from there. Otherwise, we start searching from where the last Fi nd
(...skipping 25 matching lines...) Expand all
157 return false; 155 return false;
158 } 156 }
159 157
160 // If the user is browsing a page with autosizing, adjust the zoom to the 158 // If the user is browsing a page with autosizing, adjust the zoom to the
161 // column where the next hit has been found. Doing this when autosizing is 159 // column where the next hit has been found. Doing this when autosizing is
162 // not set will result in a zoom reset on small devices. 160 // not set will result in a zoom reset on small devices.
163 if (ownerFrame().frame()->document()->textAutosizer()->pageNeedsAutosizing() ) { 161 if (ownerFrame().frame()->document()->textAutosizer()->pageNeedsAutosizing() ) {
164 ownerFrame().viewImpl()->zoomToFindInPageRect(ownerFrame().frameView()-> contentsToRootFrame(enclosingIntRect(LayoutObject::absoluteBoundingBoxRectForRan ge(m_activeMatch.get())))); 162 ownerFrame().viewImpl()->zoomToFindInPageRect(ownerFrame().frameView()-> contentsToRootFrame(enclosingIntRect(LayoutObject::absoluteBoundingBoxRectForRan ge(m_activeMatch.get()))));
165 } 163 }
166 164
167 WebLocalFrameImpl* oldActiveFrame = mainFrameImpl->ensureTextFinder().m_curr entActiveMatchFrame; 165 bool wasActiveFrame = m_currentActiveMatchFrame;
168 mainFrameImpl->ensureTextFinder().m_currentActiveMatchFrame = &ownerFrame(); 166 m_currentActiveMatchFrame = true;
169
170 // Make sure no node is focused. See http://crbug.com/38700.
171 ownerFrame().frame()->document()->clearFocusedElement();
172 167
173 bool isActive = setMarkerActive(m_activeMatch.get(), true); 168 bool isActive = setMarkerActive(m_activeMatch.get(), true);
174 if (activeNow) 169 if (activeNow)
175 *activeNow = isActive; 170 *activeNow = isActive;
176 171
172 // Make sure no node is focused. See http://crbug.com/38700.
173 ownerFrame().frame()->document()->clearFocusedElement();
174
175 // Set this frame as focused.
176 ownerFrame().viewImpl()->setFocusedFrame(&ownerFrame());
177
177 if (!options.findNext || activeSelection || !isActive) { 178 if (!options.findNext || activeSelection || !isActive) {
178 // This is either a Find operation, a Find-next from a new start point 179 // This is either an initial Find operation, a Find-next from a new
179 // due to a selection, or new matches were found during Find-next due 180 // start point due to a selection, or new matches were found during
180 // to DOM alteration (that couldn't be set as active), so we set the 181 // Find-next due to DOM alteration (that couldn't be set as active), so
181 // flag to ask the scoping effort to find the active rect for us and 182 // we set the flag to ask the scoping effort to find the active rect for
182 // report it back to the UI. 183 // us and report it back to the UI.
183 m_locatingActiveRect = true; 184 m_locatingActiveRect = true;
184 } else { 185 } else {
185 if (oldActiveFrame != &ownerFrame()) { 186 if (!wasActiveFrame) {
186 if (options.forward) 187 if (options.forward)
187 m_activeMatchIndexInCurrentFrame = 0; 188 m_activeMatchIndex = 0;
188 else 189 else
189 m_activeMatchIndexInCurrentFrame = m_lastMatchCount - 1; 190 m_activeMatchIndex = m_lastMatchCount - 1;
190 } else { 191 } else {
191 if (options.forward) 192 if (options.forward)
192 ++m_activeMatchIndexInCurrentFrame; 193 ++m_activeMatchIndex;
193 else 194 else
194 --m_activeMatchIndexInCurrentFrame; 195 --m_activeMatchIndex;
195 196
196 if (m_activeMatchIndexInCurrentFrame + 1 > m_lastMatchCount) 197 if (m_activeMatchIndex + 1 > m_lastMatchCount)
197 m_activeMatchIndexInCurrentFrame = 0; 198 m_activeMatchIndex = 0;
198 if (m_activeMatchIndexInCurrentFrame == -1) 199 else if (m_activeMatchIndex < 0)
199 m_activeMatchIndexInCurrentFrame = m_lastMatchCount - 1; 200 m_activeMatchIndex = m_lastMatchCount - 1;
200 } 201 }
201 if (selectionRect) { 202 if (selectionRect) {
202 *selectionRect = ownerFrame().frameView()->contentsToRootFrame(m_act iveMatch->boundingBox()); 203 *selectionRect = ownerFrame().frameView()->contentsToRootFrame(m_act iveMatch->boundingBox());
203 reportFindInPageSelection(*selectionRect, m_activeMatchIndexInCurren tFrame + 1, identifier); 204 reportFindInPageSelection(*selectionRect, m_activeMatchIndex + 1, id entifier);
204 } 205 }
205 } 206 }
206 207
207 return true; 208 return true;
208 } 209 }
209 210
211 void TextFinder::clearActiveFindMatch()
212 {
213 m_currentActiveMatchFrame = false;
214 setMarkerActive(m_activeMatch.get(), false);
215 }
216
210 void TextFinder::stopFindingAndClearSelection() 217 void TextFinder::stopFindingAndClearSelection()
211 { 218 {
212 cancelPendingScopingEffort(); 219 cancelPendingScopingEffort();
213 220
214 // Remove all markers for matches found and turn off the highlighting. 221 // Remove all markers for matches found and turn off the highlighting.
215 ownerFrame().frame()->document()->markers().removeMarkers(DocumentMarker::Te xtMatch); 222 ownerFrame().frame()->document()->markers().removeMarkers(DocumentMarker::Te xtMatch);
216 ownerFrame().frame()->editor().setMarkedTextMatchesAreHighlighted(false); 223 ownerFrame().frame()->editor().setMarkedTextMatchesAreHighlighted(false);
217 clearFindMatchesCache(); 224 clearFindMatchesCache();
218 resetActiveMatch(); 225 resetActiveMatch();
219 226
220 // Let the frame know that we don't want tickmarks anymore. 227 // Let the frame know that we don't want tickmarks anymore.
221 ownerFrame().frameView()->invalidatePaintForTickmarks(); 228 ownerFrame().frameView()->invalidatePaintForTickmarks();
222 } 229 }
223 230
224 void TextFinder::reportFindInPageResultToAccessibility(int identifier) 231 void TextFinder::reportFindInPageResultToAccessibility(int identifier)
225 { 232 {
226 AXObjectCacheImpl* axObjectCache = toAXObjectCacheImpl(ownerFrame().frame()- >document()->existingAXObjectCache()); 233 AXObjectCacheImpl* axObjectCache = toAXObjectCacheImpl(ownerFrame().frame()- >document()->existingAXObjectCache());
227 if (!axObjectCache) 234 if (!axObjectCache)
228 return; 235 return;
229 236
230 AXObject* startObject = axObjectCache->get(m_activeMatch->startContainer()); 237 AXObject* startObject = axObjectCache->get(m_activeMatch->startContainer());
231 AXObject* endObject = axObjectCache->get(m_activeMatch->endContainer()); 238 AXObject* endObject = axObjectCache->get(m_activeMatch->endContainer());
232 if (!startObject || !endObject) 239 if (!startObject || !endObject)
233 return; 240 return;
234 241
235 WebLocalFrameImpl* mainFrameImpl = ownerFrame().viewImpl()->mainFrameImpl(); 242 if (ownerFrame().client()) {
236 if (mainFrameImpl && mainFrameImpl->client()) { 243 ownerFrame().client()->handleAccessibilityFindInPageResult(
237 mainFrameImpl->client()->handleAccessibilityFindInPageResult( 244 identifier, m_activeMatchIndex + 1,
238 identifier, m_activeMatchIndexInCurrentFrame + 1,
239 WebAXObject(startObject), m_activeMatch->startOffset(), 245 WebAXObject(startObject), m_activeMatch->startOffset(),
240 WebAXObject(endObject), m_activeMatch->endOffset()); 246 WebAXObject(endObject), m_activeMatch->endOffset());
241 } 247 }
242 } 248 }
243 249
244 void TextFinder::scopeStringMatches(int identifier, const WebString& searchText, const WebFindOptions& options, bool reset) 250 void TextFinder::scopeStringMatches(int identifier, const WebString& searchText, const WebFindOptions& options, bool reset)
245 { 251 {
246 if (reset) { 252 if (reset) {
247 // This is a brand new search, so we need to reset everything. 253 // This is a brand new search, so we need to reset everything.
248 // Scoping is just about to begin. 254 // Scoping is just about to begin.
(...skipping 10 matching lines...) Expand all
259 clearFindMatchesCache(); 265 clearFindMatchesCache();
260 266
261 // Clear the counters from last operation. 267 // Clear the counters from last operation.
262 m_lastMatchCount = 0; 268 m_lastMatchCount = 0;
263 m_nextInvalidateAfter = 0; 269 m_nextInvalidateAfter = 0;
264 m_resumeScopingFromRange = nullptr; 270 m_resumeScopingFromRange = nullptr;
265 271
266 // The view might be null on detached frames. 272 // The view might be null on detached frames.
267 LocalFrame* frame = ownerFrame().frame(); 273 LocalFrame* frame = ownerFrame().frame();
268 if (frame && frame->page()) 274 if (frame && frame->page())
269 ownerFrame().viewImpl()->mainFrameImpl()->ensureTextFinder().m_frame sScopingCount++; 275 m_frameScoping = true;
270 276
271 // Now, defer scoping until later to allow find operation to finish quic kly. 277 // Now, defer scoping until later to allow find operation to finish quic kly.
272 scopeStringMatchesSoon(identifier, searchText, options, false); // false means just reset, so don't do it again. 278 scopeStringMatchesSoon(identifier, searchText, options, false); // false means just reset, so don't do it again.
273 return; 279 return;
274 } 280 }
275 281
276 if (!shouldScopeMatches(searchText)) { 282 if (!shouldScopeMatches(searchText)) {
277 // Note that we want to defer the final update when resetting even if sh ouldScopeMatches returns false.
278 // This is done in order to prevent sending a final message based only o n the results of the first frame
279 // since m_framesScopingCount would be 0 as other frames have yet to res et.
280 finishCurrentScopingEffort(identifier); 283 finishCurrentScopingEffort(identifier);
281 return; 284 return;
282 } 285 }
283 286
284 WebLocalFrameImpl* mainFrameImpl = ownerFrame().viewImpl()->mainFrameImpl();
285 PositionInFlatTree searchStart = PositionInFlatTree::firstPositionInNode(own erFrame().frame()->document()); 287 PositionInFlatTree searchStart = PositionInFlatTree::firstPositionInNode(own erFrame().frame()->document());
286 PositionInFlatTree searchEnd = PositionInFlatTree::lastPositionInNode(ownerF rame().frame()->document()); 288 PositionInFlatTree searchEnd = PositionInFlatTree::lastPositionInNode(ownerF rame().frame()->document());
287 DCHECK_EQ(searchStart.document(), searchEnd.document()); 289 DCHECK_EQ(searchStart.document(), searchEnd.document());
288 290
289 if (m_resumeScopingFromRange) { 291 if (m_resumeScopingFromRange) {
290 // This is a continuation of a scoping operation that timed out and didn 't 292 // This is a continuation of a scoping operation that timed out and didn 't
291 // complete last time around, so we should start from where we left off. 293 // complete last time around, so we should start from where we left off.
292 DCHECK(m_resumeScopingFromRange->collapsed()); 294 DCHECK(m_resumeScopingFromRange->collapsed());
293 searchStart = fromPositionInDOMTree<EditingInFlatTreeStrategy>(m_resumeS copingFromRange->endPosition()); 295 searchStart = fromPositionInDOMTree<EditingInFlatTreeStrategy>(m_resumeS copingFromRange->endPosition());
294 if (searchStart.document() != searchEnd.document()) 296 if (searchStart.document() != searchEnd.document())
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 m_activeMatch->boundingBox() : resultBounds; 336 m_activeMatch->boundingBox() : resultBounds;
335 } 337 }
336 338
337 // If the Find function found a match it will have stored where the 339 // If the Find function found a match it will have stored where the
338 // match was found in m_activeSelectionRect on the current frame. If we 340 // match was found in m_activeSelectionRect on the current frame. If we
339 // find this rect during scoping it means we have found the active 341 // find this rect during scoping it means we have found the active
340 // tickmark. 342 // tickmark.
341 bool foundActiveMatch = false; 343 bool foundActiveMatch = false;
342 if (m_locatingActiveRect && (activeSelectionRect == resultBounds)) { 344 if (m_locatingActiveRect && (activeSelectionRect == resultBounds)) {
343 // We have found the active tickmark frame. 345 // We have found the active tickmark frame.
344 mainFrameImpl->ensureTextFinder().m_currentActiveMatchFrame = &owner Frame(); 346 m_currentActiveMatchFrame = true;
345 foundActiveMatch = true; 347 foundActiveMatch = true;
346 // We also know which tickmark is active now. 348 // We also know which tickmark is active now.
347 m_activeMatchIndexInCurrentFrame = matchCount - 1; 349 m_activeMatchIndex = matchCount - 1;
348 // To stop looking for the active tickmark, we set this flag. 350 // To stop looking for the active tickmark, we set this flag.
349 m_locatingActiveRect = false; 351 m_locatingActiveRect = false;
350 352
351 // Notify browser of new location for the selected rectangle. 353 // Notify browser of new location for the selected rectangle.
352 reportFindInPageSelection( 354 reportFindInPageSelection(
353 ownerFrame().frameView()->contentsToRootFrame(resultBounds), 355 ownerFrame().frameView()->contentsToRootFrame(resultBounds),
354 m_activeMatchIndexInCurrentFrame + 1, 356 m_activeMatchIndex + 1,
355 identifier); 357 identifier);
356 } 358 }
357 359
358 addMarker(resultRange, foundActiveMatch); 360 addMarker(resultRange, foundActiveMatch);
359 361
360 m_findMatchesCache.append(FindMatch(resultRange, m_lastMatchCount + matc hCount)); 362 m_findMatchesCache.append(FindMatch(resultRange, m_lastMatchCount + matc hCount));
361 363
362 // Set the new start for the search range to be the end of the previous 364 // Set the new start for the search range to be the end of the previous
363 // result range. There is no need to use a VisiblePosition here, 365 // result range. There is no need to use a VisiblePosition here,
364 // since findPlainText will use a TextIterator to go over the visible 366 // since findPlainText will use a TextIterator to go over the visible
365 // text nodes. 367 // text nodes.
366 searchStart = result.endPosition(); 368 searchStart = result.endPosition();
367 369
368 m_resumeScopingFromRange = Range::create(result.document(), toPositionIn DOMTree(result.endPosition()), toPositionInDOMTree(result.endPosition())); 370 m_resumeScopingFromRange = Range::create(result.document(), toPositionIn DOMTree(result.endPosition()), toPositionInDOMTree(result.endPosition()));
369 timedOut = (currentTime() - startTime) >= maxScopingDuration; 371 timedOut = (currentTime() - startTime) >= maxScopingDuration;
370 } while (!timedOut); 372 } while (!timedOut);
371 373
372 // Remember what we search for last time, so we can skip searching if more 374 // Remember what we search for last time, so we can skip searching if more
373 // letters are added to the search string (and last outcome was 0). 375 // letters are added to the search string (and last outcome was 0).
374 m_lastSearchString = searchText; 376 m_lastSearchString = searchText;
375 377
376 if (matchCount > 0) { 378 if (matchCount > 0) {
377 ownerFrame().frame()->editor().setMarkedTextMatchesAreHighlighted(true); 379 ownerFrame().frame()->editor().setMarkedTextMatchesAreHighlighted(true);
378 380
379 m_lastMatchCount += matchCount; 381 m_lastMatchCount += matchCount;
380 382
381 ownerFrame().client()->reportFindInFrameMatchCount(identifier, m_lastMat chCount, false); 383 ownerFrame().client()->reportFindInFrameMatchCount(identifier, m_lastMat chCount, false);
382 384
383 // Let the mainframe know how much we found during this pass. 385 // Let the frame know how many matches we found during this pass.
384 mainFrameImpl->increaseMatchCount(matchCount, identifier); 386 ownerFrame().increaseMatchCount(matchCount, identifier);
385 } 387 }
386 388
387 if (timedOut) { 389 if (timedOut) {
388 // If we found anything during this pass, we should redraw. However, we 390 // If we found anything during this pass, we should redraw. However, we
389 // don't want to spam too much if the page is extremely long, so if we 391 // don't want to spam too much if the page is extremely long, so if we
390 // reach a certain point we start throttling the redraw requests. 392 // reach a certain point we start throttling the redraw requests.
391 if (matchCount > 0) 393 if (matchCount > 0)
392 invalidateIfNecessary(); 394 invalidateIfNecessary();
393 395
394 // Scoping effort ran out of time, lets ask for another time-slice. 396 // Scoping effort ran out of time, lets ask for another time-slice.
395 scopeStringMatchesSoon( 397 scopeStringMatchesSoon(
396 identifier, 398 identifier,
397 searchText, 399 searchText,
398 options, 400 options,
399 false); // don't reset. 401 false); // don't reset.
400 return; // Done for now, resume work later. 402 return; // Done for now, resume work later.
401 } 403 }
402 404
403 finishCurrentScopingEffort(identifier); 405 finishCurrentScopingEffort(identifier);
404 } 406 }
405 407
406 void TextFinder::flushCurrentScopingEffort(int identifier) 408 void TextFinder::flushCurrentScopingEffort(int identifier)
407 { 409 {
408 if (!ownerFrame().frame() || !ownerFrame().frame()->page()) 410 if (!ownerFrame().frame() || !ownerFrame().frame()->page())
409 return; 411 return;
410 412
411 WebLocalFrameImpl* mainFrameImpl = ownerFrame().viewImpl()->mainFrameImpl(); 413 m_frameScoping = false;
412 mainFrameImpl->ensureTextFinder().decrementFramesScopingCount(identifier); 414 ownerFrame().increaseMatchCount(0, identifier);
413 } 415 }
414 416
415 void TextFinder::finishCurrentScopingEffort(int identifier) 417 void TextFinder::finishCurrentScopingEffort(int identifier)
416 { 418 {
417 flushCurrentScopingEffort(identifier); 419 flushCurrentScopingEffort(identifier);
418 420
419 m_scopingInProgress = false; 421 m_scopingInProgress = false;
420 m_lastFindRequestCompletedWithNoMatches = !m_lastMatchCount; 422 m_lastFindRequestCompletedWithNoMatches = !m_lastMatchCount;
421 423
422 ownerFrame().client()->reportFindInFrameMatchCount(identifier, m_lastMatchCo unt, true); 424 ownerFrame().client()->reportFindInFrameMatchCount(identifier, m_lastMatchCo unt, true);
423 425
424 // This frame is done, so show any scrollbar tickmarks we haven't drawn yet. 426 // This frame is done, so show any scrollbar tickmarks we haven't drawn yet.
425 ownerFrame().frameView()->invalidatePaintForTickmarks(); 427 ownerFrame().frameView()->invalidatePaintForTickmarks();
426 } 428 }
427 429
428 void TextFinder::cancelPendingScopingEffort() 430 void TextFinder::cancelPendingScopingEffort()
429 { 431 {
430 for (DeferredScopeStringMatches* deferredWork : m_deferredScopingWork) 432 for (DeferredScopeStringMatches* deferredWork : m_deferredScopingWork)
431 deferredWork->dispose(); 433 deferredWork->dispose();
432 m_deferredScopingWork.clear(); 434 m_deferredScopingWork.clear();
433 435
434 m_activeMatchIndexInCurrentFrame = -1; 436 m_activeMatchIndex = -1;
435 437
436 // Last request didn't complete. 438 // Last request didn't complete.
437 if (m_scopingInProgress) 439 if (m_scopingInProgress)
438 m_lastFindRequestCompletedWithNoMatches = false; 440 m_lastFindRequestCompletedWithNoMatches = false;
439 441
440 m_scopingInProgress = false; 442 m_scopingInProgress = false;
441 } 443 }
442 444
443 void TextFinder::increaseMatchCount(int identifier, int count) 445 void TextFinder::increaseMatchCount(int identifier, int count)
444 { 446 {
445 if (count) 447 if (count)
446 ++m_findMatchMarkersVersion; 448 ++m_findMatchMarkersVersion;
447 449
448 m_totalMatchCount += count; 450 m_totalMatchCount += count;
449 451
450 // Update the UI with the latest findings. 452 // Update the UI with the latest findings.
451 if (ownerFrame().client()) 453 if (ownerFrame().client())
452 ownerFrame().client()->reportFindInPageMatchCount(identifier, m_totalMat chCount, !m_framesScopingCount); 454 ownerFrame().client()->reportFindInPageMatchCount(identifier, m_totalMat chCount, !m_frameScoping);
453 } 455 }
454 456
455 void TextFinder::reportFindInPageSelection(const WebRect& selectionRect, int act iveMatchOrdinal, int identifier) 457 void TextFinder::reportFindInPageSelection(const WebRect& selectionRect, int act iveMatchOrdinal, int identifier)
456 { 458 {
457 // Update the UI with the latest selection rect. 459 // Update the UI with the latest selection rect.
458 if (ownerFrame().client()) 460 if (ownerFrame().client())
459 ownerFrame().client()->reportFindInPageSelection(identifier, ordinalOfFi rstMatch() + activeMatchOrdinal, selectionRect); 461 ownerFrame().client()->reportFindInPageSelection(identifier, activeMatch Ordinal, selectionRect);
460 462
461 // Update accessibility too, so if the user commits to this query 463 // Update accessibility too, so if the user commits to this query
462 // we can move accessibility focus to this result. 464 // we can move accessibility focus to this result.
463 reportFindInPageResultToAccessibility(identifier); 465 reportFindInPageResultToAccessibility(identifier);
464 } 466 }
465 467
466 void TextFinder::resetMatchCount() 468 void TextFinder::resetMatchCount()
467 { 469 {
468 if (m_totalMatchCount > 0) 470 if (m_totalMatchCount > 0)
469 ++m_findMatchMarkersVersion; 471 ++m_findMatchMarkersVersion;
470 472
471 m_totalMatchCount = 0; 473 m_totalMatchCount = 0;
472 m_framesScopingCount = 0; 474 m_frameScoping = false;
473 } 475 }
474 476
475 void TextFinder::clearFindMatchesCache() 477 void TextFinder::clearFindMatchesCache()
476 { 478 {
477 if (!m_findMatchesCache.isEmpty()) 479 if (!m_findMatchesCache.isEmpty())
478 ownerFrame().viewImpl()->mainFrameImpl()->ensureTextFinder().m_findMatch MarkersVersion++; 480 ++m_findMatchMarkersVersion;
479 481
480 m_findMatchesCache.clear(); 482 m_findMatchesCache.clear();
481 m_findMatchRectsAreValid = false; 483 m_findMatchRectsAreValid = false;
482 } 484 }
483 485
484 bool TextFinder::isActiveMatchFrameValid() const
485 {
486 WebLocalFrameImpl* mainFrameImpl = ownerFrame().viewImpl()->mainFrameImpl();
487 if (!mainFrameImpl->textFinder())
488 return false;
489
490 if (WebLocalFrameImpl* activeMatchFrame = mainFrameImpl->textFinder()->activ eMatchFrame())
491 return activeMatchFrame->textFinder()->activeMatch() && activeMatchFrame ->frame()->tree().isDescendantOf(mainFrameImpl->frame());
492 return false;
493 }
494
495 void TextFinder::updateFindMatchRects() 486 void TextFinder::updateFindMatchRects()
496 { 487 {
497 IntSize currentContentsSize = ownerFrame().contentsSize(); 488 IntSize currentContentsSize = ownerFrame().contentsSize();
498 if (m_contentsSizeForCurrentFindMatchRects != currentContentsSize) { 489 if (m_contentsSizeForCurrentFindMatchRects != currentContentsSize) {
499 m_contentsSizeForCurrentFindMatchRects = currentContentsSize; 490 m_contentsSizeForCurrentFindMatchRects = currentContentsSize;
500 m_findMatchRectsAreValid = false; 491 m_findMatchRectsAreValid = false;
501 } 492 }
502 493
503 size_t deadMatches = 0; 494 size_t deadMatches = 0;
504 for (FindMatch& match : m_findMatchesCache) { 495 for (FindMatch& match : m_findMatchesCache) {
(...skipping 22 matching lines...) Expand all
527 // Invalidate the rects in child frames. Will be updated later during traver sal. 518 // Invalidate the rects in child frames. Will be updated later during traver sal.
528 if (!m_findMatchRectsAreValid) 519 if (!m_findMatchRectsAreValid)
529 for (WebFrame* child = ownerFrame().firstChild(); child; child = child-> nextSibling()) 520 for (WebFrame* child = ownerFrame().firstChild(); child; child = child-> nextSibling())
530 toWebLocalFrameImpl(child)->ensureTextFinder().m_findMatchRectsAreVa lid = false; 521 toWebLocalFrameImpl(child)->ensureTextFinder().m_findMatchRectsAreVa lid = false;
531 522
532 m_findMatchRectsAreValid = true; 523 m_findMatchRectsAreValid = true;
533 } 524 }
534 525
535 WebFloatRect TextFinder::activeFindMatchRect() 526 WebFloatRect TextFinder::activeFindMatchRect()
536 { 527 {
537 if (!isActiveMatchFrameValid()) 528 if (!m_currentActiveMatchFrame || !m_activeMatch)
538 return WebFloatRect(); 529 return WebFloatRect();
539 530
540 return WebFloatRect(findInPageRectFromRange(m_currentActiveMatchFrame->textF inder()->activeMatch())); 531 return WebFloatRect(findInPageRectFromRange(activeMatch()));
541 } 532 }
542 533
543 void TextFinder::findMatchRects(WebVector<WebFloatRect>& outputRects) 534 void TextFinder::findMatchRects(WebVector<WebFloatRect>& outputRects)
544 { 535 {
536 updateFindMatchRects();
537
545 Vector<WebFloatRect> matchRects; 538 Vector<WebFloatRect> matchRects;
546 for (WebLocalFrameImpl* frame = &ownerFrame(); frame; frame = toWebLocalFram eImpl(frame->traverseNextLocal(false))) 539 matchRects.reserveCapacity(matchRects.size() + m_findMatchesCache.size());
547 frame->ensureTextFinder().appendFindMatchRects(matchRects); 540 for (const FindMatch& match : m_findMatchesCache) {
541 DCHECK(!match.m_rect.isEmpty());
542 matchRects.append(match.m_rect);
543 }
548 544
549 outputRects = matchRects; 545 outputRects = matchRects;
550 } 546 }
551 547
552 void TextFinder::appendFindMatchRects(Vector<WebFloatRect>& frameRects)
553 {
554 updateFindMatchRects();
555 frameRects.reserveCapacity(frameRects.size() + m_findMatchesCache.size());
556 for (const FindMatch& match : m_findMatchesCache) {
557 DCHECK(!match.m_rect.isEmpty());
558 frameRects.append(match.m_rect);
559 }
560 }
561
562 int TextFinder::selectNearestFindMatch(const WebFloatPoint& point, WebRect* sele ctionRect) 548 int TextFinder::selectNearestFindMatch(const WebFloatPoint& point, WebRect* sele ctionRect)
563 { 549 {
564 TextFinder* bestFinder = nullptr; 550 int index = nearestFindMatch(point, nullptr);
565 int indexInBestFrame = -1; 551 if (index != -1)
566 float distanceInBestFrame = FLT_MAX; 552 return selectFindMatch(static_cast<unsigned>(index), selectionRect);
567
568 for (WebLocalFrameImpl* frame = &ownerFrame(); frame; frame = toWebLocalFram eImpl(frame->traverseNextLocal(false))) {
569 float distanceInFrame;
570 TextFinder& finder = frame->ensureTextFinder();
571 int indexInFrame = finder.nearestFindMatch(point, distanceInFrame);
572 if (distanceInFrame < distanceInBestFrame) {
573 bestFinder = &finder;
574 indexInBestFrame = indexInFrame;
575 distanceInBestFrame = distanceInFrame;
576 }
577 }
578
579 if (indexInBestFrame != -1)
580 return bestFinder->selectFindMatch(static_cast<unsigned>(indexInBestFram e), selectionRect);
581 553
582 return -1; 554 return -1;
583 } 555 }
584 556
585 int TextFinder::nearestFindMatch(const FloatPoint& point, float& distanceSquared ) 557 int TextFinder::nearestFindMatch(const FloatPoint& point, float* distanceSquared )
586 { 558 {
587 updateFindMatchRects(); 559 updateFindMatchRects();
588 560
589 int nearest = -1; 561 int nearest = -1;
590 distanceSquared = FLT_MAX; 562 float nearestDistanceSquared = FLT_MAX;
591 for (size_t i = 0; i < m_findMatchesCache.size(); ++i) { 563 for (size_t i = 0; i < m_findMatchesCache.size(); ++i) {
592 DCHECK(!m_findMatchesCache[i].m_rect.isEmpty()); 564 DCHECK(!m_findMatchesCache[i].m_rect.isEmpty());
593 FloatSize offset = point - m_findMatchesCache[i].m_rect.center(); 565 FloatSize offset = point - m_findMatchesCache[i].m_rect.center();
594 float width = offset.width(); 566 float width = offset.width();
595 float height = offset.height(); 567 float height = offset.height();
596 float currentDistanceSquared = width * width + height * height; 568 float currentDistanceSquared = width * width + height * height;
597 if (currentDistanceSquared < distanceSquared) { 569 if (currentDistanceSquared < nearestDistanceSquared) {
598 nearest = i; 570 nearest = i;
599 distanceSquared = currentDistanceSquared; 571 nearestDistanceSquared = currentDistanceSquared;
600 } 572 }
601 } 573 }
574
575 if (distanceSquared)
576 *distanceSquared = nearestDistanceSquared;
577
602 return nearest; 578 return nearest;
603 } 579 }
604 580
605 int TextFinder::selectFindMatch(unsigned index, WebRect* selectionRect) 581 int TextFinder::selectFindMatch(unsigned index, WebRect* selectionRect)
606 { 582 {
607 ASSERT_WITH_SECURITY_IMPLICATION(index < m_findMatchesCache.size()); 583 ASSERT_WITH_SECURITY_IMPLICATION(index < m_findMatchesCache.size());
608 584
609 Range* range = m_findMatchesCache[index].m_range; 585 Range* range = m_findMatchesCache[index].m_range;
610 if (!range->boundaryPointsValid() || !range->startContainer()->inShadowInclu dingDocument()) 586 if (!range->boundaryPointsValid() || !range->startContainer()->inShadowInclu dingDocument())
611 return -1; 587 return -1;
612 588
613 // Check if the match is already selected. 589 // Check if the match is already selected.
614 TextFinder& mainFrameTextFinder = ownerFrame().viewImpl()->mainFrameImpl()-> ensureTextFinder(); 590 if (!m_currentActiveMatchFrame || !m_activeMatch || !areRangesEqual(m_active Match.get(), range)) {
615 WebLocalFrameImpl* activeMatchFrame = mainFrameTextFinder.m_currentActiveMat chFrame; 591 m_activeMatchIndex = m_findMatchesCache[index].m_ordinal - 1;
616 if (&ownerFrame() != activeMatchFrame || !m_activeMatch || !areRangesEqual(m _activeMatch.get(), range)) {
617 if (isActiveMatchFrameValid())
618 activeMatchFrame->ensureTextFinder().setMatchMarkerActive(false);
619
620 m_activeMatchIndexInCurrentFrame = m_findMatchesCache[index].m_ordinal - 1;
621 592
622 // Set this frame as the active frame (the one with the active highlight ). 593 // Set this frame as the active frame (the one with the active highlight ).
623 mainFrameTextFinder.m_currentActiveMatchFrame = &ownerFrame(); 594 m_currentActiveMatchFrame = true;
624 ownerFrame().viewImpl()->setFocusedFrame(&ownerFrame()); 595 ownerFrame().viewImpl()->setFocusedFrame(&ownerFrame());
625 596
597 if (m_activeMatch)
598 setMarkerActive(m_activeMatch.get(), false);
626 m_activeMatch = range; 599 m_activeMatch = range;
627 setMarkerActive(m_activeMatch.get(), true); 600 setMarkerActive(m_activeMatch.get(), true);
628 601
629 // Clear any user selection, to make sure Find Next continues on from th e match we just activated. 602 // Clear any user selection, to make sure Find Next continues on from th e match we just activated.
630 ownerFrame().frame()->selection().clear(); 603 ownerFrame().frame()->selection().clear();
631 604
632 // Make sure no node is focused. See http://crbug.com/38700. 605 // Make sure no node is focused. See http://crbug.com/38700.
633 ownerFrame().frame()->document()->clearFocusedElement(); 606 ownerFrame().frame()->document()->clearFocusedElement();
634 } 607 }
635 608
636 IntRect activeMatchRect; 609 IntRect activeMatchRect;
637 IntRect activeMatchBoundingBox = enclosingIntRect(LayoutObject::absoluteBoun dingBoxRectForRange(m_activeMatch.get())); 610 IntRect activeMatchBoundingBox = enclosingIntRect(LayoutObject::absoluteBoun dingBoxRectForRange(m_activeMatch.get()));
638 611
639 if (!activeMatchBoundingBox.isEmpty()) { 612 if (!activeMatchBoundingBox.isEmpty()) {
640 if (m_activeMatch->firstNode() && m_activeMatch->firstNode()->layoutObje ct()) { 613 if (m_activeMatch->firstNode() && m_activeMatch->firstNode()->layoutObje ct()) {
641 m_activeMatch->firstNode()->layoutObject()->scrollRectToVisible( 614 m_activeMatch->firstNode()->layoutObject()->scrollRectToVisible(
642 LayoutRect(activeMatchBoundingBox), ScrollAlignment::alignCenter IfNeeded, ScrollAlignment::alignCenterIfNeeded, UserScroll); 615 LayoutRect(activeMatchBoundingBox), ScrollAlignment::alignCenter IfNeeded, ScrollAlignment::alignCenterIfNeeded, UserScroll);
643 } 616 }
644 617
645 // Zoom to the active match. 618 // Zoom to the active match.
646 activeMatchRect = ownerFrame().frameView()->contentsToRootFrame(activeMa tchBoundingBox); 619 activeMatchRect = ownerFrame().frameView()->contentsToRootFrame(activeMa tchBoundingBox);
647 ownerFrame().viewImpl()->zoomToFindInPageRect(activeMatchRect); 620 ownerFrame().viewImpl()->zoomToFindInPageRect(activeMatchRect);
648 } 621 }
649 622
650 if (selectionRect) 623 if (selectionRect)
651 *selectionRect = activeMatchRect; 624 *selectionRect = activeMatchRect;
652 625
653 return ordinalOfFirstMatch() + m_activeMatchIndexInCurrentFrame + 1; 626 return m_activeMatchIndex + 1;
654 } 627 }
655 628
656 TextFinder* TextFinder::create(WebLocalFrameImpl& ownerFrame) 629 TextFinder* TextFinder::create(WebLocalFrameImpl& ownerFrame)
657 { 630 {
658 return new TextFinder(ownerFrame); 631 return new TextFinder(ownerFrame);
659 } 632 }
660 633
661 TextFinder::TextFinder(WebLocalFrameImpl& ownerFrame) 634 TextFinder::TextFinder(WebLocalFrameImpl& ownerFrame)
662 : m_ownerFrame(&ownerFrame) 635 : m_ownerFrame(&ownerFrame)
663 , m_currentActiveMatchFrame(nullptr) 636 , m_currentActiveMatchFrame(false)
664 , m_activeMatchIndexInCurrentFrame(-1) 637 , m_activeMatchIndex(-1)
665 , m_resumeScopingFromRange(nullptr) 638 , m_resumeScopingFromRange(nullptr)
666 , m_lastMatchCount(-1) 639 , m_lastMatchCount(-1)
667 , m_totalMatchCount(-1) 640 , m_totalMatchCount(-1)
668 , m_framesScopingCount(-1) 641 , m_frameScoping(false)
669 , m_findRequestIdentifier(-1) 642 , m_findRequestIdentifier(-1)
670 , m_nextInvalidateAfter(0) 643 , m_nextInvalidateAfter(0)
671 , m_findMatchMarkersVersion(0) 644 , m_findMatchMarkersVersion(0)
672 , m_locatingActiveRect(false) 645 , m_locatingActiveRect(false)
673 , m_scopingInProgress(false) 646 , m_scopingInProgress(false)
674 , m_lastFindRequestCompletedWithNoMatches(false) 647 , m_lastFindRequestCompletedWithNoMatches(false)
675 , m_findMatchRectsAreValid(false) 648 , m_findMatchRectsAreValid(false)
676 { 649 {
677 } 650 }
678 651
679 TextFinder::~TextFinder() 652 TextFinder::~TextFinder()
680 { 653 {
681 } 654 }
682 655
683 void TextFinder::addMarker(Range* range, bool activeMatch) 656 void TextFinder::addMarker(Range* range, bool activeMatch)
684 { 657 {
685 ownerFrame().frame()->document()->markers().addTextMatchMarker(range, active Match); 658 ownerFrame().frame()->document()->markers().addTextMatchMarker(range, active Match);
686 } 659 }
687 660
688 bool TextFinder::setMarkerActive(Range* range, bool active) 661 bool TextFinder::setMarkerActive(Range* range, bool active)
689 { 662 {
690 if (!range || range->collapsed()) 663 if (!range || range->collapsed())
691 return false; 664 return false;
692 return ownerFrame().frame()->document()->markers().setMarkersActive(range, a ctive); 665 return ownerFrame().frame()->document()->markers().setMarkersActive(range, a ctive);
693 } 666 }
694 667
695 void TextFinder::unmarkAllTextMatches() 668 void TextFinder::unmarkAllTextMatches()
696 { 669 {
697 LocalFrame* frame = ownerFrame().frame(); 670 LocalFrame* frame = ownerFrame().frame();
698 if (frame && frame->page() && frame->editor().markedTextMatchesAreHighlighte d()) { 671 if (frame && frame->page() && frame->editor().markedTextMatchesAreHighlighte d())
699 if (ownerFrame().client() && ownerFrame().client()->shouldSearchSingleFr ame()) 672 frame->document()->markers().removeMarkers(DocumentMarker::TextMatch);
700 frame->document()->markers().removeMarkers(DocumentMarker::TextMatch );
701 else
702 frame->page()->unmarkAllTextMatches();
703 }
704 }
705
706 int TextFinder::ordinalOfFirstMatchForFrame(WebLocalFrameImpl* frame) const
707 {
708 int ordinal = 0;
709 WebLocalFrameImpl* mainFrameImpl = ownerFrame().viewImpl()->mainFrameImpl();
710 // Iterate from the main frame up to (but not including) |frame| and
711 // add up the number of matches found so far.
712 for (WebLocalFrameImpl* it = mainFrameImpl; it != frame; it = toWebLocalFram eImpl(it->traverseNextLocal(true))) {
713 TextFinder& finder = it->ensureTextFinder();
714 if (finder.m_lastMatchCount > 0)
715 ordinal += finder.m_lastMatchCount;
716 }
717 return ordinal;
718 } 673 }
719 674
720 bool TextFinder::shouldScopeMatches(const String& searchText) 675 bool TextFinder::shouldScopeMatches(const String& searchText)
721 { 676 {
722 // Don't scope if we can't find a frame or a view. 677 // Don't scope if we can't find a frame or a view.
723 // The user may have closed the tab/application, so abort. 678 // The user may have closed the tab/application, so abort.
724 // Also ignore detached frames, as many find operations report to the main f rame.
725 LocalFrame* frame = ownerFrame().frame(); 679 LocalFrame* frame = ownerFrame().frame();
726 if (!frame || !frame->view() || !frame->page() || !ownerFrame().hasVisibleCo ntent()) 680 if (!frame || !frame->view() || !frame->page() || !ownerFrame().hasVisibleCo ntent())
727 return false; 681 return false;
728 682
729 DCHECK(frame->document()); 683 DCHECK(frame->document());
730 DCHECK(frame->view()); 684 DCHECK(frame->view());
731 685
732 // If the frame completed the scoping operation and found 0 matches the last 686 // If the frame completed the scoping operation and found 0 matches the last
733 // time it was searched, then we don't have to search it again if the user i s 687 // time it was searched, then we don't have to search it again if the user i s
734 // just adding to the search string or sending the same search string again. 688 // just adding to the search string or sending the same search string again.
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
775 int i = m_lastMatchCount / startSlowingDownAfter; 729 int i = m_lastMatchCount / startSlowingDownAfter;
776 m_nextInvalidateAfter += i * slowdown; 730 m_nextInvalidateAfter += i * slowdown;
777 ownerFrame().frameView()->invalidatePaintForTickmarks(); 731 ownerFrame().frameView()->invalidatePaintForTickmarks();
778 } 732 }
779 733
780 void TextFinder::flushCurrentScoping() 734 void TextFinder::flushCurrentScoping()
781 { 735 {
782 flushCurrentScopingEffort(m_findRequestIdentifier); 736 flushCurrentScopingEffort(m_findRequestIdentifier);
783 } 737 }
784 738
785 void TextFinder::setMatchMarkerActive(bool active)
786 {
787 setMarkerActive(m_activeMatch.get(), active);
788 }
789
790 void TextFinder::decrementFramesScopingCount(int identifier)
791 {
792 // This frame has no further scoping left, so it is done. Other frames might ,
793 // of course, continue to scope matches.
794 --m_framesScopingCount;
795
796 // If this is the last frame to finish scoping we need to trigger the final
797 // update to be sent.
798 if (!m_framesScopingCount)
799 ownerFrame().increaseMatchCount(0, identifier);
800 }
801
802 int TextFinder::ordinalOfFirstMatch() const
803 {
804 return ordinalOfFirstMatchForFrame(m_ownerFrame.get());
805 }
806
807 DEFINE_TRACE(TextFinder) 739 DEFINE_TRACE(TextFinder)
808 { 740 {
809 visitor->trace(m_ownerFrame); 741 visitor->trace(m_ownerFrame);
810 visitor->trace(m_currentActiveMatchFrame);
811 visitor->trace(m_activeMatch); 742 visitor->trace(m_activeMatch);
812 visitor->trace(m_resumeScopingFromRange); 743 visitor->trace(m_resumeScopingFromRange);
813 visitor->trace(m_deferredScopingWork); 744 visitor->trace(m_deferredScopingWork);
814 visitor->trace(m_findMatchesCache); 745 visitor->trace(m_findMatchesCache);
815 } 746 }
816 747
817 } // namespace blink 748 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/web/TextFinder.h ('k') | third_party/WebKit/Source/web/WebLocalFrameImpl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698