2 * Copyright (C) 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "DictationCommand.h"
29 #include "AlternativeTextController.h"
31 #include "DocumentMarker.h"
32 #include "DocumentMarkerController.h"
34 #include "InsertParagraphSeparatorCommand.h"
35 #include "InsertTextCommand.h"
40 class DictationCommandLineOperation {
42 DictationCommandLineOperation(DictationCommand* dictationCommand)
43 : m_dictationCommand(dictationCommand)
46 void operator()(size_t lineOffset, size_t lineLength, bool isLastLine) const
49 m_dictationCommand->insertTextRunWithoutNewlines(lineOffset, lineLength);
51 m_dictationCommand->insertParagraphSeparator();
54 DictationCommand* m_dictationCommand;
57 class DictationMarkerSupplier : public TextInsertionMarkerSupplier {
59 static PassRefPtr<DictationMarkerSupplier> create(const Vector<DictationAlternative>& alternatives)
61 return adoptRef(new DictationMarkerSupplier(alternatives));
64 virtual void addMarkersToTextNode(Text* textNode, unsigned offsetOfInsertion, const String& textToBeInserted)
66 Document* document = textNode->document();
67 DocumentMarkerController* markerController =document->markers();
68 for (size_t i = 0; i < m_alternatives.size(); ++i) {
69 const DictationAlternative& alternative = m_alternatives[i];
70 markerController->addMarkerToNode(textNode, alternative.rangeStart + offsetOfInsertion, alternative.rangeLength, DocumentMarker::DictationAlternatives, DictationMarkerDetails::create(textToBeInserted.substring(alternative.rangeStart, alternative.rangeLength), alternative.dictationContext));
71 markerController->addMarkerToNode(textNode, alternative.rangeStart + offsetOfInsertion, alternative.rangeLength, DocumentMarker::SpellCheckingExemption);
76 DictationMarkerSupplier(const Vector<DictationAlternative>& alternatives)
77 : m_alternatives(alternatives)
81 Vector<DictationAlternative> m_alternatives;
84 DictationCommand::DictationCommand(Document* document, const String& text, const Vector<DictationAlternative>& alternatives)
85 : TextInsertionBaseCommand(document)
86 , m_textToInsert(text)
87 , m_alternatives(alternatives)
91 void DictationCommand::insertText(Document* document, const String& text, const Vector<DictationAlternative>& alternatives, const VisibleSelection& selectionForInsertion)
93 RefPtr<Frame> frame = document->frame();
96 VisibleSelection currentSelection = frame->selection()->selection();
98 String newText = dispatchBeforeTextInsertedEvent(text, selectionForInsertion, false);
100 RefPtr<DictationCommand> cmd;
102 cmd = DictationCommand::create(document, newText, alternatives);
104 // If the text was modified before insertion, the location of dictation alternatives
105 // will not be valid anymore. We will just drop the alternatives.
106 cmd = DictationCommand::create(document, newText, Vector<DictationAlternative>());
107 applyTextInsertionCommand(frame.get(), cmd, selectionForInsertion, currentSelection);
110 void DictationCommand::doApply()
112 DictationCommandLineOperation operation(this);
113 forEachLineInString(m_textToInsert, operation);
116 void DictationCommand::insertTextRunWithoutNewlines(size_t lineStart, size_t lineLength)
118 Vector<DictationAlternative> alternativesInLine;
119 collectDictationAlternativesInRange(lineStart, lineLength, alternativesInLine);
120 RefPtr<InsertTextCommand> command = InsertTextCommand::createWithMarkerSupplier(document(), m_textToInsert.substring(lineStart, lineLength), DictationMarkerSupplier::create(alternativesInLine));
121 applyCommandToComposite(command, endingSelection());
124 void DictationCommand::insertParagraphSeparator()
126 if (!canAppendNewLineFeedToSelection(endingSelection()))
129 applyCommandToComposite(InsertParagraphSeparatorCommand::create(document()));
132 void DictationCommand::collectDictationAlternativesInRange(size_t rangeStart, size_t rangeLength, Vector<DictationAlternative>& alternatives)
134 for (size_t i = 0; i < m_alternatives.size(); ++i) {
135 const DictationAlternative& alternative = m_alternatives[i];
136 if (alternative.rangeStart >= rangeStart && (alternative.rangeStart + alternative.rangeLength) <= rangeStart + rangeLength)
137 alternatives.append(DictationAlternative(alternative.rangeStart - rangeStart, alternative.rangeLength, alternative.dictationContext));