[SCM] WebKit Debian packaging branch, debian/unstable, updated. debian/1.1.15-1-40151-g37bb677
kocienda
kocienda at 268f45cc-cd09-0410-ab3c-d52691b4dbfc
Sat Sep 26 08:32:24 UTC 2009
The following commit has been merged in the debian/unstable branch:
commit 65a96e163f2f438228c6675c4e8765433f65fcb9
Author: kocienda <kocienda at 268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date: Tue Apr 6 15:14:30 2004 +0000
WebCore:
Reviewed by Dave
Added execCommand feature.
Added Javascript selection object.
This lays the groundwork for layout tests for editing.
* khtml/dom/dom_doc.cpp:
(DOM::Document::execCommand): Added. Calls through to impl's execCommand.
* khtml/dom/dom_doc.h: Added execCommand declaration.
* khtml/ecma/kjs_dom.cpp:
(DOMDocumentProtoFunc::tryCall): Switch on new ExecCommand constant and call through to the document.
* khtml/ecma/kjs_dom.h: Added ExecCommand constant.
(KJS::DOMDocument::):
* khtml/ecma/kjs_dom.lut.h: Generated file.
* khtml/ecma/kjs_window.cpp:
(Window::Window): Initialize selection object.
(Window::selection): Return window's selection object.
(Window::mark): Mark selection object.
(WindowFunc::tryCall): Return selection object on GetSelection.
(LocationFunc::tryCall): Added.
(Selection::Selection): Added.
(Selection::~Selection): Added.
(Selection::get): Added.
(Selection::put): Added.
(Selection::toPrimitive): Added.
(Selection::toString): Added.
(SelectionFunc::tryCall): Added.
* khtml/ecma/kjs_window.h:
(KJS::Selection::): Added.
(KJS::Selection::part): Added.
(KJS::Selection::classInfo): Added.
* khtml/ecma/kjs_window.lut.h: Generated file.
* khtml/editing/htmlediting_impl.cpp:
(debugPosition): Debugging aid.
(DeleteCollapsibleWhitespaceCommandImpl::deleteWhitespace): Move the ending position
if you are about to delete it. Fixes a crasher I discovered while writing tests.
(DeleteSelectionCommandImpl::doApply): Move to containing editable block position 0
instead of 1 in a block in delete case 1.
(InputTextCommandImpl::prepareForTextInsertion):
(TypingCommandImpl::issueCommandForDeleteKey):
* khtml/khtml_part.h:
* khtml/khtml_selection.cpp:
(KHTMLSelection::validate): Now adjusts the selection down to leaf nodes if needed.
(KHTMLSelection::debugPosition): Debugging aid.
* khtml/xml/dom_docimpl.cpp:
(DocumentImpl::execCommand): Added. Supports five different commands.
* khtml/xml/dom_docimpl.h:
* khtml/xml/dom_nodeimpl.cpp:
(NodeImpl::previousEditable): Use false instead of 0 for equality check.
(NodeImpl::nextEditable): Ditto.
* khtml/xml/dom_position.cpp:
(DOMPosition::equivalentLeafPosition): New function
(DOMPosition::previousRenderedEditablePosition): New function
(DOMPosition::nextRenderedEditablePosition): New function
(DOMPosition::equivalentUpstreamPosition): Refined behavior to handle more cases correctly.
(DOMPosition::equivalentDownstreamPosition): Ditto.
(DOMPosition::atStartOfContainingEditableBlock):New function
(DOMPosition::atStartOfRootEditableBlock):New function
* khtml/xml/dom_position.h:
* kwq/KWQKHTMLPart.h:
* kwq/KWQKHTMLPart.mm:
(KWQKHTMLPart::issueUndoCommand): New function for calling undo programatically.
(KWQKHTMLPart::issueRedoCommand): Ditto, but for redo.
* kwq/KWQRenderTreeDebug.cpp:
(nodePositionRelativeToRoot): New function to generate log information for the selection.
(writeSelection): Writes the selection if there is one.
(externalRepresentation): Calls writeSelection
* kwq/WebCoreBridge.h: New declarations for issueUndoCommand and issueRedoCommand.
WebKit:
Reviewed by Dave
* WebCoreSupport.subproj/WebBridge.m:
(-[WebBridge issueUndoCommand]): New method. Forwards call to the undo manager. Added
to support undo called via Javascript execCommand.
(-[WebBridge issueRedoCommand]): Ditto.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@6314 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/ChangeLog-2005-08-23 b/WebCore/ChangeLog-2005-08-23
index a8c0a1d..bb134fb 100644
--- a/WebCore/ChangeLog-2005-08-23
+++ b/WebCore/ChangeLog-2005-08-23
@@ -1,3 +1,74 @@
+2004-04-06 Ken Kocienda <kocienda at apple.com>
+
+ Reviewed by Dave
+
+ Added execCommand feature.
+ Added Javascript selection object.
+ This lays the groundwork for layout tests for editing.
+
+ * khtml/dom/dom_doc.cpp:
+ (DOM::Document::execCommand): Added. Calls through to impl's execCommand.
+ * khtml/dom/dom_doc.h: Added execCommand declaration.
+ * khtml/ecma/kjs_dom.cpp:
+ (DOMDocumentProtoFunc::tryCall): Switch on new ExecCommand constant and call through to the document.
+ * khtml/ecma/kjs_dom.h: Added ExecCommand constant.
+ (KJS::DOMDocument::):
+ * khtml/ecma/kjs_dom.lut.h: Generated file.
+ * khtml/ecma/kjs_window.cpp:
+ (Window::Window): Initialize selection object.
+ (Window::selection): Return window's selection object.
+ (Window::mark): Mark selection object.
+ (WindowFunc::tryCall): Return selection object on GetSelection.
+ (LocationFunc::tryCall): Added.
+ (Selection::Selection): Added.
+ (Selection::~Selection): Added.
+ (Selection::get): Added.
+ (Selection::put): Added.
+ (Selection::toPrimitive): Added.
+ (Selection::toString): Added.
+ (SelectionFunc::tryCall): Added.
+ * khtml/ecma/kjs_window.h:
+ (KJS::Selection::): Added.
+ (KJS::Selection::part): Added.
+ (KJS::Selection::classInfo): Added.
+ * khtml/ecma/kjs_window.lut.h: Generated file.
+ * khtml/editing/htmlediting_impl.cpp:
+ (debugPosition): Debugging aid.
+ (DeleteCollapsibleWhitespaceCommandImpl::deleteWhitespace): Move the ending position
+ if you are about to delete it. Fixes a crasher I discovered while writing tests.
+ (DeleteSelectionCommandImpl::doApply): Move to containing editable block position 0
+ instead of 1 in a block in delete case 1.
+ (InputTextCommandImpl::prepareForTextInsertion):
+ (TypingCommandImpl::issueCommandForDeleteKey):
+ * khtml/khtml_part.h:
+ * khtml/khtml_selection.cpp:
+ (KHTMLSelection::validate): Now adjusts the selection down to leaf nodes if needed.
+ (KHTMLSelection::debugPosition): Debugging aid.
+ * khtml/xml/dom_docimpl.cpp:
+ (DocumentImpl::execCommand): Added. Supports five different commands.
+ * khtml/xml/dom_docimpl.h:
+ * khtml/xml/dom_nodeimpl.cpp:
+ (NodeImpl::previousEditable): Use false instead of 0 for equality check.
+ (NodeImpl::nextEditable): Ditto.
+ * khtml/xml/dom_position.cpp:
+ (DOMPosition::equivalentLeafPosition): New function
+ (DOMPosition::previousRenderedEditablePosition): New function
+ (DOMPosition::nextRenderedEditablePosition): New function
+ (DOMPosition::equivalentUpstreamPosition): Refined behavior to handle more cases correctly.
+ (DOMPosition::equivalentDownstreamPosition): Ditto.
+ (DOMPosition::atStartOfContainingEditableBlock):New function
+ (DOMPosition::atStartOfRootEditableBlock):New function
+ * khtml/xml/dom_position.h:
+ * kwq/KWQKHTMLPart.h:
+ * kwq/KWQKHTMLPart.mm:
+ (KWQKHTMLPart::issueUndoCommand): New function for calling undo programatically.
+ (KWQKHTMLPart::issueRedoCommand): Ditto, but for redo.
+ * kwq/KWQRenderTreeDebug.cpp:
+ (nodePositionRelativeToRoot): New function to generate log information for the selection.
+ (writeSelection): Writes the selection if there is one.
+ (externalRepresentation): Calls writeSelection
+ * kwq/WebCoreBridge.h: New declarations for issueUndoCommand and issueRedoCommand.
+
2004-04-05 Darin Adler <darin at apple.com>
* khtml/html/kentities.gperf: Added © and ®, both supported by Gecko
diff --git a/WebCore/ForwardingHeaders/dom/dom_position.h b/WebCore/ForwardingHeaders/xml/dom_position.h
similarity index 100%
copy from WebCore/ForwardingHeaders/dom/dom_position.h
copy to WebCore/ForwardingHeaders/xml/dom_position.h
diff --git a/WebCore/WebCore.pbproj/project.pbxproj b/WebCore/WebCore.pbproj/project.pbxproj
index d7f374f..5f826cc 100644
--- a/WebCore/WebCore.pbproj/project.pbxproj
+++ b/WebCore/WebCore.pbproj/project.pbxproj
@@ -1227,12 +1227,6 @@
refType = 4;
sourceTree = "<group>";
};
- 832557C4061E3172007B8054 = {
- fileRef = 832557C3061E3172007B8054;
- isa = PBXBuildFile;
- settings = {
- };
- };
//830
//831
//832
diff --git a/WebCore/khtml/dom/dom_doc.cpp b/WebCore/khtml/dom/dom_doc.cpp
index a4cfaa4..fa5abcc 100644
--- a/WebCore/khtml/dom/dom_doc.cpp
+++ b/WebCore/khtml/dom/dom_doc.cpp
@@ -482,6 +482,14 @@ CSSStyleDeclaration Document::getOverrideStyle(const Element &elt, const DOMStri
return r;
}
+bool Document::execCommand(const DOMString &command, bool userInterface, const DOMString &value)
+{
+ if (!impl)
+ throw DOMException(DOMException::NOT_FOUND_ERR);
+
+ return static_cast<DocumentImpl*>(impl)->execCommand(command, userInterface, value);
+}
+
// ----------------------------------------------------------------------------
DocumentFragment::DocumentFragment() : Node()
diff --git a/WebCore/khtml/dom/dom_doc.h b/WebCore/khtml/dom/dom_doc.h
index b8b333e..62063e9 100644
--- a/WebCore/khtml/dom/dom_doc.h
+++ b/WebCore/khtml/dom/dom_doc.h
@@ -791,6 +791,14 @@ public:
DOMString toString() const;
+
+ /**
+ * not part of the DOM
+ *
+ * executes an editing command
+ */
+ bool execCommand(const DOMString &command, bool userInterface, const DOMString &value);
+
Document( DocumentImpl *i);
protected:
diff --git a/WebCore/khtml/ecma/kjs_dom.cpp b/WebCore/khtml/ecma/kjs_dom.cpp
index ba37766..9950d6a 100644
--- a/WebCore/khtml/ecma/kjs_dom.cpp
+++ b/WebCore/khtml/ecma/kjs_dom.cpp
@@ -714,6 +714,7 @@ void DOMAttr::putValue(ExecState *exec, int token, const Value& value, int /*att
createTreeWalker DOMDocument::CreateTreeWalker DontDelete|Function 4
createEvent DOMDocument::CreateEvent DontDelete|Function 1
getOverrideStyle DOMDocument::GetOverrideStyle DontDelete|Function 2
+ execCommand DOMDocument::ExecCommand DontDelete|Function 3
@end
*/
DEFINE_PROTOTYPE("DOMDocument", DOMDocumentProto)
@@ -893,6 +894,9 @@ Value DOMDocumentProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List
else
return getDOMCSSStyleDeclaration(exec,doc.getOverrideStyle(static_cast<DOM::Element>(arg0),args[1].toString(exec).string()));
}
+ case DOMDocument::ExecCommand: {
+ return Boolean(doc.execCommand(args[0].toString(exec).string(), args[1].toBoolean(exec), args[2].toString(exec).string()));
+ }
default:
break;
}
diff --git a/WebCore/khtml/ecma/kjs_dom.h b/WebCore/khtml/ecma/kjs_dom.h
index 19d4371..2f3a0ee 100644
--- a/WebCore/khtml/ecma/kjs_dom.h
+++ b/WebCore/khtml/ecma/kjs_dom.h
@@ -122,7 +122,7 @@ namespace KJS {
CreateAttributeNS, GetElementsByTagNameNS, GetElementById,
CreateRange, CreateNodeIterator, CreateTreeWalker, DefaultView,
CreateEvent, StyleSheets, PreferredStylesheetSet,
- SelectedStylesheetSet, GetOverrideStyle, ReadyState };
+ SelectedStylesheetSet, GetOverrideStyle, ReadyState, ExecCommand };
};
class DOMAttr : public DOMNode {
diff --git a/WebCore/khtml/ecma/kjs_dom.lut.h b/WebCore/khtml/ecma/kjs_dom.lut.h
index 28ade16..07fa704 100644
--- a/WebCore/khtml/ecma/kjs_dom.lut.h
+++ b/WebCore/khtml/ecma/kjs_dom.lut.h
@@ -148,7 +148,7 @@ const struct HashEntry DOMDocumentProtoTableEntries[] = {
{ "createComment", DOMDocument::CreateComment, DontDelete|Function, 1, &DOMDocumentProtoTableEntries[27] },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
- { "createNodeIterator", DOMDocument::CreateNodeIterator, DontDelete|Function, 3, 0 },
+ { "createNodeIterator", DOMDocument::CreateNodeIterator, DontDelete|Function, 3, &DOMDocumentProtoTableEntries[30] },
{ 0, 0, 0, 0, 0 },
{ "importNode", DOMDocument::ImportNode, DontDelete|Function, 2, 0 },
{ "createElementNS", DOMDocument::CreateElementNS, DontDelete|Function, 2, 0 },
@@ -157,10 +157,11 @@ const struct HashEntry DOMDocumentProtoTableEntries[] = {
{ "getElementById", DOMDocument::GetElementById, DontDelete|Function, 1, 0 },
{ "createRange", DOMDocument::CreateRange, DontDelete|Function, 0, 0 },
{ "createEvent", DOMDocument::CreateEvent, DontDelete|Function, 1, 0 },
- { "getOverrideStyle", DOMDocument::GetOverrideStyle, DontDelete|Function, 2, 0 }
+ { "getOverrideStyle", DOMDocument::GetOverrideStyle, DontDelete|Function, 2, 0 },
+ { "execCommand", DOMDocument::ExecCommand, DontDelete|Function, 3, 0 }
};
-const struct HashTable DOMDocumentProtoTable = { 2, 30, DOMDocumentProtoTableEntries, 23 };
+const struct HashTable DOMDocumentProtoTable = { 2, 31, DOMDocumentProtoTableEntries, 23 };
} // namespace
diff --git a/WebCore/khtml/ecma/kjs_window.cpp b/WebCore/khtml/ecma/kjs_window.cpp
index 5f5ef03..5a33e60 100644
--- a/WebCore/khtml/ecma/kjs_window.cpp
+++ b/WebCore/khtml/ecma/kjs_window.cpp
@@ -53,10 +53,19 @@
#include "khtmlview.h"
#include "khtml_part.h"
+#include "khtml_selection.h"
+#include "dom/dom_string.h"
+#include "dom/dom_node.h"
+#include "editing/htmlediting.h"
#include "xml/dom2_eventsimpl.h"
#include "xml/dom_docimpl.h"
#include "html/html_documentimpl.h"
+using DOM::DocumentImpl;
+using DOM::DOMString;
+using DOM::Node;
+using khtml::TypingCommand;
+
using namespace KJS;
namespace KJS {
@@ -279,7 +288,7 @@ const ClassInfo Window::info = { "Window", 0, &WindowTable, 0 };
IMPLEMENT_PROTOFUNC(WindowFunc)
Window::Window(KHTMLPart *p)
- : ObjectImp(/*no proto*/), m_part(p), screen(0), history(0), frames(0), loc(0), m_evt(0)
+ : ObjectImp(/*no proto*/), m_part(p), screen(0), history(0), frames(0), loc(0), m_selection(0), m_evt(0)
{
winq = new WindowQObject(this);
//kdDebug(6070) << "Window::Window this=" << this << " part=" << m_part << " " << m_part->name() << endl;
@@ -339,6 +348,13 @@ Location *Window::location() const
return loc;
}
+Selection *Window::selection() const
+{
+ if (!m_selection)
+ const_cast<Window*>(this)->m_selection = new Selection(m_part);
+ return m_selection;
+}
+
// reference our special objects during garbage collection
void Window::mark()
{
@@ -352,6 +368,8 @@ void Window::mark()
//kdDebug(6070) << "Window::mark " << this << " marking loc=" << loc << endl;
if (loc && !loc->marked())
loc->mark();
+ if (m_selection && !m_selection->marked())
+ m_selection->mark();
}
bool Window::hasProperty(ExecState * /*exec*/, const Identifier &/*p*/) const
@@ -1545,7 +1563,7 @@ Value WindowFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
case Window::GetSelection:
if (!window->isSafeScript(exec))
return Undefined();
- return String(part->selectedText());
+ return Value(window->selection());
case Window::Blur:
#if APPLE_CHANGES
KWQ(part)->unfocusWindow();
@@ -2079,6 +2097,196 @@ Value LocationFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
return Undefined();
}
+////////////////////// Selection Object ////////////////////////
+
+const ClassInfo Selection::info = { "Selection", 0, 0, 0 };
+/*
+ at begin SelectionTable 19
+ anchorNode Selection::AnchorNode DontDelete|ReadOnly
+ anchorOffset Selection::AnchorOffset DontDelete|ReadOnly
+ focusNode Selection::FocusNode DontDelete|ReadOnly
+ focusOffset Selection::FocusOffset DontDelete|ReadOnly
+ baseNode Selection::AnchorNode DontDelete|ReadOnly
+ baseOffset Selection::AnchorOffset DontDelete|ReadOnly
+ extentNode Selection::FocusNode DontDelete|ReadOnly
+ extentOffset Selection::FocusOffset DontDelete|ReadOnly
+ isCollapsed Selection::IsCollapsed DontDelete|ReadOnly
+ type Selection::_Type DontDelete|ReadOnly
+ [[==]] Selection::EqualEqual DontDelete|ReadOnly
+ toString Selection::ToString DontDelete|Function 0
+ collapse Selection::Collapse DontDelete|Function 2
+ collapseToEnd Selection::CollapseToEnd DontDelete|Function 0
+ collapseToStart Selection::CollapseToStart DontDelete|Function 0
+ empty Selection::Empty DontDelete|Function 0
+ setBaseAndExtent Selection::SetBaseAndExtent DontDelete|Function 4
+ setPosition Selection::SetPosition DontDelete|Function 2
+ modify Selection::Modify DontDelete|Function 3
+ at end
+*/
+IMPLEMENT_PROTOFUNC(SelectionFunc)
+Selection::Selection(KHTMLPart *p) : m_part(p)
+{
+ //kdDebug(6070) << "Selection::Selection " << this << " m_part=" << (void*)m_part << endl;
+}
+
+Selection::~Selection()
+{
+ //kdDebug(6070) << "Selection::~Selection " << this << " m_part=" << (void*)m_part << endl;
+}
+
+Value Selection::get(ExecState *exec, const Identifier &p) const
+{
+#ifdef KJS_VERBOSE
+ kdDebug(6070) << "Selection::get " << p.qstring() << " m_part=" << (void*)m_part << endl;
+#endif
+
+ if (m_part.isNull())
+ return Undefined();
+
+ const Window* window = Window::retrieveWindow(m_part);
+ if (!window || !window->isSafeScript(exec))
+ return Undefined();
+
+ DocumentImpl *docimpl = m_part->xmlDocImpl();
+ if (docimpl)
+ docimpl->updateLayout();
+
+ KURL url = m_part->url();
+ const HashEntry *entry = Lookup::findEntry(&SelectionTable, p);
+ if (entry)
+ switch (entry->value) {
+ case AnchorNode:
+ case BaseNode:
+ return getDOMNode(exec, Node(m_part->selection().baseNode()));
+ case AnchorOffset:
+ case BaseOffset:
+ return Number(m_part->selection().baseOffset());
+ case FocusNode:
+ case ExtentNode:
+ return getDOMNode(exec, Node(m_part->selection().extentNode()));
+ case FocusOffset:
+ case ExtentOffset:
+ return Number(m_part->selection().extentOffset());
+ case IsCollapsed:
+ return Boolean(m_part->selection().state() == KHTMLSelection::CARET);
+ case _Type: {
+ switch (m_part->selection().state()) {
+ case KHTMLSelection::NONE:
+ return String("None");
+ case KHTMLSelection::CARET:
+ return String("Caret");
+ case KHTMLSelection::RANGE:
+ return String("Range");
+ }
+ }
+ case EqualEqual:
+ return String(toString(exec));
+ case ToString:
+ return lookupOrCreateFunction<SelectionFunc>(exec,p,this,entry->value,entry->params,entry->attr);
+ }
+ // Look for overrides
+ ValueImp * val = ObjectImp::getDirect(p);
+ if (val)
+ return Value(val);
+ if (entry)
+ switch (entry->value) {
+ case Collapse:
+ case CollapseToEnd:
+ case CollapseToStart:
+ case Empty:
+ case SetBaseAndExtent:
+ case SetPosition:
+ case Modify:
+ return lookupOrCreateFunction<SelectionFunc>(exec,p,this,entry->value,entry->params,entry->attr);
+ }
+
+ return Undefined();
+}
+
+void Selection::put(ExecState *exec, const Identifier &p, const Value &v, int attr)
+{
+}
+
+Value Selection::toPrimitive(ExecState *exec, Type) const
+{
+ return String(toString(exec));
+}
+
+UString Selection::toString(ExecState *) const
+{
+ if (m_part->selection().state() != KHTMLSelection::RANGE)
+ return UString("");
+ return UString(m_part->selection().toRange().toString());
+}
+
+Value SelectionFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
+{
+ if (!thisObj.inherits(&Selection::info)) {
+ Object err = Error::create(exec,TypeError);
+ exec->setException(err);
+ return err;
+ }
+ Selection *selection = static_cast<Selection *>(thisObj.imp());
+ KHTMLPart *part = selection->part();
+ if (part) {
+ DocumentImpl *docimpl = part->xmlDocImpl();
+ if (docimpl)
+ docimpl->updateLayout();
+
+ switch (id) {
+ case Selection::Collapse:
+ TypingCommand::closeTyping(part->lastEditCommand());
+ part->setSelection(KHTMLSelection(KJS::toNode(args[0]).handle(), args[1].toInt32(exec)));
+ break;
+ case Selection::CollapseToEnd:
+ TypingCommand::closeTyping(part->lastEditCommand());
+ part->setSelection(KHTMLSelection(part->selection().endPosition()));
+ break;
+ case Selection::CollapseToStart:
+ TypingCommand::closeTyping(part->lastEditCommand());
+ part->setSelection(KHTMLSelection(part->selection().startPosition()));
+ break;
+ case Selection::Empty:
+ TypingCommand::closeTyping(part->lastEditCommand());
+ part->clearSelection();
+ break;
+ case Selection::SetBaseAndExtent:
+ TypingCommand::closeTyping(part->lastEditCommand());
+ part->setSelection(KHTMLSelection(KJS::toNode(args[0]).handle(), args[1].toInt32(exec), KJS::toNode(args[2]).handle(), args[3].toInt32(exec)));
+ break;
+ case Selection::SetPosition:
+ TypingCommand::closeTyping(part->lastEditCommand());
+ part->setSelection(KHTMLSelection(KJS::toNode(args[0]).handle(), args[1].toInt32(exec)));
+ break;
+ case Selection::Modify: {
+ TypingCommand::closeTyping(part->lastEditCommand());
+ KHTMLSelection s(part->selection());
+ KHTMLSelection::EAlter alter = KHTMLSelection::MOVE;
+ if (args[0].toString(exec).string().lower() == "extend")
+ alter = KHTMLSelection::EXTEND;
+ DOMString directionString = args[1].toString(exec).string().lower();
+ KHTMLSelection::EDirection direction = KHTMLSelection::FORWARD;
+ if (directionString == "backward")
+ direction = KHTMLSelection::BACKWARD;
+ else if (directionString == "left")
+ direction = KHTMLSelection::LEFT;
+ if (directionString == "right")
+ direction = KHTMLSelection::RIGHT;
+ KHTMLSelection::ETextGranularity granularity = KHTMLSelection::CHARACTER;
+ DOMString granularityString = args[2].toString(exec).string().lower();
+ if (granularityString == "word")
+ granularity = KHTMLSelection::WORD;
+ else if (granularityString == "line")
+ granularity = KHTMLSelection::LINE;
+ s.modify(alter, direction, granularity);
+ part->setSelection(s);
+ }
+ }
+ }
+
+ return Undefined();
+}
+
////////////////////// History Object ////////////////////////
const ClassInfo History::info = { "History", 0, 0, 0 };
diff --git a/WebCore/khtml/ecma/kjs_window.h b/WebCore/khtml/ecma/kjs_window.h
index 793d2c9..af210de 100644
--- a/WebCore/khtml/ecma/kjs_window.h
+++ b/WebCore/khtml/ecma/kjs_window.h
@@ -38,6 +38,7 @@ namespace KJS {
class WindowFunc;
class WindowQObject;
class Location;
+ class Selection;
class History;
class FrameArray;
class JSEventListener;
@@ -100,6 +101,7 @@ namespace KJS {
void scheduleClose();
bool isSafeScript(ExecState *exec) const;
Location *location() const;
+ Selection *selection() const;
JSEventListener *getJSEventListener(const Value &val, bool html = false);
JSLazyEventListener *getJSLazyEventListener(const QString &code, bool html = false);
void clear( ExecState *exec );
@@ -136,6 +138,7 @@ namespace KJS {
History *history;
FrameArray *frames;
Location *loc;
+ Selection *m_selection;
WindowQObject *winq;
DOM::Event *m_evt;
};
@@ -203,6 +206,25 @@ namespace KJS {
QGuardedPtr<KHTMLPart> m_part;
};
+ class Selection : public ObjectImp {
+ public:
+ ~Selection();
+ virtual Value get(ExecState *exec, const Identifier &propertyName) const;
+ virtual void put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr = None);
+ virtual Value toPrimitive(ExecState *exec, Type preferred) const;
+ virtual UString toString(ExecState *exec) const;
+ enum { AnchorNode, AnchorOffset, FocusNode, FocusOffset, BaseNode, BaseOffset, ExtentNode, ExtentOffset,
+ IsCollapsed, _Type, EqualEqual, Collapse, CollapseToEnd, CollapseToStart, Empty, ToString,
+ SetBaseAndExtent, SetPosition, Modify };
+ KHTMLPart *part() const { return m_part; }
+ virtual const ClassInfo* classInfo() const { return &info; }
+ static const ClassInfo info;
+ private:
+ friend class Window;
+ Selection(KHTMLPart *p);
+ QGuardedPtr<KHTMLPart> m_part;
+ };
+
#ifdef Q_WS_QWS
class Konqueror : public ObjectImp {
friend class KonquerorFunc;
diff --git a/WebCore/khtml/ecma/kjs_window.lut.h b/WebCore/khtml/ecma/kjs_window.lut.h
index b5f017c..a3efca1 100644
--- a/WebCore/khtml/ecma/kjs_window.lut.h
+++ b/WebCore/khtml/ecma/kjs_window.lut.h
@@ -176,6 +176,42 @@ const struct HashTable LocationTable = { 2, 16, LocationTableEntries, 11 };
namespace KJS {
+const struct HashEntry SelectionTableEntries[] = {
+ { "focusOffset", Selection::FocusOffset, DontDelete|ReadOnly, 0, &SelectionTableEntries[20] },
+ { 0, 0, 0, 0, 0 },
+ { "modify", Selection::Modify, DontDelete|Function, 3, 0 },
+ { "focusNode", Selection::FocusNode, DontDelete|ReadOnly, 0, &SelectionTableEntries[19] },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "extentOffset", Selection::FocusOffset, DontDelete|ReadOnly, 0, 0 },
+ { "setPosition", Selection::SetPosition, DontDelete|Function, 2, 0 },
+ { "empty", Selection::Empty, DontDelete|Function, 0, 0 },
+ { "extentNode", Selection::FocusNode, DontDelete|ReadOnly, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "type", Selection::_Type, DontDelete|ReadOnly, 0, 0 },
+ { "collapseToEnd", Selection::CollapseToEnd, DontDelete|Function, 0, &SelectionTableEntries[25] },
+ { "anchorOffset", Selection::AnchorOffset, DontDelete|ReadOnly, 0, &SelectionTableEntries[22] },
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ { "anchorNode", Selection::AnchorNode, DontDelete|ReadOnly, 0, &SelectionTableEntries[21] },
+ { "baseNode", Selection::AnchorNode, DontDelete|ReadOnly, 0, &SelectionTableEntries[23] },
+ { "baseOffset", Selection::AnchorOffset, DontDelete|ReadOnly, 0, 0 },
+ { "isCollapsed", Selection::IsCollapsed, DontDelete|ReadOnly, 0, 0 },
+ { "[[==]]", Selection::EqualEqual, DontDelete|ReadOnly, 0, &SelectionTableEntries[24] },
+ { "toString", Selection::ToString, DontDelete|Function, 0, &SelectionTableEntries[26] },
+ { "collapse", Selection::Collapse, DontDelete|Function, 2, 0 },
+ { "collapseToStart", Selection::CollapseToStart, DontDelete|Function, 0, 0 },
+ { "setBaseAndExtent", Selection::SetBaseAndExtent, DontDelete|Function, 4, 0 }
+};
+
+const struct HashTable SelectionTable = { 2, 27, SelectionTableEntries, 19 };
+
+} // namespace
+
+namespace KJS {
+
const struct HashEntry HistoryTableEntries[] = {
{ 0, 0, 0, 0, 0 },
{ "back", History::Back, DontDelete|Function, 0, &HistoryTableEntries[4] },
diff --git a/WebCore/khtml/editing/SelectionController.cpp b/WebCore/khtml/editing/SelectionController.cpp
index 46cb6ed..6107244 100644
--- a/WebCore/khtml/editing/SelectionController.cpp
+++ b/WebCore/khtml/editing/SelectionController.cpp
@@ -528,6 +528,23 @@ void KHTMLSelection::setEndOffset(long offset)
void KHTMLSelection::validate(ETextGranularity expandTo)
{
+ // move the base and extent nodes to their equivalent leaf positions
+ bool baseAndExtentEqual = m_baseNode == m_extentNode && m_baseOffset == m_extentOffset;
+ if (m_baseNode) {
+ DOMPosition pos = basePosition().equivalentLeafPosition();
+ m_baseNode = pos.node();
+ m_baseOffset = pos.offset();
+ if (baseAndExtentEqual) {
+ m_extentNode = pos.node();
+ m_extentOffset = pos.offset();
+ }
+ }
+ if (m_extentNode && !baseAndExtentEqual) {
+ DOMPosition pos = extentPosition().equivalentLeafPosition();
+ m_extentNode = pos.node();
+ m_extentOffset = pos.offset();
+ }
+
// make sure we do not have a dangling start or end
if (!m_baseNode && !m_extentNode) {
setBaseOffset(0);
@@ -1012,14 +1029,14 @@ void KHTMLSelection::debugPosition() const
fprintf(stderr, "downstream: %s %p:%d\n", getTagName(downstream.node()->id()).string().latin1(), downstream.node(), downstream.offset());
}
else {
- DOMPosition pos = endPosition();
+ DOMPosition pos = startPosition();
DOMPosition upstream = pos.equivalentUpstreamPosition();
DOMPosition downstream = pos.equivalentDownstreamPosition();
fprintf(stderr, "upstream: %s %p:%d\n", getTagName(upstream.node()->id()).string().latin1(), upstream.node(), upstream.offset());
fprintf(stderr, "start: %s %p:%d\n", getTagName(pos.node()->id()).string().latin1(), pos.node(), pos.offset());
fprintf(stderr, "downstream: %s %p:%d\n", getTagName(downstream.node()->id()).string().latin1(), downstream.node(), downstream.offset());
fprintf(stderr, "-----------------------------------\n");
- pos = startPosition();
+ pos = endPosition();
upstream = pos.equivalentUpstreamPosition();
downstream = pos.equivalentDownstreamPosition();
fprintf(stderr, "upstream: %s %p:%d\n", getTagName(upstream.node()->id()).string().latin1(), upstream.node(), upstream.offset());
diff --git a/WebCore/khtml/editing/htmlediting_impl.cpp b/WebCore/khtml/editing/htmlediting_impl.cpp
index 8883984..a1f1930 100644
--- a/WebCore/khtml/editing/htmlediting_impl.cpp
+++ b/WebCore/khtml/editing/htmlediting_impl.cpp
@@ -232,6 +232,11 @@ static DOMString &nonBreakingSpaceString()
return nonBreakingSpaceString;
}
+static void debugPosition(const char *prefix, const DOMPosition &pos)
+{
+ LOG(Editing, "%s%s %p : %d", prefix, getTagName(pos.node()->id()).string().latin1(), pos.node(), pos.offset());
+}
+
//------------------------------------------------------------------------------------------
// EditCommandImpl
@@ -672,6 +677,8 @@ DOMPosition DeleteCollapsibleWhitespaceCommandImpl::deleteWhitespace(const DOMPo
unsigned long count = it.current().offset() - deleteStart.offset();
if (count == textNode->length()) {
LOG(Editing, " removeNodeAndPrune 1: [%p]\n", textNode);
+ if (textNode == endingPosition.node())
+ endingPosition = DOMPosition(next.node(), next.node()->caretMinOffset());
removeNodeAndPrune(textNode);
}
else {
@@ -794,13 +801,6 @@ void DeleteSelectionCommandImpl::joinTextNodesWithSameStyle()
}
}
-static void debugPosition(const char *prefix, const DOMPosition &pos)
-{
- LOG(Editing, "%s%s %p : %d", prefix, getTagName(pos.node()->id()).string().latin1(), pos.node(), pos.offset());
-}
-
-enum { NoPositionModification, MoveDownstreamPositionModification, MoveToNextCharacterModification };
-
void DeleteSelectionCommandImpl::doApply()
{
if (m_selectionToDelete.state() != KHTMLSelection::RANGE)
@@ -846,7 +846,7 @@ void DeleteSelectionCommandImpl::doApply()
// Start is not completely selected
if (startAtStartOfBlock) {
LOG(Editing, "ending position case 1");
- endingPosition = DOMPosition(downstreamStart.node()->containingEditableBlock(), 1);
+ endingPosition = DOMPosition(downstreamStart.node()->containingEditableBlock(), 0);
adjustEndingPositionDownstream = true;
}
else if (!startCompletelySelected) {
@@ -1123,6 +1123,8 @@ DOMPosition InputTextCommandImpl::prepareForTextInsertion()
ASSERT(selection.state() == KHTMLSelection::CARET);
DOMPosition pos = selection.startPosition().equivalentUpstreamPosition();
+ if (!pos.inRenderedContent())
+ pos = pos.nextRenderedEditablePosition();
if (!pos.node()->inSameContainingEditableBlock(selection.startNode()))
pos = selection.startPosition();
@@ -1135,12 +1137,14 @@ DOMPosition InputTextCommandImpl::prepareForTextInsertion()
if (pos.node()->isEditableBlock())
appendNode(pos.node(), m_insertedTextNode);
- else if (pos.node()->id() == ID_BR || pos.offset() == 1)
- insertNodeAfter(m_insertedTextNode, pos.node());
- else {
- ASSERT(pos.offset() == 0);
+ else if (pos.node()->id() == ID_BR && pos.offset() == 1)
insertNodeBefore(m_insertedTextNode, pos.node());
- }
+ else if (pos.node()->caretMinOffset() == pos.offset())
+ insertNodeBefore(m_insertedTextNode, pos.node());
+ else if (pos.node()->caretMaxOffset() == pos.offset())
+ insertNodeAfter(m_insertedTextNode, pos.node());
+ else
+ ASSERT_NOT_REACHED();
pos = DOMPosition(m_insertedTextNode, 0);
}
@@ -1153,7 +1157,10 @@ void InputTextCommandImpl::execute(const DOMString &text)
KHTMLSelection selection = currentSelection();
// Delete the current selection
- deleteSelection();
+ if (selection.state() == KHTMLSelection::RANGE)
+ deleteSelection();
+ else
+ deleteCollapsibleWhitespace();
// Make sure the document is set up to receive text
DOMPosition pos = prepareForTextInsertion();
@@ -1711,15 +1718,12 @@ void TypingCommandImpl::issueCommandForDeleteKey()
if (selection.state() == KHTMLSelection::CARET) {
KHTMLSelection selectionToDelete(selection.startPosition().previousCharacterPosition(), selection.startPosition());
- setEndingSelection(selectionToDelete);
- deleteCollapsibleWhitespace();
- selection = currentSelection();
- deleteSelection(selection);
+ deleteCollapsibleWhitespace(selectionToDelete);
}
else { // selection.state() == KHTMLSelection::RANGE
deleteCollapsibleWhitespace();
- deleteSelection();
}
+ deleteSelection(endingSelection());
}
void TypingCommandImpl::deleteKeyPressed()
diff --git a/WebCore/khtml/editing/selection.cpp b/WebCore/khtml/editing/selection.cpp
index 46cb6ed..6107244 100644
--- a/WebCore/khtml/editing/selection.cpp
+++ b/WebCore/khtml/editing/selection.cpp
@@ -528,6 +528,23 @@ void KHTMLSelection::setEndOffset(long offset)
void KHTMLSelection::validate(ETextGranularity expandTo)
{
+ // move the base and extent nodes to their equivalent leaf positions
+ bool baseAndExtentEqual = m_baseNode == m_extentNode && m_baseOffset == m_extentOffset;
+ if (m_baseNode) {
+ DOMPosition pos = basePosition().equivalentLeafPosition();
+ m_baseNode = pos.node();
+ m_baseOffset = pos.offset();
+ if (baseAndExtentEqual) {
+ m_extentNode = pos.node();
+ m_extentOffset = pos.offset();
+ }
+ }
+ if (m_extentNode && !baseAndExtentEqual) {
+ DOMPosition pos = extentPosition().equivalentLeafPosition();
+ m_extentNode = pos.node();
+ m_extentOffset = pos.offset();
+ }
+
// make sure we do not have a dangling start or end
if (!m_baseNode && !m_extentNode) {
setBaseOffset(0);
@@ -1012,14 +1029,14 @@ void KHTMLSelection::debugPosition() const
fprintf(stderr, "downstream: %s %p:%d\n", getTagName(downstream.node()->id()).string().latin1(), downstream.node(), downstream.offset());
}
else {
- DOMPosition pos = endPosition();
+ DOMPosition pos = startPosition();
DOMPosition upstream = pos.equivalentUpstreamPosition();
DOMPosition downstream = pos.equivalentDownstreamPosition();
fprintf(stderr, "upstream: %s %p:%d\n", getTagName(upstream.node()->id()).string().latin1(), upstream.node(), upstream.offset());
fprintf(stderr, "start: %s %p:%d\n", getTagName(pos.node()->id()).string().latin1(), pos.node(), pos.offset());
fprintf(stderr, "downstream: %s %p:%d\n", getTagName(downstream.node()->id()).string().latin1(), downstream.node(), downstream.offset());
fprintf(stderr, "-----------------------------------\n");
- pos = startPosition();
+ pos = endPosition();
upstream = pos.equivalentUpstreamPosition();
downstream = pos.equivalentDownstreamPosition();
fprintf(stderr, "upstream: %s %p:%d\n", getTagName(upstream.node()->id()).string().latin1(), upstream.node(), upstream.offset());
diff --git a/WebCore/khtml/khtml_part.h b/WebCore/khtml/khtml_part.h
index 22678e5..4fb2241 100644
--- a/WebCore/khtml/khtml_part.h
+++ b/WebCore/khtml/khtml_part.h
@@ -87,6 +87,8 @@ namespace khtml
};
namespace KJS {
+ class Selection;
+ class SelectionFunc;
class Window;
class WindowFunc;
class JSEventListener;
@@ -152,6 +154,8 @@ class KHTMLPart : public KParts::ReadOnlyPart
friend class KHTMLRun;
friend class DOM::HTMLFormElementImpl;
friend class khtml::RenderPartObject;
+ friend class KJS::Selection;
+ friend class KJS::SelectionFunc;
friend class KJS::Window;
friend class KJS::WindowFunc;
friend class KJS::JSEventListener;
diff --git a/WebCore/khtml/khtml_selection.cpp b/WebCore/khtml/khtml_selection.cpp
index 46cb6ed..6107244 100644
--- a/WebCore/khtml/khtml_selection.cpp
+++ b/WebCore/khtml/khtml_selection.cpp
@@ -528,6 +528,23 @@ void KHTMLSelection::setEndOffset(long offset)
void KHTMLSelection::validate(ETextGranularity expandTo)
{
+ // move the base and extent nodes to their equivalent leaf positions
+ bool baseAndExtentEqual = m_baseNode == m_extentNode && m_baseOffset == m_extentOffset;
+ if (m_baseNode) {
+ DOMPosition pos = basePosition().equivalentLeafPosition();
+ m_baseNode = pos.node();
+ m_baseOffset = pos.offset();
+ if (baseAndExtentEqual) {
+ m_extentNode = pos.node();
+ m_extentOffset = pos.offset();
+ }
+ }
+ if (m_extentNode && !baseAndExtentEqual) {
+ DOMPosition pos = extentPosition().equivalentLeafPosition();
+ m_extentNode = pos.node();
+ m_extentOffset = pos.offset();
+ }
+
// make sure we do not have a dangling start or end
if (!m_baseNode && !m_extentNode) {
setBaseOffset(0);
@@ -1012,14 +1029,14 @@ void KHTMLSelection::debugPosition() const
fprintf(stderr, "downstream: %s %p:%d\n", getTagName(downstream.node()->id()).string().latin1(), downstream.node(), downstream.offset());
}
else {
- DOMPosition pos = endPosition();
+ DOMPosition pos = startPosition();
DOMPosition upstream = pos.equivalentUpstreamPosition();
DOMPosition downstream = pos.equivalentDownstreamPosition();
fprintf(stderr, "upstream: %s %p:%d\n", getTagName(upstream.node()->id()).string().latin1(), upstream.node(), upstream.offset());
fprintf(stderr, "start: %s %p:%d\n", getTagName(pos.node()->id()).string().latin1(), pos.node(), pos.offset());
fprintf(stderr, "downstream: %s %p:%d\n", getTagName(downstream.node()->id()).string().latin1(), downstream.node(), downstream.offset());
fprintf(stderr, "-----------------------------------\n");
- pos = startPosition();
+ pos = endPosition();
upstream = pos.equivalentUpstreamPosition();
downstream = pos.equivalentDownstreamPosition();
fprintf(stderr, "upstream: %s %p:%d\n", getTagName(upstream.node()->id()).string().latin1(), upstream.node(), upstream.offset());
diff --git a/WebCore/khtml/xml/dom_docimpl.cpp b/WebCore/khtml/xml/dom_docimpl.cpp
index 4259244..c351083 100644
--- a/WebCore/khtml/xml/dom_docimpl.cpp
+++ b/WebCore/khtml/xml/dom_docimpl.cpp
@@ -2641,6 +2641,51 @@ DOMString DocumentImpl::toString() const
#endif // APPLE_CHANGES
+bool DocumentImpl::execCommand(const DOMString &command, bool userInterface, const DOMString &value)
+{
+ static AtomicString selectAllCommand("selectall");
+ static AtomicString insertTextCommand("inserttext");
+ static AtomicString undoCommand("undo");
+ static AtomicString redoCommand("redo");
+ static AtomicString deleteCommand("delete");
+
+ updateLayout();
+
+ AtomicString atom(command.lower());
+ if (atom == selectAllCommand) {
+ if (!part())
+ return false;
+ part()->selectAll();
+ return true;
+ }
+ else if (atom == insertTextCommand) {
+ if (!part() || part()->selection().isEmpty())
+ return false;
+ TypingCommand::insertText(this, value);
+ return true;
+ }
+ else if (atom == undoCommand) {
+ if (!part())
+ return false;
+ KWQ(part())->issueUndoCommand();
+ return true;
+ }
+ else if (atom == redoCommand) {
+ if (!part())
+ return false;
+ KWQ(part())->issueRedoCommand();
+ return true;
+ }
+ else if (atom == deleteCommand) {
+ if (!part() || part()->selection().isEmpty())
+ return false;
+ TypingCommand::deleteKeyPressed(this);
+ return true;
+ }
+
+ return false;
+}
+
// ----------------------------------------------------------------------------
DocumentFragmentImpl::DocumentFragmentImpl(DocumentPtr *doc) : NodeBaseImpl(doc)
diff --git a/WebCore/khtml/xml/dom_docimpl.h b/WebCore/khtml/xml/dom_docimpl.h
index 1f7ce9c..09f587d 100644
--- a/WebCore/khtml/xml/dom_docimpl.h
+++ b/WebCore/khtml/xml/dom_docimpl.h
@@ -497,6 +497,8 @@ public:
DOMString toString() const;
+ bool execCommand(const DOMString &command, bool userInterface, const DOMString &value);
+
#ifndef KHTML_NO_XBL
// XBL methods
XBL::XBLBindingManager* bindingManager() const { return m_bindingManager; }
diff --git a/WebCore/khtml/xml/dom_nodeimpl.cpp b/WebCore/khtml/xml/dom_nodeimpl.cpp
index 6493a1e..f526e91 100644
--- a/WebCore/khtml/xml/dom_nodeimpl.cpp
+++ b/WebCore/khtml/xml/dom_nodeimpl.cpp
@@ -1156,7 +1156,7 @@ NodeImpl *NodeImpl::previousEditable() const
while (node) {
if (!node->isContentEditable())
return 0;
- if (node->hasChildNodes() == 0)
+ if (node->hasChildNodes() == false)
return node;
node = node->traversePreviousNode();
}
@@ -1169,7 +1169,7 @@ NodeImpl *NodeImpl::nextEditable() const
while (node) {
if (!node->isContentEditable())
return 0;
- if (node->hasChildNodes() == 0)
+ if (node->hasChildNodes() == false)
return node;
node = node->traverseNextNode();
}
diff --git a/WebCore/khtml/xml/dom_position.cpp b/WebCore/khtml/xml/dom_position.cpp
index cee8535..e2ef22a 100644
--- a/WebCore/khtml/xml/dom_position.cpp
+++ b/WebCore/khtml/xml/dom_position.cpp
@@ -118,6 +118,66 @@ long DOMPosition::renderedOffset() const
return result;
}
+DOMPosition DOMPosition::equivalentLeafPosition() const
+{
+ if (node()->hasChildNodes() == false)
+ return *this;
+
+ NodeImpl *n = node();
+ int count = 0;
+ while (1) {
+ n = n->nextLeafNode();
+ if (!n)
+ return *this;
+ if (count + n->maxOffset() >= offset()) {
+ count = offset() - count;
+ break;
+ }
+ count += n->maxOffset();
+ }
+ return DOMPosition(n, count);
+}
+
+DOMPosition DOMPosition::previousRenderedEditablePosition() const
+{
+ if (isEmpty())
+ return DOMPosition();
+
+ if (node()->isContentEditable() && node()->hasChildNodes() == false && inRenderedContent())
+ return *this;
+
+ NodeImpl *n = node();
+ while (1) {
+ n = n->previousEditable();
+ if (!n)
+ return DOMPosition();
+ if (n->renderer() && n->renderer()->style()->visibility() == khtml::VISIBLE)
+ break;
+ }
+
+ return DOMPosition(n, 0);
+}
+
+DOMPosition DOMPosition::nextRenderedEditablePosition() const
+{
+ if (isEmpty())
+ return DOMPosition();
+
+ if (node()->isContentEditable() && node()->hasChildNodes() == false && inRenderedContent())
+ return *this;
+
+ NodeImpl *n = node();
+ while (1) {
+ n = n->nextEditable();
+ if (!n)
+ return DOMPosition();
+ if (n->renderer() && n->renderer()->style()->visibility() == khtml::VISIBLE)
+ break;
+ }
+
+ return DOMPosition(n, 0);
+}
+
DOMPosition DOMPosition::previousCharacterPosition() const
{
if (isEmpty())
@@ -177,27 +237,47 @@ DOMPosition DOMPosition::equivalentUpstreamPosition() const
if (!node())
return DOMPosition();
- if (!node()->isTextNode() && offset() > node()->caretMinOffset())
- return *this;
-
NodeImpl *block = node()->containingEditableBlock();
-
- EditIterator it(*this);
- DOMPosition prev = it.peekPrevious();
- if (validUpstreamDownstreamPosition() && prev.validUpstreamDownstreamPosition()) {
- if (node() == prev.node())
- return *this;
- else
- return prev;
- }
- while (!it.atStart()) {
- it.previous();
- if (it.current().validUpstreamDownstreamPosition())
- return it.current();
+
+ EditIterator it(*this);
+ for (; !it.atStart(); it.previous()) {
if (block != it.current().node()->containingEditableBlock())
return it.next();
+
+ if (!node()->isContentEditable())
+ return it.next();
+
+ RenderObject *renderer = it.current().node()->renderer();
+ if (!renderer)
+ continue;
+
+ if (renderer->style()->visibility() != khtml::VISIBLE)
+ continue;
+
+ if (renderer->isBlockFlow() || renderer->isReplaced() || renderer->isBR()) {
+ if (it.current().offset() >= renderer->caretMaxOffset())
+ return DOMPosition(it.current().node(), renderer->caretMaxOffset());
+ else
+ continue;
+ }
+
+ if (renderer->isText() && static_cast<RenderText *>(renderer)->firstTextBox()) {
+ if (it.current().node() != node())
+ return DOMPosition(it.current().node(), renderer->caretMaxOffset());
+
+ if (it.current().offset() < 0)
+ continue;
+ uint textOffset = it.current().offset();
+
+ RenderText *textRenderer = static_cast<RenderText *>(renderer);
+ for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
+ if (textOffset > box->start() && textOffset <= box->start() + box->len())
+ return it.current();
+ }
+ }
}
- return *this;
+
+ return it.current();
}
DOMPosition DOMPosition::equivalentDownstreamPosition() const
@@ -205,69 +285,57 @@ DOMPosition DOMPosition::equivalentDownstreamPosition() const
if (!node())
return DOMPosition();
- if (!node()->isTextNode() && offset() < node()->caretMaxOffset())
- return *this;
-
NodeImpl *block = node()->containingEditableBlock();
-
- EditIterator it(*this);
- DOMPosition next = it.peekNext();
- if (validUpstreamDownstreamPosition() && next.validUpstreamDownstreamPosition()) {
- if (node() == next.node())
- return *this;
- else
- return next;
- }
- while (!it.atEnd()) {
- if (it.next().validUpstreamDownstreamPosition())
- return it.current();
+
+ EditIterator it(*this);
+ for (; !it.atEnd(); it.next()) {
if (block != it.current().node()->containingEditableBlock())
return it.previous();
- }
- return *this;
-}
-bool DOMPosition::validUpstreamDownstreamPosition() const
-{
- if (isEmpty())
- return false;
-
- RenderObject *renderer = node()->renderer();
- if (!renderer || !renderer->isEditable())
- return false;
+ if (!node()->isContentEditable())
+ return it.next();
+
+ RenderObject *renderer = it.current().node()->renderer();
+ if (!renderer)
+ continue;
- if (renderer->style()->visibility() != khtml::VISIBLE)
- return false;
+ if (renderer->style()->visibility() != khtml::VISIBLE)
+ continue;
- if (renderer->isBR() || renderer->isBlockFlow())
- return true;
-
- if (renderer->isText()) {
- RenderText *textRenderer = static_cast<RenderText *>(renderer);
- InlineTextBox *lastTextBox = textRenderer->lastTextBox();
- for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
- if (offset() >= box->m_start) {
- if (box == lastTextBox) {
- if (offset() <= box->m_start + box->m_len)
- return true;
- }
- else if (offset() < box->m_start + box->m_len)
- return true;
- }
- else if (offset() < box->m_start) {
- // The offset we're looking for is before this node
- // this means the offset must be in content that is
- // not rendered. Return false.
- return false;
+ if (renderer->isBlockFlow() || renderer->isReplaced() || renderer->isBR()) {
+ if (it.current().offset() <= renderer->caretMinOffset())
+ return DOMPosition(it.current().node(), renderer->caretMinOffset());
+ else
+ continue;
+ }
+
+ if (renderer->isText() && static_cast<RenderText *>(renderer)->firstTextBox()) {
+ if (it.current().node() != node())
+ return DOMPosition(it.current().node(), renderer->caretMinOffset());
+
+ if (it.current().offset() < 0)
+ continue;
+ uint textOffset = it.current().offset();
+
+ RenderText *textRenderer = static_cast<RenderText *>(renderer);
+ for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
+ if (textOffset >= box->start() && textOffset <= box->end())
+ return it.current();
}
}
- return false;
}
- if (offset() >= renderer->caretMinOffset() && offset() <= renderer->caretMaxOffset())
- return true;
-
- return false;
+ return it.current();
+}
+
+bool DOMPosition::atStartOfContainingEditableBlock() const
+{
+ return renderedOffset() == 0 && inFirstEditableInContainingEditableBlock();
+}
+
+bool DOMPosition::atStartOfRootEditableBlock() const
+{
+ return renderedOffset() == 0 && inFirstEditableInRootEditableBlock();
}
bool DOMPosition::inRenderedContent() const
diff --git a/WebCore/khtml/xml/dom_position.h b/WebCore/khtml/xml/dom_position.h
index 8e700ee..ecf4980 100644
--- a/WebCore/khtml/xml/dom_position.h
+++ b/WebCore/khtml/xml/dom_position.h
@@ -46,11 +46,15 @@ public:
bool isEmpty() const { return m_node == 0; }
bool notEmpty() const { return m_node != 0; }
+ DOMPosition equivalentLeafPosition() const;
+ DOMPosition previousRenderedEditablePosition() const;
+ DOMPosition nextRenderedEditablePosition() const;
DOMPosition previousCharacterPosition() const;
DOMPosition nextCharacterPosition() const;
DOMPosition equivalentUpstreamPosition() const;
DOMPosition equivalentDownstreamPosition() const;
- bool validUpstreamDownstreamPosition() const;
+ bool atStartOfContainingEditableBlock() const;
+ bool atStartOfRootEditableBlock() const;
bool inRenderedContent() const;
bool inRenderedText() const;
bool rendersOnSameLine(const DOMPosition &pos) const;
diff --git a/WebCore/khtml/xml/dom_selection.cpp b/WebCore/khtml/xml/dom_selection.cpp
index 46cb6ed..6107244 100644
--- a/WebCore/khtml/xml/dom_selection.cpp
+++ b/WebCore/khtml/xml/dom_selection.cpp
@@ -528,6 +528,23 @@ void KHTMLSelection::setEndOffset(long offset)
void KHTMLSelection::validate(ETextGranularity expandTo)
{
+ // move the base and extent nodes to their equivalent leaf positions
+ bool baseAndExtentEqual = m_baseNode == m_extentNode && m_baseOffset == m_extentOffset;
+ if (m_baseNode) {
+ DOMPosition pos = basePosition().equivalentLeafPosition();
+ m_baseNode = pos.node();
+ m_baseOffset = pos.offset();
+ if (baseAndExtentEqual) {
+ m_extentNode = pos.node();
+ m_extentOffset = pos.offset();
+ }
+ }
+ if (m_extentNode && !baseAndExtentEqual) {
+ DOMPosition pos = extentPosition().equivalentLeafPosition();
+ m_extentNode = pos.node();
+ m_extentOffset = pos.offset();
+ }
+
// make sure we do not have a dangling start or end
if (!m_baseNode && !m_extentNode) {
setBaseOffset(0);
@@ -1012,14 +1029,14 @@ void KHTMLSelection::debugPosition() const
fprintf(stderr, "downstream: %s %p:%d\n", getTagName(downstream.node()->id()).string().latin1(), downstream.node(), downstream.offset());
}
else {
- DOMPosition pos = endPosition();
+ DOMPosition pos = startPosition();
DOMPosition upstream = pos.equivalentUpstreamPosition();
DOMPosition downstream = pos.equivalentDownstreamPosition();
fprintf(stderr, "upstream: %s %p:%d\n", getTagName(upstream.node()->id()).string().latin1(), upstream.node(), upstream.offset());
fprintf(stderr, "start: %s %p:%d\n", getTagName(pos.node()->id()).string().latin1(), pos.node(), pos.offset());
fprintf(stderr, "downstream: %s %p:%d\n", getTagName(downstream.node()->id()).string().latin1(), downstream.node(), downstream.offset());
fprintf(stderr, "-----------------------------------\n");
- pos = startPosition();
+ pos = endPosition();
upstream = pos.equivalentUpstreamPosition();
downstream = pos.equivalentDownstreamPosition();
fprintf(stderr, "upstream: %s %p:%d\n", getTagName(upstream.node()->id()).string().latin1(), upstream.node(), upstream.offset());
diff --git a/WebCore/kwq/KWQKHTMLPart.h b/WebCore/kwq/KWQKHTMLPart.h
index ef7feeb..b8118f8 100644
--- a/WebCore/kwq/KWQKHTMLPart.h
+++ b/WebCore/kwq/KWQKHTMLPart.h
@@ -272,6 +272,8 @@ public:
void registerCommandForRedo(const khtml::EditCommand &);
void clearUndoRedoOperations();
void editingKeyEvent();
+ void issueUndoCommand();
+ void issueRedoCommand();
private:
virtual void khtmlMousePressEvent(khtml::MousePressEvent *);
diff --git a/WebCore/kwq/KWQKHTMLPart.mm b/WebCore/kwq/KWQKHTMLPart.mm
index 9861a8c..e8e707d 100644
--- a/WebCore/kwq/KWQKHTMLPart.mm
+++ b/WebCore/kwq/KWQKHTMLPart.mm
@@ -2885,3 +2885,12 @@ void KWQKHTMLPart::editingKeyEvent()
[_bridge editingKeyDown:_currentEvent];
}
+void KWQKHTMLPart::issueUndoCommand()
+{
+ [_bridge issueUndoCommand];
+}
+
+void KWQKHTMLPart::issueRedoCommand()
+{
+ [_bridge issueRedoCommand];
+}
diff --git a/WebCore/kwq/KWQRenderTreeDebug.cpp b/WebCore/kwq/KWQRenderTreeDebug.cpp
index 9444208..5a3e21d 100644
--- a/WebCore/kwq/KWQRenderTreeDebug.cpp
+++ b/WebCore/kwq/KWQRenderTreeDebug.cpp
@@ -27,14 +27,21 @@
#include "htmltags.h"
#include "khtmlview.h"
+#include "khtml_selection.h"
#include "render_replaced.h"
#include "render_table.h"
#include "render_text.h"
#include "render_canvas.h"
+#include "xml/dom_docimpl.h"
+#include "xml/dom_nodeimpl.h"
+#include "xml/dom_position.h"
#include "KWQKHTMLPart.h"
#include "KWQTextStream.h"
+using DOM::DocumentImpl;
+using DOM::DOMPosition;
+using DOM::NodeImpl;
using khtml::RenderLayer;
using khtml::RenderObject;
using khtml::RenderTableCell;
@@ -318,6 +325,82 @@ static void writeLayers(QTextStream &ts, const RenderLayer* rootLayer, RenderLay
}
}
+static QString nodePositionRelativeToRoot(NodeImpl *node, NodeImpl *root)
+{
+ QString result;
+
+ NodeImpl *n = node;
+ while (1) {
+ NodeImpl *p = n->parentNode();
+ if (!p || n == root) {
+ result += " of root {" + getTagName(n->id()).string() + "}";
+ break;
+ }
+ if (n != node)
+ result += " of ";
+ int count = 1;
+ for (NodeImpl *search = p->firstChild(); search != n; search = search->nextSibling())
+ count++;
+ result += "child " + QString::number(count) + " {" + getTagName(n->id()).string() + "}";
+ n = p;
+ }
+
+ return result;
+}
+
+static void writeSelection(QTextStream &ts, const RenderObject *o)
+{
+ DocumentImpl *doc = dynamic_cast<DocumentImpl *>(o->element());
+ if (!doc || !doc->part())
+ return;
+
+ KHTMLSelection selection = doc->part()->selection();
+ if (selection.state() == KHTMLSelection::NONE)
+ return;
+
+ if (!selection.startPosition().node()->isContentEditable() || !selection.endPosition().node()->isContentEditable())
+ return;
+
+ DOMPosition startPosition = selection.startPosition();
+ DOMPosition endPosition = selection.endPosition();
+
+ QString startNodeTagName(getTagName(startPosition.node()->id()).string());
+ QString endNodeTagName(getTagName(endPosition.node()->id()).string());
+
+ NodeImpl *rootNode = doc->getElementById("root");
+
+ if (selection.state() == KHTMLSelection::CARET) {
+ DOMPosition upstream = startPosition.equivalentUpstreamPosition();
+ DOMPosition downstream = startPosition.equivalentDownstreamPosition();
+ QString positionString = nodePositionRelativeToRoot(startPosition.node(), rootNode);
+ QString upstreamString = nodePositionRelativeToRoot(upstream.node(), rootNode);
+ QString downstreamString = nodePositionRelativeToRoot(downstream.node(), rootNode);
+ ts << "selection is CARET:\n" <<
+ "start: position " << startPosition.offset() << " of " << positionString << "\n"
+ "upstream: position " << upstream.offset() << " of " << upstreamString << "\n"
+ "downstream: position " << downstream.offset() << " of " << downstreamString << "\n";
+ }
+ else if (selection.state() == KHTMLSelection::RANGE) {
+ QString startString = nodePositionRelativeToRoot(startPosition.node(), rootNode);
+ DOMPosition upstreamStart = startPosition.equivalentUpstreamPosition();
+ QString upstreamStartString = nodePositionRelativeToRoot(upstreamStart.node(), rootNode);
+ DOMPosition downstreamStart = startPosition.equivalentDownstreamPosition();
+ QString downstreamStartString = nodePositionRelativeToRoot(downstreamStart.node(), rootNode);
+ QString endString = nodePositionRelativeToRoot(endPosition.node(), rootNode);
+ DOMPosition upstreamEnd = endPosition.equivalentUpstreamPosition();
+ QString upstreamEndString = nodePositionRelativeToRoot(upstreamEnd.node(), rootNode);
+ DOMPosition downstreamEnd = endPosition.equivalentDownstreamPosition();
+ QString downstreamEndString = nodePositionRelativeToRoot(downstreamEnd.node(), rootNode);
+ ts << "selection is RANGE:\n" <<
+ "start: position " << startPosition.offset() << " of " << startString << "\n" <<
+ "upstream: position " << upstreamStart.offset() << " of " << upstreamStartString << "\n"
+ "downstream: position " << downstreamStart.offset() << " of " << downstreamStartString << "\n"
+ "end: position " << endPosition.offset() << " of " << endString << "\n"
+ "upstream: position " << upstreamEnd.offset() << " of " << upstreamEndString << "\n"
+ "downstream: position " << downstreamEnd.offset() << " of " << downstreamEndString << "\n";
+ }
+}
+
QString externalRepresentation(RenderObject *o)
{
QString s;
@@ -329,8 +412,10 @@ QString externalRepresentation(RenderObject *o)
o->canvas()->view()->setVScrollBarMode(QScrollView::AlwaysOff);
o->canvas()->view()->layout();
RenderLayer* l = o->layer();
- if (l)
+ if (l) {
writeLayers(ts, l, l, QRect(l->xPos(), l->yPos(), l->width(), l->height()));
+ writeSelection(ts, o);
+ }
}
}
return s;
diff --git a/WebCore/kwq/WebCoreBridge.h b/WebCore/kwq/WebCoreBridge.h
index d67316b..60fefea 100644
--- a/WebCore/kwq/WebCoreBridge.h
+++ b/WebCore/kwq/WebCoreBridge.h
@@ -421,6 +421,8 @@ typedef enum {
- (void)registerCommandForUndo:(id)arg;
- (void)registerCommandForRedo:(id)arg;
- (void)clearUndoRedoOperations;
+- (void)issueUndoCommand;
+- (void)issueRedoCommand;
- (void)editingKeyDown:(NSEvent *)event;
diff --git a/WebKit/ChangeLog b/WebKit/ChangeLog
index 9282041..eddb63d 100644
--- a/WebKit/ChangeLog
+++ b/WebKit/ChangeLog
@@ -1,3 +1,12 @@
+2004-04-06 Ken Kocienda <kocienda at apple.com>
+
+ Reviewed by Dave
+
+ * WebCoreSupport.subproj/WebBridge.m:
+ (-[WebBridge issueUndoCommand]): New method. Forwards call to the undo manager. Added
+ to support undo called via Javascript execCommand.
+ (-[WebBridge issueRedoCommand]): Ditto.
+
2004-04-05 Chris Blumenberg <cblu at apple.com>
Fixed: <rdar://problem/3612580>: SPI: WebPlugin selection
diff --git a/WebKit/WebCoreSupport.subproj/WebBridge.m b/WebKit/WebCoreSupport.subproj/WebBridge.m
index 330c459..e0981e0 100644
--- a/WebKit/WebCoreSupport.subproj/WebBridge.m
+++ b/WebKit/WebCoreSupport.subproj/WebBridge.m
@@ -1183,6 +1183,20 @@ static id <WebFormDelegate> formDelegate(WebBridge *self)
[[_frame webView] editingKeyDown:event];
}
+- (void)issueUndoCommand
+{
+ NSUndoManager *undoManager = [[_frame webView] undoManager];
+ if ([undoManager canUndo])
+ [undoManager undo];
+}
+
+- (void)issueRedoCommand
+{
+ NSUndoManager *undoManager = [[_frame webView] undoManager];
+ if ([undoManager canRedo])
+ [undoManager redo];
+}
+
- (void)setIsSelected:(BOOL)isSelected forView:(NSView *)view
{
if ([view conformsToProtocol:@protocol(WebPluginSelection)]) {
--
WebKit Debian packaging
More information about the Pkg-webkit-commits
mailing list