KHtml

dom_nodeimpl.cpp
1 /*
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll ([email protected])
5  * (C) 1999 Antti Koivisto ([email protected])
6  * (C) 2001 Dirk Mueller ([email protected])
7  * (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
8  * (C) 2005, 2009, 2010 Maksim Orlovich ([email protected])
9  * (C) 2006 Allan Sandfeld Jensen ([email protected])
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU Library General Public License
22  * along with this library; see the file COPYING.LIB. If not, write to
23  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  * Boston, MA 02110-1301, USA.
25  */
26 
27 #include "dom_nodeimpl.h"
28 
29 #include <dom/dom_exception.h>
30 #include "dom_elementimpl.h"
31 #include "dom_textimpl.h"
32 #include "dom2_eventsimpl.h"
33 #include "dom_docimpl.h"
34 #include "dom_nodelistimpl.h"
35 #include "xml/dom_position.h"
36 #include "xml/dom_selection.h"
37 #include "xml/wa_selectors.h"
38 #include "dom_restyler.h"
39 #include "html/html_objectimpl.h"
40 
41 #include "khtml_debug.h"
42 
43 #include <rendering/render_text.h>
44 #include <rendering/render_flow.h>
45 #include <rendering/render_line.h>
46 
47 #include <ecma/kjs_proxy.h>
48 #include <khtmlview.h>
49 #include <khtml_part.h>
50 //Added by qt3to4:
51 #include <QMouseEvent>
52 #include <QKeyEvent>
53 #include <QEvent>
54 
55 #if 0
56 // from khtml_caret_p.h
57 namespace khtml
58 {
59 void /*KHTML_NO_EXPORT*/ mapDOMPosToRenderPos(DOM::NodeImpl *node, long offset,
60  khtml::RenderObject *&r, long &r_ofs, bool &outside, bool &outsideEnd);
61 }
62 #endif
63 
64 using namespace DOM;
65 using namespace khtml;
66 
67 NodeImpl::NodeImpl(DocumentImpl *doc)
68  : m_document(doc),
69  m_previous(nullptr),
70  m_next(nullptr),
71  m_render(nullptr),
72  m_hasId(false),
73  m_attached(false),
74  m_closed(false),
75  m_changed(false),
76  m_hasChangedChild(false),
77  m_changedAscendentAttribute(false),
78  m_inDocument(false),
79  m_hasAnchor(false),
80  m_hovered(false),
81  m_focused(false),
82  m_active(false),
83  m_implicit(false),
84  m_htmlCompat(false),
85  m_hasClass(false),
86  m_hasCombinedStyle(false),
87  m_hasHoverDependency(false),
88  m_elementHasRareData(false),
89  m_needsStyleAttributeUpdate(false)
90 {
91 }
92 
93 NodeImpl::~NodeImpl()
94 {
95  if (m_render) {
96  detach();
97  }
98  if (m_previous) {
99  m_previous->setNextSibling(nullptr);
100  }
101  if (m_next) {
102  m_next->setPreviousSibling(nullptr);
103  }
104 }
105 
106 DOMString NodeImpl::nodeValue() const
107 {
108  return DOMString();
109 }
110 
111 void NodeImpl::setNodeValue(const DOMString &/*_nodeValue*/, int &/*exceptioncode*/)
112 {
113  // by default nodeValue is null, so setting it has no effect
114  // don't throw NO_MODIFICATION_ALLOWED_ERR from here, DOMTS-Core-Level1's hc_nodevalue03
115  // (createEntityReference().setNodeValue())) says it would be wrong.
116  // This must be done by subclasses instead.
117 }
118 
119 DOMString NodeImpl::nodeName() const
120 {
121  return DOMString();
122 }
123 
124 unsigned short NodeImpl::nodeType() const
125 {
126  return 0;
127 }
128 
129 WTF::PassRefPtr<DOM::NodeListImpl> NodeImpl::childNodes()
130 {
131  return new ChildNodeListImpl(this);
132 }
133 
134 NodeImpl *NodeImpl::firstChild() const
135 {
136  return nullptr;
137 }
138 
139 NodeImpl *NodeImpl::lastChild() const
140 {
141  return nullptr;
142 }
143 
144 NodeImpl *NodeImpl::insertBefore(NodeImpl *, NodeImpl *, int &exceptioncode)
145 {
146  exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
147  return nullptr;
148 }
149 
150 void NodeImpl::replaceChild(NodeImpl *, NodeImpl *, int &exceptioncode)
151 {
152  exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
153 }
154 
155 void NodeImpl::removeChild(NodeImpl *, int &exceptioncode)
156 {
157  exceptioncode = DOMException::NOT_FOUND_ERR;
158 }
159 
160 NodeImpl *NodeImpl::appendChild(NodeImpl *, int &exceptioncode)
161 {
162  exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
163  return nullptr;
164 }
165 
166 void NodeImpl::remove(int &exceptioncode)
167 {
168  exceptioncode = 0;
169  if (!parentNode()) {
170  exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
171  return;
172  }
173 
174  parentNode()->removeChild(this, exceptioncode);
175 }
176 
177 bool NodeImpl::hasChildNodes() const
178 {
179  return false;
180 }
181 
182 void NodeImpl::normalize()
183 {
184  // ### normalize attributes? (when we store attributes using child nodes)
185  int exceptioncode = 0;
186  NodeImpl *child = firstChild();
187 
188  // Recursively go through the subtree beneath us, normalizing all nodes. In the case
189  // where there are two adjacent text nodes, they are merged together
190  while (child) {
191  NodeImpl *nextChild = child->nextSibling();
192 
193  if (nextChild && child->nodeType() == Node::TEXT_NODE && nextChild->nodeType() == Node::TEXT_NODE) {
194  // Current child and the next one are both text nodes... merge them
195  TextImpl *currentText = static_cast<TextImpl *>(child);
196  TextImpl *nextText = static_cast<TextImpl *>(nextChild);
197 
198  currentText->appendData(nextText->data(), exceptioncode);
199  if (exceptioncode) {
200  return;
201  }
202 
203  removeChild(nextChild, exceptioncode);
204  if (exceptioncode) {
205  return;
206  }
207  } else {
208  child->normalize();
209  child = nextChild;
210  }
211  }
212 }
213 
214 DOMString NodeImpl::prefix() const
215 {
216  // For nodes other than elements and attributes, the prefix is always null
217  return DOMString();
218 }
219 
220 DOMString NodeImpl::namespaceURI() const
221 {
222  return DOMString();
223 }
224 
225 void NodeImpl::setPrefix(const DOMString &/*_prefix*/, int &exceptioncode)
226 {
227  // The spec says that for nodes other than elements and attributes, prefix is always null.
228  // It does not say what to do when the user tries to set the prefix on another type of
229  // node, however mozilla throws a NAMESPACE_ERR exception
230  exceptioncode = DOMException::NAMESPACE_ERR;
231 }
232 
233 DOMString NodeImpl::textContent() const
234 {
235  switch (nodeType()) {
236  case Node::TEXT_NODE:
237  case Node::CDATA_SECTION_NODE:
238  case Node::COMMENT_NODE:
239  case Node::PROCESSING_INSTRUCTION_NODE:
240  return nodeValue();
241 
242  case Node::ELEMENT_NODE:
243  case Node::ATTRIBUTE_NODE:
244  case Node::ENTITY_NODE:
245  case Node::ENTITY_REFERENCE_NODE:
246  case Node::DOCUMENT_FRAGMENT_NODE: {
247  DOMString s = "";
248 
249  for (NodeImpl *child = firstChild(); child; child = child->nextSibling()) {
250  if (child->nodeType() == Node::COMMENT_NODE ||
251  child->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
252  continue;
253  }
254 
255  s += child->textContent();
256  }
257 
258  return s;
259  }
260 
261  case Node::DOCUMENT_NODE:
262  case Node::DOCUMENT_TYPE_NODE:
263  case Node::NOTATION_NODE:
264  default:
265  return DOMString();
266  }
267 }
268 
269 void NodeImpl::setTextContent(const DOMString &text, int &ec)
270 {
271  if (isReadOnly()) {
272  ec = DOMException::NO_MODIFICATION_ALLOWED_ERR;
273  return;
274  }
275 
276  switch (nodeType()) {
277  case Node::TEXT_NODE:
278  case Node::CDATA_SECTION_NODE:
279  case Node::COMMENT_NODE:
280  case Node::PROCESSING_INSTRUCTION_NODE:
281  setNodeValue(text, ec);
282  break;
283  case Node::ELEMENT_NODE:
284  case Node::ATTRIBUTE_NODE:
285  case Node::ENTITY_NODE:
286  case Node::ENTITY_REFERENCE_NODE:
287  case Node::DOCUMENT_FRAGMENT_NODE: {
288  NodeBaseImpl *container = static_cast<NodeBaseImpl *>(this);
289 
290  container->removeChildren();
291 
292  if (!text.isEmpty()) {
293  appendChild(document()->createTextNode(text.implementation()), ec);
294  }
295  break;
296  }
297  case Node::DOCUMENT_NODE:
298  case Node::DOCUMENT_TYPE_NODE:
299  case Node::NOTATION_NODE:
300  default:
301  // Do nothing
302  break;
303  }
304 }
305 
306 DOMString NodeImpl::localName() const
307 {
308  return DOMString();
309 }
310 
311 void NodeImpl::setFirstChild(NodeImpl *)
312 {
313 }
314 
315 void NodeImpl::setLastChild(NodeImpl *)
316 {
317 }
318 
319 NodeImpl *NodeImpl::addChild(NodeImpl *)
320 {
321  return nullptr;
322 }
323 
324 void NodeImpl::getCaret(int /*offset*/, bool override, int &_x, int &_y, int &width, int &height)
325 {
326  if (m_render) {
327  RenderObject *r = nullptr;
328  long r_ofs = 0;
329  bool outside, outsideEnd;
330 #if 0
331 // qCDebug(KHTML_LOG) << "getCaret: node " << this << " " << nodeName().string() << " offset: " << offset;
332 #endif
333 // mapDOMPosToRenderPos(this, offset, r, r_ofs, outside, outsideEnd);
334  outside = false;
335  outsideEnd = false;
336 #if 0
337 // qCDebug(KHTML_LOG) << "getCaret: r " << r << " " << (r?r->renderName():QString()) << " r_ofs: " << r_ofs << " outside " << outside << " outsideEnd " << outsideEnd;
338 #endif
339  if (r) {
340  r->caretPos(r_ofs, override * RenderObject::CFOverride
341  + outside * RenderObject::CFOutside
342  + outsideEnd * RenderObject::CFOutsideEnd, _x, _y, width, height);
343  } else {
344  _x = _y = height = -1, width = 1;
345  }
346  } else {
347  _x = _y = height = -1, width = 1;
348  }
349 }
350 
351 bool NodeImpl::isContentEditable() const
352 {
353  return parentNode() ? parentNode()->isContentEditable() : false;
354 }
355 
356 QRect NodeImpl::getRect() const
357 {
358  int _x, _y;
359  if (m_render && m_render->absolutePosition(_x, _y))
360  return QRect(_x + m_render->inlineXPos(), _y + m_render->inlineYPos(),
361  m_render->width(), m_render->height() + renderer()->borderTopExtra() + renderer()->borderBottomExtra());
362 
363  return QRect();
364 }
365 
366 void NodeImpl::setChanged(bool b)
367 {
368  if (b && !attached()) { // changed compared to what?
369  return;
370  }
371 
372  m_changed = b;
373  if (b) {
374  NodeImpl *p = parentNode();
375  while (p) {
376  p->setHasChangedChild(true);
377  p = p->parentNode();
378  }
379  document()->setDocumentChanged();
380  }
381 }
382 
383 bool NodeImpl::isInline() const
384 {
385  if (m_render) {
386  return m_render->style()->display() == khtml::INLINE;
387  }
388  return !isElementNode();
389 }
390 
391 unsigned long NodeImpl::nodeIndex() const
392 {
393  NodeImpl *_tempNode = previousSibling();
394  unsigned long count = 0;
395  for (count = 0; _tempNode; count++) {
396  _tempNode = _tempNode->previousSibling();
397  }
398  return count;
399 }
400 
401 DocumentImpl *NodeImpl::eventTargetDocument()
402 {
403  return document();
404 }
405 
406 void NodeImpl::dispatchEvent(EventImpl *evt, int &exceptioncode, bool tempEvent)
407 {
408  evt->setTarget(this);
409 
410  dispatchGenericEvent(evt, exceptioncode);
411 
412  KHTMLPart *part = document()->part();
413  // If tempEvent is true, this means that the DOM implementation will not be storing a reference to the event, i.e.
414  // there is no way to retrieve it from javascript if a script does not already have a reference to it in a variable.
415  // So there is no need for the interpreter to keep the event in its cache
416  if (tempEvent && part && part->jScript()) {
417  part->jScript()->finishedWithEvent(evt);
418  }
419 }
420 
421 void NodeImpl::dispatchGenericEvent(EventImpl *evt, int &/*exceptioncode */)
422 {
423  // ### check that type specified
424 
425  ref();
426 
427  // work out what nodes to send event to
428  QList<EventTargetImpl *> nodeChain;
429 
430  if (evt->target()->eventTargetType() != DOM_NODE) {
431  // The target is the only thing that goes into the chain.
432  nodeChain.prepend(evt->target());
433  evt->target()->ref();
434 
435  // ... except, well, load events lie and say their target is the document,
436  // so we patch that up now (since we want it as Window before we got here
437  if (evt->id() == EventImpl::LOAD_EVENT && evt->target()->eventTargetType() == WINDOW) {
438  evt->setTarget(document());
439  }
440  } else if (inDocument()) {
441  for (NodeImpl *n = this; n; n = n->parentNode()) {
442  n->ref();
443  nodeChain.prepend(n);
444  }
445 
446  // If the event isn't a load event, we propagate it up to window as well.
447  // The exclusion is so that things like image load events don't make it
448  // all the way upto window.onload. Meanwhile, the main load event
449  // is dispatched specially, via dispatchWindowEvent, with the case
450  // above doing the necessary fiddling for it.
451  if (evt->id() != EventImpl::LOAD_EVENT) {
452  EventTargetImpl *t = document()->windowEventTarget();
453  t->ref();
454  nodeChain.prepend(t);
455  }
456  } else {
457  // if node is not in the document just send event to itself
458  ref();
459  nodeChain.prepend(this);
460  }
461 
462  // trigger any capturing event handlers on our way down
463  evt->setEventPhase(Event::CAPTURING_PHASE);
464  QListIterator<EventTargetImpl *> it(nodeChain);
465  while (it.hasNext()) {
466  EventTargetImpl *cur = it.next();
467  if (cur == this || evt->propagationStopped()) {
468  break;
469  }
470  evt->setCurrentTarget(cur);
471  cur->handleLocalEvents(evt, true);
472  }
473 
474  // dispatch to the actual target node
475  it.toBack();
476  EventTargetImpl *curn = it.hasPrevious() ? it.previous() : nullptr;
477  EventTargetImpl *propagationSentinel = nullptr;
478  if (curn && !evt->propagationStopped()) {
479  evt->setEventPhase(Event::AT_TARGET);
480  evt->setCurrentTarget(curn);
481  curn->handleLocalEvents(evt, true);
482  if (!evt->propagationStopped()) {
483  curn->handleLocalEvents(evt, false);
484  } else {
485  propagationSentinel = curn;
486  }
487  }
488 
489  curn = it.hasPrevious() ? it.previous() : nullptr;
490 
491  if (evt->bubbles()) {
492  evt->setEventPhase(Event::BUBBLING_PHASE);
493  while (curn && !evt->propagationStopped()) {
494  if (evt->propagationStopped()) {
495  propagationSentinel = curn;
496  }
497  evt->setCurrentTarget(curn);
498  curn->handleLocalEvents(evt, false);
499  curn = it.hasPrevious() ? it.previous() : nullptr;
500  }
501 
502  // now we call all default event handlers (this is not part of DOM - it is internal to khtml)
503  evt->setCurrentTarget(nullptr);
504  evt->setEventPhase(0); // I guess this is correct, the spec does not seem to say
505 
506  it.toBack();
507  while (it.hasPrevious()) {
508  curn = it.previous();
509  if (curn == propagationSentinel || evt->defaultPrevented() || evt->defaultHandled()) {
510  break;
511  }
512  curn->defaultEventHandler(evt);
513  }
514 
515  if (evt->id() == EventImpl::CLICK_EVENT && !evt->defaultPrevented() &&
516  static_cast<MouseEventImpl *>(evt)->button() == 0) { // LMB click
517  dispatchUIEvent(EventImpl::DOMACTIVATE_EVENT, static_cast<UIEventImpl *>(evt)->detail());
518  }
519  }
520 
521  // deref all nodes in chain
522  it.toFront();
523  while (it.hasNext()) {
524  it.next()->deref(); // this may delete us
525  }
526 
527  DocumentImpl::updateDocumentsRendering();
528 
529  deref();
530 }
531 
532 bool NodeImpl::dispatchHTMLEvent(int _id, bool canBubbleArg, bool cancelableArg)
533 {
534  int exceptioncode = 0;
535  EventImpl *const evt = new EventImpl(static_cast<EventImpl::EventId>(_id), canBubbleArg, cancelableArg);
536  evt->ref();
537  dispatchEvent(evt, exceptioncode, true);
538  bool ret = !evt->defaultPrevented();
539  evt->deref();
540  return ret;
541 }
542 
543 void NodeImpl::dispatchWindowEvent(int _id, bool canBubbleArg, bool cancelableArg)
544 {
545  EventImpl *const evt = new EventImpl(static_cast<EventImpl::EventId>(_id), canBubbleArg, cancelableArg);
546  dispatchWindowEvent(evt);
547 }
548 
549 void NodeImpl::dispatchWindowEvent(EventImpl *evt)
550 {
551  evt->setTarget(document()->windowEventTarget());
552  evt->ref();
553 
554  int exceptioncode = 0;
555  dispatchGenericEvent(evt, exceptioncode);
556 
557  if (evt->id() == EventImpl::LOAD_EVENT) {
558  // Trigger Load Event on the enclosing frame if there is one
559  DOM::HTMLPartContainerElementImpl *elt = document()->ownerElement();
560  if (elt) {
561  elt->slotEmitLoadEvent();
562  }
563  }
564 
565  evt->deref();
566 }
567 
568 void NodeImpl::dispatchMouseEvent(QMouseEvent *_mouse, int overrideId, int overrideDetail)
569 {
570  bool cancelable = true;
571  int detail = overrideDetail; // defaults to 0
572  EventImpl::EventId evtId;
573  if (overrideId) {
574  evtId = static_cast<EventImpl::EventId>(overrideId);
575  } else {
576  switch (_mouse->type()) {
578  evtId = EventImpl::MOUSEDOWN_EVENT;
579  break;
581  evtId = EventImpl::MOUSEUP_EVENT;
582  break;
584  evtId = EventImpl::CLICK_EVENT;
585  detail = 1; // ### support for multiple double clicks
586  break;
587  case QEvent::MouseMove:
588  evtId = EventImpl::MOUSEMOVE_EVENT;
589  cancelable = false;
590  break;
591  default:
592  return;
593  }
594  }
595 
596  int exceptioncode = 0;
597  int pageX = _mouse->x();
598  int pageY = _mouse->y();
599  if (document()->view()) {
600  document()->view()->revertTransforms(pageX, pageY);
601  }
602  int clientX = pageX;
603  int clientY = pageY;
604  if (document()->view()) {
605  document()->view()->contentsToViewport(pageX, pageY, pageX, pageY);
606  }
607 
608  int screenX = _mouse->globalX();
609  int screenY = _mouse->globalY();
610 
611  int button = -1;
612  switch (_mouse->button()) {
613  case Qt::LeftButton:
614  button = 0;
615  break;
616  case Qt::MidButton:
617  button = 1;
618  break;
619  case Qt::RightButton:
620  button = 2;
621  break;
622  default:
623  break;
624  }
625  bool ctrlKey = (_mouse->modifiers() & Qt::ControlModifier);
626  bool altKey = (_mouse->modifiers() & Qt::AltModifier);
627  bool shiftKey = (_mouse->modifiers() & Qt::ShiftModifier);
628  bool metaKey = (_mouse->modifiers() & Qt::MetaModifier);
629 
630  EventImpl *const evt = new MouseEventImpl(evtId, true, cancelable, document()->defaultView(),
631  detail, screenX, screenY, clientX, clientY, pageX, pageY, ctrlKey, altKey, shiftKey, metaKey,
632  button, nullptr);
633  evt->ref();
634  dispatchEvent(evt, exceptioncode, true);
635  evt->deref();
636 }
637 
638 void NodeImpl::dispatchUIEvent(int _id, int detail)
639 {
640  assert(!((_id != EventImpl::DOMFOCUSIN_EVENT &&
641  _id != EventImpl::DOMFOCUSOUT_EVENT &&
642  _id != EventImpl::DOMACTIVATE_EVENT)));
643 
644  bool cancelable = false;
645  if (_id == EventImpl::DOMACTIVATE_EVENT) {
646  cancelable = true;
647  }
648 
649  int exceptioncode = 0;
650  UIEventImpl *const evt = new UIEventImpl(static_cast<EventImpl::EventId>(_id), true,
651  cancelable, document()->defaultView(), detail);
652  evt->ref();
653  dispatchEvent(evt, exceptioncode, true);
654  evt->deref();
655 }
656 
657 void NodeImpl::dispatchSubtreeModifiedEvent()
658 {
659  childrenChanged();
660  document()->incDOMTreeVersion(DocumentImpl::TV_Structural);
661  if (!document()->hasListenerType(DocumentImpl::DOMSUBTREEMODIFIED_LISTENER)) {
662  return;
663  }
664  int exceptioncode = 0;
665  ref();
666  MutationEventImpl *const evt = new MutationEventImpl(EventImpl::DOMSUBTREEMODIFIED_EVENT, true,
667  false, nullptr, DOMString(), DOMString(), DOMString(), 0);
668  evt->ref();
669  dispatchEvent(evt, exceptioncode, true);
670  evt->deref();
671  derefOnly();
672 }
673 
674 bool NodeImpl::dispatchKeyEvent(QKeyEvent *key, bool keypress)
675 {
676  int exceptioncode = 0;
677  //qCDebug(KHTML_LOG) << "DOM::NodeImpl: dispatching keyboard event";
678  EventImpl *keyEventImpl;
679  if (keypress) {
680  keyEventImpl = new TextEventImpl(key, document()->defaultView());
681  } else {
682  keyEventImpl = new KeyboardEventImpl(key, document()->defaultView());
683  }
684  keyEventImpl->ref();
685  dispatchEvent(keyEventImpl, exceptioncode, true);
686  bool r = keyEventImpl->defaultHandled() || keyEventImpl->defaultPrevented();
687  keyEventImpl->deref();
688  return r;
689 }
690 
691 unsigned long NodeImpl::childNodeCount()
692 {
693  return 0;
694 }
695 
696 NodeImpl *NodeImpl::childNode(unsigned long /*index*/)
697 {
698  return nullptr;
699 }
700 
701 NodeImpl *NodeImpl::traverseNextNode(NodeImpl *stayWithin) const
702 {
703  if (firstChild() || stayWithin == this) {
704  return firstChild();
705  } else if (nextSibling()) {
706  return nextSibling();
707  } else {
708  const NodeImpl *n = this;
709  while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin)) {
710  n = n->parentNode();
711  }
712  if (n) {
713  return n->nextSibling();
714  }
715  }
716  return nullptr;
717 }
718 
719 NodeImpl *NodeImpl::traversePreviousNode() const
720 {
721  if (previousSibling()) {
722  NodeImpl *n = previousSibling();
723  while (n->lastChild()) {
724  n = n->lastChild();
725  }
726  return n;
727  } else if (parentNode()) {
728  return parentNode();
729  } else {
730  return nullptr;
731  }
732 }
733 
734 void NodeImpl::checkSetPrefix(const DOMString &_prefix, int &exceptioncode)
735 {
736  // Perform error checking as required by spec for setting Node.prefix. Used by
737  // ElementImpl::setPrefix() and AttrImpl::setPrefix()
738 
739  // INVALID_CHARACTER_ERR: Raised if the specified prefix contains an illegal character.
740  if (!Element::khtmlValidPrefix(_prefix)) {
741  exceptioncode = DOMException::INVALID_CHARACTER_ERR;
742  return;
743  }
744 
745  // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
746  if (isReadOnly()) {
747  exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
748  return;
749  }
750 
751  // NAMESPACE_ERR: - Raised if the specified prefix is malformed
752  // - if the namespaceURI of this node is null,
753  // - if the specified prefix is "xml" and the namespaceURI of this node is different from
754  // "http://www.w3.org/XML/1998/namespace",
755  // - if this node is an attribute and the specified prefix is "xmlns" and
756  // the namespaceURI of this node is different from "http://www.w3.org/2000/xmlns/",
757  // - or if this node is an attribute and the qualifiedName of this node is "xmlns" [Namespaces].
758  if (Element::khtmlMalformedPrefix(_prefix) || /*FIXME: use IDString somehow here (namespacePart(id()) == defaultNamespace && id() > ID_LAST_TAG) ||*/
759  (_prefix == "xml" && namespaceURI() != "http://www.w3.org/XML/1998/namespace")) {
760  exceptioncode = DOMException::NAMESPACE_ERR;
761  return;
762  }
763 }
764 
765 void NodeImpl::checkAddChild(NodeImpl *newChild, int &exceptioncode)
766 {
767  // Perform error checking as required by spec for adding a new child. Used by
768  // appendChild(), replaceChild() and insertBefore()
769 
770  // Not mentioned in spec: throw NOT_FOUND_ERR if newChild is null
771  if (!newChild) {
772  exceptioncode = DOMException::NOT_FOUND_ERR;
773  return;
774  }
775 
776  // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly
777  if (isReadOnly()) {
778  exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
779  return;
780  }
781 
782  // WRONG_DOCUMENT_ERR: Raised if newChild was created from a different document than the one that
783  // created this node.
784  // We assume that if newChild is a DocumentFragment, all children are created from the same document
785  // as the fragment itself (otherwise they could not have been added as children)
786  if (newChild->document() != document()) {
787  exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
788  return;
789  }
790 
791  // HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not allow children of the type of the
792  // newChild node, or if the node to append is one of this node's ancestors.
793 
794  // check for ancestor/same node
795  if (isAncestor(newChild)) {
796  exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
797  return;
798  }
799 
800  // check node allowed
801  if (newChild->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) {
802  // newChild is a DocumentFragment... check all its children instead of newChild itself
803  NodeImpl *child;
804  for (child = newChild->firstChild(); child; child = child->nextSibling()) {
805  if (!childTypeAllowed(child->nodeType())) {
806  exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
807  return;
808  }
809  }
810  } else {
811  // newChild is not a DocumentFragment... check if it's allowed directly
812  if (!childTypeAllowed(newChild->nodeType())) {
813  exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
814  return;
815  }
816  }
817 }
818 
819 bool NodeImpl::isAncestor(NodeImpl *other) const
820 {
821  // Return true if other is the same as this node or an ancestor of it, otherwise false
822  const NodeImpl *n;
823  for (n = this; n; n = n->parentNode()) {
824  if (n == other) {
825  return true;
826  }
827  }
828  return false;
829 }
830 
831 bool NodeImpl::childAllowed(NodeImpl *newChild)
832 {
833  return childTypeAllowed(newChild->nodeType());
834 }
835 
836 NodeImpl::StyleChange NodeImpl::diff(khtml::RenderStyle *s1, khtml::RenderStyle *s2)
837 {
838  // This method won't work when a style contains noninherited properties with "inherit" value.
839  StyleChange ch = NoInherit;
840 
841  EDisplay display1 = s1 ? s1->display() : NONE;
842  EDisplay display2 = s2 ? s2->display() : NONE;
843  EPosition position1 = s1 ? s1->position() : PSTATIC;
844  EPosition position2 = s2 ? s2->position() : PSTATIC;
845 
846  if (display1 != display2 || position1 != position2) {
847  ch = Detach;
848  } else if (!s1 || !s2) {
849  ch = Inherit;
850  } else if (*s1 == *s2) {
851  ch = NoChange;
852  } else if (s1->useNormalContent() != s2->useNormalContent()) {
853  ch = Detach; // when we add generated content all children must be detached
854  } else if (s1->inheritedNotEqual(s2)) {
855  ch = Inherit;
856  }
857 
858  // Because the first-letter implementation is so f..ked up, the easiest way
859  // to update first-letter is to remove the entire node and readd it.
860  if (ch < Detach && pseudoDiff(s1, s2, khtml::RenderStyle::FIRST_LETTER)) {
861  ch = Detach;
862  }
863  // If the other pseudoStyles have changed, we want to return NoInherit
864  if (ch == NoChange && pseudoDiff(s1, s2, khtml::RenderStyle::BEFORE)) {
865  ch = NoInherit;
866  }
867  if (ch == NoChange && pseudoDiff(s1, s2, khtml::RenderStyle::AFTER)) {
868  ch = NoInherit;
869  }
870  if (ch == NoChange && pseudoDiff(s1, s2, khtml::RenderStyle::MARKER)) {
871  ch = NoInherit;
872  }
873  if (ch == NoChange && pseudoDiff(s1, s2, khtml::RenderStyle::SELECTION)) {
874  ch = NoInherit;
875  }
876  if (ch == NoChange && pseudoDiff(s1, s2, khtml::RenderStyle::FIRST_LINE)) {
877  ch = NoInherit;
878  }
879 
880  return ch;
881 }
882 
883 bool NodeImpl::pseudoDiff(khtml::RenderStyle *s1, khtml::RenderStyle *s2, unsigned int pid)
884 {
885  khtml::RenderStyle *ps1 = s1 ? s1->getPseudoStyle((khtml::RenderStyle::PseudoId)pid) : nullptr;
886  khtml::RenderStyle *ps2 = s2 ? s2->getPseudoStyle((khtml::RenderStyle::PseudoId)pid) : nullptr;
887 
888  if (ps1 == ps2) {
889  return false;
890  } else if (ps1 && ps2) {
891  if (*ps1 == *ps2) {
892  return false;
893  } else {
894  return true;
895  }
896  } else {
897  return true;
898  }
899 }
900 
901 bool NodeImpl::affectedByNoInherit() const
902 {
903  if (m_render && m_render->style()) {
904  return m_render->style()->inheritedNoninherited();
905  } else {
906  return false;
907  }
908 }
909 
910 void NodeImpl::close()
911 {
912  if (m_render) {
913  m_render->close();
914  }
915  m_closed = true;
916 }
917 
918 void NodeImpl::attach()
919 {
920  assert(!attached());
921  assert(!m_render || (m_render->style() && m_render->parent()));
922  if (m_render) { // set states to match node
923  if (closed()) {
924  m_render->close();
925  }
926  if (hovered()) {
927  m_render->setMouseInside();
928  }
929  }
930  document()->incDOMTreeVersion(DocumentImpl::TV_Structural);
931  m_attached = true;
932 }
933 
934 void NodeImpl::detach()
935 {
936 // assert(m_attached);
937 
938  if (m_render) {
939  m_render->detach();
940  }
941 
942  m_render = nullptr;
943  document()->incDOMTreeVersion(DocumentImpl::TV_Structural);
944  m_attached = false;
945 }
946 
947 bool NodeImpl::maintainsState()
948 {
949  return false;
950 }
951 
952 QString NodeImpl::state()
953 {
954  return QString();
955 }
956 
957 void NodeImpl::restoreState(const QString &/*state*/)
958 {
959 }
960 
961 void NodeImpl::insertedIntoDocument()
962 {
963  setInDocument(true);
964 }
965 
966 void NodeImpl::removedFromDocument()
967 {
968  setInDocument(false);
969 }
970 
971 void NodeImpl::childrenChanged()
972 {
973  if (parentNode()) {
974  parentNode()->childrenChanged();
975  }
976 }
977 
978 bool NodeImpl::isReadOnly()
979 {
980  // Entity & Entity Reference nodes and their descendants are read-only
981  NodeImpl *n = this;
982  while (n) {
983  if (n->nodeType() == Node::ENTITY_NODE ||
984  n->nodeType() == Node::ENTITY_REFERENCE_NODE) {
985  return true;
986  }
987  n = n->parentNode();
988  }
989  return false;
990 }
991 
992 NodeImpl *NodeImpl::previousEditable() const
993 {
994  NodeImpl *node = previousLeafNode();
995  while (node) {
996  if (node->document()->part()->isCaretMode() || node->isContentEditable()) {
997  return node;
998  }
999  node = node->previousLeafNode();
1000  }
1001  return nullptr;
1002 }
1003 
1004 NodeImpl *NodeImpl::nextEditable() const
1005 {
1006  NodeImpl *node = nextLeafNode();
1007  while (node) {
1008  if (node->document()->part()->isCaretMode() || node->isContentEditable()) {
1009  return node;
1010  }
1011  node = node->nextLeafNode();
1012  }
1013  return nullptr;
1014 }
1015 
1016 RenderObject *NodeImpl::previousRenderer()
1017 {
1018  for (NodeImpl *n = previousSibling(); n; n = n->previousSibling()) {
1019  if (n->renderer()) {
1020  return n->renderer();
1021  }
1022  }
1023  return nullptr;
1024 }
1025 
1026 RenderObject *NodeImpl::nextRenderer()
1027 {
1028  for (NodeImpl *n = nextSibling(); n; n = n->nextSibling()) {
1029  if (n->renderer()) {
1030  return n->renderer();
1031  }
1032  }
1033  return nullptr;
1034 }
1035 
1036 void NodeImpl::createRendererIfNeeded()
1037 {
1038 #ifdef APPLE_CHANGES
1039  if (!document()->shouldCreateRenderers()) {
1040  return;
1041  }
1042 #endif
1043 
1044  assert(!m_render);
1045 
1046  NodeImpl *parent = parentNode();
1047  assert(parent);
1048 
1049  RenderObject *parentRenderer = parent->renderer();
1050  if (parentRenderer && parentRenderer->childAllowed()) {
1051  RenderStyle *style = styleForRenderer(parentRenderer);
1052  style->ref();
1053  if (rendererIsNeeded(style)) {
1054  m_render = createRenderer(document()->renderArena(), style);
1055  m_render->setStyle(style);
1056  parentRenderer->addChild(m_render, nextRenderer());
1057  }
1058  style->deref();
1059  }
1060 }
1061 
1062 RenderStyle *NodeImpl::styleForRenderer(RenderObject *parent)
1063 {
1064  return parent->style();
1065 }
1066 
1067 bool NodeImpl::rendererIsNeeded(RenderStyle *style)
1068 {
1069  return (document()->documentElement() == this) || (style->display() != NONE);
1070 }
1071 
1072 RenderObject *NodeImpl::createRenderer(RenderArena * /*arena*/, RenderStyle * /*style*/)
1073 {
1074  assert(false);
1075  return nullptr;
1076 }
1077 
1078 RenderStyle *NodeImpl::computedStyle()
1079 {
1080  return parentNode() ? parentNode()->computedStyle() : nullptr;
1081 }
1082 
1083 NodeImpl *NodeImpl::previousLeafNode() const
1084 {
1085  NodeImpl *node = traversePreviousNode();
1086  while (node) {
1087  if (!node->hasChildNodes()) {
1088  return node;
1089  }
1090  node = node->traversePreviousNode();
1091  }
1092  return nullptr;
1093 }
1094 
1095 NodeImpl *NodeImpl::nextLeafNode() const
1096 {
1097  NodeImpl *node = traverseNextNode();
1098  while (node) {
1099  if (!node->hasChildNodes()) {
1100  return node;
1101  }
1102  node = node->traverseNextNode();
1103  }
1104  return nullptr;
1105 }
1106 
1107 long NodeImpl::maxOffset() const
1108 {
1109  return 1;
1110 }
1111 
1112 long NodeImpl::caretMinOffset() const
1113 {
1114  return renderer() ? renderer()->caretMinOffset() : 0;
1115 }
1116 
1117 long NodeImpl::caretMaxOffset() const
1118 {
1119  return renderer() ? renderer()->caretMaxOffset() : 1;
1120 }
1121 
1122 unsigned long NodeImpl::caretMaxRenderedOffset() const
1123 {
1124  return renderer() ? renderer()->caretMaxRenderedOffset() : 1;
1125 }
1126 
1127 bool NodeImpl::isBlockFlow() const
1128 {
1129  return renderer() && renderer()->isBlockFlow();
1130 }
1131 
1132 bool NodeImpl::isEditableBlock() const
1133 {
1134  return isBlockFlow() && isContentEditable();
1135 }
1136 
1137 ElementImpl *NodeImpl::enclosingBlockFlowElement() const
1138 {
1139  NodeImpl *n = const_cast<NodeImpl *>(this);
1140  if (isBlockFlow()) {
1141  return static_cast<ElementImpl *>(n);
1142  }
1143 
1144  while (1) {
1145  n = n->parentNode();
1146  if (!n) {
1147  break;
1148  }
1149  if (n->isBlockFlow() || n->id() == ID_BODY) {
1150  return static_cast<ElementImpl *>(n);
1151  }
1152  }
1153  return nullptr;
1154 }
1155 
1156 ElementImpl *NodeImpl::rootEditableElement() const
1157 {
1158  if (!isContentEditable()) {
1159  return nullptr;
1160  }
1161 
1162  NodeImpl *n = const_cast<NodeImpl *>(this);
1163  NodeImpl *result = n->isEditableBlock() ? n : nullptr;
1164  while (1) {
1165  n = n->parentNode();
1166  if (!n || !n->isContentEditable()) {
1167  break;
1168  }
1169  if (n->id() == ID_BODY) {
1170  result = n;
1171  break;
1172  }
1173  if (n->isBlockFlow()) {
1174  result = n;
1175  }
1176  }
1177  return static_cast<ElementImpl *>(result);
1178 }
1179 
1180 bool NodeImpl::inSameRootEditableElement(NodeImpl *n)
1181 {
1182  return n ? rootEditableElement() == n->rootEditableElement() : false;
1183 }
1184 
1185 bool NodeImpl::inSameContainingBlockFlowElement(NodeImpl *n)
1186 {
1187  return n ? enclosingBlockFlowElement() == n->enclosingBlockFlowElement() : false;
1188 }
1189 
1190 RenderPosition NodeImpl::positionForCoordinates(int x, int y) const
1191 {
1192  if (renderer()) {
1193  return renderer()->positionForCoordinates(x, y);
1194  }
1195 
1196  return RenderPosition();
1197 }
1198 
1199 bool NodeImpl::isPointInsideSelection(int x, int y, const Selection &sel) const
1200 {
1201  if (sel.state() != Selection::RANGE) {
1202  return false;
1203  }
1204 
1205  RenderPosition pos(positionForCoordinates(x, y));
1206  if (pos.isEmpty()) {
1207  return false;
1208  }
1209 
1210  NodeImpl *n = sel.start().node();
1211  while (n) {
1212  if (n == pos.node()) {
1213  if ((n == sel.start().node() && pos.domOffset() < sel.start().offset()) ||
1214  (n == sel.end().node() && pos.domOffset() > sel.end().offset())) {
1215  return false;
1216  }
1217  return true;
1218  }
1219  if (n == sel.end().node()) {
1220  break;
1221  }
1222  n = n->traverseNextNode();
1223  }
1224 
1225  return false;
1226 
1227 }
1228 
1229 NodeListImpl *NodeImpl::getElementsByTagName(const DOMString &tagName)
1230 {
1231  LocalName localname;
1232  PrefixName prefixname;
1233  if (tagName == "*") {
1234  localname = LocalName::fromId(anyLocalName);
1235  prefixname = PrefixName::fromId(emptyPrefix);
1236  } else {
1237  splitPrefixLocalName(tagName, prefixname, localname, m_htmlCompat);
1238  }
1239  return new TagNodeListImpl(this, NamespaceName::fromId(0), localname, prefixname);
1240 }
1241 
1242 NodeListImpl *NodeImpl::getElementsByTagNameNS(const DOMString &namespaceURI, const DOMString &localName)
1243 {
1244  return new TagNodeListImpl(this, namespaceURI, localName);
1245 }
1246 
1247 NodeListImpl *NodeImpl::getElementsByClassName(const DOMString &name)
1248 {
1249  return new ClassNodeListImpl(this, name);
1250 }
1251 
1252 bool NodeImpl::hasAttributes() const
1253 {
1254  return false;
1255 }
1256 
1257 bool NodeImpl::isSupported(const DOMString &feature, const DOMString &version)
1258 {
1259  return DOMImplementationImpl::hasFeature(feature, version);
1260 }
1261 
1262 DocumentImpl *NodeImpl::ownerDocument() const
1263 {
1264  // braindead DOM spec says that ownerDocument
1265  // should return null if called on the document node
1266  // we thus have our nicer document, and hack it here
1267  // for DOMy clients in one central place
1268  DocumentImpl *doc = document();
1269  if (doc == this) {
1270  return nullptr;
1271  } else {
1272  return doc;
1273  }
1274 }
1275 
1276 // Helper for compareDocumentPosition --- this extends the notion of a parent node
1277 // beyond structural to also include elements containing attributes, etc.
1278 static const NodeImpl *logicalParentNode(const DOM::NodeImpl *node)
1279 {
1280  NodeImpl *parent = node->parentNode();
1281  if (parent) {
1282  return parent;
1283  }
1284 
1285  switch (node->nodeType()) {
1286  case Node::ATTRIBUTE_NODE:
1287  return static_cast<const AttrImpl *>(node)->ownerElement();
1288 
1289  case Node::ENTITY_NODE:
1290  case Node::NOTATION_NODE:
1291  return node->ownerDocument()->doctype();
1292 
1293  default:
1294  return nullptr;
1295  }
1296 }
1297 
1298 unsigned NodeImpl::compareDocumentPosition(const DOM::NodeImpl *other)
1299 {
1300  if (other == this) {
1301  return 0;
1302  }
1303 
1304  // First, collect paths of the parents of this and other to the root of their subtrees.
1305  // Root goes first, hence the use of QList, with its fast prepends
1306  QList<const NodeImpl *> thisPath;
1307  for (const NodeImpl *cur = this; cur; cur = logicalParentNode(cur)) {
1308  thisPath.prepend(cur);
1309  }
1310 
1311  QList<const NodeImpl *> otherPath;
1312  for (const NodeImpl *cur = other; cur; cur = logicalParentNode(cur)) {
1313  otherPath.prepend(cur);
1314  }
1315 
1316  // if the roots aren't the same, we're disconnected. We're also supposed to
1317  // return IMPLEMENTATION_SPECIFIC here, and, reading tea leaves, make some
1318  // sort of a stable decision to get a total order.
1319  if (thisPath[0] != otherPath[0]) {
1320  return Node::DOCUMENT_POSITION_DISCONNECTED | Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
1321  (this > other ? Node::DOCUMENT_POSITION_PRECEDING : Node::DOCUMENT_POSITION_FOLLOWING);
1322  }
1323 
1324  // Now find our common container.
1325  const NodeImpl *common = nullptr;
1326  int diffPos = -1;
1327  for (int pos = 0; pos < thisPath.size() && pos < otherPath.size(); ++pos) {
1328  if (thisPath[pos] == otherPath[pos]) {
1329  common = thisPath[pos];
1330  } else {
1331  diffPos = pos;
1332  break;
1333  }
1334  }
1335 
1336  // Do we have direct containment?
1337  if (common == this) {
1338  return Node::DOCUMENT_POSITION_CONTAINED_BY | Node::DOCUMENT_POSITION_FOLLOWING;
1339  } else if (common == other) {
1340  return Node::DOCUMENT_POSITION_CONTAINS | Node::DOCUMENT_POSITION_PRECEDING;
1341  }
1342 
1343  // OK, so now we are not nested, so there are ancestors of both nodes
1344  // below common that are different. Since some of those may be logically and not
1345  // physically contained in common, we have to treat the logical containment case specially.
1346  const NodeImpl *thisAnc = thisPath [diffPos];
1347  const NodeImpl *otherAnc = otherPath[diffPos];
1348 
1349  bool thisAncLogical = thisAnc->parentNode() == nullptr;
1350  bool otherAncLogical = otherAnc->parentNode() == nullptr;
1351  //qCDebug(KHTML_LOG) << thisAncLogical << otherAncLogical;
1352 
1353  if (thisAncLogical && otherAncLogical) {
1354  // First, try to order by nodeType.
1355  if (thisAnc->nodeType() != otherAnc->nodeType())
1356  return (thisAnc->nodeType() < otherAnc->nodeType()) ?
1357  Node::DOCUMENT_POSITION_FOLLOWING : Node::DOCUMENT_POSITION_PRECEDING;
1358 
1359  // If both are argument nodes, they have to be in the same element,
1360  // as otherwise the first difference would be in two different elements
1361  // or above, which would not have logical parents unless they were
1362  // disconnected, which would have been handled above.
1363  // In this case, order them by their position in the
1364  // attribute list. This is helpful for XPath.
1365 
1366  if (thisAnc->nodeType() == Node::ATTRIBUTE_NODE) {
1367  const AttrImpl *thisAncAttr = static_cast<const AttrImpl *>(thisAnc);
1368  const AttrImpl *otherAncAttr = static_cast<const AttrImpl *>(otherAnc);
1369 
1370  NamedAttrMapImpl *attrs = thisAncAttr->ownerElement()->attributes();
1371 
1372  unsigned l = attrs->length();
1373  for (unsigned i = 0; i < l; ++i) {
1374  if (attrs->attrAt(i) == thisAncAttr) {
1375  return Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | Node::DOCUMENT_POSITION_FOLLOWING;
1376  }
1377  if (attrs->attrAt(i) == otherAncAttr) {
1378  return Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | Node::DOCUMENT_POSITION_PRECEDING;
1379  }
1380  }
1381  assert(false);
1382  }
1383 
1384  // If not, another implementation-specific order.
1385  return Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
1386  (this > other ? Node::DOCUMENT_POSITION_PRECEDING : Node::DOCUMENT_POSITION_FOLLOWING);
1387  }
1388 
1389  if (thisAncLogical) {
1390  return Node::DOCUMENT_POSITION_FOLLOWING;
1391  }
1392 
1393  if (otherAncLogical) {
1394  return Node::DOCUMENT_POSITION_PRECEDING;
1395  }
1396 
1397  // Uff. And now the normal case -- just order thisAnc and otherAnc based on their tree order
1398  // see if otherAnc follows thisAnc)
1399  for (const NodeImpl *cur = thisAnc; cur; cur = cur->nextSibling()) {
1400  if (cur == otherAnc) {
1401  return Node::DOCUMENT_POSITION_FOLLOWING;
1402  }
1403  }
1404 
1405  return Node::DOCUMENT_POSITION_PRECEDING;
1406 }
1407 
1408 static NodeImpl *rootForSelectorQuery(DOM::NodeImpl *arg)
1409 {
1410  if (arg->nodeType() == Node::DOCUMENT_TYPE_NODE) {
1411  return static_cast<DOM::DocumentImpl *>(arg)->documentElement();
1412  } else {
1413  return arg;
1414  }
1415 }
1416 
1417 WTF::PassRefPtr<DOM::ElementImpl> NodeImpl::querySelector(const DOM::DOMString &query, int &ec)
1418 {
1419  return khtml::SelectorQuery::querySelector(rootForSelectorQuery(this),
1420  query, ec);
1421 }
1422 
1423 WTF::PassRefPtr<DOM::NodeListImpl> NodeImpl::querySelectorAll(const DOM::DOMString &query, int &ec)
1424 {
1425  return khtml::SelectorQuery::querySelectorAll(rootForSelectorQuery(this),
1426  query, ec);
1427 }
1428 
1429 void NodeImpl::setDocument(DocumentImpl *doc)
1430 {
1431  if (m_document == doc) {
1432  return;
1433  }
1434 
1435 #if 1 // implemented for one special case only so far
1436  assert(m_document == nullptr && doc != nullptr &&
1437  nodeType() == Node::DOCUMENT_TYPE_NODE);
1438  m_document = doc;
1439 #else // for general use do something like this
1440  m_document = 0;
1441  if (inDocument()) {
1442  removedFromDocument();
1443  }
1444 
1445  ScriptInterpreter::updateDOMNodeDocument(this, m_document, doc);
1446 
1447  m_document = doc;
1448  insertedIntoDocument();
1449 #endif
1450 }
1451 
1452 DOM::DOMString DOM::NodeImpl::lookupNamespaceURI(const DOM::DOMString &prefix)
1453 {
1454  //for details see https://www.w3.org/TR/DOM-Level-3-Core/namespaces-algorithms.html#lookupNamespaceURIAlgo
1455 
1456  // check if this is one of the hard defined prefixes
1457  PrefixName ppn = PrefixName::fromString(prefix);
1458  if (ppn.id() == xmlPrefix) {
1459  return DOM::DOMString(XML_NAMESPACE);
1460  }
1461  if (ppn.id() == xmlnsPrefix) {
1462  return DOM::DOMString(XMLNS_NAMESPACE);
1463  }
1464 
1465  switch (this->nodeType()) {
1466  case Node::ELEMENT_NODE:
1467  if (!this->namespaceURI().isNull() && this->prefix() == prefix) {
1468  return this->namespaceURI();
1469  }
1470  if (this->hasAttributes()) {
1471  ElementImpl *node = static_cast<ElementImpl *>(this);
1472 
1473  NamedAttrMapImpl *attributes = node->attributes(true /*readonly*/);
1474  if (ppn.id() != emptyPrefix) {
1475  LocalName pln = LocalName::fromString(prefix);
1476  PrefixName xmlns = PrefixName::fromId(xmlnsNamespace);
1477 
1478  DOM::DOMString result = attributes->getValue(pln.id(), xmlns);
1479  if (!result.isNull()) {
1480  return result;
1481  }
1482  } else {
1483  DOM::DOMString result = attributes->getValue(ATTR_XMLNS);
1484  if (!result.isEmpty()) {
1485  return result;
1486  }
1487  }
1488  }
1489  {
1490  NodeImpl *ancestor = findNextElementAncestor(this);
1491  if (ancestor) {
1492  return ancestor->lookupNamespaceURI(prefix);
1493  }
1494  }
1495  return DOM::DOMString();
1496 
1497  case Node::DOCUMENT_NODE: {
1498  DocumentImpl *node = static_cast<DocumentImpl *>(this);
1499  return node->documentElement()->lookupNamespaceURI(prefix);
1500  }
1501 
1502  case Node::ATTRIBUTE_NODE: {
1503  NodeImpl *ancestor = this->parentNode();
1504  if (ancestor) {
1505  return ancestor->lookupNamespaceURI(prefix);
1506  } else {
1507  return DOM::DOMString();
1508  }
1509  }
1510 
1511  case Node::ENTITY_NODE:
1512  case Node::NOTATION_NODE:
1513  case Node::DOCUMENT_TYPE_NODE:
1514  case Node::DOCUMENT_FRAGMENT_NODE:
1515  return DOM::DOMString();
1516 
1517  default: {
1518  NodeImpl *ancestor = findNextElementAncestor(this);
1519  if (ancestor) {
1520  return ancestor->lookupNamespaceURI(prefix);
1521  }
1522  return DOM::DOMString();
1523  }
1524  }
1525 }
1526 
1527 DOM::NodeImpl *DOM::NodeImpl::findNextElementAncestor(NodeImpl *node)
1528 {
1529  NodeImpl *iterator = node->parentNode();
1530  while (iterator) {
1531  if (iterator->nodeType() == Node::ELEMENT_NODE) {
1532  return iterator;
1533  }
1534  iterator = iterator->parentNode();
1535  }
1536  return nullptr;
1537 }
1538 
1539 //-------------------------------------------------------------------------
1540 
1541 NodeBaseImpl::~NodeBaseImpl()
1542 {
1543  //qCDebug(KHTML_LOG) << "NodeBaseImpl destructor";
1544  // we have to tell all children, that the parent has died...
1545  NodeImpl *n;
1546  NodeImpl *next;
1547 
1548  for (n = _first; n != nullptr; n = next) {
1549  next = n->nextSibling();
1550  n->setPreviousSibling(nullptr);
1551  n->setNextSibling(nullptr);
1552  n->setParent(nullptr);
1553  if (!n->refCount()) {
1554  delete n;
1555  }
1556  }
1557 }
1558 
1559 NodeImpl *NodeBaseImpl::firstChild() const
1560 {
1561  return _first;
1562 }
1563 
1564 NodeImpl *NodeBaseImpl::lastChild() const
1565 {
1566  return _last;
1567 }
1568 
1569 NodeImpl *NodeBaseImpl::insertBefore(NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode)
1570 {
1571  exceptioncode = 0;
1572 
1573  // insertBefore(...,null) is equivalent to appendChild()
1574  if (!refChild) {
1575  return appendChild(newChild, exceptioncode);
1576  }
1577 
1578  // Make sure adding the new child is ok
1579  checkAddChild(newChild, exceptioncode);
1580  if (exceptioncode) {
1581  return nullptr;
1582  }
1583 
1584  // NOT_FOUND_ERR: Raised if refChild is not a child of this node
1585  if (refChild->parentNode() != this) {
1586  exceptioncode = DOMException::NOT_FOUND_ERR;
1587  return nullptr;
1588  }
1589 
1590  bool isFragment = newChild->nodeType() == Node::DOCUMENT_FRAGMENT_NODE;
1591 
1592  // If newChild is a DocumentFragment with no children.... there's nothing to do.
1593  // Just return the document fragment
1594  if (isFragment && !newChild->firstChild()) {
1595  return newChild;
1596  }
1597 
1598  // Now actually add the child(ren)
1599  NodeImpl *nextChild;
1600  NodeImpl *child = isFragment ? newChild->firstChild() : newChild;
1601 
1602  NodeImpl *prev = refChild->previousSibling();
1603  if (prev == newChild || refChild == newChild) { // nothing to do
1604  return newChild;
1605  }
1606 
1607  while (child) {
1608  nextChild = isFragment ? child->nextSibling() : nullptr;
1609 
1610  // If child is already present in the tree, first remove it
1611  NodeImpl *newParent = child->parentNode();
1612 
1613  //...guard it in case we need to move it..
1614  SharedPtr<NodeImpl> guard(child);
1615 
1616  if (newParent) {
1617  newParent->removeChild(child, exceptioncode);
1618  }
1619  if (exceptioncode) {
1620  return nullptr;
1621  }
1622 
1623  // Add child in the correct position
1624  if (prev) {
1625  prev->setNextSibling(child);
1626  } else {
1627  _first = child;
1628  }
1629  refChild->setPreviousSibling(child);
1630  child->setParent(this);
1631  child->setPreviousSibling(prev);
1632  child->setNextSibling(refChild);
1633 
1634  // Add child to the rendering tree
1635  // ### should we detach() it first if it's already attached?
1636  if (attached() && !child->attached()) {
1637  child->attach();
1638  }
1639 
1640  // Dispatch the mutation events
1641  dispatchChildInsertedEvents(child, exceptioncode);
1642 
1643  prev = child;
1644  child = nextChild;
1645  }
1646 
1647  if (!newChild->closed()) {
1648  newChild->close();
1649  }
1650 
1651  structureChanged();
1652 
1653  // ### set style in case it's attached
1654  dispatchSubtreeModifiedEvent();
1655  return newChild;
1656 }
1657 
1658 void NodeBaseImpl::replaceChild(NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode)
1659 {
1660  exceptioncode = 0;
1661 
1662  if (oldChild == newChild) { // nothing to do
1663  return;
1664  }
1665 
1666  // Make sure adding the new child is ok
1667  checkAddChild(newChild, exceptioncode);
1668  if (exceptioncode) {
1669  return;
1670  }
1671 
1672  // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
1673  if (!oldChild || oldChild->parentNode() != this) {
1674  exceptioncode = DOMException::NOT_FOUND_ERR;
1675  return;
1676  }
1677 
1678  bool isFragment = newChild->nodeType() == Node::DOCUMENT_FRAGMENT_NODE;
1679  NodeImpl *nextChild;
1680  NodeImpl *child = isFragment ? newChild->firstChild() : newChild;
1681 
1682  // Remove the old child
1683  NodeImpl *prev = oldChild->previousSibling();
1684  NodeImpl *next = oldChild->nextSibling();
1685 
1686  removeChild(oldChild, exceptioncode);
1687  if (exceptioncode) {
1688  return;
1689  }
1690 
1691  // Add the new child(ren)
1692  while (child) {
1693  nextChild = isFragment ? child->nextSibling() : nullptr;
1694 
1695  // If child is already present in the tree, first remove it
1696  NodeImpl *newParent = child->parentNode();
1697  if (child == next) {
1698  next = child->nextSibling();
1699  }
1700  if (child == prev) {
1701  prev = child->previousSibling();
1702  }
1703  //...guard it in case we need to move it..
1704  SharedPtr<NodeImpl> guard(child);
1705  if (newParent) {
1706  newParent->removeChild(child, exceptioncode);
1707  }
1708  if (exceptioncode) {
1709  return;
1710  }
1711 
1712  // Add child in the correct position
1713  if (prev) {
1714  prev->setNextSibling(child);
1715  }
1716  if (next) {
1717  next->setPreviousSibling(child);
1718  }
1719  if (!prev) {
1720  _first = child;
1721  }
1722  if (!next) {
1723  _last = child;
1724  }
1725  child->setParent(this);
1726  child->setPreviousSibling(prev);
1727  child->setNextSibling(next);
1728 
1729  // Add child to the rendering tree
1730  // ### should we detach() it first if it's already attached?
1731  if (attached() && !child->attached()) {
1732  child->attach();
1733  }
1734 
1735  // Dispatch the mutation events
1736  dispatchChildInsertedEvents(child, exceptioncode);
1737 
1738  prev = child;
1739  child = nextChild;
1740  }
1741 
1742  if (!newChild->closed()) {
1743  newChild->close();
1744  }
1745 
1746  structureChanged();
1747 
1748  // ### set style in case it's attached
1749  dispatchSubtreeModifiedEvent();
1750  return;
1751 }
1752 
1753 void NodeBaseImpl::removeChild(NodeImpl *oldChild, int &exceptioncode)
1754 {
1755  exceptioncode = 0;
1756 
1757  // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
1758  if (isReadOnly()) {
1759  exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
1760  return;
1761  }
1762 
1763  // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
1764  if (!oldChild || oldChild->parentNode() != this) {
1765  exceptioncode = DOMException::NOT_FOUND_ERR;
1766  return;
1767  }
1768 
1769  dispatchChildRemovalEvents(oldChild, exceptioncode);
1770  if (exceptioncode) {
1771  return;
1772  }
1773 
1774  SharedPtr<NodeImpl> memManage(oldChild); //Make sure to free if needed
1775 
1776  // Remove from rendering tree
1777  if (oldChild->attached()) {
1778  oldChild->detach();
1779  }
1780 
1781  // Remove the child
1782  NodeImpl *prev, *next;
1783  prev = oldChild->previousSibling();
1784  next = oldChild->nextSibling();
1785 
1786  if (next) {
1787  next->setPreviousSibling(prev);
1788  }
1789  if (prev) {
1790  prev->setNextSibling(next);
1791  }
1792  if (_first == oldChild) {
1793  _first = next;
1794  }
1795  if (_last == oldChild) {
1796  _last = prev;
1797  }
1798 
1799  oldChild->setPreviousSibling(nullptr);
1800  oldChild->setNextSibling(nullptr);
1801  oldChild->setParent(nullptr);
1802 
1803  structureChanged();
1804 
1805  // Dispatch post-removal mutation events
1806  dispatchSubtreeModifiedEvent();
1807 
1808  NodeImpl *p = this;
1809  while (p->parentNode()) {
1810  p = p->parentNode();
1811  }
1812  if (p->nodeType() == Node::DOCUMENT_NODE) {
1813  for (NodeImpl *c = oldChild; c; c = c->traverseNextNode(oldChild)) {
1814  c->removedFromDocument();
1815  }
1816  }
1817 }
1818 
1819 void NodeBaseImpl::removeChildren()
1820 {
1821  bool inDoc = inDocument();
1822  NodeImpl *n, *next;
1823  for (n = _first, _first = nullptr; n; n = next) {
1824  next = n->nextSibling();
1825  if (n->attached()) {
1826  n->detach();
1827  }
1828  n->setPreviousSibling(nullptr);
1829  n->setNextSibling(nullptr);
1830  n->setParent(nullptr);
1831 
1832  if (inDoc)
1833  for (NodeImpl *c = n; c; c = c->traverseNextNode(n)) {
1834  c->removedFromDocument();
1835  }
1836 
1837  if (!n->refCount()) {
1838  delete n;
1839  }
1840  }
1841  _last = nullptr;
1842 }
1843 
1844 NodeImpl *NodeBaseImpl::appendChild(NodeImpl *newChild, int &exceptioncode)
1845 {
1846  exceptioncode = 0;
1847 
1848  // Make sure adding the new child is ok
1849  checkAddChild(newChild, exceptioncode);
1850  if (exceptioncode) {
1851  return nullptr;
1852  }
1853 
1854  if (newChild == _last) { // nothing to do
1855  return newChild;
1856  }
1857 
1858  bool isFragment = newChild->nodeType() == Node::DOCUMENT_FRAGMENT_NODE;
1859 
1860  // If newChild is a DocumentFragment with no children.... there's nothing to do.
1861  // Just return the document fragment
1862  if (isFragment && !newChild->firstChild()) {
1863  return newChild;
1864  }
1865 
1866  // Now actually add the child(ren)
1867  NodeImpl *nextChild;
1868  NodeImpl *child = isFragment ? newChild->firstChild() : newChild;
1869 
1870  while (child) {
1871  nextChild = isFragment ? child->nextSibling() : nullptr;
1872 
1873  // If child is already present in the tree, first remove it
1874  NodeImpl *oldParent = child->parentNode();
1875  SharedPtr<NodeImpl> guard(child); //Guard in case we move it
1876  if (oldParent) {
1877  oldParent->removeChild(child, exceptioncode);
1878  if (exceptioncode) {
1879  return nullptr;
1880  }
1881  }
1882 
1883  // Append child to the end of the list
1884  child->setParent(this);
1885 
1886  if (_last) {
1887  child->setPreviousSibling(_last);
1888  _last->setNextSibling(child);
1889  _last = child;
1890  } else {
1891  _first = _last = child;
1892  }
1893 
1894  // Add child to the rendering tree
1895  // ### should we detach() it first if it's already attached?
1896  if (attached() && !child->attached()) {
1897  child->attach();
1898  }
1899 
1900  // Dispatch the mutation events
1901  dispatchChildInsertedEvents(child, exceptioncode);
1902 
1903  child = nextChild;
1904  }
1905 
1906  if (!newChild->closed()) {
1907  newChild->close();
1908  }
1909 
1910  backwardsStructureChanged();
1911 
1912  // ### set style in case it's attached
1913  dispatchSubtreeModifiedEvent();
1914  return newChild;
1915 }
1916 
1917 bool NodeBaseImpl::hasChildNodes() const
1918 {
1919  return _first != nullptr;
1920 }
1921 
1922 // not part of the DOM
1923 void NodeBaseImpl::setFirstChild(NodeImpl *child)
1924 {
1925  _first = child;
1926 }
1927 
1928 void NodeBaseImpl::setLastChild(NodeImpl *child)
1929 {
1930  _last = child;
1931 }
1932 
1933 // check for same source document:
1934 bool NodeBaseImpl::checkSameDocument(NodeImpl *newChild, int &exceptioncode)
1935 {
1936  exceptioncode = 0;
1937  DocumentImpl *ownerDocThis = document();
1938  DocumentImpl *ownerDocNew = newChild->document();
1939  if (ownerDocThis != ownerDocNew) {
1940  // qCDebug(KHTML_LOG)<< "not same document, newChild = " << newChild << "document = " << document();
1941  exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
1942  return true;
1943  }
1944  return false;
1945 }
1946 
1947 // check for being child:
1948 bool NodeBaseImpl::checkIsChild(NodeImpl *oldChild, int &exceptioncode)
1949 {
1950  if (!oldChild || oldChild->parentNode() != this) {
1951  exceptioncode = DOMException::NOT_FOUND_ERR;
1952  return true;
1953  }
1954  return false;
1955 }
1956 
1957 NodeImpl *NodeBaseImpl::addChild(NodeImpl *newChild)
1958 {
1959  // do not add applyChanges here! This function is only used during parsing
1960 
1961  // short check for consistency with DTD
1962  if (document()->isHTMLDocument() && !childAllowed(newChild)) {
1963  //qCDebug(KHTML_LOG) << "AddChild failed! id=" << id() << ", child->id=" << newChild->id();
1964  return nullptr;
1965  }
1966 
1967  // just add it...
1968  newChild->setParent(this);
1969 
1970  if (_last) {
1971  newChild->setPreviousSibling(_last);
1972  _last->setNextSibling(newChild);
1973  _last = newChild;
1974  } else {
1975  _first = _last = newChild;
1976  }
1977 
1978  if (inDocument()) {
1979  newChild->insertedIntoDocument();
1980  }
1981  childrenChanged();
1982 
1983  if (newChild->nodeType() == Node::ELEMENT_NODE) {
1984  return newChild;
1985  }
1986  return this;
1987 }
1988 
1989 void NodeBaseImpl::attach()
1990 {
1991  NodeImpl *child = _first;
1992  while (child != nullptr) {
1993  child->attach();
1994  child = child->nextSibling();
1995  }
1996  NodeImpl::attach();
1997 }
1998 
1999 void NodeBaseImpl::detach()
2000 {
2001  NodeImpl *child = _first;
2002  while (child != nullptr) {
2003  NodeImpl *prev = child;
2004  child = child->nextSibling();
2005  prev->detach();
2006  }
2007  NodeImpl::detach();
2008 }
2009 
2010 void NodeBaseImpl::cloneChildNodes(NodeImpl *clone)
2011 {
2012  int exceptioncode = 0;
2013  NodeImpl *n;
2014  for (n = firstChild(); n && !exceptioncode; n = n->nextSibling()) {
2015  clone->appendChild(n->cloneNode(true).get(), exceptioncode);
2016  }
2017 }
2018 
2019 // I don't like this way of implementing the method, but I didn't find any
2020 // other way. Lars
2021 bool NodeBaseImpl::getUpperLeftCorner(int &xPos, int &yPos) const
2022 {
2023  if (!m_render) {
2024  return false;
2025  }
2026  RenderObject *o = m_render;
2027  xPos = yPos = 0;
2028  if (!o->isInline() || o->isReplaced()) {
2029  o->absolutePosition(xPos, yPos);
2030  return true;
2031  }
2032 
2033  // find the next text/image child, to get a position
2034  while (o) {
2035  if (o->firstChild()) {
2036  o = o->firstChild();
2037  } else if (o->nextSibling()) {
2038  o = o->nextSibling();
2039  } else {
2040  RenderObject *next = nullptr;
2041  while (!next) {
2042  o = o->parent();
2043  if (!o) {
2044  return false;
2045  }
2046  next = o->nextSibling();
2047  }
2048  o = next;
2049  }
2050  if ((o->isText() && !o->isBR()) || o->isReplaced()) {
2051  o->container()->absolutePosition(xPos, yPos);
2052  if (o->isText()) {
2053  xPos += o->inlineXPos();
2054  yPos += o->inlineYPos();
2055  } else {
2056  xPos += o->xPos();
2057  yPos += o->yPos();
2058  }
2059  return true;
2060  }
2061  }
2062  return true;
2063 }
2064 
2065 bool NodeBaseImpl::getLowerRightCorner(int &xPos, int &yPos) const
2066 {
2067  if (!m_render) {
2068  return false;
2069  }
2070 
2071  RenderObject *o = m_render;
2072  xPos = yPos = 0;
2073  if (!o->isInline() || o->isReplaced()) {
2074  o->absolutePosition(xPos, yPos);
2075  xPos += o->width();
2076  yPos += o->height() + o->borderTopExtra() + o->borderBottomExtra();
2077  return true;
2078  }
2079  // find the last text/image child, to get a position
2080  while (o) {
2081  if (o->lastChild()) {
2082  o = o->lastChild();
2083  } else if (o->previousSibling()) {
2084  o = o->previousSibling();
2085  } else {
2086  RenderObject *prev = nullptr;
2087  while (!prev) {
2088  o = o->parent();
2089  if (!o) {
2090  return false;
2091  }
2092  prev = o->previousSibling();
2093  }
2094  o = prev;
2095  }
2096  if ((o->isText() && !o->isBR()) || o->isReplaced()) {
2097  o->container()->absolutePosition(xPos, yPos);
2098  if (o->isText()) {
2099  xPos += o->inlineXPos() + o->width();
2100  yPos += o->inlineYPos() + o->height();
2101  } else {
2102  xPos += o->xPos() + o->width();
2103  yPos += o->yPos() + o->height();
2104  }
2105  return true;
2106  }
2107  }
2108  return true;
2109 }
2110 
2111 void NodeBaseImpl::setFocus(bool received)
2112 {
2113  if (m_focused == received) {
2114  return;
2115  }
2116 
2117  NodeImpl::setFocus(received);
2118 
2119  // note that we need to recalc the style
2120  setChanged(); // *:focus is a default style, so we just assume personal dependency
2121  if (isElementNode()) {
2122  document()->dynamicDomRestyler().restyleDependent(static_cast<ElementImpl *>(this), OtherStateDependency);
2123  }
2124 }
2125 
2126 void NodeBaseImpl::setActive(bool down)
2127 {
2128  if (down == active()) {
2129  return;
2130  }
2131 
2132  NodeImpl::setActive(down);
2133 
2134  // note that we need to recalc the style
2135  if (isElementNode()) {
2136  document()->dynamicDomRestyler().restyleDependent(static_cast<ElementImpl *>(this), ActiveDependency);
2137  }
2138 }
2139 
2140 void NodeBaseImpl::setHovered(bool hover)
2141 {
2142  if (hover == hovered()) {
2143  return;
2144  }
2145 
2146  NodeImpl::setHovered(hover);
2147 
2148  // note that we need to recalc the style
2149  if (isElementNode()) {
2150  document()->dynamicDomRestyler().restyleDependent(static_cast<ElementImpl *>(this), HoverDependency);
2151  }
2152 }
2153 
2154 unsigned long NodeBaseImpl::childNodeCount()
2155 {
2156  unsigned long count = 0;
2157  NodeImpl *n;
2158  for (n = firstChild(); n; n = n->nextSibling()) {
2159  count++;
2160  }
2161  return count;
2162 }
2163 
2164 NodeImpl *NodeBaseImpl::childNode(unsigned long index)
2165 {
2166  unsigned long i;
2167  NodeImpl *n = firstChild();
2168  for (i = 0; n && i < index; i++) {
2169  n = n->nextSibling();
2170  }
2171  return n;
2172 }
2173 
2174 void NodeBaseImpl::dispatchChildInsertedEvents(NodeImpl *child, int &exceptioncode)
2175 {
2176  if (document()->hasListenerType(DocumentImpl::DOMNODEINSERTED_LISTENER)) {
2177  // We need to weak-guard ourselves since 'this' may be a fresh node, so
2178  // we don't want the mutation event to delete it.
2179  ref();
2180  MutationEventImpl *const evt = new MutationEventImpl(EventImpl::DOMNODEINSERTED_EVENT, true, false, this, DOMString(), DOMString(), DOMString(), 0);
2181  evt->ref();
2182  child->dispatchEvent(evt, exceptioncode, true);
2183  evt->deref();
2184  derefOnly();
2185  if (exceptioncode) {
2186  return;
2187  }
2188  }
2189 
2190  // dispatch the DOMNodeInsertedIntoDocument event to all descendants
2191  bool hasInsertedListeners = document()->hasListenerType(DocumentImpl::DOMNODEINSERTEDINTODOCUMENT_LISTENER);
2192  NodeImpl *p = this;
2193  while (p->parentNode()) {
2194  p = p->parentNode();
2195  }
2196  if (p->nodeType() == Node::DOCUMENT_NODE) {
2197  for (NodeImpl *c = child; c; c = c->traverseNextNode(child)) {
2198  c->insertedIntoDocument();
2199 
2200  if (hasInsertedListeners) {
2201  ref();
2202  MutationEventImpl *const evt = new MutationEventImpl(EventImpl::DOMNODEINSERTEDINTODOCUMENT_EVENT, false, false, nullptr, DOMString(), DOMString(), DOMString(), 0);
2203  evt->ref();
2204  c->dispatchEvent(evt, exceptioncode, true);
2205  evt->deref();
2206  derefOnly();
2207  if (exceptioncode) {
2208  return;
2209  }
2210  }
2211  }
2212  }
2213 }
2214 
2215 void NodeBaseImpl::dispatchChildRemovalEvents(NodeImpl *child, int &exceptioncode)
2216 {
2217  // Dispatch pre-removal mutation events
2218  document()->notifyBeforeNodeRemoval(child); // ### use events instead
2219  if (document()->hasListenerType(DocumentImpl::DOMNODEREMOVED_LISTENER)) {
2220  ref();
2221  MutationEventImpl *const evt = new MutationEventImpl(EventImpl::DOMNODEREMOVED_EVENT, true, false, this, DOMString(), DOMString(), DOMString(), 0);
2222  evt->ref();
2223  child->dispatchEvent(evt, exceptioncode, true);
2224  evt->deref();
2225  derefOnly();
2226  if (exceptioncode) {
2227  return;
2228  }
2229  }
2230 
2231  bool hasRemovalListeners = document()->hasListenerType(DocumentImpl::DOMNODEREMOVEDFROMDOCUMENT_LISTENER);
2232 
2233  // dispatch the DOMNodeRemovedFromDocument event to all descendants
2234  NodeImpl *p = this;
2235  while (p->parentNode()) {
2236  p = p->parentNode();
2237  }
2238  if (p->nodeType() == Node::DOCUMENT_NODE) {
2239  for (NodeImpl *c = child; c; c = c->traverseNextNode(child)) {
2240  if (hasRemovalListeners) {
2241  ref();
2242  MutationEventImpl *const evt = new MutationEventImpl(EventImpl::DOMNODEREMOVEDFROMDOCUMENT_EVENT, false, false, nullptr, DOMString(), DOMString(), DOMString(), 0);
2243  evt->ref();
2244  c->dispatchEvent(evt, exceptioncode, true);
2245  evt->deref();
2246  derefOnly();
2247  if (exceptioncode) {
2248  return;
2249  }
2250  }
2251  }
2252  }
2253 }
2254 
2255 // ---------------------------------------------------------------------------
2256 
2257 NamedNodeMapImpl::NamedNodeMapImpl()
2258 {
2259 }
2260 
2261 NamedNodeMapImpl::~NamedNodeMapImpl()
2262 {
2263 }
2264 
2265 NodeImpl *NamedNodeMapImpl::getNamedItem(const DOMString &name)
2266 {
2267  PrefixName prefix;
2268  LocalName localName;
2269  splitPrefixLocalName(name, prefix, localName, htmlCompat());
2270 
2271  return getNamedItem(localName.id(), prefix, false);
2272 }
2273 
2274 Node NamedNodeMapImpl::setNamedItem(const Node &arg, int &exceptioncode)
2275 {
2276  if (!arg.handle()) {
2277  exceptioncode = DOMException::NOT_FOUND_ERR;
2278  return nullptr;
2279  }
2280 
2281  Node r = setNamedItem(arg.handle(), emptyPrefixName, false, exceptioncode);
2282  return r;
2283 }
2284 
2285 Node NamedNodeMapImpl::removeNamedItem(const DOMString &name, int &exceptioncode)
2286 {
2287  PrefixName prefix;
2288  LocalName localName;
2289  splitPrefixLocalName(name, prefix, localName, htmlCompat());
2290 
2291  Node r = removeNamedItem(localName.id(), prefix, false, exceptioncode);
2292  return r;
2293 }
2294 
2295 Node NamedNodeMapImpl::getNamedItemNS(const DOMString &namespaceURI, const DOMString &localName)
2296 {
2297  LocalName localname = LocalName::fromString(localName);
2298  NamespaceName namespacename = NamespaceName::fromString(namespaceURI);
2299  return getNamedItem(makeId(namespacename.id(), localname.id()), emptyPrefixName, true);
2300 }
2301 
2302 Node NamedNodeMapImpl::setNamedItemNS(const Node &arg, int &exceptioncode)
2303 {
2304  return setNamedItem(arg.handle(), emptyPrefixName, true, exceptioncode);
2305 }
2306 
2307 Node NamedNodeMapImpl::removeNamedItemNS(const DOMString &namespaceURI, const DOMString &localName, int &exceptioncode)
2308 {
2309  LocalName localname = LocalName::fromString(localName);
2310  NamespaceName namespacename = NamespaceName::fromString(namespaceURI);
2311  return removeNamedItem(makeId(namespacename.id(), localname.id()), emptyPrefixName, true, exceptioncode);
2312 }
2313 
2314 // ----------------------------------------------------------------------------
2315 
2316 GenericRONamedNodeMapImpl::GenericRONamedNodeMapImpl(DocumentImpl *doc)
2317  : NamedNodeMapImpl()
2318 {
2319  m_doc = doc;
2320  m_contents = new QList<NodeImpl *>;
2321 }
2322 
2323 GenericRONamedNodeMapImpl::~GenericRONamedNodeMapImpl()
2324 {
2325  while (!m_contents->isEmpty()) {
2326  m_contents->takeLast()->deref();
2327  }
2328 
2329  delete m_contents;
2330 }
2331 
2332 NodeImpl *GenericRONamedNodeMapImpl::getNamedItem(NodeImpl::Id id, const PrefixName & /*prefix*/, bool /*nsAware*/)
2333 {
2334  // ## do we need namespace support in this class?
2335  QListIterator<NodeImpl *> it(*m_contents);
2336  while (it.hasNext())
2337  if (it.next()->id() == id) {
2338  return it.peekPrevious();
2339  }
2340  return nullptr;
2341 }
2342 
2343 Node GenericRONamedNodeMapImpl::setNamedItem(NodeImpl * /*arg*/, const PrefixName & /*prefix*/, bool /*nsAware*/, int &exceptioncode)
2344 {
2345  // can't modify this list through standard DOM functions
2346  // NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly
2347  exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
2348  return nullptr;
2349 }
2350 
2351 Node GenericRONamedNodeMapImpl::removeNamedItem(NodeImpl::Id /*id*/, const PrefixName & /*prefix*/, bool /*nsAware*/, int &exceptioncode)
2352 {
2353  // can't modify this list through standard DOM functions
2354  // NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly
2355  exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
2356  return nullptr;
2357 }
2358 
2359 NodeImpl *GenericRONamedNodeMapImpl::item(unsigned index)
2360 {
2361  if (index >= (unsigned int) m_contents->count()) {
2362  return nullptr;
2363  }
2364 
2365  return m_contents->at(index);
2366 }
2367 
2368 unsigned GenericRONamedNodeMapImpl::length() const
2369 {
2370  return m_contents->count();
2371 }
2372 
2373 void GenericRONamedNodeMapImpl::addNode(NodeImpl *n)
2374 {
2375  // The spec says that in the case of duplicates we only keep the first one
2376  if (getNamedItem(n->id(), emptyPrefixName, false)) {
2377  return;
2378  }
2379 
2380  n->ref();
2381  m_contents->append(n);
2382 }
2383 
ControlModifier
MouseButtonPress
QEvent::Type type() const const
The Node interface is the primary datatype for the entire Document Object Model.
Definition: dom_node.h:278
void mapDOMPosToRenderPos(NodeImpl *node, long offset, RenderObject *&r, long &r_ofs, bool &outside, bool &outsideEnd)
Maps a DOM Range position to the corresponding caret position.
int length() const const
NodeList which lists all Nodes in a document with a given tag name.
This file is part of the HTML rendering engine for KDE.
int x() const const
int y() const const
This class is khtml&#39;s main class.
Definition: khtml_part.h:208
LeftButton
MESSAGECORE_EXPORT KMime::Content * next(KMime::Content *node, bool allowChildren=true)
virtual void caretPos(int offset, int flags, int &_x, int &_y, int &width, int &height) const
Returns the content coordinates of the caret within this render object.
void ref()
int size() const const
void deref()
Qt::MouseButton button() const const
RenderObject * container() const
returns the object containing this one.
MESSAGECORE_EXPORT KMime::Content * firstChild(const KMime::Content *node)
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
Qt::KeyboardModifiers modifiers() const const
void setParent(QObject *parent)
This library provides a full-featured HTML parser and widget.
T takeLast()
int globalX() const const
int globalY() const const
void setParent(Content *parent)
For getElementsByClassName.
virtual int inlineXPos() const
Leftmost coordinate of this inline element relative to containing block.
Base Class for all rendering tree objects.
DOMStringImpl * implementation() const
Definition: dom_string.h:145
void prepend(const T &value)
NodeImpl * handle() const
Definition: dom_node.h:936
virtual int inlineYPos() const
Topmost coordinate of this inline element relative to containing block.
MESSAGECORE_EXPORT KMime::Content * nextSibling(const KMime::Content *node)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 16 2021 22:47:52 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.