diff options
| author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-20 13:01:08 +0200 |
|---|---|---|
| committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-06-20 13:01:08 +0200 |
| commit | 49233e234e5c787396cadb2cea33b31ae0cd65c1 (patch) | |
| tree | 5410cb9a8fd53168bb60d62c54b654d86f03c38d /Source/WebCore/editing/AlternativeTextController.cpp | |
| parent | b211c645d8ab690f713515dfdc84d80b11c27d2c (diff) | |
| download | qtwebkit-49233e234e5c787396cadb2cea33b31ae0cd65c1.tar.gz | |
Imported WebKit commit 3a8c29f35d00659d2ce7a0ccdfa8304f14e82327 (http://svn.webkit.org/repository/webkit/trunk@120813)
New snapshot with Windows build fixes
Diffstat (limited to 'Source/WebCore/editing/AlternativeTextController.cpp')
| -rw-r--r-- | Source/WebCore/editing/AlternativeTextController.cpp | 203 |
1 files changed, 165 insertions, 38 deletions
diff --git a/Source/WebCore/editing/AlternativeTextController.cpp b/Source/WebCore/editing/AlternativeTextController.cpp index 8d09ff1b9..b199af156 100644 --- a/Source/WebCore/editing/AlternativeTextController.cpp +++ b/Source/WebCore/editing/AlternativeTextController.cpp @@ -68,6 +68,23 @@ private: String m_replacementString; }; +class DictationAlternativeDetails : public AlternativeTextDetails { +public: + static PassRefPtr<DictationAlternativeDetails> create(uint64_t dictationContext) + { + return adoptRef(new DictationAlternativeDetails(dictationContext)); + } + + uint64_t dictationContext() const { return m_dictationContext; } + +private: + DictationAlternativeDetails(uint64_t dictationContext) + : m_dictationContext(dictationContext) + { } + + uint64_t m_dictationContext; +}; + #if USE(AUTOCORRECTION_PANEL) static const Vector<DocumentMarker::MarkerType>& markerTypesForAutocorrection() @@ -92,6 +109,14 @@ static const Vector<DocumentMarker::MarkerType>& markerTypesForReplacement() return markerTypesForReplacement; } +static const Vector<DocumentMarker::MarkerType>& markerTypesForAppliedDictationAlternative() +{ + DEFINE_STATIC_LOCAL(Vector<DocumentMarker::MarkerType>, markerTypesForAppliedDictationAlternative, ()); + if (markerTypesForAppliedDictationAlternative.isEmpty()) + markerTypesForAppliedDictationAlternative.append(DocumentMarker::SpellCheckingExemption); + return markerTypesForAppliedDictationAlternative; +} + static bool markersHaveIdenticalDescription(const Vector<DocumentMarker*>& markers) { if (markers.isEmpty()) @@ -215,18 +240,18 @@ String AlternativeTextController::dismissSoon(ReasonForDismissingAlternativeText return String(); } -void AlternativeTextController::applyAlternativeText(const String& alternative, const Vector<DocumentMarker::MarkerType>& markerTypesToAdd) +void AlternativeTextController::applyAlternativeTextToRange(const Range* range, const String& alternative, AlternativeTextType alternativeType, const Vector<DocumentMarker::MarkerType>& markerTypesToAdd) { - if (!m_alternativeTextInfo.rangeWithAlternative) + if (!range) return; ExceptionCode ec = 0; - RefPtr<Range> paragraphRangeContainingCorrection = m_alternativeTextInfo.rangeWithAlternative->cloneRange(ec); + RefPtr<Range> paragraphRangeContainingCorrection = range->cloneRange(ec); if (ec) return; - setStart(paragraphRangeContainingCorrection.get(), startOfParagraph(m_alternativeTextInfo.rangeWithAlternative->startPosition())); - setEnd(paragraphRangeContainingCorrection.get(), endOfParagraph(m_alternativeTextInfo.rangeWithAlternative->endPosition())); + setStart(paragraphRangeContainingCorrection.get(), startOfParagraph(range->startPosition())); + setEnd(paragraphRangeContainingCorrection.get(), endOfParagraph(range->endPosition())); // After we replace the word at range rangeWithAlternative, we need to add markers to that range. // However, once the replacement took place, the value of rangeWithAlternative is not valid anymore. @@ -238,7 +263,7 @@ void AlternativeTextController::applyAlternativeText(const String& alternative, if (ec) return; - Position startPositionOfrangeWithAlternative = m_alternativeTextInfo.rangeWithAlternative->startPosition(); + Position startPositionOfrangeWithAlternative = range->startPosition(); correctionStartOffsetInParagraphAsRange->setEnd(startPositionOfrangeWithAlternative.containerNode(), startPositionOfrangeWithAlternative.computeOffsetInContainerNode(), ec); if (ec) return; @@ -247,7 +272,7 @@ void AlternativeTextController::applyAlternativeText(const String& alternative, 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> rangeWithAlternative = m_alternativeTextInfo.rangeWithAlternative->cloneRange(ec); + RefPtr<Range> rangeWithAlternative = range->cloneRange(ec); applyCommand(SpellingCorrectionCommand::create(rangeWithAlternative, alternative)); setEnd(paragraphRangeContainingCorrection.get(), m_frame->selection()->selection().start()); RefPtr<Range> replacementRange = TextIterator::subrange(paragraphRangeContainingCorrection.get(), correctionStartOffsetInParagraph, alternative.length()); @@ -259,13 +284,8 @@ void AlternativeTextController::applyAlternativeText(const String& alternative, DocumentMarkerController* markers = replacementRange->startContainer()->document()->markers(); size_t size = markerTypesToAdd.size(); - for (size_t i = 0; i < size; ++i) { - DocumentMarker::MarkerType markerType = markerTypesToAdd[i]; - String description; - if (m_alternativeTextInfo.type != AlternativeTextTypeReversion && (markerType == DocumentMarker::Replacement || markerType == DocumentMarker::Autocorrected)) - description = m_alternativeTextInfo.originalText; - markers->addMarker(replacementRange.get(), markerType, description); - } + for (size_t i = 0; i < size; ++i) + markers->addMarker(replacementRange.get(), markerTypesToAdd[i], markerDescriptionForAppliedAlternativeText(alternativeType, markerTypesToAdd[i])); } bool AlternativeTextController::applyAutocorrectionBeforeTypingIfAppropriate() @@ -348,16 +368,32 @@ void AlternativeTextController::timerFired(Timer<AlternativeTextController>*) } } break; + case AlternativeTextTypeDictationAlternatives: + { +#if USE(DICTATION_ALTERNATIVES) + const Range* rangeWithAlternative = m_alternativeTextInfo.rangeWithAlternative.get(); + const DictationAlternativeDetails* details = static_cast<const DictationAlternativeDetails*>(m_alternativeTextInfo.details.get()); + if (!rangeWithAlternative || !details || !details->dictationContext()) + return; + FloatRect boundingBox = rootViewRectForRange(rangeWithAlternative); + m_alternativeTextInfo.isActive = true; + if (!boundingBox.isEmpty()) { + if (AlternativeTextClient* client = alternativeTextClient()) + client->showDictationAlternativeUI(boundingBox, details->dictationContext()); + } +#endif + } + break; } } void AlternativeTextController::handleAlternativeTextUIResult(const String& result) { - Range* replacedRange = m_alternativeTextInfo.rangeWithAlternative.get(); - if (!replacedRange || m_frame->document() != replacedRange->ownerDocument()) + Range* rangeWithAlternative = m_alternativeTextInfo.rangeWithAlternative.get(); + if (!rangeWithAlternative || m_frame->document() != rangeWithAlternative->ownerDocument()) return; - String currentWord = plainText(m_alternativeTextInfo.rangeWithAlternative.get()); + String currentWord = plainText(rangeWithAlternative); // Check to see if the word we are about to correct has been changed between timer firing and callback being triggered. if (currentWord != m_alternativeTextInfo.originalText) return; @@ -367,14 +403,18 @@ void AlternativeTextController::handleAlternativeTextUIResult(const String& resu switch (m_alternativeTextInfo.type) { case AlternativeTextTypeCorrection: if (result.length()) - applyAlternativeText(result, markerTypesForAutocorrection()); + applyAlternativeTextToRange(rangeWithAlternative, result, m_alternativeTextInfo.type, markerTypesForAutocorrection()); else if (!m_isDismissedByEditing) - replacedRange->startContainer()->document()->markers()->addMarker(replacedRange, DocumentMarker::RejectedCorrection, m_alternativeTextInfo.originalText); + rangeWithAlternative->startContainer()->document()->markers()->addMarker(rangeWithAlternative, DocumentMarker::RejectedCorrection, m_alternativeTextInfo.originalText); break; case AlternativeTextTypeReversion: case AlternativeTextTypeSpellingSuggestions: if (result.length()) - applyAlternativeText(result, markerTypesForReplacement()); + applyAlternativeTextToRange(rangeWithAlternative, result, m_alternativeTextInfo.type, markerTypesForReplacement()); + break; + case AlternativeTextTypeDictationAlternatives: + if (result.length()) + applyAlternativeTextToRange(rangeWithAlternative, result, m_alternativeTextInfo.type, markerTypesForAppliedDictationAlternative()); break; } @@ -400,7 +440,7 @@ FloatRect AlternativeTextController::rootViewRectForRange(const Range* range) co return view->contentsToRootView(IntRect(boundingRect)); } -void AlternativeTextController::respondToChangedSelection(const VisibleSelection& oldSelection) +void AlternativeTextController::respondToChangedSelection(const VisibleSelection& oldSelection, FrameSelection::SetSelectionOptions options) { VisibleSelection currentSelection(m_frame->selection()->selection()); // When user moves caret to the end of autocorrected word and pauses, we show the panel @@ -426,28 +466,15 @@ void AlternativeTextController::respondToChangedSelection(const VisibleSelection return; Node* node = position.containerNode(); - int endOffset = position.offsetInContainerNode(); Vector<DocumentMarker*> markers = node->document()->markers()->markersFor(node); size_t markerCount = markers.size(); for (size_t i = 0; i < markerCount; ++i) { const DocumentMarker* marker = markers[i]; - if (!shouldStartTimerFor(marker, endOffset)) - continue; - RefPtr<Range> wordRange = Range::create(m_frame->document(), node, marker->startOffset(), node, marker->endOffset()); - String currentWord = plainText(wordRange.get()); - if (!currentWord.length()) + if (!marker) continue; - m_alternativeTextInfo.rangeWithAlternative = wordRange; - m_alternativeTextInfo.originalText = currentWord; - if (marker->type() == DocumentMarker::Spelling) - startAlternativeTextUITimer(AlternativeTextTypeSpellingSuggestions); - else { - m_alternativeTextInfo.details = AutocorrectionAlternativeDetails::create(marker->description()); - startAlternativeTextUITimer(AlternativeTextTypeReversion); - } - - break; + if (respondToMarkerAtEndOfWord(*marker, position, options)) + break; } } @@ -598,7 +625,63 @@ bool AlternativeTextController::processMarkersOnTextToBeReplacedByResult(const T return true; } - + +bool AlternativeTextController::shouldStartTimerFor(const WebCore::DocumentMarker &marker, int endOffset) const +{ + return (((marker.type() == DocumentMarker::Replacement && !marker.description().isNull()) || marker.type() == DocumentMarker::Spelling || marker.type() == DocumentMarker::DictationAlternatives) && static_cast<int>(marker.endOffset()) == endOffset); +} + +bool AlternativeTextController::respondToMarkerAtEndOfWord(const DocumentMarker& marker, const Position& endOfWordPosition, FrameSelection::SetSelectionOptions options) +{ + if (options & FrameSelection::DictationTriggered) + return false; + if (!shouldStartTimerFor(marker, endOfWordPosition.offsetInContainerNode())) + return false; + Node* node = endOfWordPosition.containerNode(); + RefPtr<Range> wordRange = Range::create(m_frame->document(), node, marker.startOffset(), node, marker.endOffset()); + if (!wordRange) + return false; + String currentWord = plainText(wordRange.get()); + if (!currentWord.length()) + return false; + m_alternativeTextInfo.originalText = currentWord; + switch (marker.type()) { + case DocumentMarker::Spelling: + m_alternativeTextInfo.rangeWithAlternative = wordRange; + m_alternativeTextInfo.details = AutocorrectionAlternativeDetails::create(""); + startAlternativeTextUITimer(AlternativeTextTypeSpellingSuggestions); + break; + case DocumentMarker::Replacement: + m_alternativeTextInfo.rangeWithAlternative = wordRange; + m_alternativeTextInfo.details = AutocorrectionAlternativeDetails::create(marker.description()); + startAlternativeTextUITimer(AlternativeTextTypeReversion); + break; + case DocumentMarker::DictationAlternatives: { + const DictationMarkerDetails* markerDetails = static_cast<const DictationMarkerDetails*>(marker.details()); + if (!markerDetails) + return false; + if (currentWord != markerDetails->originalText()) + return false; + m_alternativeTextInfo.rangeWithAlternative = wordRange; + m_alternativeTextInfo.details = DictationAlternativeDetails::create(markerDetails->dictationContext()); + startAlternativeTextUITimer(AlternativeTextTypeDictationAlternatives); + } + break; + default: + ASSERT_NOT_REACHED(); + break; + } + return true; +} + +String AlternativeTextController::markerDescriptionForAppliedAlternativeText(AlternativeTextType alternativeTextType, DocumentMarker::MarkerType markerType) +{ + + if (alternativeTextType != AlternativeTextTypeReversion && alternativeTextType != AlternativeTextTypeDictationAlternatives && (markerType == DocumentMarker::Replacement || markerType == DocumentMarker::Autocorrected)) + return m_alternativeTextInfo.originalText; + return ""; +} + #endif bool AlternativeTextController::insertDictatedText(const String& text, const Vector<DictationAlternative>& dictationAlternatives, Event* triggeringEvent) @@ -624,4 +707,48 @@ bool AlternativeTextController::insertDictatedText(const String& text, const Vec return event->defaultHandled(); } +void AlternativeTextController::removeDictationAlternativesForMarker(const DocumentMarker* marker) +{ +#if USE(DICTATION_ALTERNATIVES) + DictationMarkerDetails* details = static_cast<DictationMarkerDetails*>(marker->details()); + if (AlternativeTextClient* client = alternativeTextClient()) + client->removeDictationAlternatives(details->dictationContext()); +#else + UNUSED_PARAM(marker); +#endif +} + +Vector<String> AlternativeTextController::dictationAlternativesForMarker(const DocumentMarker* marker) +{ +#if USE(DICTATION_ALTERNATIVES) + ASSERT(marker->type() == DocumentMarker::DictationAlternatives); + if (AlternativeTextClient* client = alternativeTextClient()) { + DictationMarkerDetails* details = static_cast<DictationMarkerDetails*>(marker->details()); + return client->dictationAlternatives(details->dictationContext()); + } + return Vector<String>(); +#else + UNUSED_PARAM(marker); + return Vector<String>(); +#endif +} + +void AlternativeTextController::applyDictationAlternative(const String& alternativeString) +{ +#if USE(DICTATION_ALTERNATIVES) + Editor* editor = m_frame->editor(); + RefPtr<Range> selection = editor->selectedRange(); + if (!selection || !editor->shouldInsertText(alternativeString, selection.get(), EditorInsertActionPasted)) + return; + DocumentMarkerController* markers = selection->startContainer()->document()->markers(); + Vector<DocumentMarker*> dictationAlternativesMarkers = markers->markersInRange(selection.get(), DocumentMarker::DictationAlternatives); + for (size_t i = 0; i < dictationAlternativesMarkers.size(); ++i) + removeDictationAlternativesForMarker(dictationAlternativesMarkers[i]); + + applyAlternativeTextToRange(selection.get(), alternativeString, AlternativeTextTypeDictationAlternatives, markerTypesForAppliedDictationAlternative()); +#else + UNUSED_PARAM(alternativeString); +#endif +} + } // namespace WebCore |
