Changeset 143391 in webkit
- Timestamp:
- Feb 19, 2013 3:15:42 PM (11 years ago)
- Location:
- trunk/Source/WebKit/blackberry
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebKit/blackberry/ChangeLog
r143295 r143391 1 2013-02-19 Nima Ghanavatian <nghanavatian@rim.com> 2 3 [BlackBerry] Appropriately handle word wrapping in SpellingHandler 4 https://bugs.webkit.org/show_bug.cgi?id=110253 5 6 Reviewed by Rob Buis. 7 8 PR286001 9 Since we traverse through text by visual lines instead of blocks, word wrapping causes some 10 bad behavior. Changing the way we traverse text to jump by words instead of lines. This will 11 mean it takes longer to finish spellchecking, but the removal of any loops allows webkit 12 processing to continue. This gives priority to user actions while still completing a large 13 paragraph in a reasonable amount of time. 14 15 Internally reviewed by Mike Fenton 16 17 * WebKitSupport/InputHandler.cpp: 18 (BlackBerry::WebKit::InputHandler::requestCheckingOfString): 19 * WebKitSupport/SpellingHandler.cpp: 20 (BlackBerry::WebKit::SpellingHandler::createSpellCheckRequest): 21 (BlackBerry::WebKit::SpellingHandler::parseBlockForSpellChecking): 22 (BlackBerry::WebKit::SpellingHandler::getRangeForSpellCheckWithFineGranularity): 23 (BlackBerry::WebKit::SpellingHandler::startOfNextWord): 24 (WebKit): 25 (BlackBerry::WebKit::SpellingHandler::incrementByWord): 26 (BlackBerry::WebKit::SpellingHandler::doesWordWrap): 27 * WebKitSupport/SpellingHandler.h: 28 (SpellingHandler): 29 1 30 2013-02-18 Simon Fraser <simon.fraser@apple.com> 2 31 -
trunk/Source/WebKit/blackberry/WebKitSupport/DOMSupport.cpp
r140708 r143391 509 509 } 510 510 511 int offsetFromStartOfBlock(const VisiblePosition offset) 512 { 513 RefPtr<Range> range = makeRange(startOfBlock(offset), offset); 514 if (!range) 515 return -1; 516 517 return range->text().latin1().length(); 518 } 519 520 VisibleSelection visibleSelectionForFocusedBlock(Element* element) 521 { 522 int textLength = inputElementText(element).length(); 523 524 if (DOMSupport::toTextControlElement(element)) { 525 RenderTextControl* textRender = toRenderTextControl(element->renderer()); 526 if (!textRender) 527 return VisibleSelection(); 528 529 VisiblePosition startPosition = textRender->visiblePositionForIndex(0); 530 VisiblePosition endPosition; 531 532 if (textLength) 533 endPosition = textRender->visiblePositionForIndex(textLength); 534 else 535 endPosition = startPosition; 536 return VisibleSelection(startPosition, endPosition); 537 } 538 539 // Must be content editable, generate the range. 540 RefPtr<Range> selectionRange = TextIterator::rangeFromLocationAndLength(element, 0, textLength); 541 542 if (!selectionRange) 543 return VisibleSelection(); 544 545 if (!textLength) 546 return VisibleSelection(selectionRange->startPosition(), DOWNSTREAM); 547 548 return VisibleSelection(selectionRange->startPosition(), selectionRange->endPosition()); 549 } 550 511 551 // This function is copied from WebCore/page/Page.cpp. 512 552 Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag) … … 524 564 PassRefPtr<Range> trimWhitespaceFromRange(VisiblePosition startPosition, VisiblePosition endPosition) 525 565 { 526 if ( isEmptyRangeOrAllSpaces(startPosition, endPosition))566 if (startPosition == endPosition || isRangeTextAllWhitespace(startPosition, endPosition)) 527 567 return 0; 528 568 … … 536 576 } 537 577 538 bool isEmptyRangeOrAllSpaces(VisiblePosition startPosition, VisiblePosition endPosition) 539 { 540 if (startPosition == endPosition) 541 return true; 542 578 bool isRangeTextAllWhitespace(VisiblePosition startPosition, VisiblePosition endPosition) 579 { 543 580 while (isWhitespace(startPosition.characterAfter())) { 544 581 startPosition = startPosition.next(); -
trunk/Source/WebKit/blackberry/WebKitSupport/DOMSupport.h
r140562 r143391 91 91 92 92 WebCore::VisibleSelection visibleSelectionForClosestActualWordStart(const WebCore::VisibleSelection&); 93 WebCore::VisibleSelection visibleSelectionForFocusedBlock(WebCore::Element*); 94 int offsetFromStartOfBlock(const WebCore::VisiblePosition offset); 93 95 94 96 WebCore::Frame* incrementFrame(WebCore::Frame* curr, bool forward, bool wrapFlag); … … 96 98 PassRefPtr<WebCore::Range> trimWhitespaceFromRange(PassRefPtr<WebCore::Range>); 97 99 PassRefPtr<WebCore::Range> trimWhitespaceFromRange(WebCore::VisiblePosition startPosition, WebCore::VisiblePosition endPosition); 98 bool is EmptyRangeOrAllSpaces(WebCore::VisiblePosition, WebCore::VisiblePosition);100 bool isRangeTextAllWhitespace(WebCore::VisiblePosition startPosition, WebCore::VisiblePosition endPosition); 99 101 100 102 bool isFixedPositionOrHasFixedPositionAncestor(WebCore::RenderObject*); -
trunk/Source/WebKit/blackberry/WebKitSupport/InputHandler.cpp
r142884 r143391 613 613 } 614 614 615 if (requestLength > MaxSpellCheckingStringLength) {615 if (requestLength >= MaxSpellCheckingStringLength) { 616 616 // Batch requests which are generally created by us on focus, should not exceed this limit. Check that this is in fact of Incremental type. 617 617 ASSERT(textCheckingRequest->processType() == TextCheckingProcessIncremental); … … 620 620 m_request->didCancel(); 621 621 if (m_currentFocusElement->document() && m_currentFocusElement->document()->frame() && m_currentFocusElement->document()->frame()->selection()) { 622 VisiblePosition caretPosition = m_currentFocusElement->document()->frame()->selection()->start(); 622 623 // Convert from position back to selection so we can expand the range to include the previous line. This should handle cases when the user hits 623 // enter to finish composing a word and create a new line. 624 VisiblePosition caretPosition = m_currentFocusElement->document()->frame()->selection()->start(); 625 VisibleSelection visibleSelection = VisibleSelection(previousLinePosition(caretPosition, caretPosition.lineDirectionPointForBlockDirectionNavigation()), caretPosition); 624 // enter to finish composing a word and create a new line. Account for word wrapping by jumping to the start of the previous line, then moving 625 // to the start of any word which might be there. 626 VisibleSelection visibleSelection = VisibleSelection( 627 startOfWord(startOfLine(previousLinePosition(caretPosition, caretPosition.lineDirectionPointForBlockDirectionNavigation()))), 628 endOfWord(endOfLine(caretPosition))); 626 629 m_spellingHandler->spellCheckTextBlock(visibleSelection, TextCheckingProcessIncremental); 627 630 } … … 1093 1096 1094 1097 // Spellcheck the field in its entirety. 1095 VisibleSelection focusedBlock = DOMSupport::visibleSelectionForInputElement(element);1096 m_spellingHandler->spellCheckTextBlock( focusedBlock, TextCheckingProcessBatch);1098 const VisibleSelection visibleSelection = DOMSupport::visibleSelectionForFocusedBlock(element); 1099 m_spellingHandler->spellCheckTextBlock(visibleSelection, TextCheckingProcessBatch); 1097 1100 1098 1101 #ifdef ENABLE_SPELLING_LOG -
trunk/Source/WebKit/blackberry/WebKitSupport/SpellingHandler.cpp
r142019 r143391 42 42 } 43 43 44 void SpellingHandler::spellCheckTextBlock( WebCore::VisibleSelection& visibleSelection, WebCore::TextCheckingProcessType textCheckingProcessType)44 void SpellingHandler::spellCheckTextBlock(const WebCore::VisibleSelection& visibleSelection, WebCore::TextCheckingProcessType textCheckingProcessType) 45 45 { 46 SpellingLog(Platform::LogLevelInfo, "SpellingHandler::spellCheckTextBlock");47 48 46 // Check if this request can be sent off in one message, or if it needs to be broken down. 49 47 RefPtr<Range> rangeForSpellChecking = visibleSelection.toNormalizedRange(); … … 51 49 return; 52 50 51 m_textCheckingProcessType = textCheckingProcessType; 52 53 53 // Spellcheck Batch requests are used when focusing an element. During this time, we might have a lingering request 54 54 // from a previously focused element. 55 if ( textCheckingProcessType == TextCheckingProcessBatch) {55 if (m_textCheckingProcessType == TextCheckingProcessBatch) { 56 56 // If a previous request is being processed, stop it before continueing. 57 57 if (m_timer.isActive()) … … 62 62 63 63 // If we have a batch request, try to send off the entire block. 64 if ( textCheckingProcessType == TextCheckingProcessBatch) {64 if (m_textCheckingProcessType == TextCheckingProcessBatch) { 65 65 // If total block text is under the limited amount, send the entire chunk. 66 66 if (rangeForSpellChecking->text().length() < MaxSpellCheckingStringLength) { 67 createSpellCheckRequest(rangeForSpellChecking , TextCheckingProcessBatch);67 createSpellCheckRequest(rangeForSpellChecking); 68 68 return; 69 69 } … … 71 71 72 72 // Since we couldn't check the entire block at once, set up starting and ending markers to fire incrementally. 73 m_startOfCurrentLine = startOfLine(visibleSelection.visibleStart()); 74 m_endOfCurrentLine = endOfLine(m_startOfCurrentLine); 75 m_textCheckingProcessType = textCheckingProcessType; 73 // Find the start and end of the region we're intending on checking 74 m_startPosition = visibleSelection.visibleStart(); 75 m_endPosition = endOfWord(m_startPosition); 76 m_endOfRange = visibleSelection.visibleEnd(); 77 m_cachedEndPosition = m_endOfRange; 76 78 77 // Find the end of the region we're intending on checking.78 m_endOfRange = endOfLine(visibleSelection.visibleEnd());79 79 m_timer.startOneShot(0); 80 80 } 81 81 82 void SpellingHandler::createSpellCheckRequest( PassRefPtr<WebCore::Range> rangeForSpellCheckingPtr, WebCore::TextCheckingProcessType textCheckingProcessType)82 void SpellingHandler::createSpellCheckRequest(const PassRefPtr<WebCore::Range> rangeForSpellCheckingPtr) 83 83 { 84 84 RefPtr<WebCore::Range> rangeForSpellChecking = rangeForSpellCheckingPtr; … … 87 87 return; 88 88 89 SpellingLog(Platform::LogLevelInfo, "SpellingHandler::createSpellCheckRequest Substring text is '%s', of size %d"90 , rangeForSpellChecking->text().latin1().data()91 , rangeForSpellChecking->text().length());92 93 if (rangeForSpellChecking->text().length() >= MinSpellCheckingStringLength)94 m_inputHandler->callRequestCheckingFor(SpellCheckRequest::create(TextCheckingTypeSpelling, textCheckingProcessType, rangeForSpellChecking, rangeForSpellChecking));89 if (rangeForSpellChecking->text().length() >= MinSpellCheckingStringLength) { 90 SpellingLog(Platform::LogLevelInfo, "SpellingHandler::createSpellCheckRequest Substring text is '%s', of size %d" 91 , rangeForSpellChecking->text().latin1().data() 92 , rangeForSpellChecking->text().length()); 93 m_inputHandler->callRequestCheckingFor(SpellCheckRequest::create(TextCheckingTypeSpelling, m_textCheckingProcessType, rangeForSpellChecking, rangeForSpellChecking)); 94 } 95 95 } 96 96 97 97 void SpellingHandler::parseBlockForSpellChecking(WebCore::Timer<SpellingHandler>*) 98 98 { 99 // Create a selection with the start and end points of the line, and convert to Range to create a SpellCheckRequest. 100 RefPtr<Range> rangeForSpellChecking = makeRange(m_startOfCurrentLine, m_endOfCurrentLine); 99 SpellingLog(Platform::LogLevelInfo, "SpellingHandler::parseBlockForSpellChecking m_startPosition = %d, m_endPosition = %d, m_cachedEndPosition = %d, m_endOfRange = %d" 100 , DOMSupport::offsetFromStartOfBlock(m_startPosition) 101 , DOMSupport::offsetFromStartOfBlock(m_endPosition) 102 , DOMSupport::offsetFromStartOfBlock(m_cachedEndPosition) 103 , DOMSupport::offsetFromStartOfBlock(m_endOfRange)); 104 105 if (m_startPosition == m_endOfRange) 106 return; 107 108 RefPtr<Range> rangeForSpellChecking = makeRange(m_startPosition, m_endPosition); 101 109 if (!rangeForSpellChecking) { 102 110 SpellingLog(Platform::LogLevelInfo, "SpellingHandler::parseBlockForSpellChecking Failed to set text range for spellchecking."); … … 105 113 106 114 if (rangeForSpellChecking->text().length() < MaxSpellCheckingStringLength) { 107 if (m_end OfCurrentLine == m_endOfRange) {108 createSpellCheckRequest(rangeForSpellChecking , m_textCheckingProcessType);115 if (m_endPosition == m_endOfRange || m_cachedEndPosition == m_endPosition) { 116 createSpellCheckRequest(rangeForSpellChecking); 109 117 m_isSpellCheckActive = false; 110 118 return; 111 119 } 112 m_endOfCurrentLine = endOfLine(nextLinePosition(m_endOfCurrentLine, m_endOfCurrentLine.lineDirectionPointForBlockDirectionNavigation())); 120 121 incrementSentinels(false /* shouldIncrementStartPosition */); 113 122 m_timer.startOneShot(s_timeout); 114 123 return; 115 124 } 116 125 117 // Iterate through words from the start of the line to the end. 118 rangeForSpellChecking = getRangeForSpellCheckWithFineGranularity(m_startOfCurrentLine, m_endOfCurrentLine); 119 if (!rangeForSpellChecking) 120 return; 126 // Create a spellcheck request with the substring if we have a range that is of size less than MaxSpellCheckingStringLength 127 if (rangeForSpellChecking = handleOversizedRange()) 128 createSpellCheckRequest(rangeForSpellChecking); 121 129 122 m_startOfCurrentLine = VisiblePosition(rangeForSpellChecking->endPosition());123 m_endOfCurrentLine = endOfLine(m_startOfCurrentLine);124 125 // Call spellcheck with substring.126 createSpellCheckRequest(rangeForSpellChecking, m_textCheckingProcessType);127 130 if (isSpellCheckActive()) 128 131 m_timer.startOneShot(s_timeout); 129 132 } 130 133 131 PassRefPtr<Range> SpellingHandler:: getRangeForSpellCheckWithFineGranularity(WebCore::VisiblePosition startPosition, WebCore::VisiblePosition endPosition)134 PassRefPtr<Range> SpellingHandler::handleOversizedRange() 132 135 { 133 SpellingLog(Platform::LogLevelWarn, "SpellingHandler::getRangeForSpellCheckWithFineGranularity"); 134 VisiblePosition endOfCurrentWord = endOfWord(startPosition); 135 RefPtr<Range> currentRange; 136 SpellingLog(Platform::LogLevelInfo, "SpellingHandler::handleOversizedRange"); 136 137 137 // Keep iterating until one of our cases is hit, or we've incremented the starting position right to the end.138 while (startPosition != endPosition) {139 currentRange = makeRange(startPosition, endOfCurrentWord);140 if (!currentRange)141 return 0;138 if (m_startPosition == m_cachedEndPosition || m_startPosition == startOfWord(m_endPosition, LeftWordIfOnBoundary)) { 139 // Our first word has gone over the character limit. Increment the starting position past an uncheckable word. 140 incrementSentinels(true /* shouldIncrementStartPosition */); 141 return 0; 142 } 142 143 143 // Check the text length within this range. 144 if (currentRange->text().length() >= MaxSpellCheckingStringLength) { 145 // If this is not the first word, return a Range with end boundary set to the previous word. 146 if (startOfWord(endOfCurrentWord, LeftWordIfOnBoundary) != startPosition && !DOMSupport::isEmptyRangeOrAllSpaces(startPosition, endOfCurrentWord)) { 147 // When a series of whitespace follows a word, previousWordPosition will jump passed all of them, and using LeftWordIfOnBoundary brings us to 148 // our starting position. Check for this case and use RightWordIfOnBoundary to jump back over the word. 149 VisiblePosition endOfPreviousWord = endOfWord(previousWordPosition(endOfCurrentWord), LeftWordIfOnBoundary); 150 if (startPosition == endOfPreviousWord) 151 return makeRange(startPosition, endOfWord(previousWordPosition(endOfCurrentWord), RightWordIfOnBoundary)); 152 return makeRange(startPosition, endOfPreviousWord); 153 } 154 // Our first word has gone over the character limit. Increment the starting position past an uncheckable word. 155 startPosition = endOfCurrentWord; 156 endOfCurrentWord = endOfWord(nextWordPosition(endOfCurrentWord)); 157 } else if (endOfCurrentWord == endPosition) 158 return makeRange(startPosition, endPosition); // Return the last segment if the end of our word lies at the end of the range. 159 else 160 endOfCurrentWord = endOfWord(nextWordPosition(endOfCurrentWord)); // Increment the current word. 144 // If this is not the first word, return a Range with end boundary set to the previous word. 145 RefPtr<Range> rangeToStartOfOversizedWord = makeRange(m_startPosition, m_cachedEndPosition); 146 // We've created the range using the cached end position. Now increment the sentinals forward. 147 // FIXME Incrementing the start/end positions outside of incrementSentinels 148 m_startPosition = m_cachedEndPosition; 149 m_endPosition = endOfWord(m_startPosition); 150 return rangeToStartOfOversizedWord; 151 } 152 153 void SpellingHandler::incrementSentinels(bool shouldIncrementStartPosition) 154 { 155 SpellingLog(Platform::LogLevelInfo, "SpellingHandler::incrementSentinels shouldIncrementStartPosition %s", shouldIncrementStartPosition ? "true" : "false"); 156 157 if (shouldIncrementStartPosition) 158 m_startPosition = m_endPosition; 159 160 VisiblePosition nextWord = nextWordPosition(m_endPosition); 161 VisiblePosition startOfNextWord = startOfWord(nextWord, LeftWordIfOnBoundary); 162 if (DOMSupport::isRangeTextAllWhitespace(m_endPosition, startOfNextWord)) { 163 m_cachedEndPosition = startOfNextWord; 164 m_endPosition = endOfWord(startOfNextWord); 165 return; 161 166 } 162 // This will return an range with no string, but allows processing to continue 163 return makeRange(startPosition, endPosition); 167 168 m_cachedEndPosition = m_endPosition; 169 m_endPosition = endOfWord(nextWord); 164 170 } 165 171 -
trunk/Source/WebKit/blackberry/WebKitSupport/SpellingHandler.h
r141041 r143391 31 31 ~SpellingHandler(); 32 32 33 void spellCheckTextBlock( WebCore::VisibleSelection&,WebCore::TextCheckingProcessType);33 void spellCheckTextBlock(const WebCore::VisibleSelection&, const WebCore::TextCheckingProcessType); 34 34 bool isSpellCheckActive() { return m_isSpellCheckActive; } 35 35 void setSpellCheckActive(bool active) { m_isSpellCheckActive = active; } 36 36 37 37 private: 38 void createSpellCheckRequest(PassRefPtr<WebCore::Range> rangeForSpellCheckingPtr , WebCore::TextCheckingProcessType);38 void createSpellCheckRequest(PassRefPtr<WebCore::Range> rangeForSpellCheckingPtr); 39 39 void parseBlockForSpellChecking(WebCore::Timer<SpellingHandler>*); 40 PassRefPtr<WebCore::Range> getRangeForSpellCheckWithFineGranularity(WebCore::VisiblePosition startPosition, WebCore::VisiblePosition endPosition); 40 void incrementSentinels(bool shouldIncrementStartPosition); 41 PassRefPtr<WebCore::Range> handleOversizedRange(); 41 42 42 43 InputHandler* m_inputHandler; 43 44 44 45 WebCore::Timer<SpellingHandler> m_timer; 45 WebCore::VisiblePosition m_startOfCurrentLine; 46 WebCore::VisiblePosition m_endOfCurrentLine; 47 WebCore::VisibleSelection m_endOfRange; 46 WebCore::VisiblePosition m_startPosition; 47 WebCore::VisiblePosition m_endPosition; 48 WebCore::VisiblePosition m_cachedEndPosition; 49 WebCore::VisiblePosition m_endOfRange; 48 50 WebCore::TextCheckingProcessType m_textCheckingProcessType; 49 51 bool m_isSpellCheckActive;
Note: See TracChangeset
for help on using the changeset viewer.