DocumentImpl.cpp 94.4 KB
Newer Older
kocienda's avatar
kocienda committed
1
2
3
4
5
/**
 * 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)
6
 *           (C) 2001 Dirk Mueller (mueller@kde.org)
7
 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
kocienda's avatar
kocienda committed
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * 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.
 */

mjs's avatar
mjs committed
25
#include "config.h"
darin's avatar
darin committed
26
#include "DocumentImpl.h"
darin's avatar
darin committed
27

28
#include "DOMImplementationImpl.h"
darin's avatar
darin committed
29
#include "DocLoader.h"
30
#include "DocumentFragmentImpl.h"
darin's avatar
darin committed
31
32
33
34
35
36
#include "DocumentTypeImpl.h"
#include "EventNames.h"
#include "FramePrivate.h"
#include "FrameView.h"
#include "KWQAccObjectCache.h"
#include "KWQLogging.h"
37
#include "NameNodeListImpl.h"
darin's avatar
darin committed
38
39
40
41
42
43
44
45
46
47
48
49
50
#include "SegmentedString.h"
#include "css_stylesheetimpl.h"
#include "css_valueimpl.h"
#include "csshelper.h"
#include "cssstyleselector.h"
#include "cssvalues.h"
#include "dom2_events.h"
#include "dom2_eventsimpl.h"
#include "dom2_rangeimpl.h"
#include "dom2_viewsimpl.h"
#include "dom_exception.h"
#include "dom_textimpl.h"
#include "dom_xmlimpl.h"
mjs's avatar
mjs committed
51
#include "ecma/kjs_binding.h"
darin's avatar
darin committed
52
53
54
55
56
#include "ecma/kjs_proxy.h"
#include "helper.h"
#include "jsediting.h"
#include "khtml_settings.h"
#include "render_arena.h"
57
58
#include "render_canvas.h"
#include "render_frames.h"
darin's avatar
darin committed
59
60
61
62
63
64
65
#include "visible_position.h"
#include "visible_text.h"
#include "xml_tokenizer.h"
#include <kdebug.h>
#include <qpaintdevicemetrics.h>
#include <qptrstack.h>
#include <qregexp.h>
66
#include "HTMLNameCollectionImpl.h"
kocienda's avatar
kocienda committed
67

68
// FIXME: We want to cut the remaining HTML dependencies so that we don't need to include these files.
darin's avatar
darin committed
69
70
#include "HTMLInputElementImpl.h"
#include "html/html_baseimpl.h"
71
72
73
#include "html/html_documentimpl.h"
#include "html/html_headimpl.h"
#include "html/html_imageimpl.h"
74
#include "htmlfactory.h"
75
#include "htmlnames.h"
76

77
78
79
80
81
#ifdef KHTML_XSLT
#include "xsl_stylesheetimpl.h"
#include "xslt_processorimpl.h"
#endif

82
83
84
85
86
#ifndef KHTML_NO_XBL
#include "xbl/xbl_binding_manager.h"
using XBL::XBLBindingManager;
#endif

eseidel's avatar
eseidel committed
87
#if SVG_SUPPORT
eseidel's avatar
eseidel committed
88
89
90
91
#include "SVGNames.h"
#include "SVGElementFactory.h"
#include "SVGZoomEventImpl.h"
#include "SVGStyleElementImpl.h"
92
#include "KSVGTimeScheduler.h"
eseidel's avatar
eseidel committed
93
94
#endif

