| 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 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 DEFINE_TRACE(TextFinder::FindMatch) { | 63 DEFINE_TRACE(TextFinder::FindMatch) { |
| 64 visitor->trace(m_range); | 64 visitor->trace(m_range); |
| 65 } | 65 } |
| 66 | 66 |
| 67 class TextFinder::DeferredScopeStringMatches | 67 class TextFinder::DeferredScopeStringMatches |
| 68 : public GarbageCollectedFinalized<TextFinder::DeferredScopeStringMatches> { | 68 : public GarbageCollectedFinalized<TextFinder::DeferredScopeStringMatches> { |
| 69 public: | 69 public: |
| 70 static DeferredScopeStringMatches* create(TextFinder* textFinder, | 70 static DeferredScopeStringMatches* create(TextFinder* textFinder, |
| 71 int identifier, | 71 int identifier, |
| 72 const WebString& searchText, | 72 const WebString& searchText, |
| 73 const WebFindOptions& options, | 73 const WebFindOptions& options) { |
| 74 bool reset) { | |
| 75 return new DeferredScopeStringMatches(textFinder, identifier, searchText, | 74 return new DeferredScopeStringMatches(textFinder, identifier, searchText, |
| 76 options, reset); | 75 options); |
| 77 } | 76 } |
| 78 | 77 |
| 79 DEFINE_INLINE_TRACE() { visitor->trace(m_textFinder); } | 78 DEFINE_INLINE_TRACE() { visitor->trace(m_textFinder); } |
| 80 | 79 |
| 81 void dispose() { m_timer.stop(); } | 80 void dispose() { m_timer.stop(); } |
| 82 | 81 |
| 83 private: | 82 private: |
| 84 DeferredScopeStringMatches(TextFinder* textFinder, | 83 DeferredScopeStringMatches(TextFinder* textFinder, |
| 85 int identifier, | 84 int identifier, |
| 86 const WebString& searchText, | 85 const WebString& searchText, |
| 87 const WebFindOptions& options, | 86 const WebFindOptions& options) |
| 88 bool reset) | |
| 89 : m_timer(this, &DeferredScopeStringMatches::doTimeout), | 87 : m_timer(this, &DeferredScopeStringMatches::doTimeout), |
| 90 m_textFinder(textFinder), | 88 m_textFinder(textFinder), |
| 91 m_identifier(identifier), | 89 m_identifier(identifier), |
| 92 m_searchText(searchText), | 90 m_searchText(searchText), |
| 93 m_options(options), | 91 m_options(options) { |
| 94 m_reset(reset) { | |
| 95 m_timer.startOneShot(0.0, BLINK_FROM_HERE); | 92 m_timer.startOneShot(0.0, BLINK_FROM_HERE); |
| 96 } | 93 } |
| 97 | 94 |
| 98 void doTimeout(TimerBase*) { | 95 void doTimeout(TimerBase*) { |
| 99 m_textFinder->callScopeStringMatches(this, m_identifier, m_searchText, | 96 m_textFinder->resumeScopingStringMatches(m_identifier, m_searchText, |
| 100 m_options, m_reset); | 97 m_options); |
| 101 } | 98 } |
| 102 | 99 |
| 103 Timer<DeferredScopeStringMatches> m_timer; | 100 Timer<DeferredScopeStringMatches> m_timer; |
| 104 Member<TextFinder> m_textFinder; | 101 Member<TextFinder> m_textFinder; |
| 105 const int m_identifier; | 102 const int m_identifier; |
| 106 const WebString m_searchText; | 103 const WebString m_searchText; |
| 107 const WebFindOptions m_options; | 104 const WebFindOptions m_options; |
| 108 const bool m_reset; | |
| 109 }; | 105 }; |
| 110 | 106 |
| 111 bool TextFinder::find(int identifier, | 107 bool TextFinder::find(int identifier, |
| 112 const WebString& searchText, | 108 const WebString& searchText, |
| 113 const WebFindOptions& options, | 109 const WebFindOptions& options, |
| 114 bool wrapWithinFrame, | 110 bool wrapWithinFrame, |
| 115 bool* activeNow) { | 111 bool* activeNow) { |
| 116 if (!options.findNext) | 112 if (!options.findNext) |
| 117 unmarkAllTextMatches(); | 113 unmarkAllTextMatches(); |
| 118 else | 114 else |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 endObject, AXObjectCache::AXNotification::AXChildrenChanged); | 252 endObject, AXObjectCache::AXNotification::AXChildrenChanged); |
| 257 | 253 |
| 258 if (ownerFrame().client()) { | 254 if (ownerFrame().client()) { |
| 259 ownerFrame().client()->handleAccessibilityFindInPageResult( | 255 ownerFrame().client()->handleAccessibilityFindInPageResult( |
| 260 identifier, m_activeMatchIndex + 1, WebAXObject(startObject), | 256 identifier, m_activeMatchIndex + 1, WebAXObject(startObject), |
| 261 m_activeMatch->startOffset(), WebAXObject(endObject), | 257 m_activeMatch->startOffset(), WebAXObject(endObject), |
| 262 m_activeMatch->endOffset()); | 258 m_activeMatch->endOffset()); |
| 263 } | 259 } |
| 264 } | 260 } |
| 265 | 261 |
| 262 void TextFinder::startScopingStringMatches(int identifier, |
| 263 const WebString& searchText, |
| 264 const WebFindOptions& options) { |
| 265 cancelPendingScopingEffort(); |
| 266 |
| 267 // This is a brand new search, so we need to reset everything. |
| 268 // Scoping is just about to begin. |
| 269 m_scopingInProgress = true; |
| 270 |
| 271 // Need to keep the current identifier locally in order to finish the |
| 272 // request in case the frame is detached during the process. |
| 273 m_findRequestIdentifier = identifier; |
| 274 |
| 275 // Clear highlighting for this frame. |
| 276 unmarkAllTextMatches(); |
| 277 |
| 278 // Clear the tickmarks and results cache. |
| 279 clearFindMatchesCache(); |
| 280 |
| 281 // Clear the total match count and increment markers version. |
| 282 resetMatchCount(); |
| 283 |
| 284 // Clear the counters from last operation. |
| 285 m_lastMatchCount = 0; |
| 286 m_nextInvalidateAfter = 0; |
| 287 m_resumeScopingFromRange = nullptr; |
| 288 |
| 289 // The view might be null on detached frames. |
| 290 LocalFrame* frame = ownerFrame().frame(); |
| 291 if (frame && frame->page()) |
| 292 m_frameScoping = true; |
| 293 |
| 294 // Now, defer scoping until later to allow find operation to finish quickly. |
| 295 scopeStringMatchesSoon(identifier, searchText, options); |
| 296 } |
| 297 |
| 266 void TextFinder::scopeStringMatches(int identifier, | 298 void TextFinder::scopeStringMatches(int identifier, |
| 267 const WebString& searchText, | 299 const WebString& searchText, |
| 268 const WebFindOptions& options, | 300 const WebFindOptions& options) { |
| 269 bool reset) { | |
| 270 // TODO(dglazkov): The reset/continue cases need to be untangled into two | |
| 271 // separate functions. This collation of logic is unnecessary and adds to | |
| 272 // overall complexity of the code. | |
| 273 if (reset) { | |
| 274 // This is a brand new search, so we need to reset everything. | |
| 275 // Scoping is just about to begin. | |
| 276 m_scopingInProgress = true; | |
| 277 | |
| 278 // Need to keep the current identifier locally in order to finish the | |
| 279 // request in case the frame is detached during the process. | |
| 280 m_findRequestIdentifier = identifier; | |
| 281 | |
| 282 // Clear highlighting for this frame. | |
| 283 unmarkAllTextMatches(); | |
| 284 | |
| 285 // Clear the tickmarks and results cache. | |
| 286 clearFindMatchesCache(); | |
| 287 | |
| 288 // Clear the counters from last operation. | |
| 289 m_lastMatchCount = 0; | |
| 290 m_nextInvalidateAfter = 0; | |
| 291 m_resumeScopingFromRange = nullptr; | |
| 292 | |
| 293 // The view might be null on detached frames. | |
| 294 LocalFrame* frame = ownerFrame().frame(); | |
| 295 if (frame && frame->page()) | |
| 296 m_frameScoping = true; | |
| 297 | |
| 298 // Now, defer scoping until later to allow find operation to finish quickly. | |
| 299 scopeStringMatchesSoon( | |
| 300 identifier, searchText, options, | |
| 301 false); // false means just reset, so don't do it again. | |
| 302 return; | |
| 303 } | |
| 304 | |
| 305 if (!shouldScopeMatches(searchText, options)) { | 301 if (!shouldScopeMatches(searchText, options)) { |
| 306 finishCurrentScopingEffort(identifier); | 302 finishCurrentScopingEffort(identifier); |
| 307 return; | 303 return; |
| 308 } | 304 } |
| 309 | 305 |
| 310 PositionInFlatTree searchStart = | 306 PositionInFlatTree searchStart = |
| 311 PositionInFlatTree::firstPositionInNode(ownerFrame().frame()->document()); | 307 PositionInFlatTree::firstPositionInNode(ownerFrame().frame()->document()); |
| 312 PositionInFlatTree searchEnd = | 308 PositionInFlatTree searchEnd = |
| 313 PositionInFlatTree::lastPositionInNode(ownerFrame().frame()->document()); | 309 PositionInFlatTree::lastPositionInNode(ownerFrame().frame()->document()); |
| 314 DCHECK_EQ(searchStart.document(), searchEnd.document()); | 310 DCHECK_EQ(searchStart.document(), searchEnd.document()); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 422 } | 418 } |
| 423 | 419 |
| 424 if (timedOut) { | 420 if (timedOut) { |
| 425 // If we found anything during this pass, we should redraw. However, we | 421 // If we found anything during this pass, we should redraw. However, we |
| 426 // don't want to spam too much if the page is extremely long, so if we | 422 // don't want to spam too much if the page is extremely long, so if we |
| 427 // reach a certain point we start throttling the redraw requests. | 423 // reach a certain point we start throttling the redraw requests. |
| 428 if (matchCount > 0) | 424 if (matchCount > 0) |
| 429 invalidateIfNecessary(); | 425 invalidateIfNecessary(); |
| 430 | 426 |
| 431 // Scoping effort ran out of time, lets ask for another time-slice. | 427 // Scoping effort ran out of time, lets ask for another time-slice. |
| 432 scopeStringMatchesSoon(identifier, searchText, options, | 428 scopeStringMatchesSoon(identifier, searchText, options); |
| 433 false); // don't reset. | |
| 434 return; // Done for now, resume work later. | 429 return; // Done for now, resume work later. |
| 435 } | 430 } |
| 436 | 431 |
| 437 finishCurrentScopingEffort(identifier); | 432 finishCurrentScopingEffort(identifier); |
| 438 } | 433 } |
| 439 | 434 |
| 440 void TextFinder::flushCurrentScopingEffort(int identifier) { | 435 void TextFinder::flushCurrentScopingEffort(int identifier) { |
| 441 if (!ownerFrame().frame() || !ownerFrame().frame()->page()) | 436 if (!ownerFrame().frame() || !ownerFrame().frame()->page()) |
| 442 return; | 437 return; |
| 443 | 438 |
| 444 m_frameScoping = false; | 439 m_frameScoping = false; |
| 445 ownerFrame().increaseMatchCount(0, identifier); | 440 ownerFrame().increaseMatchCount(0, identifier); |
| 446 } | 441 } |
| 447 | 442 |
| 448 void TextFinder::finishCurrentScopingEffort(int identifier) { | 443 void TextFinder::finishCurrentScopingEffort(int identifier) { |
| 449 flushCurrentScopingEffort(identifier); | 444 flushCurrentScopingEffort(identifier); |
| 450 | 445 |
| 451 m_scopingInProgress = false; | 446 m_scopingInProgress = false; |
| 452 m_lastFindRequestCompletedWithNoMatches = !m_lastMatchCount; | 447 m_lastFindRequestCompletedWithNoMatches = !m_lastMatchCount; |
| 453 | 448 |
| 454 // This frame is done, so show any scrollbar tickmarks we haven't drawn yet. | 449 // This frame is done, so show any scrollbar tickmarks we haven't drawn yet. |
| 455 ownerFrame().frameView()->invalidatePaintForTickmarks(); | 450 ownerFrame().frameView()->invalidatePaintForTickmarks(); |
| 456 } | 451 } |
| 457 | 452 |
| 458 void TextFinder::cancelPendingScopingEffort() { | 453 void TextFinder::cancelPendingScopingEffort() { |
| 459 for (DeferredScopeStringMatches* deferredWork : m_deferredScopingWork) | 454 if (m_deferredScopingWork) { |
| 460 deferredWork->dispose(); | 455 m_deferredScopingWork->dispose(); |
| 461 m_deferredScopingWork.clear(); | 456 m_deferredScopingWork.clear(); |
| 457 } |
| 462 | 458 |
| 463 m_activeMatchIndex = -1; | 459 m_activeMatchIndex = -1; |
| 464 | 460 |
| 465 // Last request didn't complete. | 461 // Last request didn't complete. |
| 466 if (m_scopingInProgress) | 462 if (m_scopingInProgress) |
| 467 m_lastFindRequestCompletedWithNoMatches = false; | 463 m_lastFindRequestCompletedWithNoMatches = false; |
| 468 | 464 |
| 469 m_scopingInProgress = false; | 465 m_scopingInProgress = false; |
| 470 } | 466 } |
| 471 | 467 |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 724 | 720 |
| 725 if (previousSearchPrefix == m_lastSearchString) | 721 if (previousSearchPrefix == m_lastSearchString) |
| 726 return false; // Don't search this frame, it will be fruitless. | 722 return false; // Don't search this frame, it will be fruitless. |
| 727 } | 723 } |
| 728 | 724 |
| 729 return true; | 725 return true; |
| 730 } | 726 } |
| 731 | 727 |
| 732 void TextFinder::scopeStringMatchesSoon(int identifier, | 728 void TextFinder::scopeStringMatchesSoon(int identifier, |
| 733 const WebString& searchText, | 729 const WebString& searchText, |
| 734 const WebFindOptions& options, | 730 const WebFindOptions& options) { |
| 735 bool reset) { | 731 DCHECK_EQ(m_deferredScopingWork, nullptr); |
| 736 m_deferredScopingWork.append(DeferredScopeStringMatches::create( | 732 m_deferredScopingWork = |
| 737 this, identifier, searchText, options, reset)); | 733 DeferredScopeStringMatches::create(this, identifier, searchText, options); |
| 738 } | 734 } |
| 739 | 735 |
| 740 void TextFinder::callScopeStringMatches(DeferredScopeStringMatches* caller, | 736 void TextFinder::resumeScopingStringMatches(int identifier, |
| 741 int identifier, | 737 const WebString& searchText, |
| 742 const WebString& searchText, | 738 const WebFindOptions& options) { |
| 743 const WebFindOptions& options, | 739 m_deferredScopingWork.clear(); |
| 744 bool reset) { | |
| 745 size_t index = m_deferredScopingWork.find(caller); | |
| 746 m_deferredScopingWork.remove(index); | |
| 747 | 740 |
| 748 scopeStringMatches(identifier, searchText, options, reset); | 741 scopeStringMatches(identifier, searchText, options); |
| 749 } | 742 } |
| 750 | 743 |
| 751 void TextFinder::invalidateIfNecessary() { | 744 void TextFinder::invalidateIfNecessary() { |
| 752 if (m_lastMatchCount <= m_nextInvalidateAfter) | 745 if (m_lastMatchCount <= m_nextInvalidateAfter) |
| 753 return; | 746 return; |
| 754 | 747 |
| 755 // FIXME: (http://crbug.com/6819) Optimize the drawing of the tickmarks and | 748 // FIXME: (http://crbug.com/6819) Optimize the drawing of the tickmarks and |
| 756 // remove this. This calculation sets a milestone for when next to | 749 // remove this. This calculation sets a milestone for when next to |
| 757 // invalidate the scrollbar and the content area. We do this so that we | 750 // invalidate the scrollbar and the content area. We do this so that we |
| 758 // don't spend too much time drawing the scrollbar over and over again. | 751 // don't spend too much time drawing the scrollbar over and over again. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 773 | 766 |
| 774 DEFINE_TRACE(TextFinder) { | 767 DEFINE_TRACE(TextFinder) { |
| 775 visitor->trace(m_ownerFrame); | 768 visitor->trace(m_ownerFrame); |
| 776 visitor->trace(m_activeMatch); | 769 visitor->trace(m_activeMatch); |
| 777 visitor->trace(m_resumeScopingFromRange); | 770 visitor->trace(m_resumeScopingFromRange); |
| 778 visitor->trace(m_deferredScopingWork); | 771 visitor->trace(m_deferredScopingWork); |
| 779 visitor->trace(m_findMatchesCache); | 772 visitor->trace(m_findMatchesCache); |
| 780 } | 773 } |
| 781 | 774 |
| 782 } // namespace blink | 775 } // namespace blink |
| OLD | NEW |