+2004-12-13 Darin Adler <darin@apple.com>
+
+ Reviewed by Ken.
+
+ - moved markup-related functions into new sources files in the editing directory
+ - removed all of the uses of dynamic_cast, preparing to turn off RTTI to make our code smaller and slightly faster
+
+ * ForwardingHeaders/editing/markup.h: Added.
+ * khtml/editing/markup.h: Added.
+ * khtml/editing/markup.cpp: Added.
+
+ * WebCore.pbproj/project.pbxproj: Added markup.h/cpp.
+
+ * khtml/dom/dom_node.cpp: (Node::toHTML): Call createMarkup since there's no toHTML in NodeImpl any more.
+ * khtml/html/html_elementimpl.cpp:
+ (HTMLElementImpl::innerHTML): Changed to call createMarkup.
+ (HTMLElementImpl::outerHTML): Ditto.
+
+ * khtml/ecma/kjs_window.cpp:
+ (Window::retrieveWindow): Comment out assert that uses dynamic_cast.
+ (Window::retrieveActive): Ditto.
+
+ * khtml/editing/htmlediting.h: Added forward class declaration needed now that I removed one elsewhere.
+ * khtml/xml/dom_docimpl.h: Ditto.
+
+ * khtml/khtml_part.cpp:
+ (KHTMLPart::slotDebugDOMTree): Use createMarkup instead of toHTML.
+ (KHTMLPart::processObjectRequest): Use inherits instead of dynamic_cast.
+
+ * khtml/rendering/render_image.cpp: (RenderImage::paint): Add an explicit QChar conversion so this code
+ still works even with the additional replace overloads added to QString.
+ * kwq/KWQTextCodec.mm: (QTextCodec::fromUnicode): Ditto.
+
+ * khtml/rendering/render_object.h: Removed the version of arenaDelete that does not take an object
+ base pointer, because it used dynamic_cast in its implementation. Made the other version public.
+ * khtml/rendering/render_object.cpp: Ditto.
+ * khtml/rendering/render_replaced.cpp: (RenderWidget::deref): Pass object base pointer to arenaDelete.
+
+ * khtml/xml/dom2_rangeimpl.h: Removed extra parameters from toHTML, and unneeded includes and declarations.
+ * khtml/xml/dom2_rangeimpl.cpp: (DOM::RangeImpl::toHTML): Changed to call createMarkup, and moved all
+ the support code into markup.cpp.
+
+ * khtml/xml/dom_nodeimpl.h: Moved toHTML and related functions into markup.cpp.
+ * khtml/xml/dom_nodeimpl.cpp: Ditto.
+
+ * khtml/xml/dom_position.cpp:
+ (DOM::startPosition): Implemented the version of this that takes a RangeImpl. Also added null checks
+ so these return null positions rather than raising exceptions.
+ (DOM::endPosition): Ditto.
+
+ * khtml/khtmlview.h: Added an APPLE_CHANGES function so inherits can detect this class without dynamic_cast.
+ * kwq/KWQFrame.h: Ditto.
+ * kwq/KWQFrame.mm: (QFrame::isQFrame): Ditto.
+ * kwq/KWQKPartsPart.h: Ditto.
+ * kwq/KWQKPartsPart.mm: (KParts::ReadOnlyPart::isKPartsReadOnlyPart): Ditto.
+ * kwq/KWQScrollView.h: Ditto.
+ * kwq/KWQScrollView.mm: (QScrollView::isQScrollView): Ditto.
+ * kwq/KWQKHTMLPart.h: Ditto.
+ * kwq/KWQKHTMLPart.mm:
+ (KHTMLView::isKHTMLView): Ditto.
+ (KWQKHTMLPart::setTitle): Added an explicit QChar conversion so this code still works even with the additional
+ replace overloads added to QString.
+ (KWQKHTMLPart::setStatusBarText): Ditto.
+ (KWQKHTMLPart::runJavaScriptAlert): Ditto.
+ (KWQKHTMLPart::runJavaScriptConfirm): Ditto.
+ (KWQKHTMLPart::runJavaScriptPrompt): Ditto.
+ (KWQKHTMLPart::attributedString): Ditto.
+ (KWQKHTMLPart::isCharacterSmartReplaceExempt): Ditto.
+ (KWQKHTMLPart::isKHTMLPart): That dynamic_cast thing (see above).
+
+ * kwq/KWQObject.h: Added virtual methods for the few cases where we need dynamic_cast-like behavior.
+ * kwq/KWQObject.mm:
+ (QObject::inherits): Changed to not use dynamic cast.
+ (QObject::isKHTMLPart): Added. Returns false.
+ (QObject::isKHTMLView): Ditto.
+ (QObject::isKPartsReadOnlyPart): Ditto.
+ (QObject::isQFrame): Ditto.
+ (QObject::isQScrollView): Ditto.
+
+ * kwq/KWQRenderTreeDebug.cpp:
+ (write): Changed to use inherits rather than dynamic_cast.
+ (writeSelection): Ditto.
+
+ * kwq/KWQSlot.mm: (KWQSlot::call): Call through to the version with just a job pointer parameter rather
+ than going straight on to the "no parameters at all" version.
+
+ * kwq/KWQString.h:
+ * kwq/KWQString.mm: (QString::replace): Added overloads.
+ * kwq/WebCoreBridge.mm:
+ (-[WebCoreBridge markupStringFromNode:nodes:]): Changed to call functions in markup.h.
+ (-[WebCoreBridge markupStringFromRange:nodes:]): Ditto.
+ (-[WebCoreBridge selectedString]): Added an explicit QChar conversion so this code still works even with
+ the additional replace overloads added to QString.
+ (-[WebCoreBridge stringForRange:]): Ditto.
+ (-[WebCoreBridge copyDOMNode:copier:]): Changed to call functions in markup.h.
+ (-[WebCoreBridge elementAtPoint:]): QChar conversion.
+ (-[WebCoreBridge documentFragmentWithMarkupString:baseURLString:]): Changed to call functions in markup.h.
+ (-[WebCoreBridge documentFragmentWithText:]): Changed to call functions in markup.h.
+
2004-12-13 Ken Kocienda <kocienda@apple.com>
Reviewed by John
--- /dev/null
+#import <markup.h>
939FF8EF0702B1B100979E5E,
BECE67BE07087B250007C14B,
BEA5E01E075CEDAC0098A432,
+ 9378D9FC07640A46004B97BF,
);
isa = PBXHeadersBuildPhase;
runOnlyForDeploymentPostprocessing = 0;
93ABE074070285F600BD91F9,
939FF8EE0702B1B100979E5E,
BEA5DBDB075CEDA00098A432,
+ 9378D9FB07640A46004B97BF,
);
isa = PBXSourcesBuildPhase;
runOnlyForDeploymentPostprocessing = 0;
settings = {
};
};
+ 9378D9F907640A46004B97BF = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ lastKnownFileType = sourcecode.cpp.cpp;
+ name = markup.cpp;
+ path = editing/markup.cpp;
+ refType = 4;
+ sourceTree = "<group>";
+ };
+ 9378D9FA07640A46004B97BF = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ lastKnownFileType = sourcecode.c.h;
+ name = markup.h;
+ path = editing/markup.h;
+ refType = 4;
+ sourceTree = "<group>";
+ };
+ 9378D9FB07640A46004B97BF = {
+ fileRef = 9378D9F907640A46004B97BF;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 9378D9FC07640A46004B97BF = {
+ fileRef = 9378D9FA07640A46004B97BF;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
93859E32065FCAD300CF54EE = {
fileEncoding = 4;
isa = PBXFileReference;
BEA5E01D075CEDAC0098A432,
BE02D4E6066F908A0076809F,
BE02D4E7066F908A0076809F,
+ 9378D9FA07640A46004B97BF,
+ 9378D9F907640A46004B97BF,
93ABE067070285F600BD91F9,
93ABE066070285F600BD91F9,
BECE67BD07087B250007C14B,
#include "xml/dom_docimpl.h"
#include "xml/dom_elementimpl.h"
#include "xml/dom2_eventsimpl.h"
+#include "editing/markup.h"
#include <qrect.h>
using namespace DOM;
+using khtml::createMarkup;
+
NamedNodeMap::NamedNodeMap()
{
impl = 0;
QString Node::toHTML()
{
- if (!impl) return QString::null;
- return impl->toHTML();
+ return createMarkup(impl);
}
void Node::applyChanges()
{
assert( !obj.isNull() );
#ifndef QWS
- assert( dynamic_cast<KJS::Window*>(obj.imp()) ); // type checking
+ //assert( dynamic_cast<KJS::Window*>(obj.imp()) ); // type checking
#endif
}
#endif
ValueImp *imp = exec->dynamicInterpreter()->globalObject().imp();
assert( imp );
#ifndef QWS
- assert( dynamic_cast<KJS::Window*>(imp) );
+ //assert( dynamic_cast<KJS::Window*>(imp) );
#endif
return static_cast<KJS::Window*>(imp);
}
namespace DOM {
class CSSMutableStyleDeclarationImpl;
class CSSProperty;
+ class CSSStyleDeclarationImpl;
class DocumentFragmentImpl;
class HTMLElementImpl;
class TextImpl;
--- /dev/null
+/*
+ * 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 "html/html_elementimpl.h"
+#include "xml/dom_position.h"
+#include "xml/dom2_rangeimpl.h"
+#include "rendering/render_text.h"
+#include "misc/htmltags.h"
+#include "html/dtd.h"
+
+using DOM::AttributeImpl;
+using DOM::CommentImpl;
+using DOM::DocumentFragmentImpl;
+using DOM::DocumentImpl;
+using DOM::DOMString;
+using DOM::ElementImpl;
+using DOM::endTag;
+using DOM::FORBIDDEN;
+using DOM::HTMLElementImpl;
+using DOM::NamedAttrMapImpl;
+using DOM::Node;
+using DOM::NodeImpl;
+using DOM::Position;
+using DOM::RangeImpl;
+using DOM::TextImpl;
+
+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));
+ // 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)
+{
+ unsigned short type = node->nodeType();
+ switch (type) {
+ case Node::TEXT_NODE: {
+ if (node->parentNode()) {
+ switch (node->parentNode()->id()) {
+ case ID_SCRIPT:
+ case ID_STYLE:
+ case ID_TEXTAREA:
+ return stringValueForRange(node, range);
+ }
+ }
+ if (annotate)
+ return convertHTMLTextToInterchangeFormat(escapeHTML(renderedText(node, range)));
+ return escapeHTML(stringValueForRange(node, range));
+ }
+ 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);
+ NamedAttrMapImpl *attrs = el->attributes();
+ unsigned long length = attrs->length();
+ for (unsigned int i=0; i<length; i++) {
+ AttributeImpl *attr = attrs->attributeItem(i);
+ markup += " " + node->getDocument()->attrName(attr->id()).string() + "=\"" + attr->value().string() + "\"";
+ }
+ }
+ markup += node->isHTMLElement() ? ">" : "/>";
+ return markup;
+ }
+ }
+}
+
+static QString endMarkup(const NodeImpl *node)
+{
+ if ((!node->isHTMLElement() || endTag[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);
+ }
+ if (!current->isHTMLElement() || endTag[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();
+ for (unsigned long i = 0; i < length; i++) {
+ AttributeImpl *attr = attrs->attributeItem(i);
+ if (e->isURLAttribute(attr)) {
+ e->setAttribute(attr->id(), KURL(baseURL, attr->value().string()).url());
+ }
+ }
+ }
+ }
+}
+
+QString createMarkup(const RangeImpl *range, QPtrList<NodeImpl> *nodes, EAnnotateForInterchange annotate)
+{
+ if (!range || range->isDetached())
+ return QString();
+
+ int exceptionCode;
+ NodeImpl *commonAncestor = range->commonAncestorContainer(exceptionCode);
+ NodeImpl *commonAncestorBlock = 0;
+ if (commonAncestor != 0) {
+ commonAncestorBlock = commonAncestor->enclosingBlockFlowElement();
+ }
+ if (commonAncestorBlock == 0) {
+ return "";
+ }
+
+ QStringList markups;
+ NodeImpl *pastEnd = range->pastEndNode();
+ NodeImpl *lastClosed = 0;
+ QPtrList<NodeImpl> ancestorsToClose;
+
+ // Iterate through the nodes of the range.
+ NodeImpl *next;
+ for (NodeImpl *n = range->startNode(); n != pastEnd; n = next) {
+ next = n->traverseNextNode();
+ if (!n->renderer())
+ continue;
+
+ if (n->isBlockFlow() && next == pastEnd) {
+ // Don't write out an empty block.
+ continue;
+ }
+
+ // Add the node to the markup.
+ markups.append(startMarkup(n, range, annotate));
+ if (nodes) {
+ nodes->append(n);
+ }
+
+ if (n->firstChild() == 0) {
+ // Node has no children, add its close tag now.
+ markups.append(endMarkup(n));
+ lastClosed = n;
+
+ // Check if the node is the last leaf of a tree.
+ if (n->nextSibling() == 0 || next == pastEnd) {
+ if (!ancestorsToClose.isEmpty()) {
+ // Close up the ancestors.
+ while (NodeImpl *ancestor = ancestorsToClose.last()) {
+ if (next != pastEnd && ancestor == next->parentNode()) {
+ break;
+ }
+ // Not at the end of the range, close ancestors up to sibling of next node.
+ markups.append(endMarkup(ancestor));
+ lastClosed = ancestor;
+ ancestorsToClose.removeLast();
+ }
+ } else {
+ // No ancestors to close, but need to add ancestors not in range since next node is in another tree.
+ if (next != pastEnd) {
+ NodeImpl *nextParent = next->parentNode();
+ if (n != nextParent) {
+ for (NodeImpl *parent = n->parent(); parent != 0 && parent != nextParent; parent = parent->parentNode()) {
+ markups.prepend(startMarkup(parent, range, annotate));
+ markups.append(endMarkup(parent));
+ if (nodes) {
+ nodes->append(parent);
+ }
+ lastClosed = parent;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ // Node is an ancestor, set it to close eventually.
+ ancestorsToClose.append(n);
+ }
+ }
+
+ // Add ancestors up to the common ancestor block so inline ancestors such as FONT and B are part of the markup.
+ for (NodeImpl *ancestor = lastClosed->parentNode(); ancestor; ancestor = ancestor->parentNode()) {
+ bool breakAtEnd = false;
+ if (commonAncestorBlock == ancestor) {
+ NodeImpl::Id id = ancestor->id();
+ // Tables and lists must be part of the markup to avoid broken structures.
+ if (id == ID_TABLE || id == ID_OL || id == ID_UL) {
+ breakAtEnd = true;
+ } else {
+ break;
+ }
+ }
+ markups.prepend(startMarkup(ancestor, range, annotate));
+ markups.append(endMarkup(ancestor));
+ if (nodes) {
+ nodes->append(ancestor);
+ }
+ if (breakAtEnd) {
+ break;
+ }
+ }
+
+ if (annotate) {
+ Position pos(endPosition(range));
+ NodeImpl *block = pos.node()->enclosingBlockFlowElement();
+ NodeImpl *upstreamBlock = pos.upstream().node()->enclosingBlockFlowElement();
+ if (block != upstreamBlock) {
+ static const QString interchangeNewlineString = QString("<br class=\"") + AppleInterchangeNewline + "\">";
+ markups.append(interchangeNewlineString);
+ }
+ }
+
+ return markups.join("");
+}
+
+DocumentFragmentImpl *createFragmentFromMarkup(DocumentImpl *document, const QString &markup, const QString &baseURL)
+{
+ // FIXME: What if the document element is not an HTML element?
+ HTMLElementImpl *element = static_cast<HTMLElementImpl *>(document->documentElement());
+
+ DocumentFragmentImpl *fragment = element->createContextualFragment(markup);
+ assert(fragment);
+
+ if (!baseURL.isEmpty() && baseURL != document->baseURL())
+ completeURLs(fragment, baseURL);
+
+ return fragment;
+}
+
+QString createMarkup(const DOM::NodeImpl *node, EChildrenOnly includeChildren,
+ QPtrList<DOM::NodeImpl> *nodes, EAnnotateForInterchange annotate)
+{
+ assert(annotate == DoNotAnnotateForInterchange); // annotation not yet implemented for this code path
+ return markup(node, includeChildren, false, nodes);
+}
+
+DOM::DocumentFragmentImpl *createFragmentFromText(DOM::DocumentImpl *document, const QString &text)
+{
+ if (!document)
+ return 0;
+
+ DocumentFragmentImpl *fragment = document->createDocumentFragment();
+ QString string = text;
+
+ // Replace tabs with four plain spaces.
+ // These spaces will get converted along with the other existing spaces below.
+ string.replace('\t', " ");
+
+ int offset = 0;
+ int stringLength = string.length();
+ while (1) {
+ // FIXME: This only converts plain old spaces, and does not
+ // deal with more exotic whitespace. Note that we want to
+ // leave newlines and returns alone at this point anyway,
+ // since those are handled specially later.
+ int spacesPos = string.find(" ", offset);
+ if (spacesPos < 0)
+ break;
+
+ // Found two adjoining spaces.
+ // Now, lookahead to see if these two spaces are followed by:
+ // 1. another space and then a non-space
+ // 2. another space and then the end of the string
+ // If either 1 or 2 is true, replace the three spaces found with nbsp+nbsp+space,
+ // otherwise, replace the first two spaces with nbsp+space.
+ if ((spacesPos + 3 < stringLength && string[spacesPos + 2] == ' ' && string[spacesPos + 3] != ' ')
+ || (spacesPos + 3 == stringLength && string[spacesPos + 2] == ' ')) {
+ string.replace(spacesPos, 3, "\xA0\xA0 ");
+ } else {
+ string.replace(spacesPos, 2, "\xA0 ");
+ }
+ offset = spacesPos + 2;
+ }
+
+ // Handle line endings, replacing them with BR elements.
+ string.replace(QString("\r\n"), "\n");
+ string.replace('\r', '\n');
+ QStringList list = QStringList::split('\n', string, true); // true gets us empty strings in the list
+ bool firstNode = true;
+ while (!list.isEmpty()) {
+ int exceptionCode = 0;
+ if (firstNode) {
+ firstNode = false;
+ } else {
+ ElementImpl *breakNode = document->createHTMLElement("br", exceptionCode);
+ assert(exceptionCode == 0);
+ fragment->appendChild(breakNode, exceptionCode);
+ assert(exceptionCode == 0);
+ }
+ QString s = list.first();
+ list.pop_front();
+ if (!s.isEmpty()) {
+ NodeImpl *textNode = document->createTextNode(s);
+ fragment->appendChild(textNode, exceptionCode);
+ assert(exceptionCode == 0);
+ }
+ }
+
+ return fragment;
+}
+
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef KHTML_EDITING_MARKUP_H
+#define KHTML_EDITING_MARKUP_H
+
+#include <xml/dom_docimpl.h>
+#include "html_interchange.h"
+
+namespace khtml {
+
+enum EChildrenOnly { IncludeNode, ChildrenOnly };
+
+DOM::DocumentFragmentImpl *createFragmentFromText(DOM::DocumentImpl *document, const QString &text);
+DOM::DocumentFragmentImpl *createFragmentFromMarkup(DOM::DocumentImpl *document, const QString &markup, const QString &baseURL);
+
+QString createMarkup(const DOM::RangeImpl *range,
+ QPtrList<DOM::NodeImpl> *nodes = 0, EAnnotateForInterchange = DoNotAnnotateForInterchange);
+QString createMarkup(const DOM::NodeImpl *node, EChildrenOnly = IncludeNode,
+ QPtrList<DOM::NodeImpl> *nodes = 0, EAnnotateForInterchange = DoNotAnnotateForInterchange);
+
+}
+
+#endif // KHTML_EDITING_MARKUP_H
#include "css/css_ruleimpl.h"
#include "xml/dom_textimpl.h"
#include "xml/dom2_eventsimpl.h"
+#include "editing/markup.h"
#include <kdebug.h>
DOMString HTMLElementImpl::innerHTML() const
{
- return toHTML();
+ return createMarkup(this, ChildrenOnly);
}
DOMString HTMLElementImpl::outerHTML() const
{
- return recursive_toHTML();
+ return createMarkup(this);
}
DOMString HTMLElementImpl::innerText() const
#include "dom/dom_string.h"
#include "dom/dom_element.h"
#include "dom/html_document.h"
+#include "editing/markup.h"
#include "editing/selection.h"
#include "editing/visible_position.h"
#include "editing/visible_text.h"
void KHTMLPart::slotDebugDOMTree()
{
if ( d->m_doc && d->m_doc->firstChild() )
- qDebug("%s", d->m_doc->firstChild()->toHTML().latin1());
+ qDebug("%s", createMarkup(d->m_doc->firstChild()).latin1());
}
void KHTMLPart::slotDebugRenderTree()
#if APPLE_CHANGES
if ( child->m_part )
{
- KHTMLPart *part = dynamic_cast<KHTMLPart *>(&*child->m_part);
- if (part)
+ KHTMLPart *part = static_cast<KHTMLPart *>(&*child->m_part);
+ if (part && part->inherits("KHTMLPart"))
part->openURL(url);
}
else
{
KParts::ReadOnlyPart *part = KWQ(this)->createPart(*child, url, mimetype);
- KHTMLPart *khtml_part = dynamic_cast<KHTMLPart *>(part);
- if (khtml_part)
+ KHTMLPart *khtml_part = static_cast<KHTMLPart *>(part);
+ if (khtml_part && khtml_part->inherits("KHTMLPart"))
khtml_part->childBegin();
#else
if ( !child->m_services.contains( mimetype ) )
// completed() signal for the child by hand:
if (url.isEmpty() || url.url() == "about:blank") {
ReadOnlyPart *readOnlyPart = child->m_part;
- KHTMLPart *part = dynamic_cast<KHTMLPart *>(readOnlyPart);
- if (part) {
+ KHTMLPart *part = static_cast<KHTMLPart *>(readOnlyPart);
+ if (part && part->inherits("KHTMLPart")) {
part->completed();
}
}
void applyBodyScrollQuirk(khtml::RenderObject* o, ScrollBarMode& hMode, ScrollBarMode& vMode);
+#if APPLE_CHANGES
+ virtual bool isKHTMLView() const;
+#endif
+
// ------------------------------------- member variables ------------------------------------
private:
unsigned _refCount;
if (!alt.isEmpty()) {
QString text = alt.string();
- text.replace('\\', backslashAsCurrencySymbol());
+ text.replace(QChar('\\'), backslashAsCurrencySymbol());
p->setFont (style()->font());
p->setPen (style()->color());
int ax = _tx + leftBorder + leftPad;
arena->free(*(size_t *)base, base);
}
-void RenderObject::arenaDelete(RenderArena *arena)
-{
- arenaDelete(arena, dynamic_cast<void *>(this));
-}
-
Position RenderObject::positionForCoordinates(int x, int y, EAffinity *affinity)
{
if (affinity)
virtual void removeLeftoverAnonymousBoxes();
- void arenaDelete(RenderArena *arena);
+ void arenaDelete(RenderArena *arena, void *objectBase);
private:
RenderStyle* m_style;
bool m_hasOverflowClip : 1;
- void arenaDelete(RenderArena *arena, void *objectBase);
-
// note: do not add unnecessary bitflags, we have 32 bit already!
friend class RenderListItem;
friend class RenderContainer;
{
if (_ref) _ref--;
if (!_ref)
- arenaDelete(arena);
+ arenaDelete(arena, this);
}
#if APPLE_CHANGES
#include "dom_xmlimpl.h"
#include "html/html_elementimpl.h"
#include "misc/htmltags.h"
+#include "editing/markup.h"
#include "editing/visible_position.h"
#include "editing/visible_text.h"
#include "xml/dom_position.h"
#include "render_block.h"
+using khtml::createMarkup;
using khtml::RenderBlock;
using khtml::RenderObject;
return text;
}
-static QString interchangeNewlineMarkupString()
+DOMString RangeImpl::toHTML() const
{
- static QString interchangeNewlineString;
- if (interchangeNewlineString.length() == 0) {
- interchangeNewlineString = "<br class=\"";
- interchangeNewlineString += AppleInterchangeNewline;
- interchangeNewlineString += "\">";
- }
- return interchangeNewlineString;
-}
-
-DOMString RangeImpl::toHTML(QPtrList<NodeImpl> *nodes, EAnnotateForInterchange annotate) const
-{
- int exceptionCode;
- NodeImpl *commonAncestor = commonAncestorContainer(exceptionCode);
- NodeImpl *commonAncestorBlock = 0;
- if (commonAncestor != 0) {
- commonAncestorBlock = commonAncestor->enclosingBlockFlowElement();
- }
- if (commonAncestorBlock == 0) {
- return "";
- }
-
- QStringList markups;
- NodeImpl *pastEnd = pastEndNode();
- NodeImpl *lastClosed = 0;
- QPtrList<NodeImpl> ancestorsToClose;
-
- // Iterate through the nodes of the range.
- NodeImpl *next;
- for (NodeImpl *n = startNode(); n != pastEnd; n = next) {
- next = n->traverseNextNode();
- if (!n->renderer())
- continue;
-
- if (n->isBlockFlow() && next == pastEnd) {
- // Don't write out an empty block.
- continue;
- }
-
- // Add the node to the markup.
- markups.append(n->startMarkup(this, annotate));
- if (nodes) {
- nodes->append(n);
- }
-
- if (n->firstChild() == 0) {
- // Node has no children, add its close tag now.
- markups.append(n->endMarkup());
- lastClosed = n;
-
- // Check if the node is the last leaf of a tree.
- if (n->nextSibling() == 0 || next == pastEnd) {
- if (!ancestorsToClose.isEmpty()) {
- // Close up the ancestors.
- while (NodeImpl *ancestor = ancestorsToClose.last()) {
- if (next != pastEnd && ancestor == next->parentNode()) {
- break;
- }
- // Not at the end of the range, close ancestors up to sibling of next node.
- markups.append(ancestor->endMarkup());
- lastClosed = ancestor;
- ancestorsToClose.removeLast();
- }
- } else {
- // No ancestors to close, but need to add ancestors not in range since next node is in another tree.
- if (next != pastEnd) {
- NodeImpl *nextParent = next->parentNode();
- if (n != nextParent) {
- for (NodeImpl *parent = n->parent(); parent != 0 && parent != nextParent; parent = parent->parentNode()) {
- markups.prepend(parent->startMarkup(this, annotate));
- markups.append(parent->endMarkup());
- if (nodes) {
- nodes->append(parent);
- }
- lastClosed = parent;
- }
- }
- }
- }
- }
- } else {
- // Node is an ancestor, set it to close eventually.
- ancestorsToClose.append(n);
- }
- }
-
- // Add ancestors up to the common ancestor block so inline ancestors such as FONT and B are part of the markup.
- for (NodeImpl *ancestor = lastClosed->parentNode(); ancestor; ancestor = ancestor->parentNode()) {
- bool breakAtEnd = false;
- if (commonAncestorBlock == ancestor) {
- NodeImpl::Id id = ancestor->id();
- // Tables and lists must be part of the markup to avoid broken structures.
- if (id == ID_TABLE || id == ID_OL || id == ID_UL) {
- breakAtEnd = true;
- } else {
- break;
- }
- }
- markups.prepend(ancestor->startMarkup(this, annotate));
- markups.append(ancestor->endMarkup());
- if (nodes) {
- nodes->append(ancestor);
- }
- if (breakAtEnd) {
- break;
- }
- }
-
- if (annotate) {
- Position pos(m_endContainer, m_endOffset);
- NodeImpl *block = pos.node()->enclosingBlockFlowElement();
- NodeImpl *upstreamBlock = pos.upstream().node()->enclosingBlockFlowElement();
- if (block != upstreamBlock)
- markups.append(interchangeNewlineMarkupString());
- }
-
- return markups.join("");
+ return createMarkup(this);
}
-
DOMString RangeImpl::text() const
{
if (m_detached)
#include <qptrlist.h>
#include "dom/dom2_range.h"
-#include "editing/html_interchange.h"
#include "misc/shared.h"
-class QStringList;
-
namespace DOM {
class DocumentPtr;
DocumentFragmentImpl *cloneContents ( int &exceptioncode );
void insertNode( NodeImpl *newNode, int &exceptioncode );
DOMString toString ( int &exceptioncode ) const;
- DOMString toHTML(QPtrList<NodeImpl> *nodes=NULL, EAnnotateForInterchange annotate=DoNotAnnotateForInterchange) const;
+ DOMString toHTML() const;
DOMString text() const;
DocumentFragmentImpl *createContextualFragment ( DOMString &html, int &exceptioncode ) const;
} // namespace
#endif
-
class NodeIteratorImpl;
class NodeListImpl;
class ProcessingInstructionImpl;
+ class Range;
class RangeImpl;
class RegisteredEventListener;
class StyleSheetImpl;
return 0;
}
-QString NodeImpl::toHTML() const
-{
- return recursive_toHTML(true);
-}
-
-static QString escapeHTML( const QString& in )
-{
- QString s;
- for ( unsigned int i = 0; i < in.length(); ++i ) {
- switch( in[i].latin1() ) {
- case '&':
- s += "&";
- break;
- case '<':
- s += "<";
- break;
- case '>':
- s += ">";
- break;
- default:
- s += in[i];
- }
- }
-
- return s;
-}
-
-QString NodeImpl::stringValueForRange(const RangeImpl *range) const
-{
- DOMString str = nodeValue().copy();
- if (range) {
- int exceptionCode;
- if (this == range->endContainer(exceptionCode)) {
- str.truncate(range->endOffset(exceptionCode));
- }
- if (this == range->startContainer(exceptionCode)) {
- str.remove(0, range->startOffset(exceptionCode));
- }
- }
- return str.string();
-}
-
-QString NodeImpl::renderedText(const RangeImpl *range) const
-{
- QString result;
-
- RenderObject *r = renderer();
- if (!r)
- return result;
-
- if (!isTextNode())
- return result;
-
- int exceptionCode;
- const TextImpl *textNode = static_cast<const TextImpl *>(this);
- unsigned startOffset = 0;
- unsigned endOffset = textNode->length();
-
- if (range && this == range->startContainer(exceptionCode))
- startOffset = range->startOffset(exceptionCode);
- if (range && this == range->endContainer(exceptionCode))
- endOffset = range->endOffset(exceptionCode);
-
- RenderText *textRenderer = static_cast<RenderText *>(r);
- QString str = 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));
-
- // now add in collapsed-away spaces if at the end of the line
- InlineTextBox *nextBox = box->nextTextBox();
- if (nextBox && box->root() != nextBox->root()) {
- static QChar nbsp('0xa0');
- static QChar space(' ');
- // 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] == nbsp) {
- result.append(str[i]);
- addNextNonNBSP = true;
- }
- else if (addNextNonNBSP) {
- result.append(str[i]);
- addNextNonNBSP = false;
- }
- }
- }
- }
- }
-
- return result;
-}
-
-QString NodeImpl::startMarkup(const RangeImpl *range, EAnnotateForInterchange annotate) const
-{
- unsigned short type = nodeType();
- if (type == Node::TEXT_NODE) {
- DOMString str = nodeValue().copy();
- Id parentID = parentNode()->id();
- bool dontEscape = (parentID == ID_SCRIPT || parentID == ID_TEXTAREA || parentID == ID_STYLE);
- if (dontEscape)
- return stringValueForRange(range);
- if (annotate)
- return convertHTMLTextToInterchangeFormat(escapeHTML(renderedText(range)));
- return escapeHTML(stringValueForRange(range));
- } else if (type == Node::COMMENT_NODE) {
- return static_cast<const CommentImpl *>(this)->toString().string();
- } else if (type != Node::DOCUMENT_NODE) {
- QString markup = QChar('<') + nodeName().string();
- if (type == Node::ELEMENT_NODE) {
- const ElementImpl *el = static_cast<const ElementImpl *>(this);
- NamedAttrMapImpl *attrs = el->attributes();
- unsigned long length = attrs->length();
- for (unsigned int i=0; i<length; i++) {
- AttributeImpl *attr = attrs->attributeItem(i);
- markup += " " + getDocument()->attrName(attr->id()).string() + "=\"" + attr->value().string() + "\"";
- }
- }
- markup += isHTMLElement() ? ">" : "/>";
- return markup;
- }
- return "";
-}
-
-QString NodeImpl::endMarkup(void) const
-{
- if ((!isHTMLElement() || endTag[id()] != FORBIDDEN) && nodeType() != Node::TEXT_NODE && nodeType() != Node::DOCUMENT_NODE) {
- return "</" + nodeName().string() + ">";
- }
- return "";
-}
-
-QString NodeImpl::recursive_toString(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 += current->startMarkup(0);
- }
- if (!current->isHTMLElement() || endTag[current->id()] != FORBIDDEN) {
- // print children
- if (NodeImpl *n = current->firstChild()) {
- me += recursive_toString(n, false, true, nodes);
- }
- // Print my ending tag
- if (!onlyIncludeChildren) {
- me += current->endMarkup();
- }
- }
- }
- return me;
-}
-
-QString NodeImpl::recursive_toHTML(bool onlyIncludeChildren, QPtrList<NodeImpl> *nodes) const
-{
- return NodeImpl::recursive_toString(this, onlyIncludeChildren, false, nodes);
-}
-
-void NodeImpl::recursive_completeURLs(QString baseURL)
-{
- if (nodeType() == Node::ELEMENT_NODE) {
- ElementImpl *el = static_cast<ElementImpl *>(this);
- NamedAttrMapImpl *attrs = el->attributes();
- unsigned long length = attrs->length();
- for (unsigned int i=0; i<length; i++) {
- AttributeImpl *attr = attrs->attributeItem(i);
- if (el->isURLAttribute(attr)) {
- el->setAttribute(attr->id(), KURL(baseURL, attr->value().string()).url());
- }
- }
- }
-
- NodeImpl *n;
- if ((n = firstChild())) {
- n->recursive_completeURLs(baseURL);
- }
- if ((n = nextSibling())) {
- n->recursive_completeURLs(baseURL);
- }
-}
-
bool NodeImpl::isContentEditable() const
{
return m_parent ? m_parent->isContentEditable() : false;
#include "dom/dom_misc.h"
#include "dom/dom_string.h"
#include "dom/dom_node.h"
-#include "editing/html_interchange.h"
#include "misc/helper.h"
#include "misc/shared.h"
#include "dom_atomicstring.h"
namespace DOM {
-class CSSStyleDeclarationImpl;
class DocumentImpl;
class ElementImpl;
class EventImpl;
-class NamedNodeMapImpl;
class NodeListImpl;
-class Position;
-class Range;
-class RangeImpl;
class RegisteredEventListener;
// The namespace used for XHTML elements
virtual bool isMouseFocusable() const;
virtual bool isInline() const;
- QString stringValueForRange(const RangeImpl *range) const;
- QString renderedText(const RangeImpl *range) const;
- QString startMarkup(const RangeImpl *range, EAnnotateForInterchange annotate=DoNotAnnotateForInterchange) const;
- QString endMarkup(void) const;
- virtual QString toHTML() const;
- QString recursive_toHTML(bool onlyIncludeChildren=false, QPtrList<NodeImpl> *nodes=NULL) const;
- static QString recursive_toString(const NodeImpl *startNode, bool onlyIncludeChildren, bool includeSiblings, QPtrList<NodeImpl> *nodes);
- void recursive_completeURLs(QString baseURL);
virtual bool isContentEditable() const;
virtual QRect getRect() const;
#include "dom_nodeimpl.h"
#include "dom_positioniterator.h"
#include "dom2_range.h"
+#include "dom2_rangeimpl.h"
#include "dom2_viewsimpl.h"
#include "helper.h"
#include "htmltags.h"
Position startPosition(const Range &r)
{
+ if (r.isNull() || r.isDetached())
+ return Position();
return Position(r.startContainer().handle(), r.startOffset());
}
+Position startPosition(const RangeImpl *r)
+{
+ if (!r || r->isDetached())
+ return Position();
+ int exceptionCode;
+ return Position(r->startContainer(exceptionCode), r->startOffset(exceptionCode));
+}
+
Position endPosition(const Range &r)
{
+ if (r.isNull() || r.isDetached())
+ return Position();
return Position(r.endContainer().handle(), r.endOffset());
}
+Position endPosition(const RangeImpl *r)
+{
+ if (!r || r->isDetached())
+ return Position();
+ int exceptionCode;
+ return Position(r->endContainer(exceptionCode), r->endOffset(exceptionCode));
+}
+
} // namespace DOM
/*
- * Copyright (C) 2003 Apple Computer, Inc. All rights reserved.
+ * 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
int frameWidth() const;
private:
+ virtual bool isQFrame() const;
+
int _frameStyle;
};
/*
- * Copyright (C) 2003 Apple Computer, Inc. All rights reserved.
+ * 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
return 3;
return 0;
}
+
+bool QFrame::isQFrame() const
+{
+ return true;
+}
void didTellBridgeAboutLoad(const QString &urlString);
bool haveToldBridgeAboutLoad(const QString &urlString);
- KJS::Bindings::Instance *getEmbedInstanceForView (NSView *aView);
- KJS::Bindings::Instance *getAppletInstanceForView (NSView *aView);
+ KJS::Bindings::Instance *getEmbedInstanceForView(NSView *aView);
+ KJS::Bindings::Instance *getAppletInstanceForView(NSView *aView);
void addPluginRootObject(const KJS::Bindings::RootObject *root);
void cleanupPluginRootObjects();
- DOM::DocumentFragmentImpl *documentFragmentWithText(NSString *text);
-
void registerCommandForUndo(const khtml::EditCommandPtr &);
void registerCommandForRedo(const khtml::EditCommandPtr &);
void clearUndoRedoOperations();
khtml::RenderStyle *styleForSelectionStart(DOM::NodeImpl *&nodeToRemove) const;
+ virtual bool isKHTMLPart() const;
+
WebCoreBridge *_bridge;
KWQSignal _started;
KWQ(this)->_started.call(j);
}
+bool KHTMLView::isKHTMLView() const
+{
+ return true;
+}
+
static void redirectionTimerMonitor(void *context)
{
KWQKHTMLPart *kwq = static_cast<KWQKHTMLPart *>(context);
void KWQKHTMLPart::setTitle(const DOMString &title)
{
QString text = title.string();
- text.replace('\\', backslashAsCurrencySymbol());
+ text.replace(QChar('\\'), backslashAsCurrencySymbol());
KWQ_BLOCK_EXCEPTIONS;
[_bridge setTitle:text.getNSString()];
void KWQKHTMLPart::setStatusBarText(const QString &status)
{
QString text = status;
- text.replace('\\', backslashAsCurrencySymbol());
+ text.replace(QChar('\\'), backslashAsCurrencySymbol());
KWQ_BLOCK_EXCEPTIONS;
[_bridge setStatusText:text.getNSString()];
void KWQKHTMLPart::runJavaScriptAlert(const QString &message)
{
QString text = message;
- text.replace('\\', backslashAsCurrencySymbol());
+ text.replace(QChar('\\'), backslashAsCurrencySymbol());
KWQ_BLOCK_EXCEPTIONS;
[_bridge runJavaScriptAlertPanelWithMessage:text.getNSString()];
KWQ_UNBLOCK_EXCEPTIONS;
bool KWQKHTMLPart::runJavaScriptConfirm(const QString &message)
{
QString text = message;
- text.replace('\\', backslashAsCurrencySymbol());
+ text.replace(QChar('\\'), backslashAsCurrencySymbol());
KWQ_BLOCK_EXCEPTIONS;
return [_bridge runJavaScriptConfirmPanelWithMessage:text.getNSString()];
bool KWQKHTMLPart::runJavaScriptPrompt(const QString &prompt, const QString &defaultValue, QString &result)
{
QString promptText = prompt;
- promptText.replace('\\', backslashAsCurrencySymbol());
+ promptText.replace(QChar('\\'), backslashAsCurrencySymbol());
QString defaultValueText = defaultValue;
- defaultValueText.replace('\\', backslashAsCurrencySymbol());
+ defaultValueText.replace(QChar('\\'), backslashAsCurrencySymbol());
KWQ_BLOCK_EXCEPTIONS;
NSString *returnedText = nil;
if (ok) {
result = QString::fromNSString(returnedText);
- result.replace(backslashAsCurrencySymbol(), '\\');
+ result.replace(backslashAsCurrencySymbol(), QChar('\\'));
}
return ok;
}
}
- text.replace('\\', renderer->backslashAsCurrencySymbol());
+ text.replace(QChar('\\'), renderer->backslashAsCurrencySymbol());
if (text.length() > 0 || needSpace) {
NSMutableDictionary *attrs = [[NSMutableDictionary alloc] init];
}
}
-static NSString *nbspSpaceString = 0;
-static NSString *nbspNBSPSpaceString = 0;
-
-DocumentFragmentImpl *KWQKHTMLPart::documentFragmentWithText(NSString *text)
-{
- if (!xmlDocImpl())
- return 0;
-
- DocumentFragmentImpl *fragment = xmlDocImpl()->createDocumentFragment();
- NSMutableString *string = [text mutableCopy];
-
- // Replace tabs with four plain spaces.
- // These spaces will get converted along with the other existing spaces below.
- [string replaceOccurrencesOfString:@"\t" withString:@" " options:0 range:NSMakeRange(0, [string length])];
-
- if (!nbspSpaceString) {
- unichar nbspSpace[] = { 0xa0, ' ' };
- nbspSpaceString = [[NSString alloc] initWithCharacters:nbspSpace length:2];
- }
-
- if (!nbspNBSPSpaceString) {
- unichar nbspNBSPSpace[] = { 0xa0, 0xa0, ' ' };
- nbspNBSPSpaceString = [[NSString alloc] initWithCharacters:nbspNBSPSpace length:3];
- }
-
- unsigned stringLength = [string length];
- NSRange range = NSMakeRange(0, stringLength);
- while (1) {
- // FIXME: This only converts plain old spaces, and does not
- // deal with more exotic whitespace. Note that we want to
- // leave newlines and returns alone at this point anyway,
- // since those are handled specially later.
- NSRange replaceRange = [string rangeOfString:@" " options:NSLiteralSearch range:range];
- if (replaceRange.location == NSNotFound)
- break;
-
- // Found two adjoining spaces.
- // Now, lookahead to see if these two spaces are followed by:
- // 1. another space and then a non-space
- // 2. another space and then the end of the string
- // If either 1 or 2 is true, replace the three spaces found with nbsp+nbsp+space,
- // otherwise, replace the first two spaces with nbsp+space.
- unsigned lookahead = replaceRange.location + 2;
- if ((lookahead + 2 < stringLength && [string characterAtIndex:lookahead] == ' ' && [string characterAtIndex:lookahead + 1] != ' ') ||
- (lookahead + 1 == stringLength && [string characterAtIndex:lookahead] == ' ')) {
- replaceRange.length = 3;
- [string replaceCharactersInRange:replaceRange withString:nbspNBSPSpaceString];
- }
- else {
- [string replaceCharactersInRange:replaceRange withString:nbspSpaceString];
- }
- range.location = replaceRange.location + 2;
- range.length = stringLength - range.location;
- }
-
- // Handle line endings, replacing them with BR elements.
- [string replaceOccurrencesOfString:@"\r\n" withString:@"\n" options:0 range:NSMakeRange(0, [string length])];
- [string replaceOccurrencesOfString:@"\r" withString:@"\n" options:0 range:NSMakeRange(0, [string length])];
- NSArray *array = [string componentsSeparatedByString:@"\n"];
- [string release];
- int count = [array count];
- int i;
- for (i = 0; i < count; i++) {
- int exceptionCode = 0;
- if (i != 0) {
- ElementImpl *breakNode = xmlDocImpl()->createHTMLElement("br", exceptionCode);
- ASSERT(exceptionCode == 0);
- fragment->appendChild(breakNode, exceptionCode);
- ASSERT(exceptionCode == 0);
- }
- NSString *component = (NSString *)[array objectAtIndex:i];
- if ([component length] > 0) {
- NodeImpl *textNode = xmlDocImpl()->createTextNode(component);
- fragment->appendChild(textNode, exceptionCode);
- }
- }
-
-
- return fragment;
-}
-
void KWQKHTMLPart::registerCommandForUndo(const EditCommandPtr &cmd)
{
ASSERT(cmd.get());
{
return [_bridge isCharacterSmartReplaceExempt:c.unicode() isPreviousCharacter:isPreviousChar];
}
+
+bool KWQKHTMLPart::isKHTMLPart() const
+{
+ return true;
+}
virtual bool closeURL() = 0;
private:
+ virtual bool isKPartsReadOnlyPart() const;
+
QObject *_parent;
QString _name;
};
_name = name;
}
-};
+bool ReadOnlyPart::isKPartsReadOnlyPart() const
+{
+ return true;
+}
+
+}
/*
- * Copyright (C) 2003 Apple Computer, Inc. All rights reserved.
+ * 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
static bool _defersTimers;
+ virtual bool isKHTMLPart() const;
+ virtual bool isKHTMLView() const;
+ virtual bool isKPartsReadOnlyPart() const;
+ virtual bool isQFrame() const;
+ virtual bool isQScrollView() const;
+
friend class KWQGuardedPtrBase;
friend class KWQSignal;
friend class KWQObjectSenderScope;
/*
- * Copyright (C) 2003 Apple Computer, Inc. All rights reserved.
+ * 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
@end
-// special includes only for inherits
-
-#import "khtml_part.h"
-#import "khtmlview.h"
-
bool QObject::inherits(const char *className) const
{
if (strcmp(className, "KHTMLPart") == 0) {
- return dynamic_cast<const KHTMLPart *>(this);
+ return isKHTMLPart();
}
if (strcmp(className, "KHTMLView") == 0) {
- return dynamic_cast<const KHTMLView *>(this);
+ return isKHTMLView();
}
if (strcmp(className, "KParts::Factory") == 0) {
return false;
}
if (strcmp(className, "KParts::ReadOnlyPart") == 0) {
- return dynamic_cast<const KParts::ReadOnlyPart *>(this);
+ return isKPartsReadOnlyPart();
}
if (strcmp(className, "QFrame") == 0) {
- return dynamic_cast<const QFrame *>(this);
+ return isQFrame();
}
if (strcmp(className, "QScrollView") == 0) {
- return dynamic_cast<const QScrollView *>(this);
+ return isQScrollView();
}
ERROR("class name %s not recognized", className);
return false;
}
+
+bool QObject::isKHTMLPart() const
+{
+ return false;
+}
+
+bool QObject::isKHTMLView() const
+{
+ return false;
+}
+
+bool QObject::isKPartsReadOnlyPart() const
+{
+ return false;
+}
+
+bool QObject::isQFrame() const
+{
+ return false;
+}
+
+bool QObject::isQScrollView() const
+{
+ return false;
+}
}
if (o.isWidget()) {
- KHTMLView *view = dynamic_cast<KHTMLView *>(static_cast<const RenderWidget &>(o).widget());
- if (view) {
+ QWidget *widget = static_cast<const RenderWidget &>(o).widget();
+ if (widget && widget->inherits("KHTMLView")) {
+ KHTMLView *view = static_cast<KHTMLView *>(widget);
RenderObject *root = KWQ(view->part())->renderer();
if (root) {
view->layout();
static void writeSelection(QTextStream &ts, const RenderObject *o)
{
- DocumentImpl *doc = dynamic_cast<DocumentImpl *>(o->element());
- if (!doc || !doc->part())
+ NodeImpl *n = o->element();
+ if (!n || !n->isDocumentNode())
+ return;
+
+ DocumentImpl *doc = static_cast<DocumentImpl *>(n);
+ if (!doc->part())
return;
Selection selection = doc->part()->selection();
/*
- * Copyright (C) 2003 Apple Computer, Inc. All rights reserved.
+ * 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
void ensureRectVisibleCentered(const QRect &r, bool forceCentering=false);
NSView *getDocumentView() const;
+
+private:
+ virtual bool isQScrollView() const;
};
#endif
return nil;
}
+
+bool QScrollView::isQScrollView() const
+{
+ return true;
+}
return;
}
- call();
+ call(job);
}
void KWQSlot::call(KIO::Job *job, NSURLResponse *response) const
QString &prepend(const QString &);
QString &remove(uint, uint);
QString &replace(uint index, uint len, const QString &s);
+ QString &replace(char, const QString &);
+ QString &replace(QChar, const QString &);
+ QString &replace(const QString &, const QString &);
QString &replace(const QRegExp &, const QString &);
QString &replace(QChar, QChar);
return remove(index, len).insert(index, str);
}
+QString &QString::replace(char pattern, const QString &str)
+{
+ int slen = str.dataHandle[0]->_length;
+ int index = 0;
+ while ((index = find(pattern, index)) >= 0) {
+ replace(index, 1, str);
+ index += slen;
+ }
+ return *this;
+}
+
+
+QString &QString::replace(QChar pattern, const QString &str)
+{
+ int slen = str.dataHandle[0]->_length;
+ int index = 0;
+ while ((index = find(pattern, index)) >= 0) {
+ replace(index, 1, str);
+ index += slen;
+ }
+ return *this;
+}
+
+
+QString &QString::replace(const QString &pattern, const QString &str)
+{
+ if (pattern.isEmpty())
+ return *this;
+ int plen = pattern.dataHandle[0]->_length;
+ int slen = str.dataHandle[0]->_length;
+ int index = 0;
+ while ((index = find(pattern, index)) >= 0) {
+ replace(index, plen, str);
+ index += slen;
+ }
+ return *this;
+}
+
+
QString &QString::replace(const QRegExp &qre, const QString &str)
{
if ( isEmpty() )
// FIXME: Since there's no "force ASCII range" mode in CFString, we change the backslash into a yen sign.
// Encoding will change the yen sign back into a backslash.
QString copy = qcs;
- copy.replace('\\', backslashAsCurrencySymbol());
+ copy.replace(QChar('\\'), backslashAsCurrencySymbol());
CFStringRef cfs = copy.getCFString();
CFRange range = CFRangeMake(0, CFStringGetLength(cfs));
#import "kjs_proxy.h"
#import "kjs_window.h"
#import "loader.h"
+#import "markup.h"
#import "render_canvas.h"
#import "render_frames.h"
#import "render_image.h"
using DOM::Position;
using DOM::Range;
+using khtml::ChildrenOnly;
+using khtml::createMarkup;
using khtml::Decoder;
using khtml::DeleteSelectionCommand;
using khtml::EAffinity;
using khtml::EditCommandPtr;
using khtml::ETextGranularity;
+using khtml::IncludeNode;
using khtml::MoveSelectionCommand;
using khtml::parseURL;
using khtml::RenderCanvas;
NSString *WebCorePageCacheStateKey = @"WebCorePageCacheState";
-@interface WebCoreBridge (WebCoreBridgePrivate)
+@interface WebCoreBridge (WebCoreBridgeInternal)
- (RootObject *)executionContextForView:(NSView *)aView;
@end
- (NSString *)markupStringFromNode:(DOMNode *)node nodes:(NSArray **)nodes
{
- QPtrList<NodeImpl> *nodeList = NULL;
+ // FIXME: This is never "for interchange". Is that right? See the next method.
+ QPtrList<NodeImpl> nodeList;
+ NSString *markupString = createMarkup([node _nodeImpl], IncludeNode, nodes ? &nodeList : 0).getNSString();
if (nodes) {
- nodeList = new QPtrList<NodeImpl>;
- }
- NSString *markupString = [node _nodeImpl]->recursive_toHTML(false, nodeList).getNSString();
- if (nodes) {
- *nodes = [self nodesFromList:nodeList];
- delete nodeList;
+ *nodes = [self nodesFromList:&nodeList];
}
return [self _stringWithDocumentTypeStringAndMarkupString:markupString];
}
- (NSString *)markupStringFromRange:(DOMRange *)range nodes:(NSArray **)nodes
{
- QPtrList<NodeImpl> *nodeList = NULL;
- if (nodes) {
- nodeList = new QPtrList<NodeImpl>;
- }
- NSString *markupString = [range _rangeImpl]->toHTML(nodeList, AnnotateForInterchange).string().getNSString();
+ // FIXME: This is always "for interchange". Is that right? See the previous method.
+ QPtrList<NodeImpl> nodeList;
+ NSString *markupString = createMarkup([range _rangeImpl], nodes ? &nodeList : 0, AnnotateForInterchange).getNSString();
if (nodes) {
- *nodes = [self nodesFromList:nodeList];
- delete nodeList;
+ *nodes = [self nodesFromList:&nodeList];
}
return [self _stringWithDocumentTypeStringAndMarkupString:markupString];
}
- (NSString *)selectedString
{
QString text = _part->selectedText();
- text.replace('\\', _part->backslashAsCurrencySymbol());
+ text.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
return [[text.getNSString() copy] autorelease];
}
- (NSString *)stringForRange:(DOMRange *)range
{
QString text = _part->text([range _rangeImpl]);
- text.replace('\\', _part->backslashAsCurrencySymbol());
+ text.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
return [[text.getNSString() copy] autorelease];
}
}
NSObject *copiedNode = [copier nodeWithName:node->nodeName().string().getNSString()
value:node->nodeValue().string().getNSString()
- source:node->recursive_toHTML(true).getNSString()
+ source:createMarkup(node, ChildrenOnly).getNSString()
children:children];
[children release];
return copiedNode;
if (!title.isNull()) {
// We found a node with a title.
QString titleText = title.string();
- titleText.replace('\\', _part->backslashAsCurrencySymbol());
+ titleText.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
[element setObject:titleText.getNSString() forKey:WebCoreElementTitleKey];
break;
}
const AtomicString& title = e->getAttribute(ATTR_TITLE);
if (!title.isEmpty()) {
QString titleText = title.string();
- titleText.replace('\\', _part->backslashAsCurrencySymbol());
+ titleText.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
[element setObject:titleText.getNSString() forKey:WebCoreElementLinkTitleKey];
}
alt = static_cast<HTMLImageElementImpl *>(i)->altText();
if (!alt.isNull()) {
QString altText = alt.string();
- altText.replace('\\', _part->backslashAsCurrencySymbol());
+ altText.replace(QChar('\\'), _part->backslashAsCurrencySymbol());
[element setObject:altText.getNSString() forKey:WebCoreElementImageAltStringKey];
}
}
- (DOMDocumentFragment *)documentFragmentWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString
{
- DocumentImpl *document = _part->xmlDocImpl();
- HTMLElementImpl *element = static_cast<HTMLElementImpl *>(document->documentElement());
- DocumentFragmentImpl *fragment = element->createContextualFragment(markupString);
- ASSERT(fragment);
-
- if ([baseURLString length] > 0) {
- DOM::DOMString baseURL = baseURLString;
- if (baseURL != document->baseURL()) {
- fragment->recursive_completeURLs(baseURL.string());
- }
- }
+ if (!_part || !_part->xmlDocImpl())
+ return 0;
+
+ DocumentFragmentImpl *fragment = createFragmentFromMarkup(_part->xmlDocImpl(), QString::fromNSString(markupString), QString::fromNSString(baseURLString));
return [DOMDocumentFragment _documentFragmentWithImpl:fragment];
}
if (!_part || !_part->xmlDocImpl() || !text)
return 0;
- return [DOMDocumentFragment _documentFragmentWithImpl:_part->documentFragmentWithText(text)];
+ return [DOMDocumentFragment _documentFragmentWithImpl:createFragmentFromText(_part->xmlDocImpl(), QString::fromNSString(text))];
}
- (void)replaceSelectionWithFragment:(DOMDocumentFragment *)fragment selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace
@end
-@implementation WebCoreBridge (WebCoreBridgePrivate)
+@implementation WebCoreBridge (WebCoreBridgeInternal)
- (RootObject *)executionContextForView:(NSView *)aView
{
part->addPluginRootObject(root);
return root;
}
+
@end