darin's avatar
darin committed
95
96
97
namespace WebCore {

using namespace EventNames;
98
using namespace HTMLNames;
kocienda's avatar
kocienda committed
99

100
// #define INSTRUMENT_LAYOUT_SCHEDULING 1
hyatt's avatar
hyatt committed
101

102
103
104
105
106
// This amount of time must have elapsed before we will even consider scheduling a layout without a delay.
// FIXME: For faster machines this value can really be lowered to 200.  250 is adequate, but a little high
// for dual G5s. :)
const int cLayoutScheduleThreshold = 250;

adele's avatar
adele committed
107
108
109
// Use 1 to represent the document's default form.
HTMLFormElementImpl* const defaultForm = (HTMLFormElementImpl*) 1;

eseidel's avatar
eseidel committed
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// DOM Level 2 says (letters added):
//
// a) Name start characters must have one of the categories Ll, Lu, Lo, Lt, Nl.
// b) Name characters other than Name-start characters must have one of the categories Mc, Me, Mn, Lm, or Nd.
// c) Characters in the compatibility area (i.e. with character code greater than #xF900 and less than #xFFFE) are not allowed in XML names.
// d) Characters which have a font or compatibility decomposition (i.e. those with a "compatibility formatting tag" in field 5 of the database -- marked by field 5 beginning with a "<") are not allowed.
// e) The following characters are treated as name-start characters rather than name characters, because the property file classifies them as Alphabetic: [#x02BB-#x02C1], #x0559, #x06E5, #x06E6.
// f) Characters #x20DD-#x20E0 are excluded (in accordance with Unicode, section 5.14).
// g) Character #x00B7 is classified as an extender, because the property list so identifies it.
// h) Character #x0387 is added as a name character, because #x00B7 is its canonical equivalent.
// i) Characters ':' and '_' are allowed as name-start characters.
// j) Characters '-' and '.' are allowed as name characters.
//
// It also contains complete tables. If we decide it's better, we could include those instead of the following code.

static inline bool isValidNameStart(UChar32 c)
{
    // rule (e) above
    if ((c >= 0x02BB && c <= 0x02C1) || c == 0x559 || c == 0x6E5 || c == 0x6E6)
        return true;

    // rule (i) above
    if (c == ':' || c == '_')
        return true;

    // rules (a) and (f) above
    const uint32_t nameStartMask = U_GC_LL_MASK | U_GC_LU_MASK | U_GC_LO_MASK | U_GC_LT_MASK | U_GC_NL_MASK;
    if (!(U_GET_GC_MASK(c) & nameStartMask))
        return false;

    // rule (c) above
    if (c >= 0xF900 && c < 0xFFFE)
        return false;

    // rule (d) above
    UDecompositionType decompType = static_cast<UDecompositionType>(u_getIntPropertyValue(c, UCHAR_DECOMPOSITION_TYPE));
    if (decompType == U_DT_FONT || decompType == U_DT_COMPAT)
        return false;

    return true;
}

static inline bool isValidNamePart(UChar32 c)
darin's avatar
darin committed
153
{
eseidel's avatar
eseidel committed
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
    // rules (a), (e), and (i) above
    if (isValidNameStart(c))
        return true;

    // rules (g) and (h) above
    if (c == 0x00B7 || c == 0x0387)
        return true;

    // rule (j) above
    if (c == '-' || c == '.')
        return true;

    // rules (b) and (f) above
    const uint32_t otherNamePartMask = U_GC_MC_MASK | U_GC_ME_MASK | U_GC_MN_MASK | U_GC_LM_MASK | U_GC_ND_MASK;
    if (!(U_GET_GC_MASK(c) & otherNamePartMask))
        return false;

    // rule (c) above
    if (c >= 0xF900 && c < 0xFFFE)
darin's avatar
darin committed
173
        return false;
eseidel's avatar
eseidel committed
174
175
176
177
178
179

    // rule (d) above
    UDecompositionType decompType = static_cast<UDecompositionType>(u_getIntPropertyValue(c, UCHAR_DECOMPOSITION_TYPE));
    if (decompType == U_DT_FONT || decompType == U_DT_COMPAT)
        return false;

darin's avatar
darin committed
180
181
182
    return true;
}

183
184
QPtrList<DocumentImpl> * DocumentImpl::changedDocuments = 0;

185
186
// FrameView might be 0
DocumentImpl::DocumentImpl(DOMImplementationImpl *_implementation, FrameView *v)
mjs's avatar
mjs committed
187
    : ContainerNodeImpl(0)
mjs's avatar
mjs committed
188
      , m_domtree_version(0)
darin's avatar
darin committed
189
190
      , m_title("")
      , m_titleSetExplicitly(false)
191
192
193
194
      , m_imageLoadEventTimer(0)
#ifndef KHTML_NO_XBL
      , m_bindingManager(new XBLBindingManager(this))
#endif
195
#ifdef KHTML_XSLT
eseidel's avatar
eseidel committed
196
    , m_transformSource(0)
197
#endif
darin's avatar
darin committed
198
    , m_finishedParsing(this, SIGNAL(finishedParsing()))
adele's avatar
adele committed
199
200
201
202
    , m_savedRenderer(0)
    , m_passwordFields(0)
    , m_secureForms(0)
    , m_designMode(inherit)
203
    , m_selfOnlyRefCount(0)
204
#if __APPLE__
rjw's avatar
rjw committed
205
    , m_hasDashboardRegions(false)
rjw's avatar
rjw committed
206
    , m_dashboardRegionsDirty(false)
207
#endif
208
209
210
    , m_accessKeyMapValid(false)
    , m_createRenderers(true)
    , m_inPageCache(false)
kocienda's avatar
kocienda committed
211
{
mjs's avatar
mjs committed
212
    document.resetSkippingRef(this);
213

darin's avatar
darin committed
214
    m_paintDevice = 0;
kocienda's avatar
kocienda committed
215
216
217
    m_paintDeviceMetrics = 0;

    m_view = v;
218
    m_renderArena = 0;
219
220

    m_accCache = 0;
221
    
kocienda's avatar
kocienda committed
222
    if ( v ) {
mjs's avatar
mjs committed
223
        m_docLoader = new DocLoader(v->frame(), this );
kocienda's avatar
kocienda committed
224
225
226
        setPaintDevice( m_view );
    }
    else
227
        m_docLoader = new DocLoader( 0, this );
kocienda's avatar
kocienda committed
228
229
230

    visuallyOrdered = false;
    m_loadingSheet = false;
231
232
    m_bParsing = false;
    m_docChanged = false;
kocienda's avatar
kocienda committed
233
234
235
    m_sheet = 0;
    m_elemSheet = 0;
    m_tokenizer = 0;
236
237

    m_implementation = _implementation;
238
239
    if (m_implementation)
        m_implementation->ref();
kocienda's avatar
kocienda committed
240
    pMode = Strict;
241
    hMode = XHtml;
242
    m_textColor = Qt::black;
kocienda's avatar
kocienda committed
243
244
245
    m_elementNames = 0;
    m_elementNameAlloc = 0;
    m_elementNameCount = 0;
246
247
248
    m_attrNames = 0;
    m_attrNameAlloc = 0;
    m_attrNameCount = 0;
kocienda's avatar
kocienda committed
249
250
251
252
253
    m_defaultView = new AbstractViewImpl(this);
    m_defaultView->ref();
    m_listenerTypes = 0;
    m_styleSheets = new StyleSheetListImpl;
    m_styleSheets->ref();
254
255
    m_inDocument = true;
    m_styleSelectorDirty = false;
256
    m_inStyleRecalc = false;
257
    m_closeAfterStyleRecalc = false;
258
    m_usesDescendantRules = false;
259
260
    m_usesSiblingRules = false;

hyatt's avatar
hyatt committed
261
    m_styleSelector = new CSSStyleSelector(this, m_usersheet, m_styleSheets, !inCompatMode());
262
    m_windowEventListeners.setAutoDelete(true);
hyatt's avatar
hyatt committed
263
    m_pendingStylesheets = 0;
mjs's avatar
mjs committed
264
    m_ignorePendingStylesheets = false;
265
266

    m_cssTarget = 0;
267

268
269
270
271
    resetLinkColor();
    resetVisitedLinkColor();
    resetActiveLinkColor();

272
273
    m_processingLoadEvent = false;
    m_startTime.restart();
274
    m_overMinimumLayoutThreshold = false;
kocienda's avatar
kocienda committed
275
276
    
    m_jsEditor = 0;
darin's avatar
darin committed
277

278
279
    static int docID = 0;
    m_docID = docID++;
kocienda's avatar
kocienda committed
280
281
}

mjs's avatar
mjs committed
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
void DocumentImpl::removedLastRef()
{
    if (m_selfOnlyRefCount) {
        // if removing a child removes the last self-only ref, we don't
        // want the document to be destructed until after
        // removeAllChildren returns, so we guard ourselves with an
        // extra self-only ref

        DocPtr<DocumentImpl> guard(this);

        // we must make sure not to be retaining any of our children through
        // these extra pointers or we will create a reference cycle
        m_docType = 0;
        m_focusNode = 0;
        m_hoverNode = 0;
        m_activeNode = 0;
        m_titleElement = 0;

        removeAllChildren();
    } else
        delete this;
}

kocienda's avatar
kocienda committed
305
306
DocumentImpl::~DocumentImpl()
{
darin's avatar
darin committed
307
    assert(!m_render);
darin's avatar
darin committed
308
309
    assert(!m_inPageCache);
    assert(m_savedRenderer == 0);
darin's avatar
darin committed
310
    
mjs's avatar
mjs committed
311
    KJS::ScriptInterpreter::forgetAllDOMNodesForDocument(this);
mjs's avatar
mjs committed
312

darin's avatar
darin committed
313
    if (m_docChanged && changedDocuments)
314
        changedDocuments->remove(this);
darin's avatar
darin committed
315
    delete m_tokenizer;
mjs's avatar
mjs committed
316
    document.resetSkippingRef(0);
kocienda's avatar
kocienda committed
317
318
319
320
    delete m_sheet;
    delete m_styleSelector;
    delete m_docLoader;
    if (m_elemSheet )  m_elemSheet->deref();
321
322
    if (m_implementation)
        m_implementation->deref();
kocienda's avatar
kocienda committed
323
    delete m_paintDeviceMetrics;
adele's avatar
adele committed
324
    
kocienda's avatar
kocienda committed
325
    if (m_elementNames) {
326
        for (unsigned short id = 0; id < m_elementNameCount; id++)
kocienda's avatar
kocienda committed
327
328
329
            m_elementNames[id]->deref();
        delete [] m_elementNames;
    }
330
331
332
333
334
    if (m_attrNames) {
        for (unsigned short id = 0; id < m_attrNameCount; id++)
            m_attrNames[id]->deref();
        delete [] m_attrNames;
    }
kocienda's avatar
kocienda committed
335
336
    m_defaultView->deref();
    m_styleSheets->deref();
337

338
339
340
341
    if (m_renderArena){
        delete m_renderArena;
        m_renderArena = 0;
    }
342

343
#ifdef KHTML_XSLT
344
    xmlFreeDoc((xmlDocPtr)m_transformSource);
345
346
#endif

347
348
349
350
#ifndef KHTML_NO_XBL
    delete m_bindingManager;
#endif

darin's avatar
darin committed
351
352
    deleteAllValues(m_markers);

353
354
355
356
    if (m_accCache){
        delete m_accCache;
        m_accCache = 0;
    }
eseidel's avatar
eseidel committed
357
    m_decoder = 0;
kocienda's avatar
kocienda committed
358
359
360
361
362
    
    if (m_jsEditor) {
        delete m_jsEditor;
        m_jsEditor = 0;
    }
adele's avatar
adele committed
363
    
darin's avatar
darin committed
364
    deleteAllValues(m_selectedRadioButtons);
kocienda's avatar
kocienda committed
365
366
}

367
368
369
370
371
372
373
374
375
376
377
378
379
380
void DocumentImpl::resetLinkColor()
{
    m_linkColor = QColor(0, 0, 238);
}

void DocumentImpl::resetVisitedLinkColor()
{
    m_visitedLinkColor = QColor(85, 26, 139);    
}

void DocumentImpl::resetActiveLinkColor()
{
    m_activeLinkColor.setNamedColor(QString("red"));
}
381

382
383
384
385
386
void DocumentImpl::setDocType(DocumentTypeImpl *docType)
{
    m_docType = docType;
}

387
DocumentTypeImpl *DocumentImpl::doctype() const
kocienda's avatar
kocienda committed
388
{
darin's avatar
darin committed
389
    return m_docType.get();
kocienda's avatar
kocienda committed
390
391
}

eseidel's avatar
eseidel committed
392
DOMImplementationImpl *DocumentImpl::implementation() const
kocienda's avatar
kocienda committed
393
{
394
    return m_implementation;
kocienda's avatar
kocienda committed
395
396
397
398
399
400
401
402
403
404
}

ElementImpl *DocumentImpl::documentElement() const
{
    NodeImpl *n = firstChild();
    while (n && n->nodeType() != Node::ELEMENT_NODE)
      n = n->nextSibling();
    return static_cast<ElementImpl*>(n);
}

405
ElementImpl *DocumentImpl::createElement(const DOMString &name, int &exceptionCode)
kocienda's avatar
kocienda committed
406
{
407
    return createElementNS(nullAtom, name, exceptionCode);
kocienda's avatar
kocienda committed
408
409
}

410
411
DocumentFragmentImpl *DocumentImpl::createDocumentFragment(  )
{
mjs's avatar
mjs committed
412
    return new DocumentFragmentImpl(getDocument());
413
414
}

mjs's avatar
mjs committed
415
TextImpl *DocumentImpl::createTextNode(const DOMString &data)
416
{
mjs's avatar
mjs committed
417
    return new TextImpl(this, data);
418
419
}

mjs's avatar
mjs committed
420
CommentImpl *DocumentImpl::createComment (const DOMString &data)
421
{
mjs's avatar
mjs committed
422
    return new CommentImpl(this, data);
423
424
}

darin's avatar
darin committed
425
CDATASectionImpl *DocumentImpl::createCDATASection(const DOMString &data, int &exception)
426
{
darin's avatar
darin committed
427
428
429
430
    if (isHTMLDocument()) {
        exception = DOMException::NOT_SUPPORTED_ERR;
        return NULL;
    }
mjs's avatar
mjs committed
431
    return new CDATASectionImpl(this, data);
432
433
}

darin's avatar
darin committed
434
ProcessingInstructionImpl *DocumentImpl::createProcessingInstruction(const DOMString &target, const DOMString &data, int &exception)
435
{
darin's avatar
darin committed
436
437
438
439
440
441
442
443
    if (!isValidName(target)) {
        exception = DOMException::INVALID_CHARACTER_ERR;
        return NULL;
    }
    if (isHTMLDocument()) {
        exception = DOMException::NOT_SUPPORTED_ERR;
        return NULL;
    }
mjs's avatar
mjs committed
444
    return new ProcessingInstructionImpl(this, target, data);
445
446
}

darin's avatar
darin committed
447
EntityReferenceImpl *DocumentImpl::createEntityReference(const DOMString &name, int &exception)
448
{
darin's avatar
darin committed
449
450
451
452
453
454
455
456
    if (!isValidName(name)) {
        exception = DOMException::INVALID_CHARACTER_ERR;
        return NULL;
    }
    if (isHTMLDocument()) {
        exception = DOMException::NOT_SUPPORTED_ERR;
        return NULL;
    }
mjs's avatar
mjs committed
457
    return new EntityReferenceImpl(this, name.impl());
458
459
}

kocienda's avatar
kocienda committed
460
461
EditingTextImpl *DocumentImpl::createEditingTextNode(const DOMString &text)
{
mjs's avatar
mjs committed
462
    return new EditingTextImpl(this, text);
kocienda's avatar
kocienda committed
463
464
}

kocienda's avatar
kocienda committed
465
466
CSSStyleDeclarationImpl *DocumentImpl::createCSSStyleDeclaration()
{
darin's avatar
darin committed
467
    return new CSSMutableStyleDeclarationImpl;
kocienda's avatar
kocienda committed
468
469
}

darin's avatar
darin committed
470
NodeImpl *DocumentImpl::importNode(NodeImpl *importedNode, bool deep, int &exceptioncode)
471
{
darin's avatar
darin committed
472
    exceptioncode = 0;
darin's avatar
darin committed
473

darin's avatar
darin committed
474
475
476
477
    switch (importedNode->nodeType()) {
        case Node::TEXT_NODE:
            return createTextNode(importedNode->nodeValue());
        case Node::CDATA_SECTION_NODE:
darin's avatar
darin committed
478
            return createCDATASection(importedNode->nodeValue(), exceptioncode);
darin's avatar
darin committed
479
        case Node::ENTITY_REFERENCE_NODE:
darin's avatar
darin committed
480
            return createEntityReference(importedNode->nodeName(), exceptioncode);
darin's avatar
darin committed
481
        case Node::PROCESSING_INSTRUCTION_NODE:
darin's avatar
darin committed
482
            return createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue(), exceptioncode);
darin's avatar
darin committed
483
484
485
486
        case Node::COMMENT_NODE:
            return createComment(importedNode->nodeValue());
        case Node::ELEMENT_NODE: {
            ElementImpl *oldElement = static_cast<ElementImpl *>(importedNode);
487
            ElementImpl *newElement = createElementNS(oldElement->namespaceURI(), oldElement->tagName().toString(), exceptioncode);
darin's avatar
darin committed
488
                        
darin's avatar
darin committed
489
490
            if (exceptioncode != 0)
                return 0;
darin's avatar
darin committed
491

darin's avatar
darin committed
492
493
494
495
496
497
            newElement->ref();

            NamedAttrMapImpl *attrs = oldElement->attributes(true);
            if (attrs) {
                unsigned length = attrs->length();
                for (unsigned i = 0; i < length; i++) {
498
                    AttributeImpl* attr = attrs->attributeItem(i);
darin's avatar
darin committed
499
                    newElement->setAttribute(attr->name(), attr->value().impl(), exceptioncode);
darin's avatar
darin committed
500
501
502
503
504
505
506
                    if (exceptioncode != 0) {
                        newElement->deref();
                        return 0;
                    }
                }
            }

507
508
            newElement->copyNonAttributeProperties(oldElement);

darin's avatar
darin committed
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
            if (deep) {
                for (NodeImpl *oldChild = oldElement->firstChild(); oldChild; oldChild = oldChild->nextSibling()) {
                    NodeImpl *newChild = importNode(oldChild, true, exceptioncode);
                    if (exceptioncode != 0) {
                        newElement->deref();
                        return 0;
                    }
                    newElement->appendChild(newChild, exceptioncode);
                    if (exceptioncode != 0) {
                        newElement->deref();
                        return 0;
                    }
                }
            }

            // Trick to get the result back to the floating state, with 0 refs but not destroyed.
            newElement->setParent(this);
            newElement->deref();
            newElement->setParent(0);

            return newElement;
        }
    }

