📄 editor.cpp
字号:
/* * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "Editor.h"#include "AXObjectCache.h"#include "ApplyStyleCommand.h"#include "CSSComputedStyleDeclaration.h"#include "CSSProperty.h"#include "CSSPropertyNames.h"#include "CSSValueKeywords.h"#include "ClipboardEvent.h"#include "DeleteButtonController.h"#include "DeleteSelectionCommand.h"#include "DocLoader.h"#include "DocumentFragment.h"#include "EditorClient.h"#include "EventHandler.h"#include "EventNames.h"#include "FocusController.h"#include "Frame.h"#include "FrameTree.h"#include "FrameView.h"#include "HTMLInputElement.h"#include "HTMLTextAreaElement.h"#include "HitTestResult.h"#include "IndentOutdentCommand.h"#include "InsertListCommand.h"#include "KeyboardEvent.h"#include "ModifySelectionListLevel.h"#include "Page.h"#include "Pasteboard.h"#include "RemoveFormatCommand.h"#include "RenderBlock.h"#include "RenderPart.h"#include "ReplaceSelectionCommand.h"#include "Sound.h"#include "Text.h"#include "TextIterator.h"#include "TypingCommand.h"#include "htmlediting.h"#include "markup.h"#include "visible_units.h"#include <wtf/UnusedParam.h>namespace WebCore {using namespace std;using namespace HTMLNames;// 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){ VisibleSelection selection = m_frame->selection()->selection(); if (!event) return selection; // If the target is a text control, and the current selection is outside of its shadow tree, // then use the saved selection for that text control. Node* target = event->target()->toNode(); Node* selectionStart = selection.start().node(); if (target && (!selectionStart || target->shadowAncestorNode() != selectionStart->shadowAncestorNode())) { if (target->hasTagName(inputTag) && static_cast<HTMLInputElement*>(target)->isTextField()) return static_cast<HTMLInputElement*>(target)->selection(); if (target->hasTagName(textareaTag)) return static_cast<HTMLTextAreaElement*>(target)->selection(); } return selection;}EditorClient* Editor::client() const{ if (Page* page = m_frame->page()) return page->editorClient(); return 0;}void Editor::handleKeyboardEvent(KeyboardEvent* event){ if (EditorClient* c = client()) c->handleKeyboardEvent(event);}void Editor::handleInputMethodKeydown(KeyboardEvent* event){ if (EditorClient* c = client()) c->handleInputMethodKeydown(event);}bool Editor::canEdit() const{ return m_frame->selection()->isContentEditable();}bool Editor::canEditRichly() const{ return m_frame->selection()->isContentRichlyEditable();}// WinIE uses onbeforecut and onbeforepaste to enables the cut and paste menu items. They// also send onbeforecopy, apparently for symmetry, but it doesn't affect the menu items.// We need to use onbeforecopy as a real menu enabler because we allow elements that are not// normally selectable to implement copy/paste (like divs, or a document body).bool Editor::canDHTMLCut(){ return !m_frame->selection()->isInPasswordField() && !dispatchCPPEvent(eventNames().beforecutEvent, ClipboardNumb);}bool Editor::canDHTMLCopy(){ return !m_frame->selection()->isInPasswordField() && !dispatchCPPEvent(eventNames().beforecopyEvent, ClipboardNumb);}bool Editor::canDHTMLPaste(){ return !dispatchCPPEvent(eventNames().beforepasteEvent, ClipboardNumb);}bool Editor::canCut() const{ return canCopy() && canDelete();}static HTMLImageElement* imageElementFromImageDocument(Document* document){ if (!document) return 0; if (!document->isImageDocument()) return 0; HTMLElement* body = document->body(); if (!body) return 0; Node* node = body->firstChild(); if (!node) return 0; if (!node->hasTagName(imgTag)) return 0; return static_cast<HTMLImageElement*>(node);}bool Editor::canCopy() const{ if (imageElementFromImageDocument(m_frame->document())) return true; SelectionController* selection = m_frame->selection(); return selection->isRange() && !selection->isInPasswordField();}bool Editor::canPaste() const{ return canEdit();}bool Editor::canDelete() const{ SelectionController* selection = m_frame->selection(); return selection->isRange() && selection->isContentEditable();}bool Editor::canDeleteRange(Range* range) const{ ExceptionCode ec = 0; Node* startContainer = range->startContainer(ec); Node* endContainer = range->endContainer(ec); if (!startContainer || !endContainer) return false; if (!startContainer->isContentEditable() || !endContainer->isContentEditable()) return false; if (range->collapsed(ec)) { VisiblePosition start(startContainer, range->startOffset(ec), DOWNSTREAM); VisiblePosition previous = start.previous(); // FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item. if (previous.isNull() || previous.deepEquivalent().node()->rootEditableElement() != startContainer->rootEditableElement()) return false; } return true;}bool Editor::smartInsertDeleteEnabled(){ return client() && client()->smartInsertDeleteEnabled();} bool Editor::canSmartCopyOrDelete(){ return client() && client()->smartInsertDeleteEnabled() && m_frame->selectionGranularity() == WordGranularity;}bool Editor::isSelectTrailingWhitespaceEnabled(){ return client() && client()->isSelectTrailingWhitespaceEnabled();}bool Editor::deleteWithDirection(SelectionController::EDirection direction, TextGranularity granularity, bool killRing, bool isTypingAction){ if (!canEdit()) return false; if (m_frame->selection()->isRange()) { if (isTypingAction) { TypingCommand::deleteKeyPressed(m_frame->document(), canSmartCopyOrDelete(), granularity); revealSelectionAfterEditingOperation(); } else { if (killRing) addToKillRing(selectedRange().get(), false); deleteSelectionWithSmartDelete(canSmartCopyOrDelete()); // Implicitly calls revealSelectionAfterEditingOperation(). } } else { switch (direction) { case SelectionController::FORWARD: case SelectionController::RIGHT: TypingCommand::forwardDeleteKeyPressed(m_frame->document(), canSmartCopyOrDelete(), granularity, killRing); break; case SelectionController::BACKWARD: case SelectionController::LEFT: TypingCommand::deleteKeyPressed(m_frame->document(), canSmartCopyOrDelete(), granularity, killRing); break; } revealSelectionAfterEditingOperation(); } // FIXME: We should to move this down into deleteKeyPressed. // clear the "start new kill ring sequence" setting, because it was set to true // when the selection was updated by deleting the range if (killRing) setStartNewKillRingSequence(false); return true;}void Editor::deleteSelectionWithSmartDelete(bool smartDelete){ if (m_frame->selection()->isNone()) return; applyCommand(DeleteSelectionCommand::create(m_frame->document(), smartDelete));}void Editor::pasteAsPlainTextWithPasteboard(Pasteboard* pasteboard){ String text = pasteboard->plainText(m_frame); if (client() && client()->shouldInsertText(text, selectedRange().get(), EditorInsertActionPasted)) replaceSelectionWithText(text, false, canSmartReplaceWithPasteboard(pasteboard));}void Editor::pasteWithPasteboard(Pasteboard* pasteboard, bool allowPlainText){ RefPtr<Range> range = selectedRange(); bool chosePlainText; RefPtr<DocumentFragment> fragment = pasteboard->documentFragment(m_frame, range, allowPlainText, chosePlainText); if (fragment && shouldInsertFragment(fragment, range, EditorInsertActionPasted)) replaceSelectionWithFragment(fragment, false, canSmartReplaceWithPasteboard(pasteboard), chosePlainText);}bool Editor::canSmartReplaceWithPasteboard(Pasteboard* pasteboard){ return client() && client()->smartInsertDeleteEnabled() && pasteboard->canSmartReplace();}bool Editor::shouldInsertFragment(PassRefPtr<DocumentFragment> fragment, PassRefPtr<Range> replacingDOMRange, EditorInsertAction givenAction){ if (!client()) return false; Node* child = fragment->firstChild(); if (child && fragment->lastChild() == child && child->isCharacterDataNode()) return client()->shouldInsertText(static_cast<CharacterData*>(child)->data(), replacingDOMRange.get(), givenAction); return client()->shouldInsertNode(fragment.get(), replacingDOMRange.get(), givenAction);}void Editor::replaceSelectionWithFragment(PassRefPtr<DocumentFragment> fragment, bool selectReplacement, bool smartReplace, bool matchStyle){ if (m_frame->selection()->isNone() || !fragment) return; applyCommand(ReplaceSelectionCommand::create(m_frame->document(), fragment, selectReplacement, smartReplace, matchStyle)); revealSelectionAfterEditingOperation();}void Editor::replaceSelectionWithText(const String& text, bool selectReplacement, bool smartReplace){ replaceSelectionWithFragment(createFragmentFromText(selectedRange().get(), text), selectReplacement, smartReplace, true); }PassRefPtr<Range> Editor::selectedRange(){ if (!m_frame) return 0; return m_frame->selection()->toNormalizedRange();}bool Editor::shouldDeleteRange(Range* range) const{ ExceptionCode ec; if (!range || range->collapsed(ec)) return false; if (!canDeleteRange(range)) return false; return client() && client()->shouldDeleteRange(range);}bool Editor::tryDHTMLCopy(){ if (m_frame->selection()->isInPasswordField()) return false; // Must be done before oncopy adds types and data to the pboard, // also done for security, as it erases data from the last copy/paste. Pasteboard::generalPasteboard()->clear(); return !dispatchCPPEvent(eventNames().copyEvent, ClipboardWritable);}bool Editor::tryDHTMLCut(){ if (m_frame->selection()->isInPasswordField())
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -