summaryrefslogtreecommitdiffstats
path: root/WebCore/editing/Editor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/editing/Editor.cpp')
-rw-r--r--WebCore/editing/Editor.cpp286
1 files changed, 193 insertions, 93 deletions
diff --git a/WebCore/editing/Editor.cpp b/WebCore/editing/Editor.cpp
index c74d765..327aa5f 100644
--- a/WebCore/editing/Editor.cpp
+++ b/WebCore/editing/Editor.cpp
@@ -457,9 +457,53 @@ bool Editor::shouldShowDeleteInterface(HTMLElement* element) const
void Editor::respondToChangedSelection(const VisibleSelection& oldSelection)
{
+#if SUPPORT_AUTOCORRECTION_PANEL
+ VisibleSelection currentSelection(frame()->selection()->selection());
+ if (currentSelection != oldSelection) {
+ stopCorrectionPanelTimer();
+ dismissCorrectionPanel(CorrectionWasNotRejected);
+ }
+#endif // SUPPORT_AUTOCORRECTION_PANEL
+
if (client())
client()->respondToChangedSelection();
m_deleteButtonController->respondToChangedSelection(oldSelection);
+
+#if SUPPORT_AUTOCORRECTION_PANEL
+ // When user moves caret to the end of autocorrected word and pauses, we show the panel
+ // containing the original pre-correction word so that user can quickly revert the
+ // undesired autocorrection. Here, we start correction panel timer once we confirm that
+ // the new caret position is at the end of a word.
+ if (!currentSelection.isCaret() || currentSelection == oldSelection)
+ return;
+
+ VisiblePosition selectionPosition = currentSelection.start();
+ VisiblePosition endPositionOfWord = endOfWord(selectionPosition, LeftWordIfOnBoundary);
+ if (selectionPosition != endPositionOfWord)
+ return;
+
+ Position position = endPositionOfWord.deepEquivalent();
+ if (position.anchorType() != Position::PositionIsOffsetInAnchor)
+ return;
+
+ Node* node = position.containerNode();
+ int endOffset = position.offsetInContainerNode();
+ Vector<DocumentMarker> markers = node->document()->markers()->markersForNode(node);
+ size_t markerCount = markers.size();
+ for (size_t i = 0; i < markerCount; ++i) {
+ const DocumentMarker& marker = markers[i];
+ if (marker.type == DocumentMarker::CorrectionIndicator && static_cast<int>(marker.endOffset) == endOffset) {
+ RefPtr<Range> wordRange = Range::create(frame()->document(), node, marker.startOffset, node, marker.endOffset);
+ String currentWord = plainText(wordRange.get());
+ if (currentWord.length() > 0 && marker.description.length() > 0) {
+ m_correctionPanelInfo.m_rangeToBeReplaced = wordRange;
+ m_correctionPanelInfo.m_replacementString = marker.description;
+ startCorrectionPanelTimer(CorrectionPanelInfo::PanelTypeReversion);
+ }
+ break;
+ }
+ }
+#endif // SUPPORT_AUTOCORRECTION_PANEL
}
void Editor::respondToChangedContents(const VisibleSelection& endingSelection)
@@ -564,7 +608,8 @@ WritingDirection Editor::textDirectionForSelection(bool& hasNestedOrMultipleEmbe
}
if (m_frame->selection()->isCaret()) {
- if (CSSMutableStyleDeclaration* typingStyle = m_frame->selection()->typingStyle()) {
+ RefPtr<CSSMutableStyleDeclaration> typingStyle = m_frame->selection()->typingStyle();
+ if (typingStyle) {
RefPtr<CSSValue> unicodeBidi = typingStyle->getPropertyCSSValue(CSSPropertyUnicodeBidi);
if (unicodeBidi) {
ASSERT(unicodeBidi->isPrimitiveValue());
@@ -998,10 +1043,13 @@ static void dispatchEditableContentChangedEvents(const EditCommand& command)
void Editor::appliedEditing(PassRefPtr<EditCommand> cmd)
{
+ // We may start reversion panel timer in respondToChangedSelection().
+ // So we stop the timer for current panel before calling changeSelectionAfterCommand() later in this method.
+ stopCorrectionPanelTimer();
m_frame->document()->updateLayout();
-
+
dispatchEditableContentChangedEvents(*cmd);
-
+
VisibleSelection newSelection(cmd->endingSelection());
// Don't clear the typing style with this selection change. We do those things elsewhere if necessary.
changeSelectionAfterCommand(newSelection, false, false);
@@ -1020,7 +1068,6 @@ void Editor::appliedEditing(PassRefPtr<EditCommand> cmd)
client()->registerCommandForUndo(m_lastEditCommand);
}
respondToChangedContents(newSelection);
- stopCorrectionPanelTimer();
}
void Editor::unappliedEditing(PassRefPtr<EditCommand> cmd)
@@ -1068,9 +1115,8 @@ Editor::Editor(Frame* frame)
Editor::~Editor()
{
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
- if (client())
- client()->dismissCorrectionPanel(true);
+#if SUPPORT_AUTOCORRECTION_PANEL
+ dismissCorrectionPanel(CorrectionWasNotRejected);
#endif
}
@@ -1671,7 +1717,6 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
// repeated "check spelling" commands work.
VisibleSelection selection(frame()->selection()->selection());
RefPtr<Range> spellingSearchRange(rangeOfContents(frame()->document()));
- TextCheckingHelper checker(client(), spellingSearchRange);
bool startedWithSelection = false;
if (selection.start().node()) {
@@ -1738,7 +1783,7 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
bool isSpelling = true;
int foundOffset = 0;
GrammarDetail grammarDetail;
- String foundItem = checker.findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
+ String foundItem = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
if (isSpelling) {
misspelledWord = foundItem;
misspellingOffset = foundOffset;
@@ -1748,7 +1793,7 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
}
#else
RefPtr<Range> firstMisspellingRange;
- String misspelledWord = checker.findFirstMisspelling(misspellingOffset, false, firstMisspellingRange);
+ String misspelledWord = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspelling(misspellingOffset, false, firstMisspellingRange);
String badGrammarPhrase;
#ifndef BUILDING_ON_TIGER
@@ -1765,7 +1810,7 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
}
if (isGrammarCheckingEnabled())
- badGrammarPhrase = checker.findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
+ badGrammarPhrase = TextCheckingHelper(client(), grammarSearchRange).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
#endif
#endif
@@ -1778,7 +1823,7 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
grammarSearchRange = spellingSearchRange->cloneRange(ec);
- foundItem = checker.findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
+ foundItem = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
if (isSpelling) {
misspelledWord = foundItem;
misspellingOffset = foundOffset;
@@ -1787,7 +1832,7 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
grammarPhraseOffset = foundOffset;
}
#else
- misspelledWord = checker.findFirstMisspelling(misspellingOffset, false, firstMisspellingRange);
+ misspelledWord = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspelling(misspellingOffset, false, firstMisspellingRange);
#ifndef BUILDING_ON_TIGER
grammarSearchRange = spellingSearchRange->cloneRange(ec);
@@ -1797,8 +1842,9 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
chars.advance(misspellingOffset);
grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec);
}
+
if (isGrammarCheckingEnabled())
- badGrammarPhrase = checker.findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
+ badGrammarPhrase = TextCheckingHelper(client(), grammarSearchRange).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
#endif
#endif
}
@@ -1967,47 +2013,10 @@ void Editor::markMisspellingsAndBadGrammar(const VisibleSelection &movingSelecti
void Editor::markMisspellingsAfterTypingToPosition(const VisiblePosition &p)
{
#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
-#if !defined(BUILDING_ON_SNOW_LEOPARD)
+#if SUPPORT_AUTOCORRECTION_PANEL
// Apply pending autocorrection before next round of spell checking.
- bool didApplyCorrection = false;
- if (m_rangeToBeReplacedByCorrection) {
- ExceptionCode ec = 0;
- RefPtr<Range> paragraphRangeContainingCorrection = m_rangeToBeReplacedByCorrection->cloneRange(ec);
- if (!ec) {
- setStart(paragraphRangeContainingCorrection.get(), startOfParagraph(m_rangeToBeReplacedByCorrection->startPosition()));
- setEnd(paragraphRangeContainingCorrection.get(), endOfParagraph(m_rangeToBeReplacedByCorrection->endPosition()));
- // After we replace the word at range m_rangeToBeReplacedByCorrection, we need to add
- // autocorrection underline at that range. However, once the replacement took place, the
- // value of m_rangeToBeReplacedByCorrection is not valid anymore. So before we carry out
- // the replacement, we need to store the start position of m_rangeToBeReplacedByCorrection
- // relative to the start position of the containing paragraph. We use correctionStartOffsetInParagraph
- // to store this value. In order to obtain this offset, we need to first create a range
- // which spans from the start of paragraph to the start position of m_rangeToBeReplacedByCorrection.
- RefPtr<Range> correctionStartOffsetInParagraphAsRange = Range::create(paragraphRangeContainingCorrection->startContainer(ec)->document(), paragraphRangeContainingCorrection->startPosition(), paragraphRangeContainingCorrection->startPosition());
- if (!ec) {
- Position startPositionOfRangeToBeReplaced = m_rangeToBeReplacedByCorrection->startPosition();
- correctionStartOffsetInParagraphAsRange->setEnd(startPositionOfRangeToBeReplaced.containerNode(), startPositionOfRangeToBeReplaced.computeOffsetInContainerNode(), ec);
- if (!ec) {
- // Take note of the location of autocorrection so that we can add marker after the replacement took place.
- int correctionStartOffsetInParagraph = TextIterator::rangeLength(correctionStartOffsetInParagraphAsRange.get());
- Position caretPosition = m_frame->selection()->selection().end();
- RefPtr<Range> rangeToBeReplaced = m_rangeToBeReplacedByCorrection->cloneRange(ec);
- VisibleSelection selectionToReplace(rangeToBeReplaced.get(), DOWNSTREAM);
- if (m_frame->selection()->shouldChangeSelection(selectionToReplace)) {
- m_frame->selection()->setSelection(selectionToReplace);
- replaceSelectionWithText(m_correctionReplacementString, false, false);
- caretPosition.moveToOffset(caretPosition.offsetInContainerNode() + m_correctionReplacementString.length() - m_stringToBeReplacedByCorrection.length());
- RefPtr<Range> replacementRange = TextIterator::subrange(paragraphRangeContainingCorrection.get(), correctionStartOffsetInParagraph, m_correctionReplacementString.length());
- replacementRange->startContainer()->document()->markers()->addMarker(replacementRange.get(), DocumentMarker::Replacement, m_correctionReplacementString);
- replacementRange->startContainer()->document()->markers()->addMarker(replacementRange.get(), DocumentMarker::CorrectionIndicator);
- m_frame->selection()->moveTo(caretPosition, false);
- didApplyCorrection = true;
- }
- }
- }
- }
- m_rangeToBeReplacedByCorrection.clear();
- }
+ applyCorrectionPanelInfo(true);
+ m_correctionPanelInfo.m_rangeToBeReplaced.clear();
#endif
TextCheckingOptions textCheckingOptions = 0;
@@ -2095,7 +2104,7 @@ void Editor::markMisspellingsOrBadGrammar(const VisibleSelection& selection, boo
if (!editableNode || !editableNode->isContentEditable())
return;
- if (!isSpellCheckingEnabledInFocusedNode())
+ if (!isSpellCheckingEnabledFor(editableNode))
return;
// Get the spell checker if it is available
@@ -2115,11 +2124,8 @@ void Editor::markMisspellingsOrBadGrammar(const VisibleSelection& selection, boo
}
}
-bool Editor::isSpellCheckingEnabledInFocusedNode() const
+bool Editor::isSpellCheckingEnabledFor(Node* node) const
{
- // Ascend the DOM tree to find a "spellcheck" attribute.
- // When we find a "spellcheck" attribute, retrieve its value and return false if its value is "false".
- const Node* node = frame()->document()->focusedNode();
if (!node)
return false;
const Element* focusedElement = node->isElementNode() ? toElement(node) : node->parentElement();
@@ -2128,6 +2134,11 @@ bool Editor::isSpellCheckingEnabledInFocusedNode() const
return focusedElement->isSpellCheckingEnabled();
}
+bool Editor::isSpellCheckingEnabledInFocusedNode() const
+{
+ return isSpellCheckingEnabledFor(m_frame->selection()->start().node());
+}
+
void Editor::markMisspellings(const VisibleSelection& selection, RefPtr<Range>& firstMisspellingRange)
{
markMisspellingsOrBadGrammar(selection, true, firstMisspellingRange);
@@ -2170,7 +2181,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
if (!editableNode || !editableNode->isContentEditable())
return;
- if (!isSpellCheckingEnabledInFocusedNode())
+ if (!isSpellCheckingEnabledFor(editableNode))
return;
// Expand the range to encompass entire paragraphs, since text checking needs that much context.
@@ -2187,16 +2198,15 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
bool adjustSelectionForParagraphBoundaries = false;
String paragraphString;
RefPtr<Range> paragraphRange;
- TextCheckingHelper checker(client(), grammarRange);
if (shouldMarkGrammar) {
// The spelling range should be contained in the paragraph-aligned extension of the grammar range.
- paragraphRange = checker.paragraphAlignedRange(grammarRangeStartOffset, paragraphString);
+ paragraphRange = TextCheckingHelper(client(), grammarRange).paragraphAlignedRange(grammarRangeStartOffset, paragraphString);
RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), spellingRange->startPosition());
spellingRangeStartOffset = TextIterator::rangeLength(offsetAsRange.get());
grammarRangeEndOffset = grammarRangeStartOffset + TextIterator::rangeLength(grammarRange);
} else {
- paragraphRange = checker.paragraphAlignedRange(spellingRangeStartOffset, paragraphString);
+ paragraphRange = TextCheckingHelper(client(), spellingRange).paragraphAlignedRange(spellingRangeStartOffset, paragraphString);
}
spellingRangeEndOffset = spellingRangeStartOffset + TextIterator::rangeLength(spellingRange);
paragraphLength = paragraphString.length();
@@ -2242,7 +2252,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
}
client()->checkTextOfParagraph(paragraphString.characters(), paragraphLength, checkingTypes, results);
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#if SUPPORT_AUTOCORRECTION_PANEL
// If this checking is only for showing correction panel, we shouldn't bother to mark misspellings.
if (shouldShowCorrectionPanel)
shouldMarkSpelling = false;
@@ -2327,7 +2337,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
} else if (canEdit() && shouldInsertText(result->replacement, rangeToReplace.get(), EditorInsertActionTyped)) {
if (result->type == TextCheckingTypeCorrection)
replacedString = plainText(rangeToReplace.get());
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#if SUPPORT_AUTOCORRECTION_PANEL
if (shouldShowCorrectionPanel && resultLocation + resultLength == spellingRangeEndOffset && result->type == TextCheckingTypeCorrection) {
// We only show the correction panel on the last word.
Vector<FloatQuad> textQuads;
@@ -2336,10 +2346,11 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
FloatRect totalBoundingBox;
for (Vector<FloatQuad>::const_iterator it = textQuads.begin(); it < end; ++it)
totalBoundingBox.unite(it->boundingBox());
- m_rangeToBeReplacedByCorrection = rangeToReplace;
- m_stringToBeReplacedByCorrection = replacedString;
- m_correctionReplacementString = result->replacement;
- client()->showCorrectionPanel(totalBoundingBox, m_stringToBeReplacedByCorrection, result->replacement, this);
+ m_correctionPanelInfo.m_rangeToBeReplaced = rangeToReplace;
+ m_correctionPanelInfo.m_replacedString = replacedString;
+ m_correctionPanelInfo.m_replacementString = result->replacement;
+ m_correctionPanelInfo.m_isActive = true;
+ client()->showCorrectionPanel(m_correctionPanelInfo.m_panelType, totalBoundingBox, m_correctionPanelInfo.m_replacedString, result->replacement, this);
doReplacement = false;
}
#endif
@@ -2353,7 +2364,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
// Add a marker so that corrections can easily be undone and won't be re-corrected.
RefPtr<Range> replacedRange = TextIterator::subrange(paragraphRange.get(), resultLocation, replacementLength);
replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::Replacement, replacedString);
- replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::CorrectionIndicator);
+ replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::CorrectionIndicator, replacedString);
}
}
}
@@ -2416,60 +2427,99 @@ void Editor::markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelec
void Editor::correctionPanelTimerFired(Timer<Editor>*)
{
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
- VisibleSelection selection(frame()->selection()->selection());
- VisiblePosition start(selection.start(), selection.affinity());
- VisiblePosition p = startOfWord(start, LeftWordIfOnBoundary);
- VisibleSelection adjacentWords = VisibleSelection(p, start);
- markAllMisspellingsAndBadGrammarInRanges(MarkSpelling | ShowCorrectionPanel, adjacentWords.toNormalizedRange().get(), 0);
+#if SUPPORT_AUTOCORRECTION_PANEL
+ if (m_correctionPanelInfo.m_panelType == CorrectionPanelInfo::PanelTypeCorrection) {
+ VisibleSelection selection(frame()->selection()->selection());
+ VisiblePosition start(selection.start(), selection.affinity());
+ VisiblePosition p = startOfWord(start, LeftWordIfOnBoundary);
+ VisibleSelection adjacentWords = VisibleSelection(p, start);
+ markAllMisspellingsAndBadGrammarInRanges(MarkSpelling | ShowCorrectionPanel, adjacentWords.toNormalizedRange().get(), 0);
+ } else {
+ String currentWord = plainText(m_correctionPanelInfo.m_rangeToBeReplaced.get());
+ Vector<FloatQuad> textQuads;
+ m_correctionPanelInfo.m_rangeToBeReplaced->getBorderAndTextQuads(textQuads);
+ Vector<FloatQuad>::const_iterator end = textQuads.end();
+ FloatRect totalBoundingBox;
+ for (Vector<FloatQuad>::const_iterator it = textQuads.begin(); it < end; ++it)
+ totalBoundingBox.unite(it->boundingBox());
+ m_correctionPanelInfo.m_isActive = true;
+ m_correctionPanelInfo.m_replacedString = currentWord;
+ client()->showCorrectionPanel(m_correctionPanelInfo.m_panelType, totalBoundingBox, m_correctionPanelInfo.m_replacedString, m_correctionPanelInfo.m_replacementString, this);
+ }
#endif
}
void Editor::handleRejectedCorrection()
{
- Range* replacedRange = m_rangeToBeReplacedByCorrection.get();
+ Range* replacedRange = m_correctionPanelInfo.m_rangeToBeReplaced.get();
if (!replacedRange || m_frame->document() != replacedRange->ownerDocument())
return;
- replacedRange->startContainer()->document()->markers()->addMarker(replacedRange, DocumentMarker::RejectedCorrection, m_stringToBeReplacedByCorrection);
- m_rangeToBeReplacedByCorrection.clear();
+ if (m_correctionPanelInfo.m_panelType == CorrectionPanelInfo::PanelTypeCorrection)
+ replacedRange->startContainer()->document()->markers()->addMarker(replacedRange, DocumentMarker::RejectedCorrection, m_correctionPanelInfo.m_replacedString);
+ else {
+ m_correctionPanelInfo.m_isActive = false;
+ applyCorrectionPanelInfo(false);
+ }
+ m_correctionPanelInfo.m_rangeToBeReplaced.clear();
}
-void Editor::startCorrectionPanelTimer()
+void Editor::startCorrectionPanelTimer(CorrectionPanelInfo::PanelType type)
{
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
- static const double correctionPanelTimerInterval = 0.3;
+#if SUPPORT_AUTOCORRECTION_PANEL
+ const double correctionPanelTimerInterval = 0.3;
if (isAutomaticSpellingCorrectionEnabled()) {
- m_rangeToBeReplacedByCorrection.clear();
+ if (type == CorrectionPanelInfo::PanelTypeCorrection)
+ // If type is PanelTypeReversion, then the new range has been set. So we shouldn't clear it.
+ m_correctionPanelInfo.m_rangeToBeReplaced.clear();
+ m_correctionPanelInfo.m_panelType = type;
m_correctionPanelTimer.startOneShot(correctionPanelTimerInterval);
}
+#else
+ UNUSED_PARAM(type);
#endif
}
void Editor::stopCorrectionPanelTimer()
{
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#if SUPPORT_AUTOCORRECTION_PANEL
m_correctionPanelTimer.stop();
#endif
}
void Editor::handleCancelOperation()
{
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#if SUPPORT_AUTOCORRECTION_PANEL
+ if (!m_correctionPanelInfo.m_isActive)
+ return;
+ m_correctionPanelInfo.m_isActive = false;
if (client())
- client()->dismissCorrectionPanel(false);
+ client()->dismissCorrectionPanel(CorrectionWasRejected);
#endif
}
bool Editor::isShowingCorrectionPanel()
{
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#if SUPPORT_AUTOCORRECTION_PANEL
if (client())
return client()->isShowingCorrectionPanel();
#endif
return false;
}
+void Editor::dismissCorrectionPanel(CorrectionWasRejectedOrNot correctionWasRejectedOrNot)
+{
+#if SUPPORT_AUTOCORRECTION_PANEL
+ if (!m_correctionPanelInfo.m_isActive)
+ return;
+ m_correctionPanelInfo.m_isActive = false;
+ m_correctionPanelInfo.m_rangeToBeReplaced.clear();
+ if (client())
+ client()->dismissCorrectionPanel(correctionWasRejectedOrNot);
+#else
+ UNUSED_PARAM(correctionWasRejectedOrNot);
+#endif
+}
void Editor::removeSpellAndCorrectionMarkersFromWordsToBeEdited(bool doNotRemoveIfSelectionAtWordBoundary)
{
// We want to remove the markers from a word if an editing command will change the word. This can happen in one of
@@ -2536,6 +2586,8 @@ void Editor::removeSpellAndCorrectionMarkersFromWordsToBeEdited(bool doNotRemove
Vector<RangeMarkerPair, 16> markersToRemove;
for (TextIterator textIterator(wordRange.get()); !textIterator.atEnd(); textIterator.advance()) {
Node* node = textIterator.node();
+ if (!node)
+ continue;
if (node == startOfFirstWord.deepEquivalent().containerNode() || node == endOfLastWord.deepEquivalent().containerNode()) {
// First word and last word can belong to the same node
bool processFirstWord = node == startOfFirstWord.deepEquivalent().containerNode() && document->markers()->hasMarkers(rangeOfFirstWord.get(), DocumentMarker::Spelling | DocumentMarker::CorrectionIndicator);
@@ -2565,6 +2617,54 @@ void Editor::removeSpellAndCorrectionMarkersFromWordsToBeEdited(bool doNotRemove
document->markers()->removeMarkers(pairIterator->first.get(), pairIterator->second);
}
+void Editor::applyCorrectionPanelInfo(bool addCorrectionIndicatorMarker)
+{
+ if (!m_correctionPanelInfo.m_rangeToBeReplaced)
+ return;
+
+ ExceptionCode ec = 0;
+ RefPtr<Range> paragraphRangeContainingCorrection = m_correctionPanelInfo.m_rangeToBeReplaced->cloneRange(ec);
+ if (ec)
+ return;
+
+ setStart(paragraphRangeContainingCorrection.get(), startOfParagraph(m_correctionPanelInfo.m_rangeToBeReplaced->startPosition()));
+ setEnd(paragraphRangeContainingCorrection.get(), endOfParagraph(m_correctionPanelInfo.m_rangeToBeReplaced->endPosition()));
+
+ // After we replace the word at range m_rangeToBeReplaced, we need to add markers to that range.
+ // However, once the replacement took place, the value of m_rangeToBeReplaced is not valid anymore.
+ // So before we carry out the replacement, we need to store the start position of m_rangeToBeReplaced
+ // relative to the start position of the containing paragraph. We use correctionStartOffsetInParagraph
+ // to store this value. In order to obtain this offset, we need to first create a range
+ // which spans from the start of paragraph to the start position of m_rangeToBeReplaced.
+ RefPtr<Range> correctionStartOffsetInParagraphAsRange = Range::create(paragraphRangeContainingCorrection->startContainer(ec)->document(), paragraphRangeContainingCorrection->startPosition(), paragraphRangeContainingCorrection->startPosition());
+ if (ec)
+ return;
+
+ Position startPositionOfRangeToBeReplaced = m_correctionPanelInfo.m_rangeToBeReplaced->startPosition();
+ correctionStartOffsetInParagraphAsRange->setEnd(startPositionOfRangeToBeReplaced.containerNode(), startPositionOfRangeToBeReplaced.computeOffsetInContainerNode(), ec);
+ if (ec)
+ return;
+
+ // Take note of the location of autocorrection so that we can add marker after the replacement took place.
+ int correctionStartOffsetInParagraph = TextIterator::rangeLength(correctionStartOffsetInParagraphAsRange.get());
+ Position caretPosition = m_frame->selection()->selection().end();
+
+ // Clone the range, since the caller of this method may want to keep the original range around.
+ RefPtr<Range> rangeToBeReplaced = m_correctionPanelInfo.m_rangeToBeReplaced->cloneRange(ec);
+ VisibleSelection selectionToReplace(rangeToBeReplaced.get(), DOWNSTREAM);
+ if (m_frame->selection()->shouldChangeSelection(selectionToReplace)) {
+ m_frame->selection()->setSelection(selectionToReplace);
+ replaceSelectionWithText(m_correctionPanelInfo.m_replacementString, false, false);
+ caretPosition.moveToOffset(caretPosition.offsetInContainerNode() + m_correctionPanelInfo.m_replacementString.length() - m_correctionPanelInfo.m_replacedString.length());
+ setEnd(paragraphRangeContainingCorrection.get(), endOfParagraph(caretPosition));
+ RefPtr<Range> replacementRange = TextIterator::subrange(paragraphRangeContainingCorrection.get(), correctionStartOffsetInParagraph, m_correctionPanelInfo.m_replacementString.length());
+ replacementRange->startContainer()->document()->markers()->addMarker(replacementRange.get(), DocumentMarker::Replacement, m_correctionPanelInfo.m_replacementString);
+ if (addCorrectionIndicatorMarker)
+ replacementRange->startContainer()->document()->markers()->addMarker(replacementRange.get(), DocumentMarker::CorrectionIndicator, m_correctionPanelInfo.m_replacedString);
+ m_frame->selection()->moveTo(caretPosition, false);
+ }
+}
+
PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
{
Document* document = m_frame->documentAtPoint(windowPoint);
@@ -2831,7 +2931,7 @@ void Editor::changeSelectionAfterCommand(const VisibleSelection& newSelection, b
if (newSelection.start().isOrphan() || newSelection.end().isOrphan())
return;
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#if SUPPORT_AUTOCORRECTION_PANEL
// Check to see if the command introduced paragraph separator. If it did, we remove existing autocorrection underlines.
// This is in consistency with the behavior in AppKit
if (!inSameParagraph(m_frame->selection()->selection().visibleStart(), newSelection.visibleEnd()))
@@ -2954,7 +3054,7 @@ void Editor::computeAndSetTypingStyle(CSSStyleDeclaration* style, EditAction edi
applyCommand(ApplyStyleCommand::create(m_frame->document(), blockStyle.get(), editingAction));
// Set the remaining style as the typing style.
- m_frame->selection()->setTypingStyle(mutableStyle.release());
+ m_frame->selection()->setTypingStyle(EditingStyle::create(mutableStyle.get()));
}
PassRefPtr<CSSMutableStyleDeclaration> Editor::selectionComputedStyle(bool& shouldUseFixedFontDefaultSize) const
@@ -2985,10 +3085,10 @@ PassRefPtr<CSSMutableStyleDeclaration> Editor::selectionComputedStyle(bool& shou
if (!m_frame->selection()->typingStyle())
return mutableStyle;
- RefPtr<CSSMutableStyleDeclaration> typingStyle = m_frame->selection()->typingStyle()->copy();
- ApplyStyleCommand::removeNonEditingProperties(typingStyle.get());
- prepareEditingStyleToApplyAt(typingStyle.get(), position);
- mutableStyle->merge(typingStyle.get());
+ RefPtr<EditingStyle> typingStyle = EditingStyle::create(m_frame->selection()->typingStyle());
+ typingStyle->removeNonEditingProperties();
+ typingStyle->prepareToApplyAt(position);
+ mutableStyle->merge(typingStyle->style());
return mutableStyle;
}