    exceptioncode = DOMException::NOT_SUPPORTED_ERR;
    return 0;
535
536
}

537
538
539
540
541
542

NodeImpl *DocumentImpl::adoptNode(NodeImpl *source, int &exceptioncode)
{
    if (!source)
        return 0;
    
mjs's avatar
mjs committed
543
    RefPtr<NodeImpl> protect(source);
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575

    switch (source->nodeType()) {
        case Node::ENTITY_NODE:
        case Node::NOTATION_NODE:
            return 0;
        case Node::DOCUMENT_NODE:
        case Node::DOCUMENT_TYPE_NODE:
            exceptioncode = DOMException::NOT_SUPPORTED_ERR;
            return 0;            
        case Node::ATTRIBUTE_NODE: {                   
            AttrImpl *attr = static_cast<AttrImpl *>(source);
            
            if (attr->ownerElement())
                attr->ownerElement()->removeAttributeNode(attr, exceptioncode);

            attr->m_specified = true;
            break;
        }       
        default:
            if (source->parentNode())
                source->parentNode()->removeChild(source, exceptioncode);
    }
                
    for (NodeImpl *node = source; node; node = node->traverseNextNode(source)) {
        KJS::ScriptInterpreter::updateDOMNodeDocument(node, node->getDocument(), this);
        node->setDocument(this);
    }

    return source;

}

eseidel's avatar
eseidel committed
576
ElementImpl *DocumentImpl::createElementNS(const DOMString &_namespaceURI, const DOMString &qualifiedName, int &exceptioncode)
kocienda's avatar
kocienda committed
577
{
eseidel's avatar
eseidel committed
578
    // FIXME: We'd like a faster code path that skips this check for calls from inside the engine where the name is known to be valid.
579
    DOMString prefix, localName;
eseidel's avatar
eseidel committed
580
581
582
    if (!parseQualifiedName(qualifiedName, prefix, localName)) {
        exceptioncode = DOMException::INVALID_CHARACTER_ERR;
        return 0;
583
    }
eseidel's avatar
eseidel committed
584
585

    ElementImpl *e = 0;
eseidel's avatar
eseidel committed
586
    QualifiedName qName = QualifiedName(AtomicString(prefix), AtomicString(localName), AtomicString(_namespaceURI));
587
588
    
    // FIXME: Use registered namespaces and look up in a hash to find the right factory.
589
    if (_namespaceURI == xhtmlNamespaceURI) {
eseidel's avatar
eseidel committed
590
591
592
593
594
595
596
        e = HTMLElementFactory::createHTMLElement(qName.localName(), this, 0, false);
        if (e && !prefix.isNull()) {
            e->setPrefix(qName.prefix(), exceptioncode);
            if (exceptioncode)
                return 0;
        }
    }
eseidel's avatar
eseidel committed
597
#if SVG_SUPPORT
eseidel's avatar
eseidel committed
598
    else if (_namespaceURI == KSVG::SVGNames::svgNamespaceURI)
eseidel's avatar
eseidel committed
599
600
        e = KSVG::SVGElementFactory::createSVGElement(qName, this, false);
#endif
601
    
kocienda's avatar
kocienda committed
602
    if (!e)
eseidel's avatar
eseidel committed
603
        e = new ElementImpl(qName, getDocument());
604
    
kocienda's avatar
kocienda committed
605
606
607
    return e;
}

darin's avatar
darin committed
608
ElementImpl *DocumentImpl::getElementById(const AtomicString& elementId) const
609
{
darin's avatar
darin committed
610
    if (elementId.length() == 0)
611
        return 0;
mjs's avatar
mjs committed
612

darin's avatar
darin committed
613
    ElementImpl *element = m_elementsById.get(elementId.impl());
614
615
616
    if (element)
        return element;
        
darin's avatar
darin committed
617
    if (m_duplicateIds.contains(elementId.impl())) {
618
        for (NodeImpl *n = traverseNextNode(); n != 0; n = n->traverseNextNode()) {
darin's avatar
darin committed
619
620
621
            if (n->isElementNode()) {
                element = static_cast<ElementImpl*>(n);
                if (element->hasID() && element->getAttribute(idAttr) == elementId) {
darin's avatar
darin committed
622
                    m_duplicateIds.remove(elementId.impl());
darin's avatar
darin committed
623
624
625
                    m_elementsById.set(elementId.impl(), element);
                    return element;
                }
626
627
628
629
            }
        }
    }
    return 0;
mjs's avatar
mjs committed
630
631
}

darin's avatar
darin committed
632
ElementImpl* DocumentImpl::elementFromPoint(int x, int y) const
vicki's avatar
vicki committed
633
{
darin's avatar
darin committed
634
635
    if (!m_render)
        return 0;
darin's avatar
darin committed
636

vicki's avatar
vicki committed
637
    RenderObject::NodeInfo nodeInfo(true, true);
darin's avatar
darin committed
638
    m_render->layer()->hitTest(nodeInfo, x, y); 
vicki's avatar
vicki committed
639

darin's avatar
darin committed
640
641
    NodeImpl* n = nodeInfo.innerNode();
    while (n && !n->isElementNode())
vicki's avatar
vicki committed
642
643
644
        n = n->parentNode();
    return static_cast<ElementImpl*>(n);
}
mjs's avatar
mjs committed
645

darin's avatar
darin committed
646
void DocumentImpl::addElementById(const AtomicString& elementId, ElementImpl* element)
mjs's avatar
mjs committed
647
{
darin's avatar
darin committed
648
649
650
    if (!m_elementsById.contains(elementId.impl()))
        m_elementsById.set(elementId.impl(), element);
    else
darin's avatar
darin committed
651
        m_duplicateIds.insert(elementId.impl());
mjs's avatar
mjs committed
652
}
653

darin's avatar
darin committed
654
void DocumentImpl::removeElementById(const AtomicString& elementId, ElementImpl* element)
mjs's avatar
mjs committed
655
{
darin's avatar
darin committed
656
657
658
    if (m_elementsById.get(elementId.impl()) == element)
        m_elementsById.remove(elementId.impl());
    else
darin's avatar
darin committed
659
        m_duplicateIds.remove(elementId.impl());
660
661
}

darin's avatar
darin committed
662
ElementImpl* DocumentImpl::getElementByAccessKey(const DOMString& key)
kocienda's avatar
kocienda committed
663
{
eseidel's avatar
eseidel committed
664
    if (!key.length())
darin's avatar
darin committed
665
666
667
        return 0;
    if (!m_accessKeyMapValid) {
        for (NodeImpl* n = this; n; n = n->traverseNextNode()) {
kocienda's avatar
kocienda committed
668
669
            if (!n->isElementNode())
                continue;
darin's avatar
darin committed
670
671
672
673
            ElementImpl* element = static_cast<ElementImpl *>(n);
            const AtomicString& accessKey = element->getAttribute(accesskeyAttr);
            if (!accessKey.isEmpty())
                m_elementsByAccessKey.set(accessKey.impl(), element);
kocienda's avatar
kocienda committed
674
        }
darin's avatar
darin committed
675
        m_accessKeyMapValid = true;
kocienda's avatar
kocienda committed
676
    }
darin's avatar
darin committed
677
    return m_elementsByAccessKey.get(key.impl());
kocienda's avatar
kocienda committed
678
}
mjs's avatar
mjs committed
679

darin's avatar
darin committed
680
void DocumentImpl::updateTitle()
681
{
mjs's avatar
mjs committed
682
    Frame *p = frame();
darin's avatar
darin committed
683
    if (!p)
684
685
        return;

686
    p->setTitle(m_title);
687
688
}

darin's avatar
darin committed
689
690
691
692
693
void DocumentImpl::setTitle(DOMString title, NodeImpl *titleElement)
{
    if (!titleElement) {
        // Title set by JavaScript -- overrides any title elements.
        m_titleSetExplicitly = true;
mjs's avatar
mjs committed
694
        m_titleElement = 0;
darin's avatar
darin committed
695
    } else if (titleElement != m_titleElement) {
mjs's avatar
mjs committed
696
        if (m_titleElement)
darin's avatar
darin committed
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
            // Only allow the first title element to change the title -- others have no effect.
            return;
        m_titleElement = titleElement;
    }

    if (m_title == title)
        return;

    m_title = title;
    updateTitle();
}

void DocumentImpl::removeTitle(NodeImpl *titleElement)
{
    if (m_titleElement != titleElement)
        return;

    // FIXME: Ideally we might want this to search for the first remaining title element, and use it.
    m_titleElement = 0;

    if (!m_title.isEmpty()) {
        m_title = "";
        updateTitle();
    }
}

723
724
725
726
727
728
729
730
731
732
733
DOMString DocumentImpl::nodeName() const
{
    return "#document";
}

unsigned short DocumentImpl::nodeType() const
{
    return Node::DOCUMENT_NODE;
}

QString DocumentImpl::nextState()
kocienda's avatar
kocienda committed
734
735
736
737
738
739
740
741
742
743
{
   QString state;
   if (!m_state.isEmpty())
   {
      state = m_state.first();
      m_state.remove(m_state.begin());
   }
   return state;
}

744
QStringList DocumentImpl::docState()
kocienda's avatar
kocienda committed
745
{
746
    QStringList s;
darin's avatar
darin committed
747
748
749
    for (QPtrListIterator<NodeImpl> it(m_maintainsState); it.current(); ++it)
        s.append(it.current()->state());

750
    return s;
kocienda's avatar
kocienda committed
751
752
}

mjs's avatar
mjs committed
753
Frame *DocumentImpl::frame() const 
mjs's avatar
mjs committed
754
{
mjs's avatar
mjs committed
755
    return m_view ? m_view->frame() : 0; 
mjs's avatar
mjs committed
756
757
}

kocienda's avatar
kocienda committed
758
759
RangeImpl *DocumentImpl::createRange()
{
mjs's avatar
mjs committed
760
    return new RangeImpl(this);
kocienda's avatar
kocienda committed
761
762
}

adele's avatar
adele committed
763
NodeIteratorImpl *DocumentImpl::createNodeIterator(NodeImpl *root, unsigned whatToShow, 
kocienda's avatar
kocienda committed
764
    NodeFilterImpl *filter, bool expandEntityReferences, int &exceptioncode)
kocienda's avatar
kocienda committed
765
766
767
768
769
{
    if (!root) {
        exceptioncode = DOMException::NOT_SUPPORTED_ERR;
        return 0;
    }
kocienda's avatar
kocienda committed
770
    return new NodeIteratorImpl(root, whatToShow, filter, expandEntityReferences);
kocienda's avatar
kocienda committed
771
772
}

adele's avatar
adele committed
773
TreeWalkerImpl *DocumentImpl::createTreeWalker(NodeImpl *root, unsigned whatToShow, 
kocienda's avatar
kocienda committed
774
    NodeFilterImpl *filter, bool expandEntityReferences, int &exceptioncode)
kocienda's avatar
kocienda committed
775
{
kocienda's avatar
kocienda committed
776
777
778
779
780
    if (!root) {
        exceptioncode = DOMException::NOT_SUPPORTED_ERR;
        return 0;
    }
    return new TreeWalkerImpl(root, whatToShow, filter, expandEntityReferences);
kocienda's avatar
kocienda committed
781
782
}

783
void DocumentImpl::setDocumentChanged(bool b)
kocienda's avatar
kocienda committed
784
{
darin's avatar
darin committed
785
786
787
788
789
790
791
792
793
794
795
796
797
798
    if (b) {
        if (!m_docChanged) {
            if (!changedDocuments)
                changedDocuments = new QPtrList<DocumentImpl>;
            changedDocuments->append(this);
        }
        if (m_accessKeyMapValid) {
            m_accessKeyMapValid = false;
            m_elementsByAccessKey.clear();
        }
    } else {
        if (m_docChanged && changedDocuments)
            changedDocuments->remove(this);
    }
kocienda's avatar
kocienda committed
799

800
    m_docChanged = b;
kocienda's avatar
kocienda committed
801
802
}

803
void DocumentImpl::recalcStyle( StyleChange change )
kocienda's avatar
kocienda committed
804
{
805
806
807
808
809
    if (m_inStyleRecalc)
        return; // Guard against re-entrancy. -dwh
        
    m_inStyleRecalc = true;
    
810
    if( !m_render ) goto bail_out;
kocienda's avatar
kocienda committed
811

812
813
814
    if ( change == Force ) {
        RenderStyle* oldStyle = m_render->style();
        if ( oldStyle ) oldStyle->ref();
815
        RenderStyle* _style = new (m_renderArena) RenderStyle();
darin's avatar
darin committed
816
        _style->ref();
817
818
819
        _style->setDisplay(BLOCK);
        _style->setVisuallyOrdered( visuallyOrdered );
        // ### make the font stuff _really_ work!!!!
kocienda's avatar
kocienda committed
820

darin's avatar
darin committed
821
        FontDef fontDef;
822
823
824
825
        QFont f;
        fontDef.family = *(f.firstFamily());
        fontDef.italic = f.italic();
        fontDef.weight = f.weight();
mjs's avatar
mjs committed
826
        bool printing = m_paintDevice && (m_paintDevice->devType() == QInternal::Printer);
sullivan's avatar
sullivan committed
827
        fontDef.usePrinterFont = printing;
darin's avatar
darin committed
828
        if (m_view) {
mjs's avatar
mjs committed
829
            const KHTMLSettings *settings = m_view->frame()->settings();
sullivan's avatar
sullivan committed
830
            if (printing && !settings->shouldPrintBackgrounds()) {
sullivan's avatar
sullivan committed
831
                _style->setForceBackgroundsToWhite(true);
sullivan's avatar
sullivan committed
832
            }
darin's avatar
darin committed
833
834
835
836
837
            QString stdfont = settings->stdFontName();
            if ( !stdfont.isEmpty() ) {
                fontDef.family.setFamily(stdfont);
                fontDef.family.appendFamily(0);
            }
838
            m_styleSelector->setFontSize(fontDef, m_styleSelector->fontSizeForKeyword(CSS_VAL_MEDIUM, inCompatMode()));
839
        }
kocienda's avatar
kocienda committed
840

darin's avatar
darin committed
841
        _style->setFontDef(fontDef);
842
        _style->htmlFont().update( paintDeviceMetrics() );
843
        if ( inCompatMode() )
844
            _style->setHtmlHacks(true); // enable html specific rendering tricks
kocienda's avatar
kocienda committed
845

846
847
848
849
850
851
        StyleChange ch = diff( _style, oldStyle );
        if(m_render && ch != NoChange)
            m_render->setStyle(_style);
        if ( change != Force )
            change = ch;

darin's avatar
darin committed
852
        _style->deref(m_renderArena);
853
        if (oldStyle)
854
            oldStyle->deref(m_renderArena);
855
    }
kocienda's avatar
kocienda committed
856
857
858

    NodeImpl *n;
    for (n = _first; n; n = n->nextSibling())
859
860
        if ( change>= Inherit || n->hasChangedChild() || n->changed() )
            n->recalcStyle( change );
kocienda's avatar
kocienda committed
861

862
    if (changed() && m_view)
darin's avatar
darin committed
863
        m_view->layout();
kocienda's avatar
kocienda committed
864

865
866
867
868
bail_out:
    setChanged( false );
    setHasChangedChild( false );
    setDocumentChanged( false );
869
870
    
    m_inStyleRecalc = false;
871
872
873
874
875
876
    
    // If we wanted to emit the implicitClose() during recalcStyle, do so now that we're finished.
    if (m_closeAfterStyleRecalc) {
        m_closeAfterStyleRecalc = false;
        implicitClose();
    }
kocienda's avatar
kocienda committed
877
878
}

879
void DocumentImpl::updateRendering()
kocienda's avatar
kocienda committed
880
{
darin's avatar
darin committed
881
882
    if (hasChangedChild())
        recalcStyle(NoChange);
kocienda's avatar
kocienda committed
883
884
}

885
void DocumentImpl::updateDocumentsRendering()
kocienda's avatar
kocienda committed
886
{
887
888
    if (!changedDocuments)
        return;
kocienda's avatar
kocienda committed
889

890
891
892
    while (DocumentImpl* doc = changedDocuments->take()) {
        doc->m_docChanged = false;
        doc->updateRendering();
893
    }
kocienda's avatar
kocienda committed
894
895
}

darin's avatar
darin committed
896
void DocumentImpl::updateLayout()
darin's avatar
darin committed
897
{
darin's avatar
darin committed
898
    // FIXME: Dave Hyatt's pretty sure we can remove this because layout calls recalcStyle as needed.
darin's avatar
darin committed
899
900
901
902
    updateRendering();

    // Only do a layout if changes have occurred that make it necessary.      
    if (m_view && renderer() && renderer()->needsLayout())
darin's avatar
darin committed
903
        m_view->layout();
darin's avatar
darin committed
904
905
906
907
908
909
910
911
912
}

// FIXME: This is a bad idea and needs to be removed eventually.
// Other browsers load stylesheets before they continue parsing the web page.
// Since we don't, we can run JavaScript code that needs answers before the
// stylesheets are loaded. Doing a layout ignoring the pending stylesheets
// lets us get reasonable answers. The long term solution to this problem is
// to instead suspend JavaScript execution.
void DocumentImpl::updateLayoutIgnorePendingStylesheets()
darin's avatar
darin committed
913
{
mjs's avatar
mjs committed
914
915
    bool oldIgnore = m_ignorePendingStylesheets;
    
hyatt's avatar
hyatt committed
916
917
    if (!haveStylesheetsLoaded()) {
        m_ignorePendingStylesheets = true;
darin's avatar
darin committed
918
        updateStyleSelector();    
mjs's avatar
mjs committed
919
920
    }

darin's avatar
darin committed
921
    updateLayout();
mjs's avatar
mjs committed
922
923

    m_ignorePendingStylesheets = oldIgnore;
darin's avatar
darin committed
924
925
}

926
void DocumentImpl::attach()
kocienda's avatar
kocienda committed
927
{
928
    assert(!attached());
darin's avatar
darin committed
929
    assert(!m_inPageCache);
kocienda's avatar
kocienda committed
930

931
932
    if ( m_view )
        setPaintDevice( m_view );
kocienda's avatar
kocienda committed
933

934
935
936
    if (!m_renderArena)
        m_renderArena = new RenderArena();
    
937
    // Create the rendering tree
938
    m_render = new (m_renderArena) RenderCanvas(this, m_view);
939
    recalcStyle( Force );
kocienda's avatar
kocienda committed
940

941
942
    RenderObject* render = m_render;
    m_render = 0;
kocienda's avatar
kocienda committed
943

mjs's avatar
mjs committed
944
    ContainerNodeImpl::attach();
945
    m_render = render;
kocienda's avatar
kocienda committed
946
947
}

rjw's avatar
rjw committed
948
949
950
951
952
void DocumentImpl::restoreRenderer(RenderObject* render)
{
    m_render = render;
}

kocienda's avatar
kocienda committed
953
954
void DocumentImpl::detach()
{
955
956
957
958
    RenderObject* render = m_render;

    // indicate destruction mode,  i.e. attached() but m_render == 0
    m_render = 0;
darin's avatar
darin committed
959
960
    
    if (m_inPageCache) {
961
962
#if __APPLE__
        if (render)
harrison's avatar
harrison committed
963
            getAccObjectCache()->detach(render);
964
#endif
darin's avatar
darin committed
965
966
967
968
969
970
971
972
        return;
    }

    // Empty out these lists as a performance optimization, since detaching
    // all the individual render objects will cause all the RenderImage
    // objects to remove themselves from the lists.
    m_imageLoadEventDispatchSoonList.clear();
    m_imageLoadEventDispatchingList.clear();
kdecker's avatar
kdecker committed
973
    
mjs's avatar
mjs committed
974
    ContainerNodeImpl::detach();
kocienda's avatar
kocienda committed
975

976
    if ( render )
harrison's avatar
harrison committed
977
        render->destroy();
kocienda's avatar
kocienda committed
978

darin's avatar
darin committed
979
980
    if (m_paintDevice == m_view)
        setPaintDevice(0);
kocienda's avatar
kocienda committed
981
    m_view = 0;
982
    
983
984
985
986
    if (m_renderArena){
        delete m_renderArena;
        m_renderArena = 0;
    }
kocienda's avatar
kocienda committed
987
988
}

mjs's avatar
mjs committed
989
990
991
992
993
994
995
996
997
void DocumentImpl::removeAllEventListenersFromAllNodes()
{
    m_windowEventListeners.clear();
    removeAllDisconnectedNodeEventListeners();
    for (NodeImpl *n = this; n; n = n->traverseNextNode()) {
        n->removeAllEventListeners();
    }
}

darin's avatar
darin committed
998
void DocumentImpl::registerDisconnectedNodeWithEventListeners(NodeImpl* node)
mjs's avatar
mjs committed
999
{
darin's avatar
darin committed
1000
    m_disconnectedNodesWithEventListeners.insert(node);
mjs's avatar
mjs committed
1001
1002
}

darin's avatar
darin committed
1003
void DocumentImpl::unregisterDisconnectedNodeWithEventListeners(NodeImpl* node)
mjs's avatar
mjs committed
1004
1005
1006
1007
1008
1009
{
    m_disconnectedNodesWithEventListeners.remove(node);
}

void DocumentImpl::removeAllDisconnectedNodeEventListeners()
{
darin's avatar
darin committed
1010
1011
1012
    NodeSet::iterator end = m_disconnectedNodesWithEventListeners.end();
    for (NodeSet::iterator i = m_disconnectedNodesWithEventListeners.begin(); i != end; ++i)
        (*i)->removeAllEventListeners();
adele's avatar
adele committed
1013
    m_disconnectedNodesWithEventListeners.clear();
mjs's avatar
mjs committed
1014
1015
}

harrison's avatar
harrison committed
1016
KWQAccObjectCache* DocumentImpl::getAccObjectCache()
1017
{
1018
#if __APPLE__
harrison's avatar
harrison committed
1019
1020
1021
1022
1023
1024
    // The only document that actually has a KWQAccObjectCache is the top-level
    // document.  This is because we need to be able to get from any KWQAccObject
    // to any other KWQAccObject on the same page.  Using a single cache allows
    // lookups across nested webareas (i.e. multiple documents).
    
    if (m_accCache) {
harrison's avatar
harrison committed
1025
1026
1027