1 /*
2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, 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 COMPUTER, 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.
24 */
25
26 #ifndef Editor_h
27 #define Editor_h
28
29 #include "ClipboardAccessPolicy.h"
30 #include "Color.h"
31 #include "DocumentMarker.h"
32 #include "EditAction.h"
33 #include "EditingBehavior.h"
34 #include "EditorDeleteAction.h"
35 #include "EditorInsertAction.h"
36 #include "FindOptions.h"
37 #include "SelectionController.h"
38 #include "TextChecking.h"
39 #include "Timer.h"
40 #include "VisibleSelection.h"
41 #include "WritingDirection.h"
42
43 #if PLATFORM(MAC) && !defined(__OBJC__)
44 class NSDictionary;
45 typedef int NSWritingDirection;
46 #endif
47
48 namespace WebCore {
49
50 class CSSMutableStyleDeclaration;
51 class CSSStyleDeclaration;
52 class Clipboard;
53 class SpellingCorrectionController;
54 class DeleteButtonController;
55 class EditCommand;
56 class EditorClient;
57 class EditorInternalCommand;
58 class Frame;
59 class HTMLElement;
60 class HitTestResult;
61 class KillRing;
62 class Pasteboard;
63 class SimpleFontData;
64 class SpellChecker;
65 class Text;
66 class TextCheckerClient;
67 class TextEvent;
68
69 struct CompositionUnderline {
CompositionUnderlineCompositionUnderline70 CompositionUnderline()
71 : startOffset(0), endOffset(0), thick(false) { }
CompositionUnderlineCompositionUnderline72 CompositionUnderline(unsigned s, unsigned e, const Color& c, bool t)
73 : startOffset(s), endOffset(e), color(c), thick(t) { }
74 unsigned startOffset;
75 unsigned endOffset;
76 Color color;
77 bool thick;
78 };
79
80 enum EditorCommandSource { CommandFromMenuOrKeyBinding, CommandFromDOM, CommandFromDOMWithUserInterface };
81
82 class Editor {
83 public:
84 Editor(Frame*);
85 ~Editor();
86
87 EditorClient* client() const;
88 TextCheckerClient* textChecker() const;
89
frame()90 Frame* frame() const { return m_frame; }
deleteButtonController()91 DeleteButtonController* deleteButtonController() const { return m_deleteButtonController.get(); }
lastEditCommand()92 EditCommand* lastEditCommand() { return m_lastEditCommand.get(); }
93
94 void handleKeyboardEvent(KeyboardEvent*);
95 void handleInputMethodKeydown(KeyboardEvent*);
96 bool handleTextEvent(TextEvent*);
97
98 bool canEdit() const;
99 bool canEditRichly() const;
100
101 bool canDHTMLCut();
102 bool canDHTMLCopy();
103 bool canDHTMLPaste();
104 bool tryDHTMLCopy();
105 bool tryDHTMLCut();
106 bool tryDHTMLPaste();
107
108 bool canCut() const;
109 bool canCopy() const;
110 bool canPaste() const;
111 bool canDelete() const;
112 bool canSmartCopyOrDelete();
113
114 void cut();
115 void copy();
116 void paste();
117 void pasteAsPlainText();
118 void performDelete();
119
120 void copyURL(const KURL&, const String&);
121 void copyImage(const HitTestResult&);
122
123 void indent();
124 void outdent();
125 void transpose();
126
127 bool shouldInsertFragment(PassRefPtr<DocumentFragment>, PassRefPtr<Range>, EditorInsertAction);
128 bool shouldInsertText(const String&, Range*, EditorInsertAction) const;
129 bool shouldShowDeleteInterface(HTMLElement*) const;
130 bool shouldDeleteRange(Range*) const;
131 bool shouldApplyStyle(CSSStyleDeclaration*, Range*);
132
133 void respondToChangedSelection(const VisibleSelection& oldSelection);
134 void respondToChangedContents(const VisibleSelection& endingSelection);
135
136 bool selectionStartHasStyle(int propertyID, const String& value) const;
137 TriState selectionHasStyle(int propertyID, const String& value) const;
138 String selectionStartCSSPropertyValue(int propertyID);
139 const SimpleFontData* fontForSelection(bool&) const;
140 WritingDirection textDirectionForSelection(bool&) const;
141
142 TriState selectionUnorderedListState() const;
143 TriState selectionOrderedListState() const;
144 PassRefPtr<Node> insertOrderedList();
145 PassRefPtr<Node> insertUnorderedList();
146 bool canIncreaseSelectionListLevel();
147 bool canDecreaseSelectionListLevel();
148 PassRefPtr<Node> increaseSelectionListLevel();
149 PassRefPtr<Node> increaseSelectionListLevelOrdered();
150 PassRefPtr<Node> increaseSelectionListLevelUnordered();
151 void decreaseSelectionListLevel();
152
153 void removeFormattingAndStyle();
154
155 void clearLastEditCommand();
156
157 bool deleteWithDirection(SelectionDirection, TextGranularity, bool killRing, bool isTypingAction);
158 void deleteSelectionWithSmartDelete(bool smartDelete);
159 bool dispatchCPPEvent(const AtomicString&, ClipboardAccessPolicy);
160
removedAnchor()161 Node* removedAnchor() const { return m_removedAnchor.get(); }
setRemovedAnchor(PassRefPtr<Node> n)162 void setRemovedAnchor(PassRefPtr<Node> n) { m_removedAnchor = n; }
163
164 void applyStyle(CSSStyleDeclaration*, EditAction = EditActionUnspecified);
165 void applyParagraphStyle(CSSStyleDeclaration*, EditAction = EditActionUnspecified);
166 void applyStyleToSelection(CSSStyleDeclaration*, EditAction);
167 void applyParagraphStyleToSelection(CSSStyleDeclaration*, EditAction);
168
169 void appliedEditing(PassRefPtr<EditCommand>);
170 void unappliedEditing(PassRefPtr<EditCommand>);
171 void reappliedEditing(PassRefPtr<EditCommand>);
172 void unappliedSpellCorrection(const VisibleSelection& selectionOfCorrected, const String& corrected, const String& correction);
173
setShouldStyleWithCSS(bool flag)174 void setShouldStyleWithCSS(bool flag) { m_shouldStyleWithCSS = flag; }
shouldStyleWithCSS()175 bool shouldStyleWithCSS() const { return m_shouldStyleWithCSS; }
176
177 class Command {
178 public:
179 Command();
180 Command(const EditorInternalCommand*, EditorCommandSource, PassRefPtr<Frame>);
181
182 bool execute(const String& parameter = String(), Event* triggeringEvent = 0) const;
183 bool execute(Event* triggeringEvent) const;
184
185 bool isSupported() const;
186 bool isEnabled(Event* triggeringEvent = 0) const;
187
188 TriState state(Event* triggeringEvent = 0) const;
189 String value(Event* triggeringEvent = 0) const;
190
191 bool isTextInsertion() const;
192
193 private:
194 const EditorInternalCommand* m_command;
195 EditorCommandSource m_source;
196 RefPtr<Frame> m_frame;
197 };
198 Command command(const String& commandName); // Command source is CommandFromMenuOrKeyBinding.
199 Command command(const String& commandName, EditorCommandSource);
200 static bool commandIsSupportedFromMenuOrKeyBinding(const String& commandName); // Works without a frame.
201
202 bool insertText(const String&, Event* triggeringEvent);
203 bool insertTextForConfirmedComposition(const String& text);
204 bool insertTextWithoutSendingTextEvent(const String&, bool selectInsertedText, TextEvent* triggeringEvent);
205 bool insertLineBreak();
206 bool insertParagraphSeparator();
207
208 bool isContinuousSpellCheckingEnabled();
209 void toggleContinuousSpellChecking();
210 bool isGrammarCheckingEnabled();
211 void toggleGrammarChecking();
212 void ignoreSpelling();
213 void learnSpelling();
214 int spellCheckerDocumentTag();
215 bool isSelectionUngrammatical();
216 bool isSelectionMisspelled();
217 Vector<String> guessesForMisspelledSelection();
218 Vector<String> guessesForUngrammaticalSelection();
219 Vector<String> guessesForMisspelledOrUngrammaticalSelection(bool& misspelled, bool& ungrammatical);
220 bool isSpellCheckingEnabledInFocusedNode() const;
221 bool isSpellCheckingEnabledFor(Node*) const;
222 void markMisspellingsAfterTypingToWord(const VisiblePosition &wordStart, const VisibleSelection& selectionAfterTyping, bool doReplacement);
223 void markMisspellings(const VisibleSelection&, RefPtr<Range>& firstMisspellingRange);
224 void markBadGrammar(const VisibleSelection&);
225 void markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelection, bool markGrammar, const VisibleSelection& grammarSelection);
226
227 enum TextCheckingOptionFlags {
228 MarkSpelling = 1 << 0,
229 MarkGrammar = 1 << 1,
230 PerformReplacement = 1 << 2,
231 ShowCorrectionPanel = 1 << 3,
232 CheckForCorrection = 1 << 4,
233 };
234 typedef unsigned TextCheckingOptions;
235
236 #if USE(AUTOMATIC_TEXT_REPLACEMENT)
237 void uppercaseWord();
238 void lowercaseWord();
239 void capitalizeWord();
240 void showSubstitutionsPanel();
241 bool substitutionsPanelIsShowing();
242 void toggleSmartInsertDelete();
243 bool isAutomaticQuoteSubstitutionEnabled();
244 void toggleAutomaticQuoteSubstitution();
245 bool isAutomaticLinkDetectionEnabled();
246 void toggleAutomaticLinkDetection();
247 bool isAutomaticDashSubstitutionEnabled();
248 void toggleAutomaticDashSubstitution();
249 bool isAutomaticTextReplacementEnabled();
250 void toggleAutomaticTextReplacement();
251 bool isAutomaticSpellingCorrectionEnabled();
252 void toggleAutomaticSpellingCorrection();
253 #endif
254
255 void markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions, Range* spellingRange, Range* grammarRange);
256 void changeBackToReplacedString(const String& replacedString);
257
258 void advanceToNextMisspelling(bool startBeforeSelection = false);
259 void showSpellingGuessPanel();
260 bool spellingPanelIsShowing();
261
262 bool shouldBeginEditing(Range*);
263 bool shouldEndEditing(Range*);
264
265 void clearUndoRedoOperations();
266 bool canUndo();
267 void undo();
268 bool canRedo();
269 void redo();
270
271 void didBeginEditing();
272 void didEndEditing();
273 void didWriteSelectionToPasteboard();
274
275 void showFontPanel();
276 void showStylesPanel();
277 void showColorPanel();
278 void toggleBold();
279 void toggleUnderline();
280 void setBaseWritingDirection(WritingDirection);
281
282 // smartInsertDeleteEnabled and selectTrailingWhitespaceEnabled are
283 // mutually exclusive, meaning that enabling one will disable the other.
284 bool smartInsertDeleteEnabled();
285 bool isSelectTrailingWhitespaceEnabled();
286
287 bool hasBidiSelection() const;
288
289 // international text input composition
hasComposition()290 bool hasComposition() const { return m_compositionNode; }
291 void setComposition(const String&, const Vector<CompositionUnderline>&, unsigned selectionStart, unsigned selectionEnd);
292 void confirmComposition();
293 void confirmComposition(const String&); // if no existing composition, replaces selection
294 void confirmCompositionWithoutDisturbingSelection();
295 PassRefPtr<Range> compositionRange() const;
296 bool getCompositionSelection(unsigned& selectionStart, unsigned& selectionEnd) const;
297
298 // getting international text input composition state (for use by InlineTextBox)
compositionNode()299 Text* compositionNode() const { return m_compositionNode.get(); }
compositionStart()300 unsigned compositionStart() const { return m_compositionStart; }
compositionEnd()301 unsigned compositionEnd() const { return m_compositionEnd; }
compositionUsesCustomUnderlines()302 bool compositionUsesCustomUnderlines() const { return !m_customCompositionUnderlines.isEmpty(); }
customCompositionUnderlines()303 const Vector<CompositionUnderline>& customCompositionUnderlines() const { return m_customCompositionUnderlines; }
304
ignoreCompositionSelectionChange()305 bool ignoreCompositionSelectionChange() const { return m_ignoreCompositionSelectionChange; }
306
307 void setStartNewKillRingSequence(bool);
308
309 PassRefPtr<Range> rangeForPoint(const IntPoint& windowPoint);
310
311 void clear();
312
313 VisibleSelection selectionForCommand(Event*);
314
killRing()315 KillRing* killRing() const { return m_killRing.get(); }
spellChecker()316 SpellChecker* spellChecker() const { return m_spellChecker.get(); }
317
318 EditingBehavior behavior() const;
319
320 PassRefPtr<Range> selectedRange();
321
322 // We should make these functions private when their callers in Frame are moved over here to Editor
323 bool insideVisibleArea(const IntPoint&) const;
324 bool insideVisibleArea(Range*) const;
325
326 void addToKillRing(Range*, bool prepend);
327
328 void startCorrectionPanelTimer();
329 // If user confirmed a correction in the correction panel, correction has non-zero length, otherwise it means that user has dismissed the panel.
330 void handleCorrectionPanelResult(const String& correction);
331 void dismissCorrectionPanelAsIgnored();
332
333 void pasteAsFragment(PassRefPtr<DocumentFragment>, bool smartReplace, bool matchStyle);
334 void pasteAsPlainText(const String&, bool smartReplace);
335
336 // This is only called on the mac where paste is implemented primarily at the WebKit level.
337 void pasteAsPlainTextBypassingDHTML();
338
339 void clearMisspellingsAndBadGrammar(const VisibleSelection&);
340 void markMisspellingsAndBadGrammar(const VisibleSelection&);
341
342 Node* findEventTargetFrom(const VisibleSelection& selection) const;
343
344 String selectedText() const;
345 bool findString(const String&, FindOptions);
346 // FIXME: Switch callers over to the FindOptions version and retire this one.
347 bool findString(const String&, bool forward, bool caseFlag, bool wrapFlag, bool startInSelection);
348
349 const VisibleSelection& mark() const; // Mark, to be used as emacs uses it.
350 void setMark(const VisibleSelection&);
351
352 void computeAndSetTypingStyle(CSSStyleDeclaration* , EditAction = EditActionUnspecified);
353 void applyEditingStyleToBodyElement() const;
354 void applyEditingStyleToElement(Element*) const;
355
356 IntRect firstRectForRange(Range*) const;
357
358 void respondToChangedSelection(const VisibleSelection& oldSelection, SelectionController::SetSelectionOptions);
359 bool shouldChangeSelection(const VisibleSelection& oldSelection, const VisibleSelection& newSelection, EAffinity, bool stillSelecting) const;
360
361 RenderStyle* styleForSelectionStart(Node*& nodeToRemove) const;
362
363 unsigned countMatchesForText(const String&, FindOptions, unsigned limit, bool markMatches);
364 unsigned countMatchesForText(const String&, Range*, FindOptions, unsigned limit, bool markMatches);
365 bool markedTextMatchesAreHighlighted() const;
366 void setMarkedTextMatchesAreHighlighted(bool);
367
368 PassRefPtr<EditingStyle> selectionStartStyle() const;
369
370 void textFieldDidBeginEditing(Element*);
371 void textFieldDidEndEditing(Element*);
372 void textDidChangeInTextField(Element*);
373 bool doTextFieldCommandFromEvent(Element*, KeyboardEvent*);
374 void textWillBeDeletedInTextField(Element* input);
375 void textDidChangeInTextArea(Element*);
376
377 #if PLATFORM(MAC)
378 NSDictionary* fontAttributesForSelectionStart() const;
379 NSWritingDirection baseWritingDirectionForSelectionStart() const;
380 bool canCopyExcludingStandaloneImages();
381 void takeFindStringFromSelection();
382 void writeSelectionToPasteboard(const String& pasteboardName, const Vector<String>& pasteboardTypes);
383 void readSelectionFromPasteboard(const String& pasteboardName);
384 #endif
385
386 bool selectionStartHasMarkerFor(DocumentMarker::MarkerType, int from, int length) const;
387 void updateMarkersForWordsAffectedByEditing(bool onlyHandleWordsContainingSelection);
388
389 private:
390 Frame* m_frame;
391 OwnPtr<DeleteButtonController> m_deleteButtonController;
392 RefPtr<EditCommand> m_lastEditCommand;
393 RefPtr<Node> m_removedAnchor;
394 RefPtr<Text> m_compositionNode;
395 unsigned m_compositionStart;
396 unsigned m_compositionEnd;
397 Vector<CompositionUnderline> m_customCompositionUnderlines;
398 bool m_ignoreCompositionSelectionChange;
399 bool m_shouldStartNewKillRingSequence;
400 bool m_shouldStyleWithCSS;
401 OwnPtr<KillRing> m_killRing;
402 OwnPtr<SpellChecker> m_spellChecker;
403 OwnPtr<SpellingCorrectionController> m_spellingCorrector;
404 VisibleSelection m_mark;
405 bool m_areMarkedTextMatchesHighlighted;
406
407 bool canDeleteRange(Range*) const;
408 bool canSmartReplaceWithPasteboard(Pasteboard*);
409 PassRefPtr<Clipboard> newGeneralClipboard(ClipboardAccessPolicy, Frame*);
410 void pasteAsPlainTextWithPasteboard(Pasteboard*);
411 void pasteWithPasteboard(Pasteboard*, bool allowPlainText);
412 void replaceSelectionWithFragment(PassRefPtr<DocumentFragment>, bool selectReplacement, bool smartReplace, bool matchStyle);
413 void replaceSelectionWithText(const String&, bool selectReplacement, bool smartReplace);
414 void writeSelectionToPasteboard(Pasteboard*);
415 void revealSelectionAfterEditingOperation();
416 void markMisspellingsOrBadGrammar(const VisibleSelection&, bool checkSpelling, RefPtr<Range>& firstMisspellingRange);
417 TextCheckingTypeMask textCheckingTypeMaskFor(TextCheckingOptions);
418
419 void selectComposition();
420 void confirmComposition(const String&, bool preserveSelection);
421 void setIgnoreCompositionSelectionChange(bool ignore);
422
423 PassRefPtr<Range> firstVisibleRange(const String&, FindOptions);
424 PassRefPtr<Range> lastVisibleRange(const String&, FindOptions);
425 PassRefPtr<Range> nextVisibleRange(Range*, const String&, FindOptions);
426
427 void changeSelectionAfterCommand(const VisibleSelection& newSelection, bool closeTyping, bool clearTypingStyle);
428
429 Node* findEventTargetFromSelection() const;
430 void stopCorrectionPanelTimer();
431
432 void applyCorrectionPanelInfo(const Vector<DocumentMarker::MarkerType>& markerTypesToAdd);
433 // Return true if correction was applied, false otherwise.
434 bool applyAutocorrectionBeforeTypingIfAppropriate();
435 FloatRect windowRectForRange(const Range*) const;
436 };
437
setStartNewKillRingSequence(bool flag)438 inline void Editor::setStartNewKillRingSequence(bool flag)
439 {
440 m_shouldStartNewKillRingSequence = flag;
441 }
442
mark()443 inline const VisibleSelection& Editor::mark() const
444 {
445 return m_mark;
446 }
447
setMark(const VisibleSelection & selection)448 inline void Editor::setMark(const VisibleSelection& selection)
449 {
450 m_mark = selection;
451 }
452
markedTextMatchesAreHighlighted()453 inline bool Editor::markedTextMatchesAreHighlighted() const
454 {
455 return m_areMarkedTextMatchesHighlighted;
456 }
457
458
459 } // namespace WebCore
460
461 #endif // Editor_h
462