OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |