VisiblePosition SelectionModifier::nextWordPositionForPlatform( const VisiblePosition& originalPosition) { VisiblePosition positionAfterCurrentWord = nextWordPosition(originalPosition); if (frame() && frame()->editor().behavior().shouldSkipSpaceWhenMovingRight()) { // In order to skip spaces when moving right, we advance one // word further and then move one word back. Given the // semantics of previousWordPosition() this will put us at the // beginning of the word following. VisiblePosition positionAfterSpacingAndFollowingWord = nextWordPosition(positionAfterCurrentWord); if (positionAfterSpacingAndFollowingWord.isNotNull() && positionAfterSpacingAndFollowingWord.deepEquivalent() != positionAfterCurrentWord.deepEquivalent()) positionAfterCurrentWord = previousWordPosition(positionAfterSpacingAndFollowingWord); bool movingBackwardsMovedPositionToStartOfCurrentWord = positionAfterCurrentWord.deepEquivalent() == previousWordPosition(nextWordPosition(originalPosition)) .deepEquivalent(); if (movingBackwardsMovedPositionToStartOfCurrentWord) positionAfterCurrentWord = positionAfterSpacingAndFollowingWord; } return positionAfterCurrentWord; }
VisibleSelection visibleSelectionForClosestActualWordStart(const VisibleSelection& selection) { // VisibleSelection validation has a special case when the caret is at the end of a paragraph where // it selects the paragraph marker. As well, if the position is at the end of a word, it will select // only the space between words. We want to select an actual word so we move the selection to // the start of the leftmost word if the character after the selection point is whitespace. if (selection.selectionType() != VisibleSelection::RangeSelection) { int leftDistance = 0; int rightDistance = 0; VisibleSelection leftSelection(previousWordPosition(selection.start())); bool leftSelectionIsOnWord = !isWhitespace(leftSelection.visibleStart().characterAfter()) && leftSelection.start().containerNode() == selection.start().containerNode(); if (leftSelectionIsOnWord) { VisibleSelection rangeSelection(endOfWord(leftSelection.start()), selection.visibleStart()); leftDistance = TextIterator::rangeLength(rangeSelection.toNormalizedRange().get()); } VisibleSelection rightSelection = previousWordPosition(nextWordPosition(selection.start())); bool rightSelectionIsOnWord = !isWhitespace(rightSelection.visibleStart().characterAfter()) && rightSelection.start().containerNode() == selection.start().containerNode(); if (rightSelectionIsOnWord) { VisibleSelection rangeSelection = VisibleSelection(rightSelection.visibleStart(), selection.visibleStart()); rightDistance = TextIterator::rangeLength(rangeSelection.toNormalizedRange().get()); } // Make sure we found an actual word. If not, return the original selection. if (!leftSelectionIsOnWord && !rightSelectionIsOnWord) return selection; if (!rightSelectionIsOnWord || (leftSelectionIsOnWord && leftDistance <= rightDistance)) { // Left is closer or right is invalid. return leftSelection; } // Right is closer or equal, or left was invalid. return rightSelection; } // No adjustment required. return selection; }
void SpellChecker::updateMarkersForWordsAffectedByEditing(bool doNotRemoveIfSelectionAtWordBoundary) { if (textChecker().shouldEraseMarkersAfterChangeSelection(TextCheckingTypeSpelling)) return; // We want to remove the markers from a word if an editing command will change the word. This can happen in one of // several scenarios: // 1. Insert in the middle of a word. // 2. Appending non whitespace at the beginning of word. // 3. Appending non whitespace at the end of word. // Note that, appending only whitespaces at the beginning or end of word won't change the word, so we don't need to // remove the markers on that word. // Of course, if current selection is a range, we potentially will edit two words that fall on the boundaries of // selection, and remove words between the selection boundaries. // VisiblePosition startOfSelection = m_frame.selection().selection().visibleStart(); VisiblePosition endOfSelection = m_frame.selection().selection().visibleEnd(); if (startOfSelection.isNull()) return; // First word is the word that ends after or on the start of selection. VisiblePosition startOfFirstWord = startOfWord(startOfSelection, LeftWordIfOnBoundary); VisiblePosition endOfFirstWord = endOfWord(startOfSelection, LeftWordIfOnBoundary); // Last word is the word that begins before or on the end of selection VisiblePosition startOfLastWord = startOfWord(endOfSelection, RightWordIfOnBoundary); VisiblePosition endOfLastWord = endOfWord(endOfSelection, RightWordIfOnBoundary); if (startOfFirstWord.isNull()) { startOfFirstWord = startOfWord(startOfSelection, RightWordIfOnBoundary); endOfFirstWord = endOfWord(startOfSelection, RightWordIfOnBoundary); } if (endOfLastWord.isNull()) { startOfLastWord = startOfWord(endOfSelection, LeftWordIfOnBoundary); endOfLastWord = endOfWord(endOfSelection, LeftWordIfOnBoundary); } // If doNotRemoveIfSelectionAtWordBoundary is true, and first word ends at the start of selection, // we choose next word as the first word. if (doNotRemoveIfSelectionAtWordBoundary && endOfFirstWord == startOfSelection) { startOfFirstWord = nextWordPosition(startOfFirstWord); endOfFirstWord = endOfWord(startOfFirstWord, RightWordIfOnBoundary); if (startOfFirstWord == endOfSelection) return; } // If doNotRemoveIfSelectionAtWordBoundary is true, and last word begins at the end of selection, // we choose previous word as the last word. if (doNotRemoveIfSelectionAtWordBoundary && startOfLastWord == endOfSelection) { startOfLastWord = previousWordPosition(startOfLastWord); endOfLastWord = endOfWord(startOfLastWord, RightWordIfOnBoundary); if (endOfLastWord == startOfSelection) return; } if (startOfFirstWord.isNull() || endOfFirstWord.isNull() || startOfLastWord.isNull() || endOfLastWord.isNull()) return; // Now we remove markers on everything between startOfFirstWord and endOfLastWord. // However, if an autocorrection change a single word to multiple words, we want to remove correction mark from all the // resulted words even we only edit one of them. For example, assuming autocorrection changes "avantgarde" to "avant // garde", we will have CorrectionIndicator marker on both words and on the whitespace between them. If we then edit garde, // we would like to remove the marker from word "avant" and whitespace as well. So we need to get the continous range of // of marker that contains the word in question, and remove marker on that whole range. Document* document = m_frame.document(); ASSERT(document); RefPtr<Range> wordRange = Range::create(*document, startOfFirstWord.deepEquivalent(), endOfLastWord.deepEquivalent()); document->markers().removeMarkers(wordRange.get(), DocumentMarker::MisspellingMarkers(), DocumentMarkerController::RemovePartiallyOverlappingMarker); }