?? markup.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 "markup.h"
#include "htmlediting.h"
#include "css/css_computedstyle.h"
#include "css/css_valueimpl.h"
#include "editing/visible_position.h"
#include "editing/visible_units.h"
#include "html/html_elementimpl.h"
#include "xml/dom_position.h"
#include "xml/dom2_rangeimpl.h"
#include "rendering/render_text.h"
#include "misc/htmlattrs.h"
#include "misc/htmltags.h"
#include "html/dtd.h"
using DOM::AttributeImpl;
using DOM::CommentImpl;
using DOM::CSSComputedStyleDeclarationImpl;
using DOM::CSSMutableStyleDeclarationImpl;
using DOM::DocumentFragmentImpl;
using DOM::DocumentImpl;
using DOM::DOMString;
using DOM::ElementImpl;
using DOM::FORBIDDEN;
using DOM::endTagRequirement;
using DOM::HTMLElementImpl;
using DOM::NamedAttrMapImpl;
using DOM::Node;
using DOM::NodeImpl;
using DOM::Position;
using DOM::RangeImpl;
using DOM::TextImpl;
#if APPLE_CHANGES
#include "KWQAssertions.h"
#include "KWQLogging.h"
#else
#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)
#define ASSERT(assertion) assert(assertion)
#endif
namespace khtml {
static QString escapeHTML(const QString &in)
{
QString s = "";
unsigned len = in.length();
for (unsigned i = 0; i < len; ++i) {
switch (in[i].latin1()) {
case '&':
s += "&";
break;
case '<':
s += "<";
break;
case '>':
s += ">";
break;
default:
s += in[i];
}
}
return s;
}
static QString stringValueForRange(const NodeImpl *node, const RangeImpl *range)
{
DOMString str = node->nodeValue().copy();
if (range) {
int exceptionCode;
if (node == range->endContainer(exceptionCode)) {
str.truncate(range->endOffset(exceptionCode));
}
if (node == range->startContainer(exceptionCode)) {
str.remove(0, range->startOffset(exceptionCode));
}
}
return str.string();
}
static QString renderedText(const NodeImpl *node, const RangeImpl *range)
{
RenderObject *r = node->renderer();
if (!r)
return QString();
if (!node->isTextNode())
return QString();
QString result = "";
int exceptionCode;
const TextImpl *textNode = static_cast<const TextImpl *>(node);
unsigned startOffset = 0;
unsigned endOffset = textNode->length();
if (range && node == range->startContainer(exceptionCode))
startOffset = range->startOffset(exceptionCode);
if (range && node == range->endContainer(exceptionCode))
endOffset = range->endOffset(exceptionCode);
RenderText *textRenderer = static_cast<RenderText *>(r);
QString str = node->nodeValue().string();
for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
unsigned start = box->m_start;
unsigned end = box->m_start + box->m_len;
if (endOffset < start)
break;
if (startOffset <= end) {
unsigned s = kMax(start, startOffset);
unsigned e = kMin(end, endOffset);
result.append(str.mid(s, e-s));
if (e == end) {
// now add in collapsed-away spaces if at the end of the line
InlineTextBox *nextBox = box->nextTextBox();
if (nextBox && box->root() != nextBox->root()) {
const char nonBreakingSpace = '\xa0';
// count the number of characters between the end of the
// current box and the start of the next box.
int collapsedStart = e;
int collapsedPastEnd = kMin((unsigned)nextBox->m_start, endOffset + 1);
bool addNextNonNBSP = true;
for (int i = collapsedStart; i < collapsedPastEnd; i++) {
if (str[i] == nonBreakingSpace) {
result.append(str[i]);
addNextNonNBSP = true;
}
else if (addNextNonNBSP) {
result.append(str[i]);
addNextNonNBSP = false;
}
}
}
}
}
}
return result;
}
static QString startMarkup(const NodeImpl *node, const RangeImpl *range, EAnnotateForInterchange annotate, CSSMutableStyleDeclarationImpl *defaultStyle)
{
unsigned short type = node->nodeType();
switch (type) {
case Node::TEXT_NODE: {
if (node->parentNode()) {
switch (node->parentNode()->id()) {
case ID_PRE:
case ID_SCRIPT:
case ID_STYLE:
case ID_TEXTAREA:
return stringValueForRange(node, range);
}
}
QString markup = annotate ? escapeHTML(renderedText(node, range)) : escapeHTML(stringValueForRange(node, range));
if (defaultStyle) {
NodeImpl *element = node->parentNode();
if (element) {
CSSMutableStyleDeclarationImpl *style = Position(element, 0).computedStyle()->copyInheritableProperties();
style->ref();
defaultStyle->diff(style);
if (style->length() > 0) {
// FIXME: Handle case where style->cssText() has illegal characters in it, like "
QString openTag = QString("<span class=\"") + AppleStyleSpanClass + "\" style=\"" + style->cssText().string() + "\">";
markup = openTag + markup + "</span>";
}
style->deref();
}
}
return annotate ? convertHTMLTextToInterchangeFormat(markup) : markup;
}
case Node::COMMENT_NODE:
return static_cast<const CommentImpl *>(node)->toString().string();
case Node::DOCUMENT_NODE:
return "";
default: {
QString markup = QChar('<') + node->nodeName().string();
if (type == Node::ELEMENT_NODE) {
const ElementImpl *el = static_cast<const ElementImpl *>(node);
DOMString additionalStyle;
if (defaultStyle && el->isHTMLElement()) {
CSSMutableStyleDeclarationImpl *style = Position(const_cast<ElementImpl *>(el), 0).computedStyle()->copyInheritableProperties();
style->ref();
defaultStyle->diff(style);
if (style->length() > 0) {
CSSMutableStyleDeclarationImpl *inlineStyleDecl = static_cast<const HTMLElementImpl *>(el)->inlineStyleDecl();
if (inlineStyleDecl)
inlineStyleDecl->diff(style);
additionalStyle = style->cssText();
}
style->deref();
}
NamedAttrMapImpl *attrs = el->attributes();
unsigned long length = attrs->length();
if (length == 0 && additionalStyle.length() > 0) {
// FIXME: Handle case where additionalStyle has illegal characters in it, like "
markup += " " + node->getDocument()->attrName(ATTR_STYLE).string() + "=\"" + additionalStyle.string() + "\"";
}
else {
for (unsigned int i=0; i<length; i++) {
AttributeImpl *attr = attrs->attributeItem(i);
DOMString value = attr->value();
if (attr->id() == ATTR_STYLE && additionalStyle.length() > 0)
value += "; " + additionalStyle;
// FIXME: Handle case where value has illegal characters in it, like "
markup += " " + node->getDocument()->attrName(attr->id()).string() + "=\"" + value.string() + "\"";
}
}
}
markup += node->isHTMLElement() ? ">" : "/>";
return markup;
}
}
}
static QString endMarkup(const NodeImpl *node)
{
if ((!node->isHTMLElement() || endTagRequirement(node->id()) != FORBIDDEN) && node->nodeType() != Node::TEXT_NODE && node->nodeType() != Node::DOCUMENT_NODE) {
return "</" + node->nodeName().string() + ">";
}
return "";
}
static QString markup(const NodeImpl *startNode, bool onlyIncludeChildren, bool includeSiblings, QPtrList<NodeImpl> *nodes)
{
// Doesn't make sense to only include children and include siblings.
ASSERT(!(onlyIncludeChildren && includeSiblings));
QString me = "";
for (const NodeImpl *current = startNode; current != NULL; current = includeSiblings ? current->nextSibling() : NULL) {
if (!onlyIncludeChildren) {
if (nodes) {
nodes->append(current);
}
me += startMarkup(current, 0, DoNotAnnotateForInterchange, 0);
}
if (!current->isHTMLElement() || endTagRequirement(current->id()) != FORBIDDEN) {
// print children
if (NodeImpl *n = current->firstChild()) {
me += markup(n, false, true, nodes);
}
// Print my ending tag
if (!onlyIncludeChildren) {
me += endMarkup(current);
}
}
}
return me;
}
static void completeURLs(NodeImpl *node, const QString &baseURL)
{
NodeImpl *end = node->traverseNextSibling();
for (NodeImpl *n = node; n != end; n = n->traverseNextNode()) {
if (n->nodeType() == Node::ELEMENT_NODE) {
ElementImpl *e = static_cast<ElementImpl *>(n);
NamedAttrMapImpl *attrs = e->attributes();
unsigned long length = attrs->length();
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -