ContainerNode.cpp 28.6 KB
Newer Older
1 2 3 4 5 6
/**
 * This file is part of the DOM implementation for KDE.
 *
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 *           (C) 2001 Dirk Mueller (mueller@kde.org)
darin's avatar
darin committed
7
 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include "config.h"
darin's avatar
darin committed
26
#include "ContainerNode.h"
27

thatcher's avatar
thatcher committed
28
#include "DeleteButtonController.h"
darin's avatar
darin committed
29
#include "Document.h"
thatcher's avatar
thatcher committed
30
#include "Editor.h"
31
#include "EventNames.h"
darin's avatar
darin committed
32
#include "ExceptionCode.h"
darin's avatar
darin committed
33 34
#include "FrameView.h"
#include "InlineTextBox.h"
weinig's avatar
 
weinig committed
35
#include "MutationEvent.h"
darin's avatar
darin committed
36
#include "RenderTheme.h"
37
#include "RootInlineBox.h"
weinig's avatar
 
weinig committed
38
#include "SystemTime.h"
ggaren's avatar
ggaren committed
39
#include <wtf/Vector.h>
40

darin's avatar
darin committed
41
namespace WebCore {
42 43 44

using namespace EventNames;

darin's avatar
darin committed
45 46
static void dispatchChildInsertionEvents(Node*, ExceptionCode&);
static void dispatchChildRemovalEvents(Node*, ExceptionCode&);
darin's avatar
darin committed
47

ggaren's avatar
ggaren committed
48 49 50 51 52
typedef Vector<std::pair<NodeCallback, Node*> > NodeCallbackQueue;
static NodeCallbackQueue* s_postAttachCallbackQueue = 0;

static size_t s_attachDepth = 0;

darin's avatar
darin committed
53 54
ContainerNode::ContainerNode(Document* doc)
    : EventTargetNode(doc), m_firstChild(0), m_lastChild(0)
55 56 57
{
}

darin's avatar
darin committed
58
void ContainerNode::removeAllChildren()
59 60 61 62 63 64 65 66
{
    // Avoid deep recursion when destroying the node tree.
    static bool alreadyInsideDestructor; 
    bool topLevel = !alreadyInsideDestructor;
    if (topLevel)
        alreadyInsideDestructor = true;
    
    // List of nodes to be deleted.
darin's avatar
darin committed
67 68
    static Node *head;
    static Node *tail;
69 70
    
    // We have to tell all children that their parent has died.
darin's avatar
darin committed
71 72
    Node *n;
    Node *next;
73

darin's avatar
darin committed
74
    for (n = m_firstChild; n != 0; n = next ) {
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
        next = n->nextSibling();
        n->setPreviousSibling(0);
        n->setNextSibling(0);
        n->setParent(0);
        
        if ( !n->refCount() ) {
            // Add the node to the list of nodes to be deleted.
            // Reuse the nextSibling pointer for this purpose.
            if (tail)
                tail->setNextSibling(n);
            else
                head = n;
            tail = n;
        } else if (n->inDocument())
            n->removedFromDocument();
    }
    
    // Only for the top level call, do the actual deleting.
    if (topLevel) {
        while ((n = head) != 0) {
            next = n->nextSibling();
            n->setNextSibling(0);

            head = next;
            if (next == 0)
                tail = 0;
            
            delete n;
        }
        
        alreadyInsideDestructor = false;
darin's avatar
darin committed
106 107
        m_firstChild = 0;
        m_lastChild = 0;
108 109 110
    }
}

darin's avatar
darin committed
111
ContainerNode::~ContainerNode()
112 113 114 115 116
{
    removeAllChildren();
}


darin's avatar
darin committed
117
Node* ContainerNode::firstChild() const
118
{
darin's avatar
darin committed
119
    return m_firstChild;
120 121
}

darin's avatar
darin committed
122
Node* ContainerNode::lastChild() const
123
{
darin's avatar
darin committed
124
    return m_lastChild;
125 126
}

darin's avatar
darin committed
127
bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec)
128
{
darin's avatar
darin committed
129 130 131 132
    // Check that this node is not "floating".
    // If it is, it can be deleted as a side effect of sending mutation events.
    ASSERT(refCount() || parent());

darin's avatar
darin committed
133
    ec = 0;
134

darin's avatar
darin committed
135 136 137
    // insertBefore(node, 0) is equivalent to appendChild(node)
    if (!refChild)
        return appendChild(newChild, ec);
138

darin's avatar
darin committed
139 140 141
    // Make sure adding the new child is OK.
    checkAddChild(newChild.get(), ec);
    if (ec)
mjs's avatar
mjs committed
142
        return false;
143 144 145

    // NOT_FOUND_ERR: Raised if refChild is not a child of this node
    if (refChild->parentNode() != this) {
darin's avatar
darin committed
146
        ec = NOT_FOUND_ERR;
mjs's avatar
mjs committed
147
        return false;
148 149
    }

darin's avatar
darin committed
150
    bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
151

darin's avatar
darin committed
152
    // If newChild is a DocumentFragment with no children; there's nothing to do.
mjs's avatar
mjs committed
153
    // Just return true
154
    if (isFragment && !newChild->firstChild())
mjs's avatar
mjs committed
155
        return true;
156 157

    // Now actually add the child(ren)
darin's avatar
darin committed
158
    if (refChild->previousSibling() == newChild || refChild == newChild) // nothing to do
mjs's avatar
mjs committed
159
        return true;
darin's avatar
darin committed
160

darin's avatar
darin committed
161
    RefPtr<Node> next = refChild;
darin's avatar
darin committed
162

darin's avatar
darin committed
163
    RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
164
    while (child) {
darin's avatar
darin committed
165
        RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
166

darin's avatar
darin committed
167
        // If child is already present in the tree, first remove it from the old location.
darin's avatar
darin committed
168
        if (Node* oldParent = child->parentNode())
darin's avatar
darin committed
169
            oldParent->removeChild(child.get(), ec);
darin's avatar
darin committed
170
        if (ec)
171 172
            return 0;

darin's avatar
darin committed
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
        // FIXME: After sending the mutation events, "this" could be destroyed.
        // We can prevent that by doing a "ref", but first we have to make sure
        // that no callers call with ref count == 0 and parent = 0 (as of this
        // writing, there are definitely callers who call that way).

        // Due to arbitrary code running in response to a DOM mutation event it's
        // possible that "next" is no longer a child of "this".
        // It's also possible that "child" has been inserted elsewhere.
        // In either of those cases, we'll just stop.
        if (next->parentNode() != this)
            break;
        if (child->parentNode())
            break;

        assert(!child->nextSibling());
        assert(!child->previousSibling());

        // Add child before "next".
191
        forbidEventDispatch();
darin's avatar
darin committed
192
        Node* prev = next->previousSibling();
darin's avatar
darin committed
193 194 195 196 197 198 199 200 201 202
        assert(m_lastChild != prev);
        next->setPreviousSibling(child.get());
        if (prev) {
            assert(m_firstChild != next);
            assert(prev->nextSibling() == next);
            prev->setNextSibling(child.get());
        } else {
            assert(m_firstChild == next);
            m_firstChild = child.get();
        }
203 204
        child->setParent(this);
        child->setPreviousSibling(prev);
darin's avatar
darin committed
205
        child->setNextSibling(next.get());
206 207
        allowEventDispatch();

andersca's avatar
andersca committed
208 209 210
        // Dispatch the mutation events.
        dispatchChildInsertionEvents(child.get(), ec);
                
darin's avatar
darin committed
211
        // Add child to the rendering tree.
212 213 214
        if (attached() && !child->attached())
            child->attach();

mjs's avatar
mjs committed
215
        child = nextChild.release();
216 217
    }

ggaren's avatar
ggaren committed
218
    document()->setDocumentChanged(true);
219
    dispatchSubtreeModifiedEvent();
mjs's avatar
mjs committed
220
    return true;
221 222
}

darin's avatar
darin committed
223
bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec)
224
{
darin's avatar
darin committed
225 226 227 228
    // Check that this node is not "floating".
    // If it is, it can be deleted as a side effect of sending mutation events.
    ASSERT(refCount() || parent());

darin's avatar
darin committed
229
    ec = 0;
230

darin's avatar
darin committed
231
    if (oldChild == newChild) // nothing to do
mjs's avatar
mjs committed
232
        return true;
233 234
    
    // Make sure adding the new child is ok
darin's avatar
darin committed
235 236
    checkAddChild(newChild.get(), ec);
    if (ec)
mjs's avatar
mjs committed
237
        return false;
238 239 240

    // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
    if (!oldChild || oldChild->parentNode() != this) {
darin's avatar
darin committed
241
        ec = NOT_FOUND_ERR;
mjs's avatar
mjs committed
242
        return false;
243 244
    }

darin's avatar
darin committed
245
    RefPtr<Node> prev = oldChild->previousSibling();
246

darin's avatar
darin committed
247
    // Remove the node we're replacing
darin's avatar
darin committed
248
    RefPtr<Node> removedChild = oldChild;
mjs's avatar
mjs committed
249
    removeChild(oldChild, ec);
darin's avatar
darin committed
250
    if (ec)
mjs's avatar
mjs committed
251
        return false;
252

darin's avatar
darin committed
253 254 255 256 257
    // FIXME: After sending the mutation events, "this" could be destroyed.
    // We can prevent that by doing a "ref", but first we have to make sure
    // that no callers call with ref count == 0 and parent = 0 (as of this
    // writing, there are definitely callers who call that way).

darin's avatar
darin committed
258
    bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
darin's avatar
darin committed
259

260
    // Add the new child(ren)
darin's avatar
darin committed
261
    RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
262
    while (child) {
darin's avatar
darin committed
263
        // If the new child is already in the right place, we're done.
darin's avatar
darin committed
264
        if (prev && (prev == child || prev == child->previousSibling()))
darin's avatar
darin committed
265 266 267
            break;

        // For a fragment we have more children to do.
darin's avatar
darin committed
268
        RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
269

darin's avatar
darin committed
270
        // Remove child from its old position.
darin's avatar
darin committed
271
        if (Node* oldParent = child->parentNode())
darin's avatar
darin committed
272
            oldParent->removeChild(child.get(), ec);
darin's avatar
darin committed
273
        if (ec)
274 275
            return 0;

darin's avatar
darin committed
276 277 278 279 280 281 282 283 284 285 286 287 288
        // Due to arbitrary code running in response to a DOM mutation event it's
        // possible that "prev" is no longer a child of "this".
        // It's also possible that "child" has been inserted elsewhere.
        // In either of those cases, we'll just stop.
        if (prev && prev->parentNode() != this)
            break;
        if (child->parentNode())
            break;

        assert(!child->nextSibling());
        assert(!child->previousSibling());

        // Add child after "prev".
289
        forbidEventDispatch();
darin's avatar
darin committed
290
        Node* next;
darin's avatar
darin committed
291 292 293
        if (prev) {
            next = prev->nextSibling();
            assert(m_firstChild != next);
darin's avatar
darin committed
294
            prev->setNextSibling(child.get());
darin's avatar
darin committed
295 296
        } else {
            next = m_firstChild;
darin's avatar
darin committed
297
            m_firstChild = child.get();
darin's avatar
darin committed
298 299 300 301 302 303 304
        }
        if (next) {
            assert(m_lastChild != prev);
            assert(next->previousSibling() == prev);
            next->setPreviousSibling(child.get());
        } else {
            assert(m_lastChild == prev);
darin's avatar
darin committed
305
            m_lastChild = child.get();
darin's avatar
darin committed
306
        }
307
        child->setParent(this);
darin's avatar
darin committed
308
        child->setPreviousSibling(prev.get());
darin's avatar
darin committed
309
        child->setNextSibling(next);
310 311
        allowEventDispatch();

andersca's avatar
andersca committed
312 313 314
        // Dispatch the mutation events
        dispatchChildInsertionEvents(child.get(), ec);
                
315 316 317 318 319
        // Add child to the rendering tree
        if (attached() && !child->attached())
            child->attach();

        prev = child;
mjs's avatar
mjs committed
320
        child = nextChild.release();
321 322 323
    }

    // ### set style in case it's attached
ggaren's avatar
ggaren committed
324
    document()->setDocumentChanged(true);
325
    dispatchSubtreeModifiedEvent();
mjs's avatar
mjs committed
326
    return true;
327 328
}

darin's avatar
darin committed
329
void ContainerNode::willRemove()
330
{
darin's avatar
darin committed
331
    for (Node *n = m_firstChild; n != 0; n = n->nextSibling())
332 333 334
        n->willRemove();
}

darin's avatar
darin committed
335
static ExceptionCode willRemoveChild(Node *child)
336
{
darin's avatar
darin committed
337
    ExceptionCode ec = 0;
338 339

    // fire removed from document mutation events.
darin's avatar
darin committed
340 341 342
    dispatchChildRemovalEvents(child, ec);
    if (ec)
        return ec;
343 344 345 346 347 348 349

    if (child->attached())
        child->willRemove();
    
    return 0;
}

darin's avatar
darin committed
350
bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec)
351
{
darin's avatar
darin committed
352 353 354 355
    // Check that this node is not "floating".
    // If it is, it can be deleted as a side effect of sending mutation events.
    ASSERT(refCount() || parent());

darin's avatar
darin committed
356
    ec = 0;
357 358

    // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
adele's avatar
adele committed
359
    if (isReadOnlyNode()) {
darin's avatar
darin committed
360
        ec = NO_MODIFICATION_ALLOWED_ERR;
mjs's avatar
mjs committed
361
        return false;
362 363 364 365
    }

    // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
    if (!oldChild || oldChild->parentNode() != this) {
darin's avatar
darin committed
366
        ec = NOT_FOUND_ERR;
mjs's avatar
mjs committed
367
        return false;
368 369
    }

darin's avatar
darin committed
370
    RefPtr<Node> child = oldChild;
darin's avatar
darin committed
371
    
372
    // dispatch pre-removal mutation events
ggaren's avatar
ggaren committed
373
    if (document()->hasListenerType(Document::DOMNODEREMOVED_LISTENER)) {
darin's avatar
darin committed
374 375
        EventTargetNodeCast(child.get())->dispatchEvent(new MutationEvent(DOMNodeRemovedEvent, true, false,
            this, String(), String(), String(), 0), ec, true);
darin's avatar
darin committed
376
        if (ec)
mjs's avatar
mjs committed
377
            return false;
378 379
    }

darin's avatar
darin committed
380 381
    ec = willRemoveChild(child.get());
    if (ec)
mjs's avatar
mjs committed
382
        return false;
383

darin's avatar
darin committed
384 385
    // Mutation events might have moved this child into a different parent.
    if (child->parentNode() != this) {
darin's avatar
darin committed
386
        ec = NOT_FOUND_ERR;
mjs's avatar
mjs committed
387
        return false;
darin's avatar
darin committed
388 389 390 391 392 393 394
    }

    // FIXME: After sending the mutation events, "this" could be destroyed.
    // We can prevent that by doing a "ref", but first we have to make sure
    // that no callers call with ref count == 0 and parent = 0 (as of this
    // writing, there are definitely callers who call that way).

395 396 397
    forbidEventDispatch();

    // Remove from rendering tree
darin's avatar
darin committed
398 399
    if (child->attached())
        child->detach();
400 401

    // Remove the child
darin's avatar
darin committed
402
    Node *prev, *next;
darin's avatar
darin committed
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
    prev = child->previousSibling();
    next = child->nextSibling();

    if (next)
        next->setPreviousSibling(prev);
    if (prev)
        prev->setNextSibling(next);
    if (m_firstChild == child)
        m_firstChild = next;
    if (m_lastChild == child)
        m_lastChild = prev;

    child->setPreviousSibling(0);
    child->setNextSibling(0);
    child->setParent(0);
418 419 420

    allowEventDispatch();

ggaren's avatar
ggaren committed
421
    document()->setDocumentChanged(true);
422 423 424 425

    // Dispatch post-removal mutation events
    dispatchSubtreeModifiedEvent();

darin's avatar
darin committed
426 427
    if (child->inDocument())
        child->removedFromDocument();
428
    else
darin's avatar
darin committed
429
        child->removedFromTree(true);
430

darin's avatar
darin committed
431
    return child;
432 433 434 435
}

// this differs from other remove functions because it forcibly removes all the children,
// regardless of read-only status or event exceptions, e.g.
darin's avatar
darin committed
436
void ContainerNode::removeChildren()
437
{
darin's avatar
darin committed
438
    Node *n;
439
    
darin's avatar
darin committed
440
    if (!m_firstChild)
441 442 443 444
        return;

    // do any prep work needed before actually starting to detach
    // and remove... e.g. stop loading frames, fire unload events
darin's avatar
darin committed
445
    for (n = m_firstChild; n; n = n->nextSibling())
446 447 448
        willRemoveChild(n);
    
    forbidEventDispatch();
darin's avatar
darin committed
449
    while ((n = m_firstChild) != 0) {
darin's avatar
darin committed
450
        Node *next = n->nextSibling();
451 452 453
        
        n->ref();

454
        // Remove the node from the tree before calling detach or removedFromDocument (4427024, 4129744)
455 456 457 458
        n->setPreviousSibling(0);
        n->setNextSibling(0);
        n->setParent(0);
        
459 460 461
        m_firstChild = next;
        if (n == m_lastChild)
            m_lastChild = 0;
462 463 464

        if (n->attached())
            n->detach();
465
        
466 467 468 469 470 471 472 473 474 475 476 477
        if (n->inDocument())
            n->removedFromDocument();

        n->deref();
    }
    allowEventDispatch();
    
    // Dispatch a single post-removal mutation event denoting a modified subtree.
    dispatchSubtreeModifiedEvent();
}


darin's avatar
darin committed
478
bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec)
479
{
darin's avatar
darin committed
480 481 482 483
    // Check that this node is not "floating".
    // If it is, it can be deleted as a side effect of sending mutation events.
    ASSERT(refCount() || parent());

darin's avatar
darin committed
484
    ec = 0;
485 486

    // Make sure adding the new child is ok
darin's avatar
darin committed
487 488
    checkAddChild(newChild.get(), ec);
    if (ec)
489 490
        return 0;
    
darin's avatar
darin committed
491
    if (newChild == m_lastChild) // nothing to do
492 493
        return newChild;

darin's avatar
darin committed
494
    bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
495 496 497 498

    // If newChild is a DocumentFragment with no children.... there's nothing to do.
    // Just return the document fragment
    if (isFragment && !newChild->firstChild())
mjs's avatar
mjs committed
499
        return true;
500 501

    // Now actually add the child(ren)
darin's avatar
darin committed
502
    RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
503
    while (child) {
darin's avatar
darin committed
504
        // For a fragment we have more children to do.
darin's avatar
darin committed
505
        RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
506 507

        // If child is already present in the tree, first remove it
darin's avatar
darin committed
508
        if (Node* oldParent = child->parentNode()) {
darin's avatar
darin committed
509 510
            oldParent->removeChild(child.get(), ec);
            if (ec)
511
                return 0;
darin's avatar
darin committed
512 513 514 515 516 517
            
            // If the child has a parent again, just stop what we're doing, because
            // that means someone is doing something with DOM mutation -- can't re-parent
            // a child that already has a parent.
            if (child->parentNode())
                break;
518 519 520 521 522
        }

        // Append child to the end of the list
        forbidEventDispatch();
        child->setParent(this);
darin's avatar
darin committed
523 524 525
        if (m_lastChild) {
            child->setPreviousSibling(m_lastChild);
            m_lastChild->setNextSibling(child.get());
526
        } else
darin's avatar
darin committed
527 528
            m_firstChild = child.get();
        m_lastChild = child.get();
529 530
        allowEventDispatch();

andersca's avatar
andersca committed
531 532 533
        // Dispatch the mutation events
        dispatchChildInsertionEvents(child.get(), ec);
                
534 535 536 537 538
        // Add child to the rendering tree
        // ### should we detach() it first if it's already attached?
        if (attached() && !child->attached())
            child->attach();
        
mjs's avatar
mjs committed
539
        child = nextChild.release();
540 541
    }

ggaren's avatar
ggaren committed
542
    document()->setDocumentChanged(true);
543
    dispatchSubtreeModifiedEvent();
mjs's avatar
mjs committed
544
    return true;
545 546
}

darin's avatar
darin committed
547
bool ContainerNode::hasChildNodes() const
548
{
darin's avatar
darin committed
549
    return m_firstChild;
550 551
}

darin's avatar
darin committed
552
ContainerNode* ContainerNode::addChild(PassRefPtr<Node> newChild)
553
{
darin's avatar
darin committed
554 555
    // This function is only used during parsing.
    // It does not send any DOM mutation events.
556

darin's avatar
darin committed
557
    // Check for consistency with DTD, but only when parsing HTML.
ggaren's avatar
ggaren committed
558
    if (document()->isHTMLDocument() && !childAllowed(newChild.get()))
559 560 561 562
        return 0;

    forbidEventDispatch();
    newChild->setParent(this);
darin's avatar
darin committed
563 564 565
    if (m_lastChild) {
        newChild->setPreviousSibling(m_lastChild);
        m_lastChild->setNextSibling(newChild.get());
566
    } else
darin's avatar
darin committed
567 568
        m_firstChild = newChild.get();
    m_lastChild = newChild.get();
569 570 571 572 573 574
    allowEventDispatch();

    if (inDocument())
        newChild->insertedIntoDocument();
    childrenChanged();
    
darin's avatar
darin committed
575
    if (newChild->isElementNode())
darin's avatar
darin committed
576
        return static_cast<ContainerNode*>(newChild.get());
577 578 579
    return this;
}

ggaren's avatar
ggaren committed
580 581 582 583 584 585 586 587 588 589 590
void ContainerNode::queuePostAttachCallback(NodeCallback callback, Node* node)
{
    // To keep things simple, we forbid queueing post-attach callbacks from inside attach.
    ASSERT(s_attachDepth == 0);
    
    if (!s_postAttachCallbackQueue)
        s_postAttachCallbackQueue = new NodeCallbackQueue;
    
    s_postAttachCallbackQueue->append(std::pair<NodeCallback, Node*>(callback, node));
}

darin's avatar
darin committed
591
void ContainerNode::attach()
592
{
ggaren's avatar
ggaren committed
593 594
    ++s_attachDepth;

darin's avatar
darin committed
595
    for (Node* child = m_firstChild; child; child = child->nextSibling())
596
        child->attach();
darin's avatar
darin committed
597
    EventTargetNode::attach();
ggaren's avatar
ggaren committed
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613

    if (s_attachDepth == 1) {
        if (s_postAttachCallbackQueue) {
            // We recalculate size() each time through the loop because a callback
            // can add more callbacks to the end of the queue.
            for (size_t i = 0; i < s_postAttachCallbackQueue->size(); ++i) {
                std::pair<NodeCallback, Node*>& pair = (*s_postAttachCallbackQueue)[i];
                NodeCallback callback = pair.first;
                Node* node = pair.second;
                
                callback(node);
            }
            s_postAttachCallbackQueue->clear();
        }
    }    
    --s_attachDepth;
614 615
}

darin's avatar
darin committed
616
void ContainerNode::detach()
617
{
darin's avatar
darin committed
618
    for (Node* child = m_firstChild; child; child = child->nextSibling())
darin's avatar
darin committed
619
        child->detach();
darin's avatar
darin committed
620
    EventTargetNode::detach();
621 622
}

darin's avatar
darin committed
623
void ContainerNode::insertedIntoDocument()
624
{
darin's avatar
darin committed
625 626
    EventTargetNode::insertedIntoDocument();
    for (Node *child = m_firstChild; child; child = child->nextSibling())
627 628 629
        child->insertedIntoDocument();
}

darin's avatar
darin committed
630
void ContainerNode::removedFromDocument()
631
{
darin's avatar
darin committed
632 633
    EventTargetNode::removedFromDocument();
    for (Node *child = m_firstChild; child; child = child->nextSibling())
634 635 636
        child->removedFromDocument();
}

darin's avatar
darin committed
637
void ContainerNode::insertedIntoTree(bool deep)
638
{
darin's avatar
darin committed
639
    EventTargetNode::insertedIntoTree(deep);
640
    if (deep) {
darin's avatar
darin committed
641
        for (Node *child = m_firstChild; child; child = child->nextSibling())
642 643 644 645
            child->insertedIntoTree(deep);
    }
}

darin's avatar
darin committed
646
void ContainerNode::removedFromTree(bool deep)
647
{
darin's avatar
darin committed
648
    EventTargetNode::removedFromTree(deep);
649
    if (deep) {
darin's avatar
darin committed
650
        for (Node *child = m_firstChild; child; child = child->nextSibling())
651 652 653 654
            child->removedFromTree(deep);
    }
}

darin's avatar
darin committed
655
void ContainerNode::cloneChildNodes(Node *clone)
656
{
thatcher's avatar
thatcher committed
657 658 659
    // disable the delete button so it's elements are not serialized into the markup
    if (document()->frame())
        document()->frame()->editor()->deleteButtonController()->disable();
darin's avatar
darin committed
660
    ExceptionCode ec = 0;
darin's avatar
darin committed
661
    for (Node* n = firstChild(); n && !ec; n = n->nextSibling())
darin's avatar
darin committed
662
        clone->appendChild(n->cloneNode(true), ec);
thatcher's avatar
thatcher committed
663 664
    if (document()->frame())
        document()->frame()->editor()->deleteButtonController()->enable();
665 666
}

darin's avatar
darin committed
667
bool ContainerNode::getUpperLeftCorner(int &xPos, int &yPos) const
668
{
darin's avatar
darin committed
669
    if (!renderer())
670
        return false;
darin's avatar
darin committed
671
    RenderObject *o = renderer();
672 673 674 675
    RenderObject *p = o;

    xPos = yPos = 0;
    if (!o->isInline() || o->isReplaced()) {
676
        o->absolutePosition(xPos, yPos);
677 678 679 680 681 682
        return true;
    }

    // find the next text/image child, to get a position
    while(o) {
        p = o;
harrison's avatar
harrison committed
683
        if (o->firstChild())
684 685 686 687
            o = o->firstChild();
        else if(o->nextSibling())
            o = o->nextSibling();
        else {
vicki's avatar
vicki committed
688 689 690 691 692 693 694
            RenderObject *next = 0;
            while (!next && o->parent()) {
                o = o->parent();
                next = o->nextSibling();
            }
            o = next;

695 696 697 698 699
            if (!o)
                break;
        }

        if (!o->isInline() || o->isReplaced()) {
700
            o->absolutePosition(xPos, yPos);
701 702 703 704 705
            return true;
        }

        if (p->element() && p->element() == this && o->isText() && !o->isBR() && !static_cast<RenderText*>(o)->firstTextBox()) {
                // do nothing - skip unrendered whitespace that is a child or next sibling of the anchor
harrison's avatar
harrison committed
706
        } else if ((o->isText() && !o->isBR()) || o->isReplaced()) {
707
            o->container()->absolutePosition(xPos, yPos);
708 709 710
            if (o->isText() && static_cast<RenderText *>(o)->firstTextBox()) {
                xPos += static_cast<RenderText *>(o)->minXPos();
                yPos += static_cast<RenderText *>(o)->firstTextBox()->root()->topOverflow();
harrison's avatar
harrison committed
711
            } else {
712 713 714 715 716 717 718 719 720 721
                xPos += o->xPos();
                yPos += o->yPos();
            }
            return true;
        }
    }
    
    // If the target doesn't have any children or siblings that could be used to calculate the scroll position, we must be
    // at the end of the document.  Scroll to the bottom.
    if (!o) {
ggaren's avatar
ggaren committed
722
        yPos += document()->view()->contentsHeight();
723 724 725 726 727
        return true;
    }
    return false;
}

darin's avatar
darin committed
728
bool ContainerNode::getLowerRightCorner(int &xPos, int &yPos) const
729
{
darin's avatar
darin committed
730
    if (!renderer())
731 732
        return false;

darin's avatar
darin committed
733
    RenderObject *o = renderer();
734 735 736
    xPos = yPos = 0;
    if (!o->isInline() || o->isReplaced())
    {
737
        o->absolutePosition(xPos, yPos);
738
        xPos += o->width();
739
        yPos += o->height() + o->borderTopExtra() + o->borderBottomExtra();
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
        return true;
    }
    // find the last text/image child, to get a position
    while(o) {
        if(o->lastChild())
            o = o->lastChild();
        else if(o->previousSibling())
            o = o->previousSibling();
        else {
            RenderObject *prev = 0;
            while(!prev) {
                o = o->parent();
                if(!o) return false;
                prev = o->previousSibling();
            }
            o = prev;
        }
757
        if (o->isText() || o->isReplaced()) {
758 759 760 761 762 763 764 765 766 767 768 769
            o->container()->absolutePosition(xPos, yPos);
            if (o->isText())
                xPos += static_cast<RenderText *>(o)->minXPos() + o->width();
            else
                xPos += o->xPos()+o->width();
            yPos += o->yPos()+o->height();
            return true;
        }
    }
    return true;
}

darin's avatar
darin committed
770
IntRect ContainerNode::getRect() const
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796
{
    int xPos = 0, yPos = 0, xEnd = 0, yEnd = 0;
    bool foundUpperLeft = getUpperLeftCorner(xPos,yPos);
    bool foundLowerRight = getLowerRightCorner(xEnd,yEnd);
    
    // If we've found one corner, but not the other,
    // then we should just return a point at the corner that we did find.
    if (foundUpperLeft != foundLowerRight)
    {
        if (foundUpperLeft) {
            xEnd = xPos;
            yEnd = yPos;
        } else {
            xPos = xEnd;
            yPos = yEnd;
        }
    } 

    if (xEnd < xPos)
        xEnd = xPos;
    if (yEnd < yPos)
        yEnd = yPos;
        
    return IntRect(xPos, yPos, xEnd - xPos, yEnd - yPos);
}

darin's avatar
darin committed
797
void ContainerNode::setFocus(bool received)
798 799 800
{
    if (m_focused == received) return;

darin's avatar
darin committed
801
    EventTargetNode::setFocus(received);
802 803 804 805 806

    // note that we need to recalc the style
    setChanged();
}

darin's avatar
darin committed
807
void ContainerNode::setActive(bool down, bool pause)
808 809 810
{
    if (down == active()) return;

darin's avatar
darin committed
811
    EventTargetNode::setActive(down);
812 813

    // note that we need to recalc the style
darin's avatar
darin committed
814
    // FIXME: Move to Element
darin's avatar
darin committed
815 816
    if (renderer()) {
        bool reactsToPress = renderer()->style()->affectedByActiveRules();
817 818 819 820 821 822 823 824 825 826 827
        if (reactsToPress)
            setChanged();
        if (renderer() && renderer()->style()->hasAppearance()) {
            if (theme()->stateChanged(renderer(), PressedState))
                reactsToPress = true;
        }
        if (reactsToPress && pause) {
            // The delay here is subtle.  It relies on an assumption, namely that the amount of time it takes
            // to repaint the "down" state of the control is about the same time as it would take to repaint the
            // "up" state.  Once you assume this, you can just delay for 100ms - that time (assuming that after you
            // leave this method, it will be about that long before the flush of the up state happens again).
weinig's avatar
weinig committed
828
#ifdef HAVE_FUNC_USLEEP
darin's avatar
darin committed
829 830
            double startTime = currentTime();
#endif
831 832

            // Do an immediate repaint.
darin's avatar
darin committed
833
            renderer()->repaint(true);
834
            
darin's avatar
darin committed
835 836
            // FIXME: Find a substitute for usleep for Win32.
            // Better yet, come up with a way of doing this that doesn't use this sort of thing at all.            
weinig's avatar
weinig committed
837
#ifdef HAVE_FUNC_USLEEP
838
            // Now pause for a small amount of time (1/10th of a second from before we repainted in the pressed state)
darin's avatar
darin committed
839
            double remainingTime = 0.1 - (currentTime() - startTime);
840
            if (remainingTime > 0)
darin's avatar
darin committed
841
                usleep(static_cast<useconds_t>(remainingTime * 1000000.0));
842 843 844 845 846
#endif
        }
    }
}

darin's avatar
darin committed
847
void ContainerNode::setHovered(bool over)
848 849 850
{
    if (over == hovered()) return;

darin's avatar
darin committed
851
    EventTargetNode::setHovered(over);
852 853

    // note that we need to recalc the style
darin's avatar
darin committed
854
    // FIXME: Move to Element
darin's avatar
darin committed
855 856
    if (renderer()) {
        if (renderer()->style()->affectedByHoverRules())
857 858 859 860 861 862
            setChanged();
        if (renderer() && renderer()->style()->hasAppearance())
            theme()->stateChanged(renderer(), HoverState);
    }
}

darin's avatar
darin committed
863
unsigned ContainerNode::childNodeCount() const
864 865
{
    unsigned count = 0;
darin's avatar
darin committed
866
    Node *n;
867 868 869 870 871
    for (n = firstChild(); n; n = n->nextSibling())
        count++;
    return count;
}

darin's avatar
darin committed
872
Node *ContainerNode::childNode(unsigned index) const
873 874
{
    unsigned i;
darin's avatar
darin committed
875
    Node *n = firstChild();
876 877 878 879 880
    for (i = 0; n != 0 && i < index; i++)
        n = n->nextSibling();
    return n;
}

darin's avatar
darin committed
881
static void dispatchChildInsertionEvents(Node* child, ExceptionCode& ec)
882 883
{
    assert(!eventDispatchForbidden());
darin's avatar
darin committed
884

darin's avatar
darin committed
885
    RefPtr<Node> c = child;
ggaren's avatar
ggaren committed
886
    RefPtr<Document> doc = child->document();
darin's avatar
darin committed
887 888 889

    if (c->parentNode() && c->parentNode()->inDocument())
        c->insertedIntoDocument();
890
    else
darin's avatar
darin committed
891
        c->insertedIntoTree(true);
892

ggaren's avatar
ggaren committed
893
    if (c->parentNode() && 
darin's avatar
darin committed
894
        doc->hasListenerType(Document::DOMNODEINSERTED_LISTENER) &&
ggaren's avatar
ggaren committed
895
        c->isEventTargetNode()) {
darin's avatar
darin committed
896
        ec = 0;
darin's avatar
darin committed
897 898
        EventTargetNodeCast(c.get())->dispatchEvent(new MutationEvent(DOMNodeInsertedEvent, true, false,
            c->parentNode(), String(), String(), String(), 0), ec, true);
darin's avatar
darin committed
899
        if (ec)
900 901 902 903
            return;
    }

    // dispatch the DOMNodeInsertedIntoDocument event to all descendants
darin's avatar
darin committed
904
    if (c->inDocument() && doc->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER))
darin's avatar
darin committed
905
        for (; c; c = c->traverseNextNode(child)) {
ggaren's avatar
ggaren committed
906 907 908
            if (!c->isEventTargetNode())
                continue;
          
darin's avatar
darin committed
909
            ec = 0;
darin's avatar
darin committed
910 911
            EventTargetNodeCast(c.get())->dispatchEvent(new MutationEvent(DOMNodeInsertedIntoDocumentEvent, false, false,
                0, String(), String(), String(), 0), ec, true);
darin's avatar
darin committed
912
            if (ec)
913 914