1 /*
2 * This file is part of the DOM implementation for KDE.
3 *
4 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5 * (C) 1999 Antti Koivisto (koivisto@kde.org)
6 * (C) 2001 Dirk Mueller (mueller@kde.org)
7 * (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
8 * (C) 2005, 2009, 2010 Maksim Orlovich (maksim@kde.org)
9 * (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com)
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
NodeImpl(DocumentImpl * doc)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
~NodeImpl()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
nodeValue() const106 DOMString NodeImpl::nodeValue() const
107 {
108 return DOMString();
109 }
110
setNodeValue(const DOMString &,int &)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
nodeName() const119 DOMString NodeImpl::nodeName() const
120 {
121 return DOMString();
122 }
123
nodeType() const124 unsigned short NodeImpl::nodeType() const
125 {
126 return 0;
127 }
128
childNodes()129 WTF::PassRefPtr<DOM::NodeListImpl> NodeImpl::childNodes()
130 {
131 return new ChildNodeListImpl(this);
132 }
133
firstChild() const134 NodeImpl *NodeImpl::firstChild() const
135 {
136 return nullptr;
137 }
138
lastChild() const139 NodeImpl *NodeImpl::lastChild() const
140 {
141 return nullptr;
142 }
143
insertBefore(NodeImpl *,NodeImpl *,int & exceptioncode)144 NodeImpl *NodeImpl::insertBefore(NodeImpl *, NodeImpl *, int &exceptioncode)
145 {
146 exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
147 return nullptr;
148 }
149
replaceChild(NodeImpl *,NodeImpl *,int & exceptioncode)150 void NodeImpl::replaceChild(NodeImpl *, NodeImpl *, int &exceptioncode)
151 {
152 exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
153 }
154
removeChild(NodeImpl *,int & exceptioncode)155 void NodeImpl::removeChild(NodeImpl *, int &exceptioncode)
156 {
157 exceptioncode = DOMException::NOT_FOUND_ERR;
158 }
159
appendChild(NodeImpl *,int & exceptioncode)160 NodeImpl *NodeImpl::appendChild(NodeImpl *, int &exceptioncode)
161 {
162 exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
163 return nullptr;
164 }
165
remove(int & exceptioncode)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
hasChildNodes() const177 bool NodeImpl::hasChildNodes() const
178 {
179 return false;
180 }
181
normalize()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
prefix() const214 DOMString NodeImpl::prefix() const
215 {
216 // For nodes other than elements and attributes, the prefix is always null
217 return DOMString();
218 }
219
namespaceURI() const220 DOMString NodeImpl::namespaceURI() const
221 {
222 return DOMString();
223 }
224
setPrefix(const DOMString &,int & exceptioncode)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
textContent() const233 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
setTextContent(const DOMString & text,int & ec)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
localName() const306 DOMString NodeImpl::localName() const
307 {
308 return DOMString();
309 }
310
setFirstChild(NodeImpl *)311 void NodeImpl::setFirstChild(NodeImpl *)
312 {
313 }
314
setLastChild(NodeImpl *)315 void NodeImpl::setLastChild(NodeImpl *)
316 {
317 }
318
addChild(NodeImpl *)319 NodeImpl *NodeImpl::addChild(NodeImpl *)
320 {
321 return nullptr;
322 }
323
getCaret(int,bool override,int & _x,int & _y,int & width,int & height)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
isContentEditable() const351 bool NodeImpl::isContentEditable() const
352 {
353 return parentNode() ? parentNode()->isContentEditable() : false;
354 }
355
getRect() const356 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
setChanged(bool b)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
isInline() const383 bool NodeImpl::isInline() const
384 {
385 if (m_render) {
386 return m_render->style()->display() == khtml::INLINE;
387 }
388 return !isElementNode();
389 }
390
nodeIndex() const391 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
eventTargetDocument()401 DocumentImpl *NodeImpl::eventTargetDocument()
402 {
403 return document();
404 }
405
dispatchEvent(EventImpl * evt,int & exceptioncode,bool tempEvent)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
dispatchGenericEvent(EventImpl * evt,int &)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
dispatchHTMLEvent(int _id,bool canBubbleArg,bool cancelableArg)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
dispatchWindowEvent(int _id,bool canBubbleArg,bool cancelableArg)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
dispatchWindowEvent(EventImpl * evt)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
dispatchMouseEvent(QMouseEvent * _mouse,int overrideId,int overrideDetail)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()) {
577 case QEvent::MouseButtonPress:
578 evtId = EventImpl::MOUSEDOWN_EVENT;
579 break;
580 case QEvent::MouseButtonRelease:
581 evtId = EventImpl::MOUSEUP_EVENT;
582 break;
583 case QEvent::MouseButtonDblClick:
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
dispatchUIEvent(int _id,int detail)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
dispatchSubtreeModifiedEvent()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
dispatchKeyEvent(QKeyEvent * key,bool keypress)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
childNodeCount()691 unsigned long NodeImpl::childNodeCount()
692 {
693 return 0;
694 }
695
childNode(unsigned long)696 NodeImpl *NodeImpl::childNode(unsigned long /*index*/)
697 {
698 return nullptr;
699 }
700
traverseNextNode(NodeImpl * stayWithin) const701 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
traversePreviousNode() const719 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
checkSetPrefix(const DOMString & _prefix,int & exceptioncode)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
checkAddChild(NodeImpl * newChild,int & exceptioncode)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
isAncestor(NodeImpl * other) const819 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
childAllowed(NodeImpl * newChild)831 bool NodeImpl::childAllowed(NodeImpl *newChild)
832 {
833 return childTypeAllowed(newChild->nodeType());
834 }
835
diff(khtml::RenderStyle * s1,khtml::RenderStyle * s2)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
pseudoDiff(khtml::RenderStyle * s1,khtml::RenderStyle * s2,unsigned int pid)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
affectedByNoInherit() const901 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
close()910 void NodeImpl::close()
911 {
912 if (m_render) {
913 m_render->close();
914 }
915 m_closed = true;
916 }
917
attach()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
detach()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
maintainsState()947 bool NodeImpl::maintainsState()
948 {
949 return false;
950 }
951
state()952 QString NodeImpl::state()
953 {
954 return QString();
955 }
956
restoreState(const QString &)957 void NodeImpl::restoreState(const QString &/*state*/)
958 {
959 }
960
insertedIntoDocument()961 void NodeImpl::insertedIntoDocument()
962 {
963 setInDocument(true);
964 }
965
removedFromDocument()966 void NodeImpl::removedFromDocument()
967 {
968 setInDocument(false);
969 }
970
childrenChanged()971 void NodeImpl::childrenChanged()
972 {
973 if (parentNode()) {
974 parentNode()->childrenChanged();
975 }
976 }
977
isReadOnly()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
previousEditable() const992 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
nextEditable() const1004 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
previousRenderer()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
nextRenderer()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
createRendererIfNeeded()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
styleForRenderer(RenderObject * parent)1062 RenderStyle *NodeImpl::styleForRenderer(RenderObject *parent)
1063 {
1064 return parent->style();
1065 }
1066
rendererIsNeeded(RenderStyle * style)1067 bool NodeImpl::rendererIsNeeded(RenderStyle *style)
1068 {
1069 return (document()->documentElement() == this) || (style->display() != NONE);
1070 }
1071
createRenderer(RenderArena *,RenderStyle *)1072 RenderObject *NodeImpl::createRenderer(RenderArena * /*arena*/, RenderStyle * /*style*/)
1073 {
1074 assert(false);
1075 return nullptr;
1076 }
1077
computedStyle()1078 RenderStyle *NodeImpl::computedStyle()
1079 {
1080 return parentNode() ? parentNode()->computedStyle() : nullptr;
1081 }
1082
previousLeafNode() const1083 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
nextLeafNode() const1095 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
maxOffset() const1107 long NodeImpl::maxOffset() const
1108 {
1109 return 1;
1110 }
1111
caretMinOffset() const1112 long NodeImpl::caretMinOffset() const
1113 {
1114 return renderer() ? renderer()->caretMinOffset() : 0;
1115 }
1116
caretMaxOffset() const1117 long NodeImpl::caretMaxOffset() const
1118 {
1119 return renderer() ? renderer()->caretMaxOffset() : 1;
1120 }
1121
caretMaxRenderedOffset() const1122 unsigned long NodeImpl::caretMaxRenderedOffset() const
1123 {
1124 return renderer() ? renderer()->caretMaxRenderedOffset() : 1;
1125 }
1126
isBlockFlow() const1127 bool NodeImpl::isBlockFlow() const
1128 {
1129 return renderer() && renderer()->isBlockFlow();
1130 }
1131
isEditableBlock() const1132 bool NodeImpl::isEditableBlock() const
1133 {
1134 return isBlockFlow() && isContentEditable();
1135 }
1136
enclosingBlockFlowElement() const1137 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
rootEditableElement() const1156 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
inSameRootEditableElement(NodeImpl * n)1180 bool NodeImpl::inSameRootEditableElement(NodeImpl *n)
1181 {
1182 return n ? rootEditableElement() == n->rootEditableElement() : false;
1183 }
1184
inSameContainingBlockFlowElement(NodeImpl * n)1185 bool NodeImpl::inSameContainingBlockFlowElement(NodeImpl *n)
1186 {
1187 return n ? enclosingBlockFlowElement() == n->enclosingBlockFlowElement() : false;
1188 }
1189
positionForCoordinates(int x,int y) const1190 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
isPointInsideSelection(int x,int y,const Selection & sel) const1199 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
getElementsByTagName(const DOMString & tagName)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
getElementsByTagNameNS(const DOMString & namespaceURI,const DOMString & localName)1242 NodeListImpl *NodeImpl::getElementsByTagNameNS(const DOMString &namespaceURI, const DOMString &localName)
1243 {
1244 return new TagNodeListImpl(this, namespaceURI, localName);
1245 }
1246
getElementsByClassName(const DOMString & name)1247 NodeListImpl *NodeImpl::getElementsByClassName(const DOMString &name)
1248 {
1249 return new ClassNodeListImpl(this, name);
1250 }
1251
hasAttributes() const1252 bool NodeImpl::hasAttributes() const
1253 {
1254 return false;
1255 }
1256
isSupported(const DOMString & feature,const DOMString & version)1257 bool NodeImpl::isSupported(const DOMString &feature, const DOMString &version)
1258 {
1259 return DOMImplementationImpl::hasFeature(feature, version);
1260 }
1261
ownerDocument() const1262 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.
logicalParentNode(const DOM::NodeImpl * node)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
compareDocumentPosition(const DOM::NodeImpl * other)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
rootForSelectorQuery(DOM::NodeImpl * arg)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
querySelector(const DOM::DOMString & query,int & ec)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
querySelectorAll(const DOM::DOMString & query,int & ec)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
setDocument(DocumentImpl * doc)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
lookupNamespaceURI(const DOM::DOMString & prefix)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
findNextElementAncestor(NodeImpl * node)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
~NodeBaseImpl()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
firstChild() const1559 NodeImpl *NodeBaseImpl::firstChild() const
1560 {
1561 return _first;
1562 }
1563
lastChild() const1564 NodeImpl *NodeBaseImpl::lastChild() const
1565 {
1566 return _last;
1567 }
1568
insertBefore(NodeImpl * newChild,NodeImpl * refChild,int & exceptioncode)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
replaceChild(NodeImpl * newChild,NodeImpl * oldChild,int & exceptioncode)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
removeChild(NodeImpl * oldChild,int & exceptioncode)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
removeChildren()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
appendChild(NodeImpl * newChild,int & exceptioncode)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
hasChildNodes() const1917 bool NodeBaseImpl::hasChildNodes() const
1918 {
1919 return _first != nullptr;
1920 }
1921
1922 // not part of the DOM
setFirstChild(NodeImpl * child)1923 void NodeBaseImpl::setFirstChild(NodeImpl *child)
1924 {
1925 _first = child;
1926 }
1927
setLastChild(NodeImpl * child)1928 void NodeBaseImpl::setLastChild(NodeImpl *child)
1929 {
1930 _last = child;
1931 }
1932
1933 // check for same source document:
checkSameDocument(NodeImpl * newChild,int & exceptioncode)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:
checkIsChild(NodeImpl * oldChild,int & exceptioncode)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
addChild(NodeImpl * newChild)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
attach()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
detach()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
cloneChildNodes(NodeImpl * clone)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
getUpperLeftCorner(int & xPos,int & yPos) const2021 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
getLowerRightCorner(int & xPos,int & yPos) const2065 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
setFocus(bool received)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
setActive(bool down)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
setHovered(bool hover)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
childNodeCount()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
childNode(unsigned long index)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
dispatchChildInsertedEvents(NodeImpl * child,int & exceptioncode)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
dispatchChildRemovalEvents(NodeImpl * child,int & exceptioncode)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
NamedNodeMapImpl()2257 NamedNodeMapImpl::NamedNodeMapImpl()
2258 {
2259 }
2260
~NamedNodeMapImpl()2261 NamedNodeMapImpl::~NamedNodeMapImpl()
2262 {
2263 }
2264
getNamedItem(const DOMString & name)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
setNamedItem(const Node & arg,int & exceptioncode)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
removeNamedItem(const DOMString & name,int & exceptioncode)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
getNamedItemNS(const DOMString & namespaceURI,const DOMString & localName)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
setNamedItemNS(const Node & arg,int & exceptioncode)2302 Node NamedNodeMapImpl::setNamedItemNS(const Node &arg, int &exceptioncode)
2303 {
2304 return setNamedItem(arg.handle(), emptyPrefixName, true, exceptioncode);
2305 }
2306
removeNamedItemNS(const DOMString & namespaceURI,const DOMString & localName,int & exceptioncode)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
GenericRONamedNodeMapImpl(DocumentImpl * doc)2316 GenericRONamedNodeMapImpl::GenericRONamedNodeMapImpl(DocumentImpl *doc)
2317 : NamedNodeMapImpl()
2318 {
2319 m_doc = doc;
2320 m_contents = new QList<NodeImpl *>;
2321 }
2322
~GenericRONamedNodeMapImpl()2323 GenericRONamedNodeMapImpl::~GenericRONamedNodeMapImpl()
2324 {
2325 while (!m_contents->isEmpty()) {
2326 m_contents->takeLast()->deref();
2327 }
2328
2329 delete m_contents;
2330 }
2331
getNamedItem(NodeImpl::Id id,const PrefixName &,bool)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
setNamedItem(NodeImpl *,const PrefixName &,bool,int & exceptioncode)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
removeNamedItem(NodeImpl::Id,const PrefixName &,bool,int & exceptioncode)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
item(unsigned index)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
length() const2368 unsigned GenericRONamedNodeMapImpl::length() const
2369 {
2370 return m_contents->count();
2371 }
2372
addNode(NodeImpl * n)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
2384