summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/editing/Editor.cpp
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-06-02 12:07:03 +0100
committerBen Murdoch <benm@google.com>2011-06-10 10:47:21 +0100
commit2daae5fd11344eaa88a0d92b0f6d65f8d2255c00 (patch)
treee4964fbd1cb70599f7718ff03e50ea1dab33890b /Source/WebCore/editing/Editor.cpp
parent87bdf0060a247bfbe668342b87e0874182e0ffa9 (diff)
downloadexternal_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.zip
external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.gz
external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.bz2
Merge WebKit at r84325: Initial merge by git.
Change-Id: Ic1a909300ecc0a13ddc6b4e784371d2ac6e3d59b
Diffstat (limited to 'Source/WebCore/editing/Editor.cpp')
-rw-r--r--Source/WebCore/editing/Editor.cpp591
1 files changed, 139 insertions, 452 deletions
diff --git a/Source/WebCore/editing/Editor.cpp b/Source/WebCore/editing/Editor.cpp
index a793e0b..e7c5c1d 100644
--- a/Source/WebCore/editing/Editor.cpp
+++ b/Source/WebCore/editing/Editor.cpp
@@ -38,6 +38,7 @@
#include "CachedResourceLoader.h"
#include "ClipboardEvent.h"
#include "CompositionEvent.h"
+#include "SpellingCorrectionController.h"
#include "CreateLinkCommand.h"
#include "DeleteButtonController.h"
#include "DeleteSelectionCommand.h"
@@ -64,7 +65,6 @@
#include "NodeList.h"
#include "Page.h"
#include "Pasteboard.h"
-#include "TextCheckerClient.h"
#include "TextCheckingHelper.h"
#include "RemoveFormatCommand.h"
#include "RenderBlock.h"
@@ -94,35 +94,6 @@ using namespace HTMLNames;
using namespace WTF;
using namespace Unicode;
-static inline bool isAmbiguousBoundaryCharacter(UChar character)
-{
- // These are characters that can behave as word boundaries, but can appear within words.
- // If they are just typed, i.e. if they are immediately followed by a caret, we want to delay text checking until the next character has been typed.
- // FIXME: this is required until 6853027 is fixed and text checking can do this for us.
- return character == '\'' || character == rightSingleQuotationMark || character == hebrewPunctuationGershayim;
-}
-
-static const Vector<DocumentMarker::MarkerType>& markerTypesForAutocorrection()
-{
- DEFINE_STATIC_LOCAL(Vector<DocumentMarker::MarkerType>, markerTypesForAutoCorrection, ());
- if (markerTypesForAutoCorrection.isEmpty()) {
- markerTypesForAutoCorrection.append(DocumentMarker::Replacement);
- markerTypesForAutoCorrection.append(DocumentMarker::CorrectionIndicator);
- markerTypesForAutoCorrection.append(DocumentMarker::SpellCheckingExemption);
- }
- return markerTypesForAutoCorrection;
-}
-
-static const Vector<DocumentMarker::MarkerType>& markerTypesForReplacement()
-{
- DEFINE_STATIC_LOCAL(Vector<DocumentMarker::MarkerType>, markerTypesForReplacement, ());
- if (markerTypesForReplacement.isEmpty()) {
- markerTypesForReplacement.append(DocumentMarker::Replacement);
- markerTypesForReplacement.append(DocumentMarker::SpellCheckingExemption);
- }
- return markerTypesForReplacement;
-}
-
// When an event handler has moved the selection outside of a text control
// we should use the target control's selection for this editing operation.
VisibleSelection Editor::selectionForCommand(Event* event)
@@ -210,7 +181,7 @@ bool Editor::handleTextEvent(TextEvent* event)
bool Editor::canEdit() const
{
- return m_frame->selection()->isContentEditable();
+ return m_frame->selection()->rootEditableElement();
}
bool Editor::canEditRichly() const
@@ -278,7 +249,7 @@ bool Editor::canPaste() const
bool Editor::canDelete() const
{
SelectionController* selection = m_frame->selection();
- return selection->isRange() && selection->isContentEditable();
+ return selection->isRange() && selection->rootEditableElement();
}
bool Editor::canDeleteRange(Range* range) const
@@ -324,7 +295,7 @@ bool Editor::deleteWithDirection(SelectionDirection direction, TextGranularity g
if (m_frame->selection()->isRange()) {
if (isTypingAction) {
- TypingCommand::deleteKeyPressed(m_frame->document(), canSmartCopyOrDelete(), granularity);
+ TypingCommand::deleteKeyPressed(m_frame->document(), canSmartCopyOrDelete() ? TypingCommand::SmartDelete : 0, granularity);
revealSelectionAfterEditingOperation();
} else {
if (killRing)
@@ -333,14 +304,19 @@ bool Editor::deleteWithDirection(SelectionDirection direction, TextGranularity g
// Implicitly calls revealSelectionAfterEditingOperation().
}
} else {
+ TypingCommand::Options options = 0;
+ if (canSmartCopyOrDelete())
+ options |= TypingCommand::SmartDelete;
+ if (killRing)
+ options |= TypingCommand::KillRing;
switch (direction) {
case DirectionForward:
case DirectionRight:
- TypingCommand::forwardDeleteKeyPressed(m_frame->document(), canSmartCopyOrDelete(), granularity, killRing);
+ TypingCommand::forwardDeleteKeyPressed(m_frame->document(), options, granularity);
break;
case DirectionBackward:
case DirectionLeft:
- TypingCommand::deleteKeyPressed(m_frame->document(), canSmartCopyOrDelete(), granularity, killRing);
+ TypingCommand::deleteKeyPressed(m_frame->document(), options, granularity);
break;
}
revealSelectionAfterEditingOperation();
@@ -440,7 +416,7 @@ void Editor::replaceSelectionWithFragment(PassRefPtr<DocumentFragment> fragment,
Node* nodeToCheck = m_frame->selection()->rootEditableElement();
if (m_spellChecker->canCheckAsynchronously(nodeToCheck))
- m_spellChecker->requestCheckingFor(nodeToCheck);
+ m_spellChecker->requestCheckingFor(textCheckingTypeMaskFor(MarkSpelling | MarkGrammar), nodeToCheck);
}
void Editor::replaceSelectionWithText(const String& text, bool selectReplacement, bool smartReplace)
@@ -518,48 +494,7 @@ void Editor::respondToChangedSelection(const VisibleSelection& oldSelection)
if (client())
client()->respondToChangedSelection();
m_deleteButtonController->respondToChangedSelection(oldSelection);
-
-#if SUPPORT_AUTOCORRECTION_PANEL
- VisibleSelection currentSelection(frame()->selection()->selection());
- // 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::Replacement && !marker.description.isNull()) || marker.type == DocumentMarker::Spelling) && 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()) {
- m_correctionPanelInfo.rangeToBeReplaced = wordRange;
- m_correctionPanelInfo.replacedString = currentWord;
- if (marker.type == DocumentMarker::Spelling)
- startCorrectionPanelTimer(CorrectionPanelInfo::PanelTypeSpellingSuggestions);
- else {
- m_correctionPanelInfo.replacementString = marker.description;
- startCorrectionPanelTimer(CorrectionPanelInfo::PanelTypeReversion);
- }
- }
- break;
- }
- }
-#endif // SUPPORT_AUTOCORRECTION_PANEL
+ m_spellingCorrector->respondToChangedSelection(oldSelection);
}
void Editor::respondToChangedContents(const VisibleSelection& endingSelection)
@@ -570,9 +505,7 @@ void Editor::respondToChangedContents(const VisibleSelection& endingSelection)
m_frame->document()->axObjectCache()->postNotification(node->renderer(), AXObjectCache::AXValueChanged, false);
}
-#if REMOVE_MARKERS_UPON_EDITING
- removeSpellAndCorrectionMarkersFromWordsToBeEdited(true);
-#endif
+ updateMarkersForWordsAffectedByEditing(true);
if (client())
client()->respondToChangedContents();
@@ -983,7 +916,7 @@ TriState Editor::selectionHasStyle(int propertyID, const String& value) const
return state;
}
-static bool hasTransparentBackgroundColor(CSSStyleDeclaration* style)
+bool Editor::hasTransparentBackgroundColor(CSSStyleDeclaration* style)
{
RefPtr<CSSValue> cssValue = style->getPropertyCSSValue(CSSPropertyBackgroundColor);
if (!cssValue)
@@ -1059,10 +992,7 @@ void Editor::appliedEditing(PassRefPtr<EditCommand> cmd)
dispatchEditableContentChangedEvents(*cmd);
VisibleSelection newSelection(cmd->endingSelection());
-#if SUPPORT_AUTOCORRECTION_PANEL
- if (cmd->isTopLevelCommand() && !cmd->shouldRetainAutocorrectionIndicator())
- m_frame->document()->markers()->removeMarkers(DocumentMarker::CorrectionIndicator);
-#endif
+ m_spellingCorrector->respondToAppliedEditing(cmd.get());
// Don't clear the typing style with this selection change. We do those things elsewhere if necessary.
changeSelectionAfterCommand(newSelection, false, false);
@@ -1121,17 +1051,14 @@ Editor::Editor(Frame* frame)
// This is off by default, since most editors want this behavior (this matches IE but not FF).
, m_shouldStyleWithCSS(false)
, m_killRing(adoptPtr(new KillRing))
- , m_spellChecker(new SpellChecker(frame, frame->page() ? frame->page()->editorClient()->textChecker() : 0))
- , m_correctionPanelTimer(this, &Editor::correctionPanelTimerFired)
+ , m_spellChecker(adoptPtr(new SpellChecker(frame, frame->page() ? frame->page()->editorClient()->textChecker() : 0)))
+ , m_spellingCorrector(adoptPtr(new SpellingCorrectionController(frame)))
, m_areMarkedTextMatchesHighlighted(false)
{
}
Editor::~Editor()
{
-#if SUPPORT_AUTOCORRECTION_PANEL
- dismissCorrectionPanel(ReasonForDismissingCorrectionPanelIgnored);
-#endif
}
void Editor::clear()
@@ -1164,10 +1091,8 @@ bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectIn
if (!shouldInsertText(text, range.get(), EditorInsertActionTyped))
return true;
-#if REMOVE_MARKERS_UPON_EDITING
if (!text.isEmpty())
- removeSpellAndCorrectionMarkersFromWordsToBeEdited(isSpaceOrNewline(text[0]));
-#endif
+ updateMarkersForWordsAffectedByEditing(text[0]);
bool shouldConsiderApplyingAutocorrection = false;
if (text == " " || text == "\t")
@@ -1176,7 +1101,7 @@ bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectIn
if (text.length() == 1 && isPunct(text[0]) && !isAmbiguousBoundaryCharacter(text[0]))
shouldConsiderApplyingAutocorrection = true;
- bool autocorrectionWasApplied = shouldConsiderApplyingAutocorrection && applyAutocorrectionBeforeTypingIfAppropriate();
+ bool autocorrectionWasApplied = shouldConsiderApplyingAutocorrection && m_spellingCorrector->applyAutocorrectionBeforeTypingIfAppropriate();
// Get the selection to use for the event that triggered this insertText.
// If the event handler changed the selection, we may want to use a different selection
@@ -1187,7 +1112,7 @@ bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectIn
RefPtr<Document> document = selectionStart->document();
// Insert the text
- TypingCommand::TypingCommandOptions options = 0;
+ TypingCommand::Options options = 0;
if (selectInsertedText)
options |= TypingCommand::SelectInsertedText;
if (autocorrectionWasApplied)
@@ -1212,7 +1137,7 @@ bool Editor::insertLineBreak()
if (!shouldInsertText("\n", m_frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped))
return true;
- bool autocorrectionIsApplied = applyAutocorrectionBeforeTypingIfAppropriate();
+ bool autocorrectionIsApplied = m_spellingCorrector->applyAutocorrectionBeforeTypingIfAppropriate();
TypingCommand::insertLineBreak(m_frame->document(), autocorrectionIsApplied ? TypingCommand::RetainAutocorrectionIndicator : 0);
revealSelectionAfterEditingOperation();
@@ -1230,7 +1155,7 @@ bool Editor::insertParagraphSeparator()
if (!shouldInsertText("\n", m_frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped))
return true;
- bool autocorrectionIsApplied = applyAutocorrectionBeforeTypingIfAppropriate();
+ bool autocorrectionIsApplied = m_spellingCorrector->applyAutocorrectionBeforeTypingIfAppropriate();
TypingCommand::insertParagraphSeparator(m_frame->document(), autocorrectionIsApplied ? TypingCommand::RetainAutocorrectionIndicator : 0);
revealSelectionAfterEditingOperation();
@@ -1247,9 +1172,7 @@ void Editor::cut()
}
RefPtr<Range> selection = selectedRange();
if (shouldDeleteRange(selection.get())) {
-#if REMOVE_MARKERS_UPON_EDITING
- removeSpellAndCorrectionMarkersFromWordsToBeEdited(true);
-#endif
+ updateMarkersForWordsAffectedByEditing(true);
if (isNodeInTextFormControl(m_frame->selection()->start().deprecatedNode()))
Pasteboard::generalPasteboard()->writePlainText(selectedText());
else
@@ -1288,9 +1211,7 @@ void Editor::paste()
return; // DHTML did the whole operation
if (!canPaste())
return;
-#if REMOVE_MARKERS_UPON_EDITING
- removeSpellAndCorrectionMarkersFromWordsToBeEdited(false);
-#endif
+ updateMarkersForWordsAffectedByEditing(false);
CachedResourceLoader* loader = m_frame->document()->cachedResourceLoader();
loader->setAllowStaleResources(true);
if (m_frame->selection()->isContentRichlyEditable())
@@ -1306,9 +1227,7 @@ void Editor::pasteAsPlainText()
return;
if (!canPaste())
return;
-#if REMOVE_MARKERS_UPON_EDITING
- removeSpellAndCorrectionMarkersFromWordsToBeEdited(false);
-#endif
+ updateMarkersForWordsAffectedByEditing(false);
pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
}
@@ -1461,7 +1380,7 @@ void Editor::toggleAutomaticTextReplacement()
bool Editor::isAutomaticSpellingCorrectionEnabled()
{
- return client() && client()->isAutomaticSpellingCorrectionEnabled();
+ return m_spellingCorrector->isAutomaticSpellingCorrectionEnabled();
}
void Editor::toggleAutomaticSpellingCorrection()
@@ -1614,7 +1533,7 @@ void Editor::confirmComposition(const String& text, bool preserveSelection)
// If text is empty, then delete the old composition here. If text is non-empty, InsertTextCommand::input
// will delete the old composition with an optimized replace operation.
if (text.isEmpty())
- TypingCommand::deleteSelection(m_frame->document(), false);
+ TypingCommand::deleteSelection(m_frame->document(), 0);
m_compositionNode = 0;
m_customCompositionUnderlines.clear();
@@ -1682,13 +1601,13 @@ void Editor::setComposition(const String& text, const Vector<CompositionUnderlin
// If text is empty, then delete the old composition here. If text is non-empty, InsertTextCommand::input
// will delete the old composition with an optimized replace operation.
if (text.isEmpty())
- TypingCommand::deleteSelection(m_frame->document(), false);
+ TypingCommand::deleteSelection(m_frame->document(), TypingCommand::PreventSpellChecking);
m_compositionNode = 0;
m_customCompositionUnderlines.clear();
if (!text.isEmpty()) {
- TypingCommand::insertText(m_frame->document(), text, true, TypingCommand::TextCompositionUpdate);
+ TypingCommand::insertText(m_frame->document(), text, TypingCommand::SelectInsertedText | TypingCommand::PreventSpellChecking, TypingCommand::TextCompositionUpdate);
// Find out what node has the composition now.
Position base = m_frame->selection()->base().downstream();
@@ -2050,39 +1969,24 @@ void Editor::markMisspellingsAndBadGrammar(const VisibleSelection &movingSelecti
markBadGrammar(movingSelection);
}
-void Editor::markMisspellingsAfterTypingToWord(const VisiblePosition &wordStart, const VisibleSelection& selectionAfterTyping)
+void Editor::markMisspellingsAfterTypingToWord(const VisiblePosition &wordStart, const VisibleSelection& selectionAfterTyping, bool doReplacement)
{
#if USE(UNIFIED_TEXT_CHECKING)
-#if SUPPORT_AUTOCORRECTION_PANEL
- // Apply pending autocorrection before next round of spell checking.
- bool doApplyCorrection = true;
- VisiblePosition startOfSelection = selectionAfterTyping.visibleStart();
- VisibleSelection currentWord = VisibleSelection(startOfWord(startOfSelection, LeftWordIfOnBoundary), endOfWord(startOfSelection, RightWordIfOnBoundary));
- if (currentWord.visibleEnd() == startOfSelection) {
- String wordText = plainText(currentWord.toNormalizedRange().get());
- if (wordText.length() > 0 && isAmbiguousBoundaryCharacter(wordText[wordText.length() - 1]))
- doApplyCorrection = false;
- }
- if (doApplyCorrection)
- handleCorrectionPanelResult(dismissCorrectionPanelSoon(ReasonForDismissingCorrectionPanelAccepted));
- else
- m_correctionPanelInfo.rangeToBeReplaced.clear();
-#else
- UNUSED_PARAM(selectionAfterTyping);
-#endif
+ m_spellingCorrector->applyPendingCorrection(selectionAfterTyping);
+
TextCheckingOptions textCheckingOptions = 0;
if (isContinuousSpellCheckingEnabled())
textCheckingOptions |= MarkSpelling;
#if USE(AUTOMATIC_TEXT_REPLACEMENT)
- if (isAutomaticQuoteSubstitutionEnabled()
- || isAutomaticLinkDetectionEnabled()
- || isAutomaticDashSubstitutionEnabled()
- || isAutomaticTextReplacementEnabled()
- || ((textCheckingOptions & MarkSpelling) && isAutomaticSpellingCorrectionEnabled()))
+ if (doReplacement
+ && (isAutomaticQuoteSubstitutionEnabled()
+ || isAutomaticLinkDetectionEnabled()
+ || isAutomaticDashSubstitutionEnabled()
+ || isAutomaticTextReplacementEnabled()
+ || ((textCheckingOptions & MarkSpelling) && isAutomaticSpellingCorrectionEnabled())))
textCheckingOptions |= PerformReplacement;
#endif
-
if (!textCheckingOptions & (MarkSpelling | PerformReplacement))
return;
@@ -2099,6 +2003,8 @@ void Editor::markMisspellingsAfterTypingToWord(const VisiblePosition &wordStart,
#else
UNUSED_PARAM(selectionAfterTyping);
+ UNUSED_PARAM(doReplacement);
+
if (!isContinuousSpellCheckingEnabled())
return;
@@ -2207,12 +2113,13 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
{
#if USE(UNIFIED_TEXT_CHECKING)
// There shouldn't be pending autocorrection at this moment.
- ASSERT(!m_correctionPanelInfo.rangeToBeReplaced);
+ ASSERT(!m_spellingCorrector->hasPendingCorrection());
bool shouldMarkSpelling = textCheckingOptions & MarkSpelling;
bool shouldMarkGrammar = textCheckingOptions & MarkGrammar;
bool shouldPerformReplacement = textCheckingOptions & PerformReplacement;
bool shouldShowCorrectionPanel = textCheckingOptions & ShowCorrectionPanel;
+ bool shouldCheckForCorrection = shouldShowCorrectionPanel || (textCheckingOptions & CheckForCorrection);
// This function is called with selections already expanded to word boundaries.
ExceptionCode ec = 0;
@@ -2240,7 +2147,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
if (shouldMarkGrammar ? (spellingParagraph.isRangeEmpty() && grammarParagraph.isEmpty()) : spellingParagraph.isEmpty())
return;
- if (shouldPerformReplacement || shouldMarkSpelling) {
+ if (shouldPerformReplacement || shouldMarkSpelling || shouldCheckForCorrection) {
if (m_frame->selection()->selectionType() == VisibleSelection::CaretSelection) {
// Attempt to save the caret position so we can restore it later if needed
Position caretPosition = m_frame->selection()->end();
@@ -2257,38 +2164,17 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
}
Vector<TextCheckingResult> results;
- uint64_t checkingTypes = 0;
- if (shouldMarkSpelling)
- checkingTypes |= TextCheckingTypeSpelling;
- if (shouldMarkGrammar)
- checkingTypes |= TextCheckingTypeGrammar;
- if (shouldShowCorrectionPanel)
- checkingTypes |= TextCheckingTypeCorrection;
- if (shouldPerformReplacement) {
-#if USE(AUTOMATIC_TEXT_REPLACEMENT)
- if (isAutomaticLinkDetectionEnabled())
- checkingTypes |= TextCheckingTypeLink;
- if (isAutomaticQuoteSubstitutionEnabled())
- checkingTypes |= TextCheckingTypeQuote;
- if (isAutomaticDashSubstitutionEnabled())
- checkingTypes |= TextCheckingTypeDash;
- if (isAutomaticTextReplacementEnabled())
- checkingTypes |= TextCheckingTypeReplacement;
- if (shouldMarkSpelling && isAutomaticSpellingCorrectionEnabled())
- checkingTypes |= TextCheckingTypeCorrection;
-#endif
- }
if (shouldMarkGrammar)
- textChecker()->checkTextOfParagraph(grammarParagraph.textCharacters(), grammarParagraph.textLength(), checkingTypes, results);
+ textChecker()->checkTextOfParagraph(grammarParagraph.textCharacters(), grammarParagraph.textLength(),
+ textCheckingTypeMaskFor(textCheckingOptions), results);
else
- textChecker()->checkTextOfParagraph(spellingParagraph.textCharacters(), spellingParagraph.textLength(), checkingTypes, results);
+ textChecker()->checkTextOfParagraph(spellingParagraph.textCharacters(), spellingParagraph.textLength(),
+ textCheckingTypeMaskFor(textCheckingOptions), results);
-#if SUPPORT_AUTOCORRECTION_PANEL
// If this checking is only for showing correction panel, we shouldn't bother to mark misspellings.
if (shouldShowCorrectionPanel)
shouldMarkSpelling = false;
-#endif
int offsetDueToReplacement = 0;
@@ -2307,10 +2193,8 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
if (shouldMarkSpelling && result->type == TextCheckingTypeSpelling && resultLocation >= spellingParagraph.checkingStart() && resultLocation + resultLength <= spellingRangeEndOffset && !resultEndsAtAmbiguousBoundary) {
ASSERT(resultLength > 0 && resultLocation >= 0);
RefPtr<Range> misspellingRange = spellingParagraph.subrange(resultLocation, resultLength);
-#if SUPPORT_AUTOCORRECTION_PANEL
- if (m_frame->document()->markers()->hasMarkers(misspellingRange.get(), DocumentMarker::SpellCheckingExemption))
+ if (!m_spellingCorrector->isSpellingMarkerAllowed(misspellingRange))
continue;
-#endif // SUPPORT_AUTOCORRECTION_PANEL
misspellingRange->startContainer(ec)->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
} else if (shouldMarkGrammar && result->type == TextCheckingTypeGrammar && grammarParagraph.checkingRangeCovers(resultLocation, resultLength)) {
ASSERT(resultLength > 0 && resultLocation >= 0);
@@ -2322,7 +2206,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
grammarRange->startContainer(ec)->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription);
}
}
- } else if ((shouldPerformReplacement || shouldShowCorrectionPanel) && resultLocation + resultLength <= spellingRangeEndOffset && resultLocation + resultLength >= spellingParagraph.checkingStart()
+ } else if (resultLocation + resultLength <= spellingRangeEndOffset && resultLocation + resultLength >= spellingParagraph.checkingStart()
&& (result->type == TextCheckingTypeLink
|| result->type == TextCheckingTypeQuote
|| result->type == TextCheckingTypeDash
@@ -2348,45 +2232,33 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
if (result->type == TextCheckingTypeLink && selectionOffset > resultLocation + resultLength + 1)
continue;
+ String replacedString;
+
// Don't correct spelling in an already-corrected word.
if (result->type == TextCheckingTypeCorrection) {
- Node* node = rangeToReplace->startContainer();
- int startOffset = rangeToReplace->startOffset();
- int endOffset = startOffset + replacementLength;
- 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::Replacement || marker.type == DocumentMarker::RejectedCorrection) && static_cast<int>(marker.startOffset) < endOffset && static_cast<int>(marker.endOffset) > startOffset) {
- doReplacement = false;
- break;
- }
- if (static_cast<int>(marker.startOffset) >= endOffset)
- break;
- }
+ replacedString = plainText(rangeToReplace.get());
+ DocumentMarkerController* markers = m_frame->document()->markers();
+ if (markers->hasMarkers(rangeToReplace.get(), DocumentMarker::Replacement)) {
+ doReplacement = false;
+ m_spellingCorrector->recordSpellcheckerResponseForModifiedCorrection(rangeToReplace.get(), replacedString, result->replacement);
+ } else if (markers->hasMarkers(rangeToReplace.get(), DocumentMarker::RejectedCorrection))
+ doReplacement = false;
}
- if (!doReplacement)
+ if (!(shouldPerformReplacement || shouldShowCorrectionPanel) || !doReplacement)
continue;
-#if SUPPORT_AUTOCORRECTION_PANEL
if (shouldShowCorrectionPanel) {
+ ASSERT(SUPPORT_AUTOCORRECTION_PANEL);
+ // shouldShowCorrectionPanel can be true only when the panel is available.
if (resultLocation + resultLength == spellingRangeEndOffset) {
// We only show the correction panel on the last word.
- FloatRect boundingBox = windowRectForRange(rangeToReplace.get());
- if (boundingBox.isEmpty())
- break;
- m_correctionPanelInfo.rangeToBeReplaced = rangeToReplace;
- m_correctionPanelInfo.replacedString = plainText(rangeToReplace.get());
- m_correctionPanelInfo.replacementString = result->replacement;
- m_correctionPanelInfo.isActive = true;
- client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBox, m_correctionPanelInfo.replacedString, result->replacement, Vector<String>());
+ m_spellingCorrector->show(rangeToReplace, result->replacement);
break;
}
// If this function is called for showing correction panel, we ignore other correction or replacement.
continue;
}
-#endif
if (selectionToReplace != m_frame->selection()->selection()) {
if (!m_frame->selection()->shouldChangeSelection(selectionToReplace))
@@ -2400,22 +2272,18 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
if (canEditRichly())
applyCommand(CreateLinkCommand::create(m_frame->document(), result->replacement));
} else if (canEdit() && shouldInsertText(result->replacement, rangeToReplace.get(), EditorInsertActionTyped)) {
- String replacedString;
if (result->type == TextCheckingTypeCorrection)
- replacedString = plainText(rangeToReplace.get());
-
- bool useSpellingCorrectionCommand = false;
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
- if (result->type == TextCheckingTypeCorrection)
- useSpellingCorrectionCommand = true;
-#endif
- if (useSpellingCorrectionCommand)
applyCommand(SpellingCorrectionCommand::create(rangeToReplace, result->replacement));
else {
m_frame->selection()->setSelection(selectionToReplace);
replaceSelectionWithText(result->replacement, false, false);
}
+ if (AXObjectCache::accessibilityEnabled()) {
+ if (Element* root = m_frame->selection()->selection().rootEditableElement())
+ m_frame->document()->axObjectCache()->postNotification(root->renderer(), AXObjectCache::AXAutocorrectionOccured, true);
+ }
+
selectionChanged = true;
offsetDueToReplacement += replacementLength - resultLength;
if (resultLocation < selectionOffset) {
@@ -2424,13 +2292,9 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
ambiguousBoundaryOffset = selectionOffset - 1;
}
- if (result->type == TextCheckingTypeCorrection) {
- // Add a marker so that corrections can easily be undone and won't be re-corrected.
- RefPtr<Range> replacedRange = spellingParagraph.subrange(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::SpellCheckingExemption);
- }
+ // Add a marker so that corrections can easily be undone and won't be re-corrected.
+ if (result->type == TextCheckingTypeCorrection)
+ m_spellingCorrector->markCorrection(spellingParagraph.subrange(resultLocation, replacementLength), replacedString);
}
}
}
@@ -2467,17 +2331,12 @@ void Editor::changeBackToReplacedString(const String& replacedString)
if (!shouldInsertText(replacedString, selection.get(), EditorInsertActionPasted))
return;
-#if SUPPORT_AUTOCORRECTION_PANEL
- String replacement = plainText(selection.get());
- client()->recordAutocorrectionResponse(EditorClient::AutocorrectionReverted, replacedString, replacement);
-#endif
+ m_spellingCorrector->recordAutocorrectionResponseReversed(replacedString, selection);
TextCheckingParagraph paragraph(selection);
replaceSelectionWithText(replacedString, false, false);
RefPtr<Range> changedRange = paragraph.subrange(paragraph.checkingStart(), replacedString.length());
changedRange->startContainer()->document()->markers()->addMarker(changedRange.get(), DocumentMarker::Replacement, String());
-#if SUPPORT_AUTOCORRECTION_PANEL
- changedRange->startContainer()->document()->markers()->addMarker(changedRange.get(), DocumentMarker::SpellCheckingExemption);
-#endif
+ m_spellingCorrector->markReversed(changedRange.get());
#else
ASSERT_NOT_REACHED();
UNUSED_PARAM(replacedString);
@@ -2490,7 +2349,7 @@ void Editor::markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelec
#if USE(UNIFIED_TEXT_CHECKING)
if (!isContinuousSpellCheckingEnabled())
return;
- TextCheckingOptions textCheckingOptions = MarkSpelling;
+ TextCheckingOptions textCheckingOptions = MarkSpelling | CheckForCorrection;
if (markGrammar && isGrammarCheckingEnabled())
textCheckingOptions |= MarkGrammar;
markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, spellingSelection.toNormalizedRange().get(), grammarSelection.toNormalizedRange().get());
@@ -2502,140 +2361,16 @@ void Editor::markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelec
#endif
}
-void Editor::correctionPanelTimerFired(Timer<Editor>*)
-{
-#if SUPPORT_AUTOCORRECTION_PANEL
- m_correctionPanelIsDismissedByEditor = false;
- switch (m_correctionPanelInfo.panelType) {
- case 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);
- }
- break;
- case CorrectionPanelInfo::PanelTypeReversion: {
- m_correctionPanelInfo.isActive = true;
- m_correctionPanelInfo.replacedString = plainText(m_correctionPanelInfo.rangeToBeReplaced.get());
- FloatRect boundingBox = windowRectForRange(m_correctionPanelInfo.rangeToBeReplaced.get());
- if (!boundingBox.isEmpty())
- client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBox, m_correctionPanelInfo.replacedString, m_correctionPanelInfo.replacementString, Vector<String>());
- }
- break;
- case CorrectionPanelInfo::PanelTypeSpellingSuggestions: {
- if (plainText(m_correctionPanelInfo.rangeToBeReplaced.get()) != m_correctionPanelInfo.replacedString)
- break;
- String paragraphText = plainText(TextCheckingParagraph(m_correctionPanelInfo.rangeToBeReplaced).paragraphRange().get());
- Vector<String> suggestions;
- textChecker()->getGuessesForWord(m_correctionPanelInfo.replacedString, paragraphText, suggestions);
- if (suggestions.isEmpty()) {
- m_correctionPanelInfo.rangeToBeReplaced.clear();
- break;
- }
- String topSuggestion = suggestions.first();
- suggestions.remove(0);
- m_correctionPanelInfo.isActive = true;
- FloatRect boundingBox = windowRectForRange(m_correctionPanelInfo.rangeToBeReplaced.get());
- if (!boundingBox.isEmpty())
- client()->showCorrectionPanel(m_correctionPanelInfo.panelType, boundingBox, m_correctionPanelInfo.replacedString, topSuggestion, suggestions);
- }
- break;
- }
-#endif
-}
-
-void Editor::handleCorrectionPanelResult(const String& correction)
-{
- Range* replacedRange = m_correctionPanelInfo.rangeToBeReplaced.get();
- if (!replacedRange || m_frame->document() != replacedRange->ownerDocument())
- return;
-
- String currentWord = plainText(m_correctionPanelInfo.rangeToBeReplaced.get());
- // Check to see if the word we are about to correct has been changed between timer firing and callback being triggered.
- if (currentWord != m_correctionPanelInfo.replacedString)
- return;
-
- m_correctionPanelInfo.isActive = false;
-
- switch (m_correctionPanelInfo.panelType) {
- case CorrectionPanelInfo::PanelTypeCorrection:
- if (correction.length()) {
- m_correctionPanelInfo.replacementString = correction;
- applyCorrectionPanelInfo(markerTypesForAutocorrection());
- } else {
- if (!m_correctionPanelIsDismissedByEditor)
- replacedRange->startContainer()->document()->markers()->addMarker(replacedRange, DocumentMarker::RejectedCorrection, m_correctionPanelInfo.replacedString);
- }
- break;
- case CorrectionPanelInfo::PanelTypeReversion:
- case CorrectionPanelInfo::PanelTypeSpellingSuggestions:
- if (correction.length()) {
- m_correctionPanelInfo.replacementString = correction;
- applyCorrectionPanelInfo(markerTypesForReplacement());
- }
- break;
- }
-
- m_correctionPanelInfo.rangeToBeReplaced.clear();
-}
-
-void Editor::startCorrectionPanelTimer(CorrectionPanelInfo::PanelType type)
-{
-#if SUPPORT_AUTOCORRECTION_PANEL
- const double correctionPanelTimerInterval = 0.3;
- if (isAutomaticSpellingCorrectionEnabled()) {
- if (type == CorrectionPanelInfo::PanelTypeCorrection)
- // If type is PanelTypeReversion, then the new range has been set. So we shouldn't clear it.
- m_correctionPanelInfo.rangeToBeReplaced.clear();
- m_correctionPanelInfo.panelType = type;
- m_correctionPanelTimer.startOneShot(correctionPanelTimerInterval);
- }
-#else
- UNUSED_PARAM(type);
-#endif
-}
-
-void Editor::stopCorrectionPanelTimer()
+void Editor::unappliedSpellCorrection(const VisibleSelection& selectionOfCorrected, const String& corrected, const String& correction)
{
-#if SUPPORT_AUTOCORRECTION_PANEL
- m_correctionPanelTimer.stop();
- m_correctionPanelInfo.rangeToBeReplaced.clear();
-#endif
+ m_spellingCorrector->respondToUnappliedSpellCorrection(selectionOfCorrected, corrected, correction);
}
-void Editor::dismissCorrectionPanel(ReasonForDismissingCorrectionPanel reasonForDismissing)
+void Editor::updateMarkersForWordsAffectedByEditing(bool doNotRemoveIfSelectionAtWordBoundary)
{
-#if SUPPORT_AUTOCORRECTION_PANEL
- if (!m_correctionPanelInfo.isActive)
+ if (!m_spellingCorrector->shouldRemoveMarkersUponEditing())
return;
- m_correctionPanelInfo.isActive = false;
- m_correctionPanelIsDismissedByEditor = true;
- if (client())
- client()->dismissCorrectionPanel(reasonForDismissing);
-#else
- UNUSED_PARAM(reasonForDismissing);
-#endif
-}
-String Editor::dismissCorrectionPanelSoon(ReasonForDismissingCorrectionPanel reasonForDismissing)
-{
-#if SUPPORT_AUTOCORRECTION_PANEL
- if (!m_correctionPanelInfo.isActive)
- return String();
- m_correctionPanelInfo.isActive = false;
- m_correctionPanelIsDismissedByEditor = true;
- if (!client())
- return String();
- return client()->dismissCorrectionPanelSoon(reasonForDismissing);
-#else
- UNUSED_PARAM(reasonForDismissing);
- return String();
-#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
// several scenarios:
// 1. Insert in the middle of a word.
@@ -2701,102 +2436,6 @@ void Editor::removeSpellAndCorrectionMarkersFromWordsToBeEdited(bool doNotRemove
document->markers()->clearDescriptionOnMarkersIntersectingRange(wordRange.get(), DocumentMarker::Replacement);
}
-void Editor::applyCorrectionPanelInfo(const Vector<DocumentMarker::MarkerType>& markerTypesToAdd)
-{
-#if SUPPORT_AUTOCORRECTION_PANEL
- if (!m_correctionPanelInfo.rangeToBeReplaced)
- return;
-
- ExceptionCode ec = 0;
- RefPtr<Range> paragraphRangeContainingCorrection = m_correctionPanelInfo.rangeToBeReplaced->cloneRange(ec);
- if (ec)
- return;
-
- setStart(paragraphRangeContainingCorrection.get(), startOfParagraph(m_correctionPanelInfo.rangeToBeReplaced->startPosition()));
- setEnd(paragraphRangeContainingCorrection.get(), endOfParagraph(m_correctionPanelInfo.rangeToBeReplaced->endPosition()));
-
- // After we replace the word at range rangeToBeReplaced, we need to add markers to that range.
- // However, once the replacement took place, the value of rangeToBeReplaced is not valid anymore.
- // So before we carry out the replacement, we need to store the start position of 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 rangeToBeReplaced.
- RefPtr<Range> correctionStartOffsetInParagraphAsRange = Range::create(paragraphRangeContainingCorrection->startContainer(ec)->document(), paragraphRangeContainingCorrection->startPosition(), paragraphRangeContainingCorrection->startPosition());
- if (ec)
- return;
-
- Position startPositionOfRangeToBeReplaced = m_correctionPanelInfo.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());
-
- // Clone the range, since the caller of this method may want to keep the original range around.
- RefPtr<Range> rangeToBeReplaced = m_correctionPanelInfo.rangeToBeReplaced->cloneRange(ec);
- applyCommand(SpellingCorrectionCommand::create(rangeToBeReplaced, m_correctionPanelInfo.replacementString));
- setEnd(paragraphRangeContainingCorrection.get(), m_frame->selection()->selection().start());
- RefPtr<Range> replacementRange = TextIterator::subrange(paragraphRangeContainingCorrection.get(), correctionStartOffsetInParagraph, m_correctionPanelInfo.replacementString.length());
- String newText = plainText(replacementRange.get());
-
- // Check to see if replacement succeeded.
- if (newText != m_correctionPanelInfo.replacementString)
- return;
-
- DocumentMarkerController* markers = replacementRange->startContainer()->document()->markers();
- size_t size = markerTypesToAdd.size();
- for (size_t i = 0; i < size; ++i) {
- if (m_correctionPanelInfo.panelType == CorrectionPanelInfo::PanelTypeReversion)
- markers->addMarker(replacementRange.get(), markerTypesToAdd[i]);
- else
- markers->addMarker(replacementRange.get(), markerTypesToAdd[i], m_correctionPanelInfo.replacedString);
- }
-#else // SUPPORT_AUTOCORRECTION_PANEL
- UNUSED_PARAM(markerTypesToAdd);
-#endif // SUPPORT_AUTOCORRECTION_PANEL
-}
-
-bool Editor::applyAutocorrectionBeforeTypingIfAppropriate()
-{
- if (!m_correctionPanelInfo.rangeToBeReplaced || !m_correctionPanelInfo.isActive)
- return false;
-
- if (m_correctionPanelInfo.panelType != CorrectionPanelInfo::PanelTypeCorrection)
- return false;
-
- Position caretPosition = m_frame->selection()->selection().start();
-
- if (m_correctionPanelInfo.rangeToBeReplaced->endPosition() == caretPosition) {
- handleCorrectionPanelResult(dismissCorrectionPanelSoon(ReasonForDismissingCorrectionPanelAccepted));
- return true;
- }
-
- // Pending correction should always be where caret is. But in case this is not always true, we still want to dismiss the panel without accepting the correction.
- ASSERT(m_correctionPanelInfo.rangeToBeReplaced->endPosition() == caretPosition);
- dismissCorrectionPanel(ReasonForDismissingCorrectionPanelIgnored);
- return false;
-}
-
-void Editor::unappliedSpellCorrection(const VisibleSelection& selectionOfCorrected, const String& corrected, const String& correction)
-{
-#if SUPPORT_AUTOCORRECTION_PANEL
- client()->recordAutocorrectionResponse(EditorClient::AutocorrectionReverted, corrected, correction);
- m_frame->document()->updateLayout();
- m_frame->selection()->setSelection(selectionOfCorrected, SelectionController::CloseTyping | SelectionController::ClearTypingStyle | SelectionController::SpellCorrectionTriggered);
- RefPtr<Range> range = Range::create(m_frame->document(), m_frame->selection()->selection().start(), m_frame->selection()->selection().end());
-
- DocumentMarkerController* markers = m_frame->document()->markers();
- markers->removeMarkers(range.get(), DocumentMarker::Spelling);
- markers->addMarker(range.get(), DocumentMarker::Replacement);
- markers->addMarker(range.get(), DocumentMarker::SpellCheckingExemption);
-#else // SUPPORT_AUTOCORRECTION_PANEL
- UNUSED_PARAM(selectionOfCorrected);
- UNUSED_PARAM(corrected);
- UNUSED_PARAM(correction);
-#endif // SUPPORT_AUTOCORRECTION_PANEL
-}
-
PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
{
Document* document = m_frame->documentAtPoint(windowPoint);
@@ -2919,6 +2558,22 @@ void Editor::addToKillRing(Range* range, bool prepend)
m_shouldStartNewKillRingSequence = false;
}
+void Editor::startCorrectionPanelTimer()
+{
+ m_spellingCorrector->startCorrectionPanelTimer(CorrectionPanelInfo::PanelTypeCorrection);
+}
+
+void Editor::handleCorrectionPanelResult(const String& correction)
+{
+ m_spellingCorrector->handleCorrectionPanelResult(correction);
+}
+
+
+void Editor::dismissCorrectionPanelAsIgnored()
+{
+ m_spellingCorrector->dismiss(ReasonForDismissingCorrectionPanelIgnored);
+}
+
bool Editor::insideVisibleArea(const IntPoint& point) const
{
if (m_frame->excludeFromTextSearch())
@@ -3491,14 +3146,7 @@ void Editor::setMarkedTextMatchesAreHighlighted(bool flag)
void Editor::respondToChangedSelection(const VisibleSelection& oldSelection, SelectionController::SetSelectionOptions options)
{
-#if SUPPORT_AUTOCORRECTION_PANEL
- // Make sure there's no pending autocorrection before we call markMisspellingsAndBadGrammar() below.
- VisibleSelection currentSelection(frame()->selection()->selection());
- if (currentSelection != oldSelection) {
- stopCorrectionPanelTimer();
- dismissCorrectionPanel(ReasonForDismissingCorrectionPanelIgnored);
- }
-#endif // SUPPORT_AUTOCORRECTION_PANEL
+ m_spellingCorrector->stopPendingCorrection(oldSelection);
bool closeTyping = options & SelectionController::CloseTyping;
bool isContinuousSpellCheckingEnabled = this->isContinuousSpellCheckingEnabled();
@@ -3514,11 +3162,8 @@ void Editor::respondToChangedSelection(const VisibleSelection& oldSelection, Sel
newSelectedSentence = VisibleSelection(startOfSentence(newStart), endOfSentence(newStart));
}
- bool shouldCheckSpellingAndGrammar = true;
-#if SUPPORT_AUTOCORRECTION_PANEL
// Don't check spelling and grammar if the change of selection is triggered by spelling correction itself.
- shouldCheckSpellingAndGrammar = !(options & SelectionController::SpellCorrectionTriggered);
-#endif
+ bool shouldCheckSpellingAndGrammar = !(options & SelectionController::SpellCorrectionTriggered);
// When typing we check spelling elsewhere, so don't redo it here.
// If this is a change in selection resulting from a delete operation,
@@ -3593,7 +3238,49 @@ bool Editor::selectionStartHasMarkerFor(DocumentMarker::MarkerType markerType, i
FloatRect Editor::windowRectForRange(const Range* range) const
{
FrameView* view = frame()->view();
- return view ? view->contentsToWindow(IntRect(range->boundingRect())) : FloatRect();
+ if (!view)
+ return FloatRect();
+ Vector<FloatQuad> textQuads;
+ range->textQuads(textQuads);
+ FloatRect boundingRect;
+ size_t size = textQuads.size();
+ for (size_t i = 0; i < size; ++i)
+ boundingRect.unite(textQuads[i].boundingBox());
+ return view->contentsToWindow(IntRect(boundingRect));
}
+TextCheckingTypeMask Editor::textCheckingTypeMaskFor(TextCheckingOptions textCheckingOptions)
+{
+ bool shouldMarkSpelling = textCheckingOptions & MarkSpelling;
+ bool shouldMarkGrammar = textCheckingOptions & MarkGrammar;
+ bool shouldShowCorrectionPanel = textCheckingOptions & ShowCorrectionPanel;
+ bool shouldCheckForCorrection = shouldShowCorrectionPanel || (textCheckingOptions & CheckForCorrection);
+
+ TextCheckingTypeMask checkingTypes = 0;
+ if (shouldMarkSpelling)
+ checkingTypes |= TextCheckingTypeSpelling;
+ if (shouldMarkGrammar)
+ checkingTypes |= TextCheckingTypeGrammar;
+ if (shouldCheckForCorrection)
+ checkingTypes |= TextCheckingTypeCorrection;
+
+#if USE(AUTOMATIC_TEXT_REPLACEMENT)
+ bool shouldPerformReplacement = textCheckingOptions & PerformReplacement;
+ if (shouldPerformReplacement) {
+ if (isAutomaticLinkDetectionEnabled())
+ checkingTypes |= TextCheckingTypeLink;
+ if (isAutomaticQuoteSubstitutionEnabled())
+ checkingTypes |= TextCheckingTypeQuote;
+ if (isAutomaticDashSubstitutionEnabled())
+ checkingTypes |= TextCheckingTypeDash;
+ if (isAutomaticTextReplacementEnabled())
+ checkingTypes |= TextCheckingTypeReplacement;
+ if (shouldMarkSpelling && isAutomaticSpellingCorrectionEnabled())
+ checkingTypes |= TextCheckingTypeCorrection;
+ }
+#endif
+
+ return checkingTypes;
+}
+
} // namespace WebCore