📄 dom_nodeimpl.cpp
字号:
}
EventListener *NodeImpl::getHTMLEventListener(int id)
{
if (!m_regdListeners)
return 0;
QPtrListIterator<RegisteredEventListener> it(*m_regdListeners);
for (; it.current(); ++it)
if (it.current()->id == id &&
it.current()->listener->eventListenerType() == "_khtml_HTMLEventListener") {
return it.current()->listener;
}
return 0;
}
bool NodeImpl::dispatchEvent(EventImpl *evt, int &exceptioncode, bool tempEvent)
{
evt->ref();
evt->setTarget(this);
// We've had at least one report of a crash on a page where document is nil here.
// Unfortunately that page no longer exists, but we'll make this code robust against
// that anyway.
// FIXME: Much code in this class assumes document is non-nil; it would be better to
// ensure that document can never be nil.
KHTMLPart *part = 0;
KHTMLView *view = 0;
if (document && document->document()) {
part = document->document()->part();
view = document->document()->view();
// Since event handling code could cause this object to be deleted, grab a reference to the view now
if (view)
view->ref();
}
bool ret = dispatchGenericEvent( evt, exceptioncode );
// If tempEvent is true, this means that the DOM implementation will not be storing a reference to the event, i.e.
// there is no way to retrieve it from javascript if a script does not already have a reference to it in a variable.
// So there is no need for the interpreter to keep the event in it's cache
if (tempEvent && part && part->jScript())
part->jScript()->finishedWithEvent(evt);
if (view)
view->deref();
evt->deref();
return ret;
}
bool NodeImpl::dispatchGenericEvent( EventImpl *evt, int &/*exceptioncode */)
{
evt->ref();
// ### check that type specified
// work out what nodes to send event to
QPtrList<NodeImpl> nodeChain;
NodeImpl *n;
for (n = this; n; n = n->parentNode()) {
n->ref();
nodeChain.prepend(n);
}
// trigger any capturing event handlers on our way down
evt->setEventPhase(Event::CAPTURING_PHASE);
QPtrListIterator<NodeImpl> it(nodeChain);
for (; it.current() && it.current() != this && !evt->propagationStopped(); ++it) {
evt->setCurrentTarget(it.current());
it.current()->handleLocalEvents(evt,true);
}
// dispatch to the actual target node
it.toLast();
if (!evt->propagationStopped()) {
evt->setEventPhase(Event::AT_TARGET);
evt->setCurrentTarget(it.current());
// Capturing first. -dwh
it.current()->handleLocalEvents(evt,true);
// Bubbling second. -dwh
if (!evt->propagationStopped())
it.current()->handleLocalEvents(evt,false);
}
--it;
// ok, now bubble up again (only non-capturing event handlers will be called)
// ### recalculate the node chain here? (e.g. if target node moved in document by previous event handlers)
// no. the DOM specs says:
// The chain of EventTargets from the event target to the top of the tree
// is determined before the initial dispatch of the event.
// If modifications occur to the tree during event processing,
// event flow will proceed based on the initial state of the tree.
//
// since the initial dispatch is before the capturing phase,
// there's no need to recalculate the node chain.
// (tobias)
if (evt->bubbles()) {
evt->setEventPhase(Event::BUBBLING_PHASE);
for (; it.current() && !evt->propagationStopped() && !evt->getCancelBubble(); --it) {
evt->setCurrentTarget(it.current());
it.current()->handleLocalEvents(evt,false);
}
}
evt->setCurrentTarget(0);
evt->setEventPhase(0); // I guess this is correct, the spec does not seem to say
// anything about the default event handler phase.
if (evt->bubbles()) {
// now we call all default event handlers (this is not part of DOM - it is internal to khtml)
it.toLast();
for (; it.current() && !evt->propagationStopped() && !evt->defaultPrevented() && !evt->defaultHandled(); --it)
it.current()->defaultEventHandler(evt);
}
// deref all nodes in chain
it.toFirst();
for (; it.current(); ++it)
it.current()->deref(); // this may delete us
DocumentImpl::updateDocumentsRendering();
bool defaultPrevented = evt->defaultPrevented();
evt->deref();
return !defaultPrevented; // ### what if defaultPrevented was called before dispatchEvent?
}
bool NodeImpl::dispatchHTMLEvent(int _id, bool canBubbleArg, bool cancelableArg)
{
int exceptioncode = 0;
EventImpl *evt = new EventImpl(static_cast<EventImpl::EventId>(_id),canBubbleArg,cancelableArg);
return dispatchEvent(evt,exceptioncode,true);
}
bool NodeImpl::dispatchWindowEvent(int _id, bool canBubbleArg, bool cancelableArg)
{
int exceptioncode = 0;
EventImpl *evt = new EventImpl(static_cast<EventImpl::EventId>(_id),canBubbleArg,cancelableArg);
evt->setTarget( 0 );
evt->ref();
DocumentPtr *doc = document;
doc->ref();
bool r = dispatchGenericEvent( evt, exceptioncode );
if (!evt->defaultPrevented() && doc->document())
doc->document()->defaultEventHandler(evt);
if (_id == EventImpl::LOAD_EVENT && !evt->propagationStopped() && doc->document()) {
// For onload events, send them to the enclosing frame only.
// This is a DOM extension and is independent of bubbling/capturing rules of
// the DOM. You send the event only to the enclosing frame. It does not
// bubble through the parent document.
ElementImpl* elt = doc->document()->ownerElement();
if (elt && (elt->getDocument()->domain().isEmpty() ||
elt->getDocument()->domain() == doc->document()->domain())) {
// We also do a security check, since we don't want to allow the enclosing
// iframe to see loads of child documents in other domains.
evt->setCurrentTarget(elt);
// Capturing first.
elt->handleLocalEvents(evt,true);
// Bubbling second.
if (!evt->propagationStopped())
elt->handleLocalEvents(evt,false);
r = !evt->defaultPrevented();
}
}
doc->deref();
evt->deref();
return r;
}
bool NodeImpl::dispatchMouseEvent(QMouseEvent *_mouse, int overrideId, int overrideDetail)
{
bool cancelable = true;
int detail = overrideDetail; // defaults to 0
EventImpl::EventId evtId = EventImpl::UNKNOWN_EVENT;
if (overrideId) {
evtId = static_cast<EventImpl::EventId>(overrideId);
}
else {
switch (_mouse->type()) {
case QEvent::MouseButtonPress:
evtId = EventImpl::MOUSEDOWN_EVENT;
break;
case QEvent::MouseButtonRelease:
evtId = EventImpl::MOUSEUP_EVENT;
break;
case QEvent::MouseButtonDblClick:
evtId = EventImpl::CLICK_EVENT;
#if APPLE_CHANGES
detail = _mouse->clickCount();
#else
detail = 1; // ### support for multiple double clicks
#endif
break;
case QEvent::MouseMove:
evtId = EventImpl::MOUSEMOVE_EVENT;
cancelable = false;
break;
default:
break;
}
}
if (evtId == EventImpl::UNKNOWN_EVENT)
return false; // shouldn't happen
int exceptioncode = 0;
#if APPLE_CHANGES
// Careful here - our viewportToContents() converts points from NSEvents, in NSWindow coord system to
// our khtmlview's coord system. This works for QMouseEvents coming from Cocoa because those events
// hold the location from the NSEvent. The QMouseEvent param here was made by other khtml code, so it
// will be a "proper" QT event with coords in terms of this widget. So in WebCore it would never be
// right to pass coords from _mouse to viewportToContents().
#endif
// int clientX, clientY;
// viewportToContents(_mouse->x(), _mouse->y(), clientX, clientY);
int clientX = _mouse->x(); // ### adjust to be relative to view
int clientY = _mouse->y(); // ### adjust to be relative to view
#if APPLE_CHANGES
int screenX;
int screenY;
KHTMLView *view = document->document()->view();
if (view) {
// This gets us as far as NSWindow coords
QPoint windowLoc = view->contentsToViewport(_mouse->pos());
// Then from NSWindow coords to screen coords
QPoint screenLoc = view->viewportToGlobal(windowLoc);
screenX = screenLoc.x();
screenY = screenLoc.y();
} else {
screenX = _mouse->x();
screenY = _mouse->y();
}
#else
int screenX = _mouse->globalX();
int screenY = _mouse->globalY();
#endif
int button = -1;
switch (_mouse->button()) {
case Qt::LeftButton:
button = 0;
break;
case Qt::MidButton:
button = 1;
break;
case Qt::RightButton:
button = 2;
break;
default:
break;
}
bool ctrlKey = (_mouse->state() & Qt::ControlButton);
bool altKey = (_mouse->state() & Qt::AltButton);
bool shiftKey = (_mouse->state() & Qt::ShiftButton);
bool metaKey = (_mouse->state() & Qt::MetaButton);
bool swallowEvent = false;
EventImpl *me = new MouseEventImpl(evtId,true,cancelable,getDocument()->defaultView(),
detail,screenX,screenY,clientX,clientY,ctrlKey,altKey,shiftKey,metaKey,
button,0);
me->ref();
dispatchEvent(me, exceptioncode, true);
bool defaultHandled = me->defaultHandled();
bool defaultPrevented = me->defaultPrevented();
if (defaultHandled || defaultPrevented)
swallowEvent = true;
me->deref();
#if APPLE_CHANGES
// Special case: If it's a click event, we also send the KHTML_CLICK or KHTML_DBLCLICK event. This is not part
// of the DOM specs, but is used for compatibility with the traditional onclick="" and ondblclick="" attributes,
// as there is no way to tell the difference between single & double clicks using DOM (only the click count is
// stored, which is not necessarily the same)
if (evtId == EventImpl::CLICK_EVENT) {
evtId = EventImpl::KHTML_CLICK_EVENT;
me = new MouseEventImpl(EventImpl::KHTML_CLICK_EVENT,
true,cancelable,getDocument()->defaultView(),
detail,screenX,screenY,clientX,clientY,
ctrlKey,altKey,shiftKey,metaKey,
button,0);
me->ref();
if (defaultHandled)
me->setDefaultHandled();
dispatchEvent(me,exceptioncode,true);
if (me->defaultHandled())
defaultHandled = true;
if (me->defaultPrevented())
defaultPrevented = true;
if (me->defaultHandled() || me->defaultPrevented())
swallowEvent = true;
me->deref();
if (_mouse->isDoubleClick()) {
me = new MouseEventImpl(EventImpl::KHTML_DBLCLICK_EVENT,
true,cancelable,getDocument()->defaultView(),
detail,screenX,screenY,clientX,clientY,
ctrlKey,altKey,shiftKey,metaKey,
button,0);
me->ref();
if (defaultHandled)
me->setDefaultHandled();
dispatchEvent(me,exceptioncode,true);
if (me->defaultHandled() || me->defaultPrevented())
swallowEvent = true;
me->deref();
}
}
#endif
// Also send a DOMActivate event, which causes things like form submissions to occur.
if (evtId == EventImpl::KHTML_CLICK_EVENT && !defaultPrevented && !disabled())
dispatchUIEvent(EventImpl::DOMACTIVATE_EVENT, detail);
return swallowEvent;
}
bool NodeImpl::dispatchUIEvent(int _id, int detail)
{
assert (!( (_id != EventImpl::DOMFOCUSIN_EVENT &&
_id != EventImpl::DOMFOCUSOUT_EVENT &&
_id != EventImpl::DOMACTIVATE_EVENT)));
bool cancelable = false;
if (_id == EventImpl::DOMACTIVATE_EVENT)
cancelable = true;
int exceptioncode = 0;
if (getDocument()) {
UIEventImpl *evt = new UIEventImpl(static_cast<EventImpl::EventId>(_id),true,
cancelable,getDocument()->defaultView(),detail);
return dispatchEvent(evt,exceptioncode,true);
}
return false;
}
void NodeImpl::registerNodeList(NodeListImpl *list)
{
if (!m_nodeLists) {
m_nodeLists = new QPtrDict<NodeListImpl>;
}
m_nodeLists->insert(list, list);
}
void NodeImpl::unregisterNodeList(NodeListImpl *list)
{
if (!m_nodeLists)
return;
m_nodeLists->remove(list);
}
void NodeImpl::notifyLocalNodeListsSubtreeModified()
{
if (!m_nodeLists)
return;
QPtrDictIterator<NodeListImpl> i(*m_nodeLists);
while (NodeListImpl *list = i.current()) {
list->rootNodeSubtreeModified();
++i;
}
}
void NodeImpl::notifyNodeListsSubtreeModified()
{
for (NodeImpl *n = this; n; n = n->parentNode()) {
n->notifyLocalNodeListsSubtreeModified();
}
}
bool NodeImpl::dispatchSubtreeModifiedEvent(bool sendChildrenChanged)
{
notifyNodeListsSubtreeModified();
if (sendChildrenChanged)
childrenChanged();
if (!getDocument()->hasListenerType(DocumentImpl::DOMSUBTREEMODIFIED_LISTENER))
return false;
int exceptioncode = 0;
return dispatchEvent(new MutationEventImpl(EventImpl::DOMSUBTREEMODIFIED_EVENT,
true,false,0,DOMString(),DOMString(),DOMString(),0),exceptioncode,true);
}
bool NodeImpl::dispatchKeyEvent(QKeyEvent *key)
{
int exceptioncode = 0;
//kdDebug(6010) << "DOM::NodeImpl: dispatching keyboard event" << endl;
KeyboardEventImpl *keyboardEventImpl = new KeyboardEventImpl(key, getDocument()->defaultView());
keyboardEventImpl->ref();
bool r = dispatchEvent(keyboardEventImpl,exceptioncode,true);
#if APPLE_CHANGES
// we want to return false if default is prevented (already taken care of)
// or if the element is default-handled by the DOM. Otherwise we let it just
// let it get handled by AppKit
if (keyboardEventImpl->defaultHandled())
#else
// the default event handler should accept() the internal QKeyEvent
// to prevent the view from further evaluating it.
if (!keyboardEventImpl->defaultPrevented() && !keyboardEventImpl->qKeyEvent->isAccepted())
#endif
r = false;
keyboardEventImpl->deref();
return r;
}
void NodeImpl::handleLocalEvents(EventImpl *evt, bool useCapture)
{
if (!m_regdListeners)
return;
if (disabled() && evt->isMouseEvent())
return;
QPtrList<RegisteredEventListener> listenersCopy = *m_regdListeners;
QPtrListIterator<RegisteredEventListener> it(listenersCopy);
Event ev = evt;
for (; it.current(); ++it) {
if (it.current()->id == evt->id() && it.current()->useCapture == useCapture)
it.current()->listener->handleEvent(ev, false);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -