2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Trolltech ASA
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "AXObjectCache.h"
31 #include "ApplyStyleCommand.h"
32 #include "CSSComputedStyleDeclaration.h"
33 #include "CSSProperty.h"
34 #include "CSSPropertyNames.h"
35 #include "CharacterData.h"
36 #include "Clipboard.h"
37 #include "ClipboardEvent.h"
38 #include "DeleteButtonController.h"
39 #include "DeleteSelectionCommand.h"
40 #include "DocLoader.h"
42 #include "DocumentFragment.h"
43 #include "EditCommand.h"
45 #include "EditorClient.h"
47 #include "EventHandler.h"
48 #include "EventNames.h"
49 #include "FocusController.h"
51 #include "HTMLElement.h"
52 #include "HTMLInputElement.h"
53 #include "HTMLNames.h"
54 #include "HTMLTextAreaElement.h"
55 #include "HitTestResult.h"
56 #include "IndentOutdentCommand.h"
57 #include "KeyboardEvent.h"
60 #include "Pasteboard.h"
62 #include "ReplaceSelectionCommand.h"
63 #include "SelectionController.h"
65 #include "TextIterator.h"
66 #include "TypingCommand.h"
67 #include "htmlediting.h"
72 using namespace EventNames;
73 using namespace HTMLNames;
75 // When an event handler has moved the selection outside of a text control
76 // we should use the target control's selection for this editing operation.
77 static Selection selectionForEvent(Frame* frame, Event* event)
79 Page* page = frame->page();
82 Selection selection = page->selection();
85 Node* target = event->target()->toNode();
86 Node* selectionStart = selection.start().node();
88 // If the target is a text control, and the current selection is outside of its shadow tree,
89 // then use the saved selection for that text control.
90 if (target && (!selectionStart || target->shadowAncestorNode() != selectionStart->shadowAncestorNode())) {
91 if (target->hasTagName(inputTag) && static_cast<HTMLInputElement*>(target)->isTextField())
92 return static_cast<HTMLInputElement*>(target)->selection();
93 if (target->hasTagName(textareaTag))
94 return static_cast<HTMLTextAreaElement*>(target)->selection();
99 EditorClient* Editor::client() const
101 if (Page* page = m_frame->page())
102 return page->editorClient();
106 void Editor::handleKeypress(KeyboardEvent* event)
108 if (EditorClient* c = client())
109 if (selectionForEvent(m_frame, event).isContentEditable())
110 c->handleKeypress(event);
113 void Editor::handleInputMethodKeypress(KeyboardEvent* event)
115 if (EditorClient* c = client())
116 if (selectionForEvent(m_frame, event).isContentEditable())
117 c->handleInputMethodKeypress(event);
120 bool Editor::canEdit() const
122 return m_frame->selectionController()->isContentEditable();
125 bool Editor::canEditRichly() const
127 return m_frame->selectionController()->isContentRichlyEditable();
130 // WinIE uses onbeforecut and onbeforepaste to enables the cut and paste menu items. They
131 // also send onbeforecopy, apparently for symmetry, but it doesn't affect the menu items.
132 // We need to use onbeforecopy as a real menu enabler because we allow elements that are not
133 // normally selectable to implement copy/paste (like divs, or a document body).
135 bool Editor::canDHTMLCut()
137 return !m_frame->selectionController()->isInPasswordField() && !dispatchCPPEvent(beforecutEvent, ClipboardNumb);
140 bool Editor::canDHTMLCopy()
142 return !m_frame->selectionController()->isInPasswordField() && !dispatchCPPEvent(beforecopyEvent, ClipboardNumb);
145 bool Editor::canDHTMLPaste()
147 return !dispatchCPPEvent(beforepasteEvent, ClipboardNumb);
150 bool Editor::canCut() const
152 return canCopy() && canDelete();
155 bool Editor::canCopy() const
157 SelectionController* selectionController = m_frame->selectionController();
158 return selectionController->isRange() && !selectionController->isInPasswordField();
161 bool Editor::canPaste() const
166 bool Editor::canDelete() const
168 SelectionController* selectionController = m_frame->selectionController();
169 return selectionController->isRange() && selectionController->isContentEditable();
172 bool Editor::canDeleteRange(Range* range) const
174 ExceptionCode ec = 0;
175 Node* startContainer = range->startContainer(ec);
176 Node* endContainer = range->endContainer(ec);
177 if (!startContainer || !endContainer)
180 if (!startContainer->isContentEditable() || !endContainer->isContentEditable())
183 if (range->collapsed(ec)) {
184 VisiblePosition start(startContainer, range->startOffset(ec), DOWNSTREAM);
185 VisiblePosition previous = start.previous();
186 // FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item.
187 if (previous.isNull() || previous.deepEquivalent().node()->rootEditableElement() != startContainer->rootEditableElement())
193 bool Editor::smartInsertDeleteEnabled()
196 return client()->smartInsertDeleteEnabled();
200 bool Editor::canSmartCopyOrDelete()
203 return client()->smartInsertDeleteEnabled() && m_frame->selectionGranularity() == WordGranularity;
207 void Editor::deleteRange(Range* range, bool killRing, bool prepend, bool smartDeleteOK, EditorDeleteAction deletionAction, TextGranularity granularity)
210 addToKillRing(range, prepend);
212 ExceptionCode ec = 0;
214 SelectionController* selectionController = m_frame->selectionController();
215 bool smartDelete = smartDeleteOK && canSmartCopyOrDelete();
216 switch (deletionAction) {
217 case deleteSelectionAction:
218 selectionController->setSelectedRange(range, DOWNSTREAM, true, ec);
221 deleteSelectionWithSmartDelete(smartDelete);
223 case deleteKeyAction:
224 selectionController->setSelectedRange(range, DOWNSTREAM, (granularity != CharacterGranularity), ec);
227 if (m_frame->document()) {
228 TypingCommand::deleteKeyPressed(m_frame->document(), smartDelete, granularity);
229 m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
232 case forwardDeleteKeyAction:
233 selectionController->setSelectedRange(range, DOWNSTREAM, (granularity != CharacterGranularity), ec);
236 if (m_frame->document()) {
237 TypingCommand::forwardDeleteKeyPressed(m_frame->document(), smartDelete, granularity);
238 m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
243 // clear the "start new kill ring sequence" setting, because it was set to true
244 // when the selection was updated by deleting the range
246 setStartNewKillRingSequence(false);
249 bool Editor::deleteWithDirection(SelectionController::EDirection direction, TextGranularity granularity, bool killRing, bool isTypingAction)
251 // Delete the selection, if there is one.
252 // If not, make a selection using the passed-in direction and granularity.
258 EditorDeleteAction deletionAction = deleteSelectionAction;
260 bool smartDeleteOK = false;
262 if (m_frame->selectionController()->isRange()) {
263 range = selectedRange();
264 smartDeleteOK = true;
266 deletionAction = deleteKeyAction;
268 SelectionController selectionController;
269 selectionController.setSelection(m_frame->selectionController()->selection());
270 selectionController.modify(SelectionController::EXTEND, direction, granularity);
271 if (killRing && selectionController.isCaret() && granularity != CharacterGranularity)
272 selectionController.modify(SelectionController::EXTEND, direction, CharacterGranularity);
274 range = selectionController.toRange();
277 case SelectionController::FORWARD:
278 case SelectionController::RIGHT:
279 deletionAction = forwardDeleteKeyAction;
281 case SelectionController::BACKWARD:
282 case SelectionController::LEFT:
283 deletionAction = deleteKeyAction;
288 deleteRange(range.get(), killRing, false, smartDeleteOK, deletionAction, granularity);
293 void Editor::deleteSelectionWithSmartDelete()
295 deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
298 void Editor::deleteSelectionWithSmartDelete(bool smartDelete)
300 if (m_frame->selectionController()->isNone())
303 applyCommand(new DeleteSelectionCommand(m_frame->document(), smartDelete));
306 void Editor::pasteAsPlainTextWithPasteboard(Pasteboard* pasteboard)
308 String text = pasteboard->plainText(m_frame);
309 if (client() && client()->shouldInsertText(text, selectedRange().get(), EditorInsertActionPasted))
310 replaceSelectionWithText(text, false, canSmartReplaceWithPasteboard(pasteboard));
313 void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText)
315 RefPtr<Range> range = selectedRange();
317 RefPtr<DocumentFragment> fragment = pasteboard->documentFragment(m_frame, range, allowPlainText, chosePlainText);
318 if (fragment && shouldInsertFragment(fragment, range, EditorInsertActionPasted))
319 replaceSelectionWithFragment(fragment, false, canSmartReplaceWithPasteboard(pasteboard), chosePlainText);
322 bool Editor::canSmartReplaceWithPasteboard(Pasteboard* pasteboard)
325 return client()->smartInsertDeleteEnabled() && pasteboard->canSmartReplace();
329 bool Editor::shouldInsertFragment(PassRefPtr<DocumentFragment> fragment, PassRefPtr<Range> replacingDOMRange, EditorInsertAction givenAction)
332 Node* child = fragment->firstChild();
333 if (child && fragment->lastChild() == child && child->isCharacterDataNode())
334 return client()->shouldInsertText(static_cast<CharacterData*>(child)->data(), replacingDOMRange.get(), givenAction);
335 return client()->shouldInsertNode(fragment.get(), replacingDOMRange.get(), givenAction);
340 void Editor::replaceSelectionWithFragment(PassRefPtr<DocumentFragment> fragment, bool selectReplacement, bool smartReplace, bool matchStyle)
342 if (m_frame->selectionController()->isNone() || !fragment)
345 applyCommand(new ReplaceSelectionCommand(m_frame->document(), fragment, selectReplacement, smartReplace, matchStyle));
346 m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
349 void Editor::replaceSelectionWithText(const String& text, bool selectReplacement, bool smartReplace)
351 replaceSelectionWithFragment(createFragmentFromText(selectedRange().get(), text), selectReplacement, smartReplace, true);
354 PassRefPtr<Range> Editor::selectedRange()
358 return m_frame->selectionController()->toRange();
361 bool Editor::shouldDeleteRange(Range* range) const
364 if (!range || range->collapsed(ec))
367 if (!canDeleteRange(range))
371 return client()->shouldDeleteRange(range);
375 bool Editor::tryDHTMLCopy()
377 if (m_frame->selectionController()->isInPasswordField())
380 // Must be done before oncopy adds types and data to the pboard,
381 // also done for security, as it erases data from the last copy/paste.
382 Pasteboard::generalPasteboard()->clear();
384 return !dispatchCPPEvent(copyEvent, ClipboardWritable);
387 bool Editor::tryDHTMLCut()
389 if (m_frame->selectionController()->isInPasswordField())
392 // Must be done before oncut adds types and data to the pboard,
393 // also done for security, as it erases data from the last copy/paste.
394 Pasteboard::generalPasteboard()->clear();
396 return !dispatchCPPEvent(cutEvent, ClipboardWritable);
399 bool Editor::tryDHTMLPaste()
401 return !dispatchCPPEvent(pasteEvent, ClipboardReadable);
404 void Editor::writeSelectionToPasteboard(Pasteboard* pasteboard)
406 pasteboard->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
409 bool Editor::shouldInsertText(const String& text, Range* range, EditorInsertAction action) const
412 return client()->shouldInsertText(text, range, action);
416 bool Editor::shouldShowDeleteInterface(HTMLElement* element) const
419 return client()->shouldShowDeleteInterface(element);
423 void Editor::respondToChangedSelection(const Selection& oldSelection)
426 client()->respondToChangedSelection();
427 m_deleteButtonController->respondToChangedSelection(oldSelection);
430 void Editor::respondToChangedContents(const Selection& endingSelection)
432 if (AXObjectCache::accessibilityEnabled()) {
433 Node* node = endingSelection.start().node();
435 m_frame->renderer()->document()->axObjectCache()->postNotification(node->renderer(), "AXValueChanged");
439 client()->respondToChangedContents();
440 m_deleteButtonController->respondToChangedContents();
443 const FontData* Editor::fontForSelection(bool& hasMultipleFonts) const
445 if (hasMultipleFonts)
446 hasMultipleFonts = false;
448 if (!m_frame->selectionController()->isRange()) {
450 RenderStyle* style = m_frame->styleForSelectionStart(nodeToRemove); // sets nodeToRemove
452 const FontData* result = 0;
454 result = style->font().primaryFont();
458 nodeToRemove->remove(ec);
465 const FontData* font = 0;
467 RefPtr<Range> range = m_frame->selectionController()->toRange();
468 Node* startNode = range->editingStartPosition().node();
470 Node* pastEnd = range->pastEndNode();
471 // In the loop below, n should eventually match pastEnd and not become nil, but we've seen at least one
472 // unreproducible case where this didn't happen, so check for nil also.
473 for (Node* n = startNode; n && n != pastEnd; n = n->traverseNextNode()) {
474 RenderObject *renderer = n->renderer();
477 // FIXME: Are there any node types that have renderers, but that we should be skipping?
478 const FontData* f = renderer->style()->font().primaryFont();
481 if (!hasMultipleFonts)
483 } else if (font != f) {
484 hasMultipleFonts = true;
493 Frame::TriState Editor::selectionUnorderedListState() const
495 if (m_frame->selectionController()->isCaret()) {
496 Node* selectionNode = m_frame->selectionController()->selection().start().node();
497 if (enclosingNodeWithTag(selectionNode, ulTag))
498 return Frame::trueTriState;
499 } else if (m_frame->selectionController()->isRange()) {
500 Node* startNode = enclosingNodeWithTag(m_frame->selectionController()->selection().start().node(), ulTag);
501 Node* endNode = enclosingNodeWithTag(m_frame->selectionController()->selection().end().node(), ulTag);
502 if (startNode && endNode && startNode == endNode)
503 return Frame::trueTriState;
506 return Frame::falseTriState;
509 Frame::TriState Editor::selectionOrderedListState() const
511 if (m_frame->selectionController()->isCaret()) {
512 Node* selectionNode = m_frame->selectionController()->selection().start().node();
513 if (enclosingNodeWithTag(selectionNode, olTag))
514 return Frame::trueTriState;
515 } else if (m_frame->selectionController()->isRange()) {
516 Node* startNode = enclosingNodeWithTag(m_frame->selectionController()->selection().start().node(), olTag);
517 Node* endNode = enclosingNodeWithTag(m_frame->selectionController()->selection().end().node(), olTag);
518 if (startNode && endNode && startNode == endNode)
519 return Frame::trueTriState;
522 return Frame::falseTriState;
525 void Editor::removeFormattingAndStyle()
527 Document* document = m_frame->document();
529 // Make a plain text string from the selection to remove formatting like tables and lists.
530 String string = m_frame->selectionController()->toString();
532 // Get the default style for this editable root, it's the style that we'll give the
533 // content that we're operating on.
534 Node* root = m_frame->selectionController()->rootEditableElement();
535 RefPtr<CSSComputedStyleDeclaration> computedStyle = new CSSComputedStyleDeclaration(root);
536 RefPtr<CSSMutableStyleDeclaration> defaultStyle = computedStyle->copyInheritableProperties();
538 // Delete the selected content.
539 // FIXME: We should be able to leave this to insertText, but its delete operation
540 // doesn't preserve the style we're about to set.
541 deleteSelectionWithSmartDelete(false);
542 // Normally, deleting a fully selected anchor and then inserting text will re-create
543 // the removed anchor, but we don't want that behavior here.
545 // Insert the content with the default style.
546 m_frame->setTypingStyle(defaultStyle.get());
547 TypingCommand::insertText(document, string, true);
550 void Editor::setLastEditCommand(PassRefPtr<EditCommand> lastEditCommand)
552 m_lastEditCommand = lastEditCommand;
555 // Returns whether caller should continue with "the default processing", which is the same as
556 // the event handler NOT setting the return value to false
557 bool Editor::dispatchCPPEvent(const AtomicString &eventType, ClipboardAccessPolicy policy)
559 Node* target = m_frame->selectionController()->start().element();
560 if (!target && m_frame->document())
561 target = m_frame->document()->body();
564 target = target->shadowAncestorNode();
566 RefPtr<Clipboard> clipboard = newGeneralClipboard(policy);
568 ExceptionCode ec = 0;
569 RefPtr<Event> evt = new ClipboardEvent(eventType, true, true, clipboard.get());
570 EventTargetNodeCast(target)->dispatchEvent(evt, ec, true);
571 bool noDefaultProcessing = evt->defaultPrevented();
573 // invalidate clipboard here for security
574 clipboard->setAccessPolicy(ClipboardNumb);
576 return !noDefaultProcessing;
579 void Editor::applyStyle(CSSStyleDeclaration* style, EditAction editingAction)
581 switch (m_frame->selectionController()->state()) {
582 case Selection::NONE:
585 case Selection::CARET: {
586 m_frame->computeAndSetTypingStyle(style, editingAction);
589 case Selection::RANGE:
590 if (m_frame->document() && style)
591 applyCommand(new ApplyStyleCommand(m_frame->document(), style, editingAction));
596 bool Editor::shouldApplyStyle(CSSStyleDeclaration* style, Range* range)
598 return client()->shouldApplyStyle(style, range);
601 void Editor::applyParagraphStyle(CSSStyleDeclaration* style, EditAction editingAction)
603 switch (m_frame->selectionController()->state()) {
604 case Selection::NONE:
607 case Selection::CARET:
608 case Selection::RANGE:
609 if (m_frame->document() && style)
610 applyCommand(new ApplyStyleCommand(m_frame->document(), style, editingAction, ApplyStyleCommand::ForceBlockProperties));
615 void Editor::applyStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
617 if (!style || style->length() == 0 || !canEditRichly())
620 if (client() && client()->shouldApplyStyle(style, m_frame->selectionController()->toRange().get()))
621 applyStyle(style, editingAction);
624 void Editor::applyParagraphStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
626 if (!style || style->length() == 0 || !canEditRichly())
629 if (client() && client()->shouldApplyStyle(style, m_frame->selectionController()->toRange().get()))
630 applyParagraphStyle(style, editingAction);
633 bool Editor::selectWordBeforeMenuEvent() const
636 return client()->selectWordBeforeMenuEvent();
640 bool Editor::clientIsEditable() const
643 return client()->isEditable();
647 bool Editor::selectionStartHasStyle(CSSStyleDeclaration* style) const
650 RefPtr<CSSStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
654 RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
657 DeprecatedValueListConstIterator<CSSProperty> end;
658 for (DeprecatedValueListConstIterator<CSSProperty> it = mutableStyle->valuesIterator(); it != end; ++it) {
659 int propertyID = (*it).id();
660 if (!equalIgnoringCase(mutableStyle->getPropertyValue(propertyID), selectionStyle->getPropertyValue(propertyID))) {
667 ExceptionCode ec = 0;
668 nodeToRemove->remove(ec);
675 void Editor::indent()
677 applyCommand(new IndentOutdentCommand(m_frame->document(), IndentOutdentCommand::Indent));
680 void Editor::outdent()
682 applyCommand(new IndentOutdentCommand(m_frame->document(), IndentOutdentCommand::Outdent));
685 static void dispatchEditableContentChangedEvents(const EditCommand& command)
687 Element* startRoot = command.startingRootEditableElement();
688 Element* endRoot = command.endingRootEditableElement();
691 startRoot->dispatchEvent(new Event(webkitEditableContentChangedEvent, false, false), ec, true);
692 if (endRoot && endRoot != startRoot)
693 endRoot->dispatchEvent(new Event(webkitEditableContentChangedEvent, false, false), ec, true);
696 void Editor::appliedEditing(PassRefPtr<EditCommand> cmd)
698 dispatchEditableContentChangedEvents(*cmd);
700 // FIXME: We shouldn't tell setSelection to clear the typing style or removed anchor here.
701 // If we didn't, we wouldn't have to save/restore the removedAnchor, and we wouldn't have to have
702 // the typing style stored in two places (the Frame and commands).
703 RefPtr<Node> anchor = removedAnchor();
705 Selection newSelection(cmd->endingSelection());
706 // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
707 // because there is work that it must do in this situation.
708 if (newSelection == m_frame->selectionController()->selection() || m_frame->shouldChangeSelection(newSelection))
709 m_frame->selectionController()->setSelection(newSelection, false);
711 setRemovedAnchor(anchor);
713 // Now set the typing style from the command. Clear it when done.
714 // This helps make the case work where you completely delete a piece
715 // of styled text and then type a character immediately after.
716 // That new character needs to take on the style of the just-deleted text.
717 // FIXME: Improve typing style.
718 // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
719 if (cmd->typingStyle()) {
720 m_frame->setTypingStyle(cmd->typingStyle());
721 cmd->setTypingStyle(0);
724 // Command will be equal to last edit command only in the case of typing
725 if (m_lastEditCommand.get() == cmd)
726 ASSERT(cmd->isTypingCommand());
728 // Only register a new undo command if the command passed in is
729 // different from the last command
730 m_lastEditCommand = cmd;
732 client()->registerCommandForUndo(m_lastEditCommand);
734 respondToChangedContents(newSelection);
737 void Editor::unappliedEditing(PassRefPtr<EditCommand> cmd)
739 dispatchEditableContentChangedEvents(*cmd);
741 Selection newSelection(cmd->startingSelection());
742 // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
743 // because there is work that it must do in this situation.
744 if (newSelection == m_frame->selectionController()->selection() || m_frame->shouldChangeSelection(newSelection))
745 m_frame->selectionController()->setSelection(newSelection, true);
747 m_lastEditCommand = 0;
749 client()->registerCommandForRedo(cmd);
750 respondToChangedContents(newSelection);
753 void Editor::reappliedEditing(PassRefPtr<EditCommand> cmd)
755 dispatchEditableContentChangedEvents(*cmd);
757 Selection newSelection(cmd->endingSelection());
758 // If there is no selection change, don't bother sending shouldChangeSelection, but still call setSelection,
759 // because there is work that it must do in this situation.
760 if (newSelection == m_frame->selectionController()->selection() || m_frame->shouldChangeSelection(newSelection))
761 m_frame->selectionController()->setSelection(newSelection, true);
763 m_lastEditCommand = 0;
765 client()->registerCommandForUndo(cmd);
766 respondToChangedContents(newSelection);
769 // Execute command functions
771 static bool execCopy(Frame* frame, Event*)
773 frame->editor()->copy();
777 static bool execCut(Frame* frame, Event*)
779 frame->editor()->cut();
783 static bool execDelete(Frame* frame, Event*)
785 frame->editor()->performDelete();
789 static bool execDeleteWordBackward(Frame* frame, Event*)
791 frame->editor()->deleteWithDirection(SelectionController::BACKWARD, WordGranularity, true, false);
795 static bool execDeleteWordForward(Frame* frame, Event*)
797 frame->editor()->deleteWithDirection(SelectionController::FORWARD, WordGranularity, true, false);
801 static bool execBackwardDelete(Frame* frame, Event*)
803 frame->editor()->deleteWithDirection(SelectionController::BACKWARD, CharacterGranularity, false, true);
807 static bool execForwardDelete(Frame* frame, Event*)
809 frame->editor()->deleteWithDirection(SelectionController::FORWARD, CharacterGranularity, false, true);
813 static bool execMoveBackward(Frame* frame, Event*)
815 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, CharacterGranularity, true);
819 static bool execMoveBackwardAndModifySelection(Frame* frame, Event*)
821 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, CharacterGranularity, true);
825 static bool execMoveUpByPageAndModifyCaret(Frame* frame, Event*)
827 RenderObject* renderer = frame->document()->focusedNode()->renderer();
828 if (renderer->style()->overflowY() == OSCROLL
829 || renderer->style()->overflowY() == OAUTO
830 || renderer->isTextArea()) {
831 int height = -(frame->document()->focusedNode()->renderer()->clientHeight()-PAGE_KEEP);
832 bool handledScroll = renderer->scroll(ScrollUp, ScrollByPage);
833 bool handledCaretMove = frame->selectionController()->modify(SelectionController::MOVE, height);
834 return handledScroll || handledCaretMove;
839 static bool execMoveDown(Frame* frame, Event*)
841 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineGranularity, true);
845 static bool execMoveDownAndModifySelection(Frame* frame, Event*)
847 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineGranularity, true);
851 static bool execMoveForward(Frame* frame, Event*)
853 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, CharacterGranularity, true);
857 static bool execMoveForwardAndModifySelection(Frame* frame, Event*)
859 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, CharacterGranularity, true);
863 static bool execMoveDownByPageAndModifyCaret(Frame* frame, Event*)
865 RenderObject* renderer = frame->document()->focusedNode()->renderer();
866 if (renderer->style()->overflowY() == OSCROLL
867 || renderer->style()->overflowY() == OAUTO
868 || renderer->isTextArea()) {
869 int height = frame->document()->focusedNode()->renderer()->clientHeight()-PAGE_KEEP;
870 bool handledScroll = renderer->scroll(ScrollDown, ScrollByPage);
871 bool handledCaretMove = frame->selectionController()->modify(SelectionController::MOVE, height);
872 return handledScroll || handledCaretMove;
877 static bool execMoveLeft(Frame* frame, Event*)
879 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::LEFT, CharacterGranularity, true);
883 static bool execMoveLeftAndModifySelection(Frame* frame, Event*)
885 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::LEFT, CharacterGranularity, true);
889 static bool execMoveRight(Frame* frame, Event*)
891 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::RIGHT, CharacterGranularity, true);
895 static bool execMoveRightAndModifySelection(Frame* frame, Event*)
897 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::RIGHT, CharacterGranularity, true);
901 static bool execMoveToBeginningOfDocument(Frame* frame, Event*)
903 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, DocumentBoundary, true);
907 static bool execMoveToBeginningOfDocumentAndModifySelection(Frame* frame, Event*)
909 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, DocumentBoundary, true);
913 static bool execMoveToBeginningOfSentence(Frame* frame, Event*)
915 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, SentenceBoundary, true);
919 static bool execMoveToBeginningOfSentenceAndModifySelection(Frame* frame, Event*)
921 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, SentenceBoundary, true);
925 static bool execMoveToBeginningOfLine(Frame* frame, Event*)
927 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineBoundary, true);
931 static bool execMoveToBeginningOfLineAndModifySelection(Frame* frame, Event*)
933 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineBoundary, true);
937 static bool execMoveToBeginningOfParagraph(Frame* frame, Event*)
939 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, ParagraphBoundary, true);
943 static bool execMoveToBeginningOfParagraphAndModifySelection(Frame* frame, Event*)
945 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphBoundary, true);
949 static bool execMoveToEndOfDocument(Frame* frame, Event*)
951 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, DocumentBoundary, true);
955 static bool execMoveToEndOfDocumentAndModifySelection(Frame* frame, Event*)
957 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, DocumentBoundary, true);
961 static bool execMoveToEndOfSentence(Frame* frame, Event*)
963 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, SentenceBoundary, true);
967 static bool execMoveToEndOfSentenceAndModifySelection(Frame* frame, Event*)
969 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, SentenceBoundary, true);
973 static bool execMoveToEndOfLine(Frame* frame, Event*)
975 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineBoundary, true);
979 static bool execMoveToEndOfLineAndModifySelection(Frame* frame, Event*)
981 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineBoundary, true);
985 static bool execMoveToEndOfParagraph(Frame* frame, Event*)
987 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, ParagraphBoundary, true);
991 static bool execMoveToEndOfParagraphAndModifySelection(Frame* frame, Event*)
993 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphBoundary, true);
997 static bool execMoveParagraphBackwardAndModifySelection(Frame* frame, Event*)
999 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphGranularity, true);
1003 static bool execMoveParagraphForwardAndModifySelection(Frame* frame, Event*)
1005 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphGranularity, true);
1009 static bool execMoveUp(Frame* frame, Event*)
1011 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineGranularity, true);
1015 static bool execMoveUpAndModifySelection(Frame* frame, Event*)
1017 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineGranularity, true);
1021 static bool execMoveWordBackward(Frame* frame, Event*)
1023 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, WordGranularity, true);
1027 static bool execMoveWordBackwardAndModifySelection(Frame* frame, Event*)
1029 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, WordGranularity, true);
1033 static bool execMoveWordForward(Frame* frame, Event*)
1035 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, WordGranularity, true);
1039 static bool execMoveWordForwardAndModifySelection(Frame* frame, Event*)
1041 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, WordGranularity, true);
1045 static bool execMoveWordLeft(Frame* frame, Event*)
1047 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::LEFT, WordGranularity, true);
1051 static bool execMoveWordLeftAndModifySelection(Frame* frame, Event*)
1053 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::LEFT, WordGranularity, true);
1057 static bool execMoveWordRight(Frame* frame, Event*)
1059 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::RIGHT, WordGranularity, true);
1063 static bool execMoveWordRightAndModifySelection(Frame* frame, Event*)
1065 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::RIGHT, WordGranularity, true);
1069 static bool execPaste(Frame* frame, Event*)
1071 frame->editor()->paste();
1075 static bool execSelectAll(Frame* frame, Event*)
1077 frame->selectionController()->selectAll();
1081 static bool execToggleBold(Frame* frame, Event*)
1085 RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
1086 style->setProperty(CSS_PROP_FONT_WEIGHT, "bold", false, ec);
1087 if (frame->editor()->selectionStartHasStyle(style.get()))
1088 style->setProperty(CSS_PROP_FONT_WEIGHT, "normal", false, ec);
1089 frame->editor()->applyStyleToSelection(style.get(), EditActionSetFont);
1093 static bool execToggleItalic(Frame* frame, Event*)
1097 RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
1098 style->setProperty(CSS_PROP_FONT_STYLE, "italic", false, ec);
1099 if (frame->editor()->selectionStartHasStyle(style.get()))
1100 style->setProperty(CSS_PROP_FONT_STYLE, "normal", false, ec);
1101 frame->editor()->applyStyleToSelection(style.get(), EditActionSetFont);
1105 static bool execRedo(Frame* frame, Event*)
1107 frame->editor()->redo();
1111 static bool execUndo(Frame* frame, Event*)
1113 frame->editor()->undo();
1117 static inline Frame* targetFrame(Frame* frame, Event* evt)
1119 Node* node = evt ? evt->target()->toNode() : 0;
1122 return node->document()->frame();
1125 static bool execInsertTab(Frame* frame, Event* evt)
1127 return targetFrame(frame, evt)->eventHandler()->handleTextInputEvent("\t", evt, false, false);
1130 static bool execInsertBacktab(Frame* frame, Event* evt)
1132 return targetFrame(frame, evt)->eventHandler()->handleTextInputEvent("\t", evt, false, true);
1135 static bool execInsertNewline(Frame* frame, Event* evt)
1137 Frame* targetFrame = WebCore::targetFrame(frame, evt);
1138 return targetFrame->eventHandler()->handleTextInputEvent("\n", evt, !targetFrame->editor()->canEditRichly());
1141 static bool execInsertLineBreak(Frame* frame, Event* evt)
1143 return targetFrame(frame, evt)->eventHandler()->handleTextInputEvent("\n", evt, true);
1146 // Enabled functions
1148 static bool enabled(Frame*, Event*)
1153 static bool canPaste(Frame* frame, Event*)
1155 return frame->editor()->canPaste();
1158 static bool hasEditableSelection(Frame* frame, Event* evt)
1161 return selectionForEvent(frame, evt).isContentEditable();
1162 return frame->selectionController()->isContentEditable();
1165 static bool hasEditableRangeSelection(Frame* frame, Event*)
1167 return frame->selectionController()->isRange() && frame->selectionController()->isContentEditable();
1170 static bool hasRangeSelection(Frame* frame, Event*)
1172 return frame->selectionController()->isRange();
1175 static bool hasRichlyEditableSelection(Frame* frame, Event*)
1177 return frame->selectionController()->isCaretOrRange() && frame->selectionController()->isContentRichlyEditable();
1180 static bool canRedo(Frame* frame, Event*)
1182 return frame->editor()->canRedo();
1185 static bool canUndo(Frame* frame, Event*)
1187 return frame->editor()->canUndo();
1191 bool (*enabled)(Frame*, Event*);
1192 bool (*exec)(Frame*, Event*);
1195 typedef HashMap<RefPtr<AtomicStringImpl>, const Command*> CommandMap;
1197 static CommandMap* createCommandMap()
1199 struct CommandEntry { const char* name; Command command; };
1201 static const CommandEntry commands[] = {
1202 { "BackwardDelete", { hasEditableSelection, execBackwardDelete } },
1203 { "Copy", { hasRangeSelection, execCopy } },
1204 { "Cut", { hasEditableRangeSelection, execCut } },
1205 { "Delete", { hasEditableSelection, execDelete } },
1206 { "DeleteWordBackward", { hasEditableSelection, execDeleteWordBackward } },
1207 { "DeleteWordForward", { hasEditableSelection, execDeleteWordForward} },
1208 { "ForwardDelete", { hasEditableSelection, execForwardDelete } },
1209 { "InsertBacktab", { hasEditableSelection, execInsertBacktab } },
1210 { "InsertTab", { hasEditableSelection, execInsertTab } },
1211 { "InsertLineBreak", { hasEditableSelection, execInsertLineBreak } },
1212 { "InsertNewline", { hasEditableSelection, execInsertNewline } },
1213 { "MoveBackward", { hasEditableSelection, execMoveBackward } },
1214 { "MoveBackwardAndModifySelection", { hasEditableSelection, execMoveBackwardAndModifySelection } },
1215 { "MoveUpByPageAndModifyCaret", { hasEditableSelection, execMoveUpByPageAndModifyCaret } },
1216 { "MoveDown", { hasEditableSelection, execMoveDown } },
1217 { "MoveDownAndModifySelection", { hasEditableSelection, execMoveDownAndModifySelection } },
1218 { "MoveForward", { hasEditableSelection, execMoveForward } },
1219 { "MoveForwardAndModifySelection", { hasEditableSelection, execMoveForwardAndModifySelection } },
1220 { "MoveDownByPageAndModifyCaret", { hasEditableSelection, execMoveDownByPageAndModifyCaret } },
1221 { "MoveLeft", { hasEditableSelection, execMoveLeft } },
1222 { "MoveLeftAndModifySelection", { hasEditableSelection, execMoveLeftAndModifySelection } },
1223 { "MoveRight", { hasEditableSelection, execMoveRight } },
1224 { "MoveRightAndModifySelection", { hasEditableSelection, execMoveRightAndModifySelection } },
1225 { "MoveToBeginningOfDocument", { hasEditableSelection, execMoveToBeginningOfDocument } },
1226 { "MoveToBeginningOfDocumentAndModifySelection", { hasEditableSelection, execMoveToBeginningOfDocumentAndModifySelection } },
1227 { "MoveToBeginningOfSentence", { hasEditableSelection, execMoveToBeginningOfSentence } },
1228 { "MoveToBeginningOfSentenceAndModifySelection", { hasEditableSelection, execMoveToBeginningOfSentenceAndModifySelection } },
1229 { "MoveToBeginningOfLine", { hasEditableSelection, execMoveToBeginningOfLine } },
1230 { "MoveToBeginningOfLineAndModifySelection", { hasEditableSelection, execMoveToBeginningOfLineAndModifySelection } },
1231 { "MoveToBeginningOfParagraph", { hasEditableSelection, execMoveToBeginningOfParagraph } },
1232 { "MoveToBeginningOfParagraphAndModifySelection", { hasEditableSelection, execMoveToBeginningOfParagraphAndModifySelection } },
1233 { "MoveToEndOfDocument", { hasEditableSelection, execMoveToEndOfDocument } },
1234 { "MoveToEndOfDocumentAndModifySelection", { hasEditableSelection, execMoveToEndOfDocumentAndModifySelection } },
1235 { "MoveToEndOfSentence", { hasEditableSelection, execMoveToEndOfSentence } },
1236 { "MoveToEndOfSentenceAndModifySelection", { hasEditableSelection, execMoveToEndOfSentenceAndModifySelection } },
1237 { "MoveToEndOfLine", { hasEditableSelection, execMoveToEndOfLine } },
1238 { "MoveToEndOfLineAndModifySelection", { hasEditableSelection, execMoveToEndOfLineAndModifySelection } },
1239 { "MoveToEndOfParagraph", { hasEditableSelection, execMoveToEndOfParagraph } },
1240 { "MoveToEndOfParagraphAndModifySelection", { hasEditableSelection, execMoveToEndOfParagraphAndModifySelection } },
1241 { "MoveParagraphBackwardAndModifySelection", { hasEditableSelection, execMoveParagraphBackwardAndModifySelection } },
1242 { "MoveParagraphForwardAndModifySelection", { hasEditableSelection, execMoveParagraphForwardAndModifySelection } },
1243 { "MoveUp", { hasEditableSelection, execMoveUp } },
1244 { "MoveUpAndModifySelection", { hasEditableSelection, execMoveUpAndModifySelection } },
1245 { "MoveWordBackward", { hasEditableSelection, execMoveWordBackward } },
1246 { "MoveWordBackwardAndModifySelection", { hasEditableSelection, execMoveWordBackwardAndModifySelection } },
1247 { "MoveWordForward", { hasEditableSelection, execMoveWordForward } },
1248 { "MoveWordForwardAndModifySelection", { hasEditableSelection, execMoveWordForwardAndModifySelection } },
1249 { "MoveWordLeft", { hasEditableSelection, execMoveWordLeft } },
1250 { "MoveWordLeftAndModifySelection", { hasEditableSelection, execMoveWordLeftAndModifySelection } },
1251 { "MoveWordRight", { hasEditableSelection, execMoveWordRight } },
1252 { "MoveWordRightAndModifySelection", { hasEditableSelection, execMoveWordRightAndModifySelection } },
1253 { "Paste", { canPaste, execPaste } },
1254 { "Redo", { canRedo, execRedo } },
1255 { "SelectAll", { enabled, execSelectAll } },
1256 { "ToggleBold", { hasRichlyEditableSelection, execToggleBold } },
1257 { "ToggleItalic", { hasRichlyEditableSelection, execToggleItalic } },
1258 { "Undo", { canUndo, execUndo } }
1261 CommandMap* commandMap = new CommandMap;
1263 const unsigned numCommands = sizeof(commands) / sizeof(commands[0]);
1264 for (unsigned i = 0; i < numCommands; i++)
1265 commandMap->set(AtomicString(commands[i].name).impl(), &commands[i].command);
1270 // =============================================================================
1272 // public editing commands
1274 // =============================================================================
1276 Editor::Editor(Frame* frame)
1278 , m_deleteButtonController(new DeleteButtonController(frame))
1279 , m_ignoreMarkedTextSelectionChange(false)
1287 bool Editor::execCommand(const AtomicString& command, Event* triggeringEvent)
1289 if (!m_frame->document())
1292 static CommandMap* commandMap;
1294 commandMap = createCommandMap();
1296 const Command* c = commandMap->get(command.impl());
1300 bool handled = false;
1302 if (c->enabled(m_frame, triggeringEvent)) {
1303 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1304 handled = c->exec(m_frame, triggeringEvent);
1310 bool Editor::insertText(const String& text, Event* triggeringEvent)
1312 return m_frame->eventHandler()->handleTextInputEvent(text, triggeringEvent);
1315 bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectInsertedText, Event* triggeringEvent)
1320 RefPtr<Range> range = m_frame->markedTextRange();
1322 Selection selection = selectionForEvent(m_frame, triggeringEvent);
1323 if (!selection.isContentEditable())
1325 range = selection.toRange();
1328 if (!shouldInsertText(text, range.get(), EditorInsertActionTyped)) {
1329 discardMarkedText();
1333 setIgnoreMarkedTextSelectionChange(true);
1335 // If we had marked text, replace that instead of the selection/caret.
1338 // Get the selection to use for the event that triggered this insertText.
1339 // If the event handler changed the selection, we may want to use a different selection
1340 // that is contained in the event target.
1341 Selection selection = selectionForEvent(m_frame, triggeringEvent);
1342 if (selection.isContentEditable()) {
1343 if (Node* selectionStart = selection.start().node()) {
1344 RefPtr<Document> document = selectionStart->document();
1347 TypingCommand::insertText(document.get(), text, selection, selectInsertedText);
1349 // Reveal the current selection
1350 if (Frame* editedFrame = document->frame())
1351 if (Page* page = editedFrame->page())
1352 page->focusController()->focusedOrMainFrame()->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
1356 setIgnoreMarkedTextSelectionChange(false);
1358 // Inserting unmarks any marked text.
1364 bool Editor::insertLineBreak()
1369 if (!shouldInsertText("\n", m_frame->selectionController()->toRange().get(), EditorInsertActionTyped))
1372 TypingCommand::insertLineBreak(m_frame->document());
1373 m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
1377 bool Editor::insertParagraphSeparator()
1382 if (!canEditRichly())
1383 return insertLineBreak();
1385 if (!shouldInsertText("\n", m_frame->selectionController()->toRange().get(), EditorInsertActionTyped))
1388 TypingCommand::insertParagraphSeparator(m_frame->document());
1389 m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
1396 return; // DHTML did the whole operation
1401 RefPtr<Range> selection = selectedRange();
1402 if (shouldDeleteRange(selection.get())) {
1403 Pasteboard::generalPasteboard()->writeSelection(selection.get(), canSmartCopyOrDelete(), m_frame);
1404 didWriteSelectionToPasteboard();
1405 deleteSelectionWithSmartDelete();
1412 return; // DHTML did the whole operation
1417 Pasteboard::generalPasteboard()->writeSelection(selectedRange().get(), canSmartCopyOrDelete(), m_frame);
1418 didWriteSelectionToPasteboard();
1421 void Editor::paste()
1423 ASSERT(m_frame->document());
1424 DocLoader* loader = m_frame->document()->docLoader();
1426 // using the platform independent code below requires moving all of
1427 // WEBHTMLView: _documentFragmentFromPasteboard over to PasteboardMac.
1428 loader->setAllowStaleResources(true);
1429 m_frame->issuePasteCommand();
1430 loader->setAllowStaleResources(false);
1432 if (tryDHTMLPaste())
1433 return; // DHTML did the whole operation
1436 loader->setAllowStaleResources(true);
1437 if (m_frame->selectionController()->isContentRichlyEditable())
1438 pasteWithPasteboard(Pasteboard::generalPasteboard(), true);
1440 pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
1441 loader->setAllowStaleResources(false);
1445 void Editor::pasteAsPlainText()
1449 pasteAsPlainTextWithPasteboard(Pasteboard::generalPasteboard());
1452 void Editor::performDelete()
1458 deleteRange(selectedRange().get(), true, false, true, deleteSelectionAction, CharacterGranularity);
1461 void Editor::copyURL(const KURL& url, const String& title)
1463 Pasteboard::generalPasteboard()->writeURL(url, title, m_frame);
1466 void Editor::copyImage(const HitTestResult& result)
1468 Pasteboard::generalPasteboard()->writeImage(result);
1471 bool Editor::isContinuousSpellCheckingEnabled()
1474 return client()->isContinuousSpellCheckingEnabled();
1478 void Editor::toggleContinuousSpellChecking()
1481 client()->toggleContinuousSpellChecking();
1484 bool Editor::isGrammarCheckingEnabled()
1487 return client()->isGrammarCheckingEnabled();
1491 void Editor::toggleGrammarChecking()
1494 client()->toggleGrammarChecking();
1497 int Editor::spellCheckerDocumentTag()
1500 return client()->spellCheckerDocumentTag();
1504 bool Editor::shouldEndEditing(Range* range)
1507 return client()->shouldEndEditing(range);
1511 bool Editor::shouldBeginEditing(Range* range)
1514 return client()->shouldBeginEditing(range);
1518 void Editor::clearUndoRedoOperations()
1521 client()->clearUndoRedoOperations();
1524 bool Editor::canUndo()
1527 return client()->canUndo();
1537 bool Editor::canRedo()
1540 return client()->canRedo();
1550 void Editor::didBeginEditing()
1553 client()->didBeginEditing();
1556 void Editor::didEndEditing()
1559 client()->didEndEditing();
1562 void Editor::didWriteSelectionToPasteboard()
1565 client()->didWriteSelectionToPasteboard();
1568 void Editor::toggleBold()
1570 execToggleBold(frame(), 0);
1573 void Editor::toggleUnderline()
1575 ExceptionCode ec = 0;
1577 RefPtr<CSSStyleDeclaration> style = frame()->document()->createCSSStyleDeclaration();
1578 style->setProperty(CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, "underline", false, ec);
1579 if (selectionStartHasStyle(style.get()))
1580 style->setProperty(CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT, "none", false, ec);
1581 applyStyleToSelection(style.get(), EditActionUnderline);
1584 void Editor::setBaseWritingDirection(String direction)
1586 ExceptionCode ec = 0;
1588 RefPtr<CSSStyleDeclaration> style = frame()->document()->createCSSStyleDeclaration();
1589 style->setProperty(CSS_PROP_DIRECTION, direction, false, ec);
1590 applyParagraphStyleToSelection(style.get(), EditActionSetWritingDirection);
1593 void Editor::selectMarkedText()
1595 Range* range = m_frame->markedTextRange();
1598 ExceptionCode ec = 0;
1599 m_frame->selectionController()->setSelectedRange(m_frame->markedTextRange(), DOWNSTREAM, false, ec);
1602 void Editor::discardMarkedText()
1604 if (!m_frame->markedTextRange())
1607 setIgnoreMarkedTextSelectionChange(true);
1612 if (EditorClient* c = client())
1613 c->markedTextAbandoned(m_frame);
1615 deleteSelectionWithSmartDelete(false);
1617 setIgnoreMarkedTextSelectionChange(false);
1621 void Editor::unmarkText()
1626 } // namespace WebCore