📄 htmlediting_impl.cpp
字号:
/*
* Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
*
* 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 "htmlediting_impl.h"
#include "cssproperties.h"
#include "css/css_valueimpl.h"
#include "dom/css_value.h"
#include "dom/dom_position.h"
#include "html/html_elementimpl.h"
#include "html/html_imageimpl.h"
#include "htmlattrs.h"
#include "htmltags.h"
#include "khtml_part.h"
#include "khtmlview.h"
#include "qptrlist.h"
#include "rendering/render_object.h"
#include "rendering/render_style.h"
#include "rendering/render_text.h"
#include "xml/dom_docimpl.h"
#include "xml/dom_elementimpl.h"
#include "xml/dom_positioniterator.h"
#include "xml/dom_nodeimpl.h"
#include "xml/dom_selection.h"
#include "xml/dom_stringimpl.h"
#include "xml/dom_textimpl.h"
#include "xml/dom2_rangeimpl.h"
#include "xml/dom2_viewsimpl.h"
#if APPLE_CHANGES
#include "KWQAssertions.h"
#include "KWQLogging.h"
#endif
using DOM::AttrImpl;
using DOM::CSSPrimitiveValue;
using DOM::CSSPrimitiveValueImpl;
using DOM::CSSProperty;
using DOM::CSSStyleDeclarationImpl;
using DOM::CSSValueImpl;
using DOM::DocumentFragmentImpl;
using DOM::DocumentImpl;
using DOM::DOMString;
using DOM::DOMStringImpl;
using DOM::EditingTextImpl;
using DOM::PositionIterator;
using DOM::ElementImpl;
using DOM::HTMLElementImpl;
using DOM::HTMLImageElementImpl;
using DOM::NamedAttrMapImpl;
using DOM::Node;
using DOM::NodeImpl;
using DOM::NodeListImpl;
using DOM::Position;
using DOM::Range;
using DOM::RangeImpl;
using DOM::Selection;
using DOM::TextImpl;
using DOM::TreeWalkerImpl;
#if !APPLE_CHANGES
#define ASSERT(assertion) ((void)0)
#define ASSERT_WITH_MESSAGE(assertion, formatAndArgs...) ((void)0)
#define ASSERT_NOT_REACHED() ((void)0)
#define LOG(channel, formatAndArgs...) ((void)0)
#define ERROR(formatAndArgs...) ((void)0)
#if LOG_DISABLED
#define debugPosition(a,b) ((void)0)
#endif
#endif
namespace khtml {
static inline bool isNBSP(const QChar &c)
{
return c == QChar(0xa0);
}
static inline bool isWS(const QChar &c)
{
return c.isSpace() && c != QChar(0xa0);
}
static inline bool isWS(const DOMString &text)
{
if (text.length() != 1)
return false;
return isWS(text[0]);
}
static inline bool isWS(const Position &pos)
{
if (!pos.node())
return false;
if (!pos.node()->isTextNode())
return false;
const DOMString &string = static_cast<TextImpl *>(pos.node())->data();
return isWS(string[pos.offset()]);
}
static bool shouldPruneNode(NodeImpl *node)
{
if (!node)
return false;
RenderObject *renderer = node->renderer();
if (!renderer)
return true;
if (node->hasChildNodes())
return false;
if (node->rootEditableElement() == node)
return false;
if (renderer->isBR() || renderer->isReplaced())
return false;
if (node->isTextNode()) {
TextImpl *text = static_cast<TextImpl *>(node);
if (text->length() == 0)
return true;
return false;
}
if (!node->isHTMLElement() && !node->isXMLElementNode())
return false;
if (node->id() == ID_BODY)
return false;
if (!node->isContentEditable())
return false;
return true;
}
static Position leadingWhitespacePosition(const Position &pos)
{
ASSERT(pos.notEmpty());
Selection selection(pos);
Position prev = pos.previousCharacterPosition();
if (prev != pos && prev.node()->inSameContainingBlockFlowElement(pos.node()) && prev.node()->isTextNode()) {
DOMString string = static_cast<TextImpl *>(prev.node())->data();
if (isWS(string[prev.offset()]))
return prev;
}
return Position();
}
static Position trailingWhitespacePosition(const Position &pos)
{
ASSERT(pos.notEmpty());
if (pos.node()->isTextNode()) {
TextImpl *textNode = static_cast<TextImpl *>(pos.node());
if (pos.offset() >= (long)textNode->length()) {
Position next = pos.nextCharacterPosition();
if (next != pos && next.node()->inSameContainingBlockFlowElement(pos.node()) && next.node()->isTextNode()) {
DOMString string = static_cast<TextImpl *>(next.node())->data();
if (isWS(string[0]))
return next;
}
}
else {
DOMString string = static_cast<TextImpl *>(pos.node())->data();
if (isWS(string[pos.offset()]))
return pos;
}
}
return Position();
}
static bool textNodesAreJoinable(TextImpl *text1, TextImpl *text2)
{
ASSERT(text1);
ASSERT(text2);
return (text1->nextSibling() == text2);
}
static DOMString &nonBreakingSpaceString()
{
static DOMString nonBreakingSpaceString = QString(QChar(0xa0));
return nonBreakingSpaceString;
}
static DOMString &styleSpanClassString()
{
static DOMString styleSpanClassString = "khtml-style-span";
return styleSpanClassString;
}
static void debugPosition(const char *prefix, const Position &pos)
{
//LOG(Editing, "%s%s %p : %d", prefix, getTagName(pos.node()->id()).string().latin1(), pos.node(), pos.offset());
}
//------------------------------------------------------------------------------------------
// EditCommandImpl
EditCommandImpl::EditCommandImpl(DocumentImpl *document)
: SharedCommandImpl(), m_document(document), m_state(NotApplied), m_parent(0)
{
ASSERT(m_document);
ASSERT(m_document->part());
m_document->ref();
m_startingSelection = m_document->part()->selection();
m_endingSelection = m_startingSelection;
}
EditCommandImpl::~EditCommandImpl()
{
ASSERT(m_document);
m_document->deref();
}
int EditCommandImpl::commandID() const
{
return EditCommandID;
}
void EditCommandImpl::apply()
{
ASSERT(m_document);
ASSERT(m_document->part());
ASSERT(state() == NotApplied);
doApply();
m_state = Applied;
if (!isCompositeStep()) {
EditCommand cmd(this);
m_document->part()->appliedEditing(cmd);
}
}
void EditCommandImpl::unapply()
{
ASSERT(m_document);
ASSERT(m_document->part());
ASSERT(state() == Applied);
doUnapply();
m_state = NotApplied;
if (!isCompositeStep()) {
EditCommand cmd(this);
m_document->part()->unappliedEditing(cmd);
}
}
void EditCommandImpl::reapply()
{
ASSERT(m_document);
ASSERT(m_document->part());
ASSERT(state() == NotApplied);
doReapply();
m_state = Applied;
if (!isCompositeStep()) {
EditCommand cmd(this);
m_document->part()->reappliedEditing(cmd);
}
}
void EditCommandImpl::doReapply()
{
doApply();
}
void EditCommandImpl::setStartingSelection(const Selection &s)
{
m_startingSelection = s;
EditCommand cmd = parent();
while (cmd.notNull()) {
cmd.handle()->m_startingSelection = s;
cmd = cmd.parent();
}
}
void EditCommandImpl::setEndingSelection(const Selection &s)
{
m_endingSelection = s;
EditCommand cmd = parent();
while (cmd.notNull()) {
cmd.handle()->m_endingSelection = s;
cmd = cmd.parent();
}
}
EditCommand EditCommandImpl::parent() const
{
return m_parent;
}
void EditCommandImpl::setParent(const EditCommand &cmd)
{
m_parent = cmd;
}
//------------------------------------------------------------------------------------------
// CompositeEditCommandImpl
CompositeEditCommandImpl::CompositeEditCommandImpl(DocumentImpl *document)
: EditCommandImpl(document)
{
}
CompositeEditCommandImpl::~CompositeEditCommandImpl()
{
}
int CompositeEditCommandImpl::commandID() const
{
return CompositeEditCommandID;
}
void CompositeEditCommandImpl::doUnapply()
{
if (m_cmds.count() == 0) {
return;
}
for (int i = m_cmds.count() - 1; i >= 0; --i)
m_cmds[i]->unapply();
setState(NotApplied);
}
void CompositeEditCommandImpl::doReapply()
{
if (m_cmds.count() == 0) {
return;
}
for (QValueList<EditCommand>::ConstIterator it = m_cmds.begin(); it != m_cmds.end(); ++it)
(*it)->reapply();
setState(Applied);
}
//
// sugary-sweet convenience functions to help create and apply edit commands in composite commands
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -