# khtml Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# dom_docimpl.cpp

    00001
    00024 #include "dom/dom_exception.h"
    00025
    00026 #include "xml/dom_textimpl.h"
    00027 #include "xml/dom_xmlimpl.h"
    00028 #include "xml/dom2_rangeimpl.h"
    00029 #include "xml/dom2_eventsimpl.h"
    00030 #include "xml/xml_tokenizer.h"
    00031
    00032 #include "css/csshelper.h"
    00033 #include "css/cssstyleselector.h"
    00034 #include "css/css_stylesheetimpl.h"
    00035 #include "misc/htmlhashes.h"
    00036 #include "misc/helper.h"
    00037 #include "ecma/kjs_proxy.h"
    00038
    00039 #include <qptrstack.h>
    00040 #include <qpaintdevicemetrics.h>
    00041 #include <kdebug.h>
    00042 #include <kstaticdeleter.h>
    00043
    00044 #include "rendering/render_root.h"
    00045 #include "rendering/render_replaced.h"
    00046
    00047 #include "khtmlview.h"
    00048 #include "khtml_part.h"
    00049
    00050 #include <kglobalsettings.h>
    00051 #include <kstringhandler.h>
    00052 #include <krfcdate.h>
    00053 #include "khtml_settings.h"
    00054 #include "khtmlpart_p.h"
    00055
    00056 #include "html/html_baseimpl.h"
    00057 #include "html/html_blockimpl.h"
    00058 #include "html/html_documentimpl.h"
    00059 #include "html/html_formimpl.h"
    00060 #include "html/html_headimpl.h"
    00061 #include "html/html_imageimpl.h"
    00062 #include "html/html_listimpl.h"
    00063 #include "html/html_miscimpl.h"
    00064 #include "html/html_tableimpl.h"
    00065 #include "html/html_objectimpl.h"
    00066
    00067 #include <kio/job.h>
    00068 #include <kapplication.h>
    00069
    00070 using namespace DOM;
    00071 using namespace khtml;
    00072
    00073 DOMImplementationImpl *DOMImplementationImpl::m_instance = 0;
    00074
    00075 DOMImplementationImpl::DOMImplementationImpl()
    00076 {
    00077 }
    00078
    00079 DOMImplementationImpl::~DOMImplementationImpl()
    00080 {
    00081 }
    00082
    00083 bool DOMImplementationImpl::hasFeature ( const DOMString &feature, const DOMString &version )
    00084 {
    00085     // ### update when we (fully) support the relevant features
    00086     QString lower = feature.string().lower();
    00087     if ((lower == "html" || lower == "xml") &&
    00088         (version == "1.0" || version == "null" || version == "" || version.isNull()))
    00089         return true;
    00090     else
    00091         return false;
    00092 }
    00093
    00094 DocumentTypeImpl *DOMImplementationImpl::createDocumentType( const DOMString &qualifiedName, const DOMString &publicId,
    00095                                                              const DOMString &systemId, int &exceptioncode )
    00096 {
    00097     // Not mentioned in spec: throw NAMESPACE_ERR if no qualifiedName supplied
    00098     if (qualifiedName.isNull()) {
    00099         exceptioncode = DOMException::NAMESPACE_ERR;
    00100         return 0;
    00101     }
    00102
    00103     // INVALID_CHARACTER_ERR: Raised if the specified qualified name contains an illegal character.
    00104     if (!Element::khtmlValidQualifiedName(qualifiedName)) {
    00105         exceptioncode = DOMException::INVALID_CHARACTER_ERR;
    00106         return 0;
    00107     }
    00108
    00109     // NAMESPACE_ERR: Raised if the qualifiedName is malformed.
    00110     if (Element::khtmlMalformedQualifiedName(qualifiedName)) {
    00111         exceptioncode = DOMException::NAMESPACE_ERR;
    00112         return 0;
    00113     }
    00114
    00115     return new DocumentTypeImpl(this,0,qualifiedName,publicId,systemId);
    00116 }
    00117
    00118 DOMImplementationImpl* DOMImplementationImpl::getInterface(const DOMString& /*feature*/) const
    00119 {
    00120     // ###
    00121     return 0;
    00122 }
    00123
    00124 DocumentImpl *DOMImplementationImpl::createDocument( const DOMString &namespaceURI, const DOMString &qualifiedName,
    00125                                                      const DocumentType &doctype, int &exceptioncode )
    00126 {
    00127     exceptioncode = 0;
    00128
    00129     DocumentTypeImpl *dtype = static_cast<DocumentTypeImpl*>(doctype.handle());
    00130     // WRONG_DOCUMENT_ERR: Raised if doctype has already been used with a different document or was
    00131     // created from a different implementation.
    00132     if (dtype && (dtype->getDocument() || dtype->implementation() != this)) {
    00133         exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
    00134         return 0;
    00135     }
    00136
    00137     // ### this is completely broken.. without a view it will not work (Dirk)
    00138     DocumentImpl *doc = new DocumentImpl(this, 0);
    00139
    00140     // now get the interesting parts of the doctype
    00141     // ### create new one if not there (currently always there)
    00142     if (doc->doctype() && dtype)
    00143         doc->doctype()->copyFrom(*dtype);
    00144
    00145     ElementImpl *element = doc->createElementNS(namespaceURI, qualifiedName, &exceptioncode);
    00146     if (!exceptioncode)
    00147         doc->appendChild(element,exceptioncode);
    00148
    00149     if (exceptioncode) {
    00150         delete element;
    00151         delete doc;
    00152         return 0;
    00153     }
    00154
    00155     return doc;
    00156 }
    00157
    00158 CSSStyleSheetImpl *DOMImplementationImpl::createCSSStyleSheet(DOMStringImpl */*title*/, DOMStringImpl *media,
    00159                                                               int &/*exceptioncode*/)
    00160 {
    00161     // ### TODO : title should be set, and media could have wrong syntax, in which case we should
    00162         // generate an exception.
    00163         CSSStyleSheetImpl *parent = 0L;
    00164         CSSStyleSheetImpl *sheet = new CSSStyleSheetImpl(parent, DOMString());
    00165         sheet->setMedia(new MediaListImpl(sheet, media));
    00166         return sheet;
    00167 }
    00168
    00169 DocumentImpl *DOMImplementationImpl::createDocument( KHTMLView *v )
    00170 {
    00171     return new DocumentImpl(this, v);
    00172 }
    00173
    00174 HTMLDocumentImpl *DOMImplementationImpl::createHTMLDocument( KHTMLView *v )
    00175 {
    00176     return new HTMLDocumentImpl(this, v);
    00177 }
    00178
    00179 DOMImplementationImpl *DOMImplementationImpl::instance()
    00180 {
    00181     if (!m_instance) {
    00182         m_instance = new DOMImplementationImpl();
    00183         m_instance->ref();
    00184     }
    00185
    00186     return m_instance;
    00187 }
    00188
    00189 // ------------------------------------------------------------------------
    00190
    00191 static KStaticDeleter< QPtrList<DocumentImpl> > s_changedDocumentsDeleter;
    00192 QPtrList<DocumentImpl> * DocumentImpl::changedDocuments;
    00193
    00194 // KHTMLView might be 0
    00195 DocumentImpl::DocumentImpl(DOMImplementationImpl *_implementation, KHTMLView *v)
    00196     : NodeBaseImpl( new DocumentPtr() )
    00197 {
    00198     document->doc = this;
    00199     m_paintDeviceMetrics = 0;
    00200     m_decoderMibEnum = 0;
    00201     m_textColor = Qt::black;
    00202
    00203     m_view = v;
    00204
    00205     if ( v ) {
    00206         m_docLoader = new DocLoader(v->part(), this );
    00207         setPaintDevice( m_view );
    00208     }
    00209     else
    00210         m_docLoader = new DocLoader( 0, this );
    00211
    00212     visuallyOrdered = false;
    00213     m_loadingSheet = false;
    00214     m_bParsing = false;
    00215     m_docChanged = false;
    00216     m_sheet = 0;
    00217     m_elemSheet = 0;
    00218     m_tokenizer = 0;
    00219
    00220     // ### this should be created during parsing a <!DOCTYPE>
    00221     // not during construction. Not sure who added that and why (Dirk)
    00222     m_doctype = new DocumentTypeImpl(_implementation, document,
    00223                                      DOMString() /* qualifiedName */,
    00224                                      DOMString() /* publicId */,
    00225                                      DOMString() /* systemId */);
    00226     m_doctype->ref();
    00227
    00228     m_implementation = _implementation;
    00229     m_implementation->ref();
    00230     pMode = Strict;
    00231     hMode = XHtml;
    00232     m_textColor = "#000000";
    00233     m_elementNames = 0;
    00234     m_elementNameAlloc = 0;
    00235     m_elementNameCount = 0;
    00236     m_attrNames = 0;
    00237     m_attrNameAlloc = 0;
    00238     m_attrNameCount = 0;
    00239     m_namespaceURIAlloc = 4;
    00240     m_namespaceURICount = 1;
    00241     QString xhtml(XHTML_NAMESPACE);
    00242     m_namespaceURIs = new DOMStringImpl* [m_namespaceURIAlloc];
    00243     m_namespaceURIs[0] = new DOMStringImpl(xhtml.unicode(), xhtml.length());
    00244     m_namespaceURIs[0]->ref();
    00245     m_focusNode = 0;
    00246     m_defaultView = new AbstractViewImpl(this);
    00247     m_defaultView->ref();
    00248     m_listenerTypes = 0;
    00249     m_styleSheets = new StyleSheetListImpl;
    00250     m_styleSheets->ref();
    00251     m_inDocument = true;
    00252     m_styleSelectorDirty = false;
    00253     m_styleSelector = 0;
    00254     m_windowEventListeners.setAutoDelete(true);
    00255
    00256     m_inStyleRecalc = false;
    00257 }
    00258
    00259 DocumentImpl::~DocumentImpl()
    00260 {
    00261     assert( !m_render );
    00262
    00263     if (changedDocuments && m_docChanged)
    00264         changedDocuments->remove(this);
    00265     delete m_tokenizer;
    00266     document->doc = 0;
    00267     delete m_sheet;
    00268     delete m_styleSelector;
    00269     delete m_docLoader;
    00270     if (m_elemSheet )  m_elemSheet->deref();
    00271     if (m_doctype)
    00272         m_doctype->deref();
    00273     m_implementation->deref();
    00274     delete m_paintDeviceMetrics;
    00275
    00276     if (m_elementNames) {
    00277         for (unsigned short id = 0; id < m_elementNameCount; id++)
    00278             m_elementNames[id]->deref();
    00279         delete [] m_elementNames;
    00280     }
    00281     if (m_attrNames) {
    00282         for (unsigned short id = 0; id < m_attrNameCount; id++)
    00283             m_attrNames[id]->deref();
    00284         delete [] m_attrNames;
    00285     }
    00286     for (unsigned short id = 0; id < m_namespaceURICount; ++id)
    00287         m_namespaceURIs[id]->deref();
    00288     delete [] m_namespaceURIs;
    00289     m_defaultView->deref();
    00290     m_styleSheets->deref();
    00291     if (m_focusNode)
    00292         m_focusNode->deref();
    00293 }
    00294
    00295
    00296 DocumentTypeImpl *DocumentImpl::doctype() const
    00297 {
    00298     return m_doctype;
    00299 }
    00300
    00301 DOMImplementationImpl *DocumentImpl::implementation() const
    00302 {
    00303     return m_implementation;
    00304 }
    00305
    00306 ElementImpl *DocumentImpl::documentElement() const
    00307 {
    00308     NodeImpl *n = firstChild();
    00309     while (n && n->nodeType() != Node::ELEMENT_NODE)
    00310       n = n->nextSibling();
    00311     return static_cast<ElementImpl*>(n);
    00312 }
    00313
    00314 ElementImpl *DocumentImpl::createElement( const DOMString &name, int *pExceptioncode )
    00315 {
    00316     Id id = tagId(0 /* no namespace */, name.implementation(),
    00317                   false /* allocate */, pExceptioncode);
    00318     if ( pExceptioncode && *pExceptioncode )
    00319         return 0;
    00320     return new XMLElementImpl( document, id );
    00321 }
    00322
    00323 DocumentFragmentImpl *DocumentImpl::createDocumentFragment(  )
    00324 {
    00325     return new DocumentFragmentImpl( docPtr() );
    00326 }
    00327
    00328 CommentImpl *DocumentImpl::createComment ( DOMStringImpl* data )
    00329 {
    00330     return new CommentImpl( docPtr(), data );
    00331 }
    00332
    00333 CDATASectionImpl *DocumentImpl::createCDATASection ( DOMStringImpl* data )
    00334 {
    00335     return new CDATASectionImpl( docPtr(), data );
    00336 }
    00337
    00338 ProcessingInstructionImpl *DocumentImpl::createProcessingInstruction ( const DOMString &target, DOMStringImpl* data )
    00339 {
    00340     return new ProcessingInstructionImpl( docPtr(),target,data);
    00341 }
    00342
    00343 Attr DocumentImpl::createAttribute( NodeImpl::Id id )
    00344 {
    00345     return new AttrImpl(0, docPtr(), new AttributeImpl(id, DOMString("").implementation()));
    00346 }
    00347
    00348 EntityReferenceImpl *DocumentImpl::createEntityReference ( const DOMString &name )
    00349 {
    00350     return new EntityReferenceImpl(docPtr(), name.implementation());
    00351 }
    00352
    00353 NodeImpl *DocumentImpl::importNode(NodeImpl *importedNode, bool deep, int &exceptioncode)
    00354 {
    00355     NodeImpl *result = 0;
    00356
    00357     // Not mentioned in spec: throw NOT_FOUND_ERR if evt is null
    00358     if (!importedNode) {
    00359         exceptioncode = DOMException::NOT_FOUND_ERR;
    00360         return 0;
    00361     }
    00362
    00363
    00364         if(importedNode->nodeType() == Node::ELEMENT_NODE)
    00365         {
    00366                 ElementImpl *tempElementImpl = createElementNS(getDocument()->namespaceURI(id()), importedNode->nodeName(), 0);
    00367                 result = tempElementImpl;
    00368
    00369                 if(static_cast<ElementImpl *>(importedNode)->attributes(true) && static_cast<ElementImpl *>(importedNode)->attributes(true)->length())
    00370                 {
    00371                         NamedNodeMapImpl *attr = static_cast<ElementImpl *>(importedNode)->attributes();
    00372
    00373                         for(unsigned int i = 0; i < attr->length(); i++)
    00374                         {
    00375                                 DOM::DOMString qualifiedName = attr->item(i)->nodeName();
    00376                                 DOM::DOMString value = attr->item(i)->nodeValue();
    00377
    00378                                 int colonpos = qualifiedName.find(':');
    00379                                 DOMString localName = qualifiedName;
    00380                                 if(colonpos >= 0)
    00381                                 {
    00382                                         localName.remove(0, colonpos + 1);
    00383                                         // ### extract and set new prefix
    00384                                 }
    00385
    00386                                 NodeImpl::Id nodeId = getDocument()->attrId(getDocument()->namespaceURI(id()), localName.implementation(), false /* allocate */, 0);
    00387                                 tempElementImpl->setAttribute(nodeId, value.implementation(), exceptioncode);
    00388
    00389                                 if(exceptioncode != 0)
    00390                                         break;
    00391                         }
    00392                 }
    00393         }
    00394         else if(importedNode->nodeType() == Node::TEXT_NODE)
    00395         {
    00396                 result = createTextNode(static_cast<TextImpl*>(importedNode)->string());
    00397                 deep = false;
    00398         }
    00399         else if(importedNode->nodeType() == Node::CDATA_SECTION_NODE)
    00400         {
    00401                 result = createCDATASection(static_cast<CDATASectionImpl*>(importedNode)->string());
    00402                 deep = false;
    00403         }
    00404         else if(importedNode->nodeType() == Node::ENTITY_REFERENCE_NODE)
    00405                 result = createEntityReference(importedNode->nodeName());
    00406         else if(importedNode->nodeType() == Node::PROCESSING_INSTRUCTION_NODE)
    00407         {
    00408                 result = createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue().implementation());
    00409                 deep = false;
    00410         }
    00411         else if(importedNode->nodeType() == Node::COMMENT_NODE)
    00412         {
    00413                 result = createComment(static_cast<CommentImpl*>(importedNode)->string());
    00414                 deep = false;
    00415         }
    00416         else
    00417                 exceptioncode = DOMException::NOT_SUPPORTED_ERR;
    00418
    00419         if(deep)
    00420         {
    00421                 for(Node n = importedNode->firstChild(); !n.isNull(); n = n.nextSibling())
    00422                         result->appendChild(importNode(n.handle(), true, exceptioncode), exceptioncode);
    00423         }
    00424
    00425         return result;
    00426 }
    00427
    00428 ElementImpl *DocumentImpl::createElementNS( const DOMString &_namespaceURI, const DOMString &_qualifiedName, int* pExceptioncode )
    00429 {
    00430     QString qName = _qualifiedName.string();
    00431     int colonPos = qName.find(':',0);
    00432
    00433     if ( pExceptioncode ) // skip those checks during parsing
    00434     {
    00435         // INVALID_CHARACTER_ERR: Raised if the specified qualified name contains an illegal character.
    00436         if (!Element::khtmlValidQualifiedName(_qualifiedName)) {
    00437             *pExceptioncode = DOMException::INVALID_CHARACTER_ERR;
    00438             return 0;
    00439         }
    00440
    00441         // NAMESPACE_ERR:
    00442         // - Raised if the qualifiedName is malformed,
    00443         // - if the qualifiedName has a prefix and the namespaceURI is null, or
    00444         // - if the qualifiedName has a prefix that is "xml" and the namespaceURI is different
    00445         //   from "http://www.w3.org/XML/1998/namespace" [Namespaces].
    00446         if (Element::khtmlMalformedQualifiedName(_qualifiedName) ||
    00447             (colonPos >= 0 && _namespaceURI.isNull()) ||
    00448             (colonPos == 3 && _qualifiedName[0] == 'x' && _qualifiedName[1] == 'm' && _qualifiedName[2] == 'l' &&
    00449              _namespaceURI != "http://www.w3.org/XML/1998/namespace")) {
    00450
    00451             *pExceptioncode = DOMException::NAMESPACE_ERR;
    00452             return 0;
    00453         }
    00454     }
    00455
    00456     ElementImpl *e = 0;
    00457     if ((_namespaceURI.isNull() && colonPos < 0) ||
    00458         _namespaceURI == XHTML_NAMESPACE) {
    00459         // User requested an element in the XHTML namespace - this means we create a HTML element
    00460         // (elements not in this namespace are treated as normal XML elements)
    00461         e = createHTMLElement(qName.mid(colonPos+1));
    00462         if ( e )
    00463         {
    00464             int _exceptioncode = 0;
    00465             if (colonPos >= 0)
    00466                 e->setPrefix(qName.left(colonPos), _exceptioncode);
    00467             if ( _exceptioncode ) {
    00468                 if ( pExceptioncode ) *pExceptioncode = _exceptioncode;
    00469                 return 0;
    00470             }
    00471         }
    00472     }
    00473     if (!e)
    00474         e = new XMLElementImpl( document, _qualifiedName.implementation(), _namespaceURI.implementation() );
    00475
    00476     return e;
    00477 }
    00478
    00479 ElementImpl *DocumentImpl::getElementById( const DOMString &elementId ) const
    00480 {
    00481     QPtrStack<NodeImpl> nodeStack;
    00482     NodeImpl *current = _first;
    00483
    00484     while(1)
    00485     {
    00486         if(!current)
    00487         {
    00488             if(nodeStack.isEmpty()) break;
    00489             current = nodeStack.pop();
    00490             current = current->nextSibling();
    00491         }
    00492         else
    00493         {
    00494             if(current->isElementNode())
    00495             {
    00496                 ElementImpl *e = static_cast<ElementImpl *>(current);
    00497                 if(e->getAttribute(ATTR_ID) == elementId)
    00498                     return e;
    00499             }
    00500
    00501             NodeImpl *child = current->firstChild();
    00502             if(child)
    00503             {
    00504                 nodeStack.push(current);
    00505                 current = child;
    00506             }
    00507             else
    00508             {
    00509                 current = current->nextSibling();
    00510             }
    00511         }
    00512     }
    00513
    00514     //kdDebug() << "WARNING: *DocumentImpl::getElementById not found " << elementId.string() << endl;
    00515     return 0;
    00516 }
    00517
    00518 void DocumentImpl::setTitle(DOMString _title)
    00519 {
    00520     m_title = _title;
    00521
    00522     QString titleStr = m_title.string();
    00523     for (unsigned int i = 0; i < titleStr.length(); ++i)
    00524         if (titleStr[i] < ' ')
    00525             titleStr[i] = ' ';
    00526     titleStr = titleStr.simplifyWhiteSpace();
    00527     titleStr.compose();
    00528     if ( !view()->part()->parentPart() ) {
    00529         if (titleStr.isNull() || titleStr.isEmpty()) {
    00530             // empty title... set window caption as the URL
    00531             KURL url = m_url;
    00532             url.setRef(QString::null);
    00533             url.setQuery(QString::null);
    00534             titleStr = url.url();
    00535         }
    00536
    00537         emit view()->part()->setWindowCaption( KStringHandler::csqueeze( titleStr, 128 ) );
    00538     }
    00539 }
    00540
    00541 DOMString DocumentImpl::nodeName() const
    00542 {
    00543     return "#document";
    00544 }
    00545
    00546 unsigned short DocumentImpl::nodeType() const
    00547 {
    00548     return Node::DOCUMENT_NODE;
    00549 }
    00550
    00551 ElementImpl *DocumentImpl::createHTMLElement( const DOMString &name )
    00552 {
    00553     QString qstr = name.string().lower();
    00554     uint id = khtml::getTagID( qstr.latin1(), qstr.length() );
    00555
    00556     ElementImpl *n = 0;
    00557     switch(id)
    00558     {
    00559     case ID_HTML:
    00560         n = new HTMLHtmlElementImpl(docPtr());
    00561         break;
    00562     case ID_HEAD:
    00563         n = new HTMLHeadElementImpl(docPtr());
    00564         break;
    00565     case ID_BODY:
    00566         n = new HTMLBodyElementImpl(docPtr());
    00567         break;
    00568
    00569 // head elements
    00570     case ID_BASE:
    00571         n = new HTMLBaseElementImpl(docPtr());
    00572         break;
    00573     case ID_LINK:
    00574         n = new HTMLLinkElementImpl(docPtr());
    00575         break;
    00576     case ID_META:
    00577         n = new HTMLMetaElementImpl(docPtr());
    00578         break;
    00579     case ID_STYLE:
    00580         n = new HTMLStyleElementImpl(docPtr());
    00581         break;
    00582     case ID_TITLE:
    00583         n = new HTMLTitleElementImpl(docPtr());
    00584         break;
    00585
    00586 // frames
    00587     case ID_FRAME:
    00588         n = new HTMLFrameElementImpl(docPtr());
    00589         break;
    00590     case ID_FRAMESET:
    00591         n = new HTMLFrameSetElementImpl(docPtr());
    00592         break;
    00593     case ID_IFRAME:
    00594         n = new HTMLIFrameElementImpl(docPtr());
    00595         break;
    00596
    00597 // form elements
    00598 // ### FIXME: we need a way to set form dependency after we have made the form elements
    00599     case ID_FORM:
    00600             n = new HTMLFormElementImpl(docPtr(), false);
    00601         break;
    00602     case ID_BUTTON:
    00603             n = new HTMLButtonElementImpl(docPtr());
    00604         break;
    00605     case ID_FIELDSET:
    00606             n = new HTMLFieldSetElementImpl(docPtr());
    00607         break;
    00608     case ID_INPUT:
    00609             n = new HTMLInputElementImpl(docPtr());
    00610         break;
    00611     case ID_ISINDEX:
    00612             n = new HTMLIsIndexElementImpl(docPtr());
    00613         break;
    00614     case ID_LABEL:
    00615             n = new HTMLLabelElementImpl(docPtr());
    00616         break;
    00617     case ID_LEGEND:
    00618             n = new HTMLLegendElementImpl(docPtr());
    00619         break;
    00620     case ID_OPTGROUP:
    00621             n = new HTMLOptGroupElementImpl(docPtr());
    00622         break;
    00623     case ID_OPTION:
    00624             n = new HTMLOptionElementImpl(docPtr());
    00625         break;
    00626     case ID_SELECT:
    00627             n = new HTMLSelectElementImpl(docPtr());
    00628         break;
    00629     case ID_TEXTAREA:
    00630             n = new HTMLTextAreaElementImpl(docPtr());
    00631         break;
    00632
    00633 // lists
    00634     case ID_DL:
    00635         n = new HTMLDListElementImpl(docPtr());
    00636         break;
    00637     case ID_DD:
    00638         n = new HTMLGenericElementImpl(docPtr(), id);
    00639         break;
    00640     case ID_DT:
    00641         n = new HTMLGenericElementImpl(docPtr(), id);
    00642         break;
    00643     case ID_UL:
    00644         n = new HTMLUListElementImpl(docPtr());
    00645         break;
    00646     case ID_OL:
    00647         n = new HTMLOListElementImpl(docPtr());
    00648         break;
    00649     case ID_DIR:
    00650         n = new HTMLDirectoryElementImpl(docPtr());
    00651         break;
    00652     case ID_MENU:
    00653         n = new HTMLMenuElementImpl(docPtr());
    00654         break;
    00655     case ID_LI:
    00656         n = new HTMLLIElementImpl(docPtr());
    00657         break;
    00658
    00659 // formatting elements (block)
    00660     case ID_DIV:
    00661     case ID_P:
    00662         n = new HTMLDivElementImpl(docPtr(), id);
    00663         break;
    00664     case ID_BLOCKQUOTE:
    00665     case ID_H1:
    00666     case ID_H2:
    00667     case ID_H3:
    00668     case ID_H4:
    00669     case ID_H5:
    00670     case ID_H6:
    00671         n = new HTMLGenericElementImpl(docPtr(), id);
    00672         break;
    00673     case ID_HR:
    00674         n = new HTMLHRElementImpl(docPtr());
    00675         break;
    00676     case ID_PRE:
    00677         n = new HTMLPreElementImpl(docPtr(), id);
    00678         break;
    00679
    00680 // font stuff
    00681     case ID_BASEFONT:
    00682         n = new HTMLBaseFontElementImpl(docPtr());
    00683         break;
    00684     case ID_FONT:
    00685         n = new HTMLFontElementImpl(docPtr());
    00686         break;
    00687
    00688 // ins/del
    00689     case ID_DEL:
    00690     case ID_INS:
    00691         n = new HTMLGenericElementImpl(docPtr(), id);
    00692         break;
    00693
    00694 // anchor
    00695     case ID_A:
    00696         n = new HTMLAnchorElementImpl(docPtr());
    00697         break;
    00698
    00699 // images
    00700     case ID_IMG:
    00701         n = new HTMLImageElementImpl(docPtr());
    00702         break;
    00703     case ID_MAP:
    00704         n = new HTMLMapElementImpl(docPtr());
    00705         /*n = map;*/
    00706         break;
    00707     case ID_AREA:
    00708         n = new HTMLAreaElementImpl(docPtr());
    00709         break;
    00710
    00711 // objects, applets and scripts
    00712     case ID_APPLET:
    00713         n = new HTMLAppletElementImpl(docPtr());
    00714         break;
    00715     case ID_OBJECT:
    00716         n = new HTMLObjectElementImpl(docPtr());
    00717         break;
    00718     case ID_PARAM:
    00719         n = new HTMLParamElementImpl(docPtr());
    00720         break;
    00721     case ID_SCRIPT:
    00722         n = new HTMLScriptElementImpl(docPtr());
    00723         break;
    00724
    00725 // tables
    00726     case ID_TABLE:
    00727         n = new HTMLTableElementImpl(docPtr());
    00728         break;
    00729     case ID_CAPTION:
    00730         n = new HTMLTableCaptionElementImpl(docPtr());
    00731         break;
    00732     case ID_COLGROUP:
    00733     case ID_COL:
    00734         n = new HTMLTableColElementImpl(docPtr(), id);
    00735         break;
    00736     case ID_TR:
    00737         n = new HTMLTableRowElementImpl(docPtr());
    00738         break;
    00739     case ID_TD:
    00740     case ID_TH:
    00741         n = new HTMLTableCellElementImpl(docPtr(), id);
    00742         break;
    00743     case ID_THEAD:
    00744     case ID_TBODY:
    00745     case ID_TFOOT:
    00746         n = new HTMLTableSectionElementImpl(docPtr(), id, false);
    00747         break;
    00748
    00749 // inline elements
    00750     case ID_BR:
    00751         n = new HTMLBRElementImpl(docPtr());
    00752         break;
    00753     case ID_Q:
    00754         n = new HTMLGenericElementImpl(docPtr(), id);
    00755         break;
    00756
    00757 // elements with no special representation in the DOM
    00758
    00759 // block:
    00760     case ID_ADDRESS:
    00761     case ID_CENTER:
    00762         n = new HTMLGenericElementImpl(docPtr(), id);
    00763         break;
    00764 // inline
    00765         // %fontstyle
    00766     case ID_TT:
    00767     case ID_U:
    00768     case ID_B:
    00769     case ID_I:
    00770     case ID_S:
    00771     case ID_STRIKE:
    00772     case ID_BIG:
    00773     case ID_SMALL:
    00774
    00775         // %phrase
    00776     case ID_EM:
    00777     case ID_STRONG:
    00778     case ID_DFN:
    00779     case ID_CODE:
    00780     case ID_SAMP:
    00781     case ID_KBD:
    00782     case ID_VAR:
    00783     case ID_CITE:
    00784     case ID_ABBR:
    00785     case ID_ACRONYM:
    00786
    00787         // %special
    00788     case ID_SUB:
    00789     case ID_SUP:
    00790     case ID_SPAN:
    00791     case ID_NOBR:
    00792     case ID_WBR:
    00793         n = new HTMLGenericElementImpl(docPtr(), id);
    00794         break;
    00795
    00796     case ID_BDO:
    00797         break;
    00798
    00799 // text
    00800     case ID_TEXT:
    00801         kdDebug( 6020 ) << "Use document->createTextNode()" << endl;
    00802         break;
    00803
    00804     default:
    00805         if ( id )  // known tag but missing in this list
    00806             kdDebug( 6020 ) << "Unsupported tag " << qstr << " id=" << id << endl;
    00807         break;
    00808     }
    00809     return n;
    00810 }
    00811
    00812 QString DocumentImpl::nextState()
    00813 {
    00814    QString state;
    00815    if (!m_state.isEmpty())
    00816    {
    00817       state = m_state.first();
    00818       m_state.remove(m_state.begin());
    00819    }
    00820    return state;
    00821 }
    00822
    00823 QStringList DocumentImpl::docState()
    00824 {
    00825     QStringList s;
    00826     for (QPtrListIterator<NodeImpl> it(m_maintainsState); it.current(); ++it)
    00827         s.append(it.current()->state());
    00828
    00829     return s;
    00830 }
    00831
    00832 RangeImpl *DocumentImpl::createRange()
    00833 {
    00834     return new RangeImpl( docPtr() );
    00835 }
    00836
    00837 NodeIteratorImpl *DocumentImpl::createNodeIterator(NodeImpl *root, unsigned long whatToShow,
    00838                                                    NodeFilter &filter, bool entityReferenceExpansion,
    00839                                                    int &exceptioncode)
    00840 {
    00841     if (!root) {
    00842         exceptioncode = DOMException::NOT_SUPPORTED_ERR;
    00843         return 0;
    00844     }
    00845
    00846     return new NodeIteratorImpl(root,whatToShow,filter,entityReferenceExpansion);
    00847 }
    00848
    00849 TreeWalkerImpl *DocumentImpl::createTreeWalker(Node /*root*/, unsigned long /*whatToShow*/, NodeFilter &/*filter*/,
    00850                                 bool /*entityReferenceExpansion*/)
    00851 {
    00852     // ###
    00853     return new TreeWalkerImpl;
    00854 }
    00855
    00856 void DocumentImpl::setDocumentChanged(bool b)
    00857 {
    00858     if (!changedDocuments)
    00859         changedDocuments = s_changedDocumentsDeleter.setObject( new QPtrList<DocumentImpl>() );
    00860
    00861     if (b && !m_docChanged)
    00862         changedDocuments->append(this);
    00863     else if (!b && m_docChanged)
    00864         changedDocuments->remove(this);
    00865     m_docChanged = b;
    00866 }
    00867
    00868 void DocumentImpl::recalcStyle( StyleChange change )
    00869 {
    00870 //     qDebug("recalcStyle(%p)", this);
    00871 //     QTime qt;
    00872 //     qt.start();
    00873     if (m_inStyleRecalc)
    00874         return; // Guard against re-entrancy. -dwh
    00875
    00876     m_inStyleRecalc = true;
    00877
    00878     if( !m_render ) goto bail_out;
    00879
    00880     if ( change == Force ) {
    00881         RenderStyle* oldStyle = m_render->style();
    00882         if ( oldStyle ) oldStyle->ref();
    00883         RenderStyle* _style = new RenderStyle();
    00884         _style->setDisplay(BLOCK);
    00885         _style->setVisuallyOrdered( visuallyOrdered );
    00886         // ### make the font stuff _really_ work!!!!
    00887
    00888         khtml::FontDef fontDef;
    00889         QFont f = KGlobalSettings::generalFont();
    00890         fontDef.family = f.family();
    00891         fontDef.italic = f.italic();
    00892         fontDef.weight = f.weight();
    00893         if (m_view) {
    00894             const KHTMLSettings *settings = m_view->part()->settings();
    00895             QString stdfont = settings->stdFontName();
    00896             if ( !stdfont.isEmpty() )
    00897                 fontDef.family = stdfont;
    00898
    00899             fontDef.size = m_styleSelector->fontSizes()[3];
    00900         }
    00901
    00902         //kdDebug() << "DocumentImpl::attach: setting to charset " << settings->charset() << endl;
    00903         _style->setFontDef(fontDef);
    00904         _style->htmlFont().update( paintDeviceMetrics() );
    00905         if ( parseMode() != Strict )
    00906             _style->setHtmlHacks(true); // enable html specific rendering tricks
    00907
    00908         StyleChange ch = diff( _style, oldStyle );
    00909         if(m_render && ch != NoChange)
    00910             m_render->setStyle(_style);
    00911         else
    00912             delete _style;
    00913         if ( change != Force )
    00914             change = ch;
    00915
    00916         if (oldStyle)
    00917             oldStyle->deref();
    00918     }
    00919
    00920     NodeImpl *n;
    00921     for (n = _first; n; n = n->nextSibling())
    00922         if ( change>= Inherit || n->hasChangedChild() || n->changed() )
    00923             n->recalcStyle( change );
    00924     //kdDebug( 6020 ) << "TIME: recalcStyle() dt=" << qt.elapsed() << endl;
    00925
    00926     // ### should be done by the rendering tree itself,
    00927     // this way is rather crude and CPU intensive
    00928     if ( changed() ) {
    00929         renderer()->setLayouted( false );
    00930         renderer()->setMinMaxKnown( false );
    00931     }
    00932
    00933 bail_out:
    00934     setChanged( false );
    00935     setHasChangedChild( false );
    00936     setDocumentChanged( false );
    00937
    00938     m_inStyleRecalc = false;
    00939 }
    00940
    00941 void DocumentImpl::updateRendering()
    00942 {
    00943     if (!hasChangedChild()) return;
    00944
    00945 //     QTime time;
    00946 //     time.start();
    00947 //     kdDebug() << "UPDATERENDERING: "<<endl;
    00948
    00949     StyleChange change = NoChange;
    00950 #if 0
    00951     if ( m_styleSelectorDirty ) {
    00952         recalcStyleSelector();
    00953         change = Force;
    00954     }
    00955 #endif
    00956     recalcStyle( change );
    00957
    00958 //    kdDebug() << "UPDATERENDERING time used="<<time.elapsed()<<endl;
    00959 }
    00960
    00961 void DocumentImpl::updateDocumentsRendering()
    00962 {
    00963     if (!changedDocuments)
    00964         return;
    00965
    00966     while ( !changedDocuments->isEmpty() ) {
    00967         changedDocuments->first();
    00968         DocumentImpl* it = changedDocuments->take();
    00969         if (it->isDocumentChanged())
    00970             it->updateRendering();
    00971     }
    00972 }
    00973
    00974 void DocumentImpl::attach()
    00975 {
    00976     assert(!attached());
    00977
    00978     if ( m_view )
    00979         setPaintDevice( m_view );
    00980
    00981     // Create the rendering tree
    00982     assert(!m_styleSelector);
    00983     m_styleSelector = new CSSStyleSelector( this, m_usersheet, m_styleSheets, m_url,
    00984                                             pMode == Strict );
    00985     m_render = new RenderRoot(this, m_view);
    00986     m_styleSelector->computeFontSizes(paintDeviceMetrics(), m_view ? m_view->part()->zoomFactor() : 100);
    00987     recalcStyle( Force );
    00988
    00989     RenderObject* render = m_render;
    00990     m_render = 0;
    00991
    00992     NodeBaseImpl::attach();
    00993     m_render = render;
    00994 }
    00995
    00996 void DocumentImpl::detach()
    00997 {
    00998     RenderObject* render = m_render;
    00999
    01000     // indicate destruction mode,  i.e. attached() but m_render == 0
    01001     m_render = 0;
    01002
    01003     delete m_tokenizer;
    01004     m_tokenizer = 0;
    01005
    01006     NodeBaseImpl::detach();
    01007
    01008     if ( render )
    01009         render->detach();
    01010
    01011     m_view = 0;
    01012 }
    01013
    01014 void DocumentImpl::setVisuallyOrdered()
    01015 {
    01016     visuallyOrdered = true;
    01017     if (m_render)
    01018         m_render->style()->setVisuallyOrdered(true);
    01019 }
    01020
    01021 void DocumentImpl::setSelection(NodeImpl* s, int sp, NodeImpl* e, int ep)
    01022 {
    01023     if ( m_render )
    01024         static_cast<RenderRoot*>(m_render)->setSelection(s->renderer(),sp,e->renderer(),ep);
    01025 }
    01026
    01027 void DocumentImpl::clearSelection()
    01028 {
    01029     if ( m_render )
    01030         static_cast<RenderRoot*>(m_render)->clearSelection();
    01031 }
    01032
    01033 Tokenizer *DocumentImpl::createTokenizer()
    01034 {
    01035     return new XMLTokenizer(docPtr(),m_view);
    01036 }
    01037
    01038 void DocumentImpl::setPaintDevice( QPaintDevice *dev )
    01039 {
    01040     m_paintDevice = dev;
    01041     delete m_paintDeviceMetrics;
    01042     m_paintDeviceMetrics = new QPaintDeviceMetrics( dev );
    01043 }
    01044
    01045 void DocumentImpl::open(  )
    01046 {
    01047     if (parsing()) return;
    01048
    01049     if (m_tokenizer)
    01050         close();
    01051
    01052     delete m_tokenizer;
    01053     m_tokenizer = 0;
    01054
    01055     {
    01056         RenderObject* render = m_render;
    01057         m_render = 0; // indicate destruction mode
    01058         removeChildren();
    01059         QPtrListIterator<RegisteredEventListener> it(m_windowEventListeners);
    01060         for (; it.current();)
    01061             m_windowEventListeners.removeRef(it.current());
    01062         m_render = render;
    01063     }
    01064
    01065     m_tokenizer = createTokenizer();
    01066     m_decoderMibEnum = 0;
    01067     connect(m_tokenizer,SIGNAL(finishedParsing()),this,SIGNAL(finishedParsing()));
    01068     m_tokenizer->begin();
    01069
    01070     if (m_view && m_view->part()->jScript())
    01071         m_view->part()->jScript()->setSourceFile(m_url,"");
    01072 }
    01073
    01074 void DocumentImpl::close(  )
    01075 {
    01076     if (parsing() || !m_tokenizer) return;
    01077
    01078     if ( m_render )
    01079         m_render->close();
    01080
    01081     delete m_tokenizer;
    01082     m_tokenizer = 0;
    01083
    01084     if (m_view)
    01085         m_view->part()->checkEmitLoadEvent();
    01086 }
    01087
    01088 void DocumentImpl::write( const DOMString &text )
    01089 {
    01090     write(text.string());
    01091 }
    01092
    01093 void DocumentImpl::write( const QString &text )
    01094 {
    01095     if (!m_tokenizer) {
    01096         open();
    01097         write(QString::fromLatin1("<html><title></title><body>"));
    01098     }
    01099     m_tokenizer->write(text, false);
    01100
    01101     if (m_view && m_view->part()->jScript())
    01102         m_view->part()->jScript()->appendSourceFile(m_url,text);
    01103 }
    01104
    01105 void DocumentImpl::writeln( const DOMString &text )
    01106 {
    01107     write(text);
    01108     write(DOMString("\n"));
    01109 }
    01110
    01111 void DocumentImpl::finishParsing (  )
    01112 {
    01113     if(m_tokenizer)
    01114         m_tokenizer->finish();
    01115 }
    01116
    01117 void DocumentImpl::setStyleSheet(const DOM::DOMString &url, const DOM::DOMString &sheet)
    01118 {
    01119 //    kdDebug( 6030 ) << "HTMLDocument::setStyleSheet()" << endl;
    01120     m_sheet = new CSSStyleSheetImpl(this, url);
    01121     m_sheet->ref();
    01122     m_sheet->parseString(sheet);
    01123     m_loadingSheet = false;
    01124
    01125     updateStyleSelector();
    01126 }
    01127
    01128 void DocumentImpl::setUserStyleSheet( const QString& sheet )
    01129 {
    01130     if ( m_usersheet != sheet ) {
    01131         m_usersheet = sheet;
    01132         updateStyleSelector();
    01133     }
    01134 }
    01135
    01136 CSSStyleSheetImpl* DocumentImpl::elementSheet()
    01137 {
    01138     if (!m_elemSheet) {
    01139         m_elemSheet = new CSSStyleSheetImpl(this, baseURL() );
    01140         m_elemSheet->ref();
    01141     }
    01142     return m_elemSheet;
    01143 }
    01144
    01145 void DocumentImpl::determineParseMode( const QString &/*str*/ )
    01146 {
    01147     // For xML documents, use string parse mode
    01148     pMode = Strict;
    01149     kdDebug(6020) << " using strict parseMode" << endl;
    01150 }
    01151
    01152 // Please see if there`s a possibility to merge that code
    01153 // with the next function and getElementByID().
    01154 NodeImpl *DocumentImpl::findElement( Id id )
    01155 {
    01156     QPtrStack<NodeImpl> nodeStack;
    01157     NodeImpl *current = _first;
    01158
    01159     while(1)
    01160     {
    01161         if(!current)
    01162         {
    01163             if(nodeStack.isEmpty()) break;
    01164             current = nodeStack.pop();
    01165             current = current->nextSibling();
    01166         }
    01167         else
    01168         {
    01169             if(current->id() == id)
    01170                 return current;
    01171
    01172             NodeImpl *child = current->firstChild();
    01173             if(child)
    01174             {
    01175                 nodeStack.push(current);
    01176                 current = child;
    01177             }
    01178             else
    01179             {
    01180                 current = current->nextSibling();
    01181             }
    01182         }
    01183     }
    01184
    01185     return 0;
    01186 }
    01187
    01188 NodeImpl *DocumentImpl::nextFocusNode(NodeImpl *fromNode)
    01189 {
    01190     unsigned short fromTabIndex;
    01191
    01192     if (!fromNode) {
    01193         // No starting node supplied; begin with the top of the document
    01194         NodeImpl *n;
    01195
    01196         int lowestTabIndex = 65535;
    01197         for (n = this; n != 0; n = n->traverseNextNode()) {
    01198             if (n->isSelectable()) {
    01199                 if ((n->tabIndex() > 0) && (n->tabIndex() < lowestTabIndex))
    01200                     lowestTabIndex = n->tabIndex();
    01201             }
    01202         }
    01203
    01204         if (lowestTabIndex == 65535)
    01205             lowestTabIndex = 0;
    01206
    01207         // Go to the first node in the document that has the desired tab index
    01208         for (n = this; n != 0; n = n->traverseNextNode()) {
    01209             if (n->isSelectable() && (n->tabIndex() == lowestTabIndex))
    01210                 return n;
    01211         }
    01212
    01213         return 0;
    01214     }
    01215     else {
    01216         fromTabIndex = fromNode->tabIndex();
    01217     }
    01218
    01219     if (fromTabIndex == 0) {
    01220         // Just need to find the next selectable node after fromNode (in document order) that doesn't have a tab index
    01221         NodeImpl *n = fromNode->traverseNextNode();
    01222         while (n && !(n->isSelectable() && n->tabIndex() == 0))
    01223             n = n->traverseNextNode();
    01224         return n;
    01225     }
    01226     else {
    01227         // Find the lowest tab index out of all the nodes except fromNode, that is greater than or equal to fromNode's
    01228         // tab index. For nodes with the same tab index as fromNode, we are only interested in those that come after
    01229         // fromNode in document order.
    01230         // If we don't find a suitable tab index, the next focus node will be one with a tab index of 0.
    01231         unsigned short lowestSuitableTabIndex = 65535;
    01232         NodeImpl *n;
    01233
    01234         bool reachedFromNode = false;
    01235         for (n = this; n != 0; n = n->traverseNextNode()) {
    01236             if (n->isSelectable() &&
    01237                 ((reachedFromNode && (n->tabIndex() >= fromTabIndex)) ||
    01238                  (!reachedFromNode && (n->tabIndex() > fromTabIndex))) &&
    01239                 (n->tabIndex() < lowestSuitableTabIndex) &&
    01240                 (n != fromNode)) {
    01241
    01242                 // We found a selectable node with a tab index at least as high as fromNode's. Keep searching though,
    01243                 // as there may be another node which has a lower tab index but is still suitable for use.
    01244                 lowestSuitableTabIndex = n->tabIndex();
    01245             }
    01246
    01247             if (n == fromNode)
    01248                 reachedFromNode = true;
    01249         }
    01250
    01251         if (lowestSuitableTabIndex == 65535) {
    01252             // No next node with a tab index -> just take first node with tab index of 0
    01253             NodeImpl *n = this;
    01254             while (n && !(n->isSelectable() && n->tabIndex() == 0))
    01255                 n = n->traverseNextNode();
    01256             return n;
    01257         }
    01258
    01259         // Search forwards from fromNode
    01260         for (n = fromNode->traverseNextNode(); n != 0; n = n->traverseNextNode()) {
    01261             if (n->isSelectable() && (n->tabIndex() == lowestSuitableTabIndex))
    01262                 return n;
    01263         }
    01264
    01265         // The next node isn't after fromNode, start from the beginning of the document
    01266         for (n = this; n != fromNode; n = n->traverseNextNode()) {
    01267             if (n->isSelectable() && (n->tabIndex() == lowestSuitableTabIndex))
    01268                 return n;
    01269         }
    01270
    01271         assert(false); // should never get here
    01272         return 0;
    01273     }
    01274 }
    01275
    01276 NodeImpl *DocumentImpl::previousFocusNode(NodeImpl *fromNode)
    01277 {
    01278     NodeImpl *lastNode = this;
    01279     while (lastNode->lastChild())
    01280         lastNode = lastNode->lastChild();
    01281
    01282     if (!fromNode) {
    01283         // No starting node supplied; begin with the very last node in the document
    01284         NodeImpl *n;
    01285
    01286         int highestTabIndex = 0;
    01287         for (n = lastNode; n != 0; n = n->traversePreviousNode()) {
    01288             if (n->isSelectable()) {
    01289                 if (n->tabIndex() == 0)
    01290                     return n;
    01291                 else if (n->tabIndex() > highestTabIndex)
    01292                     highestTabIndex = n->tabIndex();
    01293             }
    01294         }
    01295
    01296         // No node with a tab index of 0; just go to the last node with the highest tab index
    01297         for (n = lastNode; n != 0; n = n->traversePreviousNode()) {
    01298             if (n->isSelectable() && (n->tabIndex() == highestTabIndex))
    01299                 return n;
    01300         }
    01301
    01302         return 0;
    01303     }
    01304     else {
    01305         unsigned short fromTabIndex = fromNode->tabIndex();
    01306
    01307         if (fromTabIndex == 0) {
    01308             // Find the previous selectable node before fromNode (in document order) that doesn't have a tab index
    01309             NodeImpl *n = fromNode->traversePreviousNode();
    01310             while (n && !(n->isSelectable() && n->tabIndex() == 0))
    01311                 n = n->traversePreviousNode();
    01312             if (n)
    01313                 return n;
    01314
    01315             // No previous nodes with a 0 tab index, go to the last node in the document that has the highest tab index
    01316             int highestTabIndex = 0;
    01317             for (n = this; n != 0; n = n->traverseNextNode()) {
    01318                 if (n->isSelectable() && (n->tabIndex() > highestTabIndex))
    01319                     highestTabIndex = n->tabIndex();
    01320             }
    01321
    01322             if (highestTabIndex == 0)
    01323                 return 0;
    01324
    01325             for (n = lastNode; n != 0; n = n->traversePreviousNode()) {
    01326                 if (n->isSelectable() && (n->tabIndex() == highestTabIndex))
    01327                     return n;
    01328             }
    01329
    01330             assert(false); // should never get here
    01331             return 0;
    01332         }
    01333         else {
    01334             // Find the lowest tab index out of all the nodes except fromNode, that is less than or equal to fromNode's
    01335             // tab index. For nodes with the same tab index as fromNode, we are only interested in those before
    01336             // fromNode.
    01337             // If we don't find a suitable tab index, then there will be no previous focus node.
    01338             unsigned short highestSuitableTabIndex = 0;
    01339             NodeImpl *n;
    01340
    01341             bool reachedFromNode = false;
    01342             for (n = this; n != 0; n = n->traverseNextNode()) {
    01343                 if (n->isSelectable() &&
    01344                     ((!reachedFromNode && (n->tabIndex() <= fromTabIndex)) ||
    01345                      (reachedFromNode && (n->tabIndex() < fromTabIndex)))  &&
    01346                     (n->tabIndex() > highestSuitableTabIndex) &&
    01347                     (n != fromNode)) {
    01348
    01349                     // We found a selectable node with a tab index no higher than fromNode's. Keep searching though, as
    01350                     // there may be another node which has a higher tab index but is still suitable for use.
    01351                     highestSuitableTabIndex = n->tabIndex();
    01352                 }
    01353
    01354                 if (n == fromNode)
    01355                     reachedFromNode = true;
    01356             }
    01357
    01358             if (highestSuitableTabIndex == 0) {
    01359                 // No previous node with a tab index. Since the order specified by HTML is nodes with tab index > 0
    01360                 // first, this means that there is no previous node.
    01361                 return 0;
    01362             }
    01363
    01364             // Search backwards from fromNode
    01365             for (n = fromNode->traversePreviousNode(); n != 0; n = n->traversePreviousNode()) {
    01366                 if (n->isSelectable() && (n->tabIndex() == highestSuitableTabIndex))
    01367                     return n;
    01368             }
    01369             // The previous node isn't before fromNode, start from the end of the document
    01370             for (n = lastNode; n != fromNode; n = n->traversePreviousNode()) {
    01371                 if (n->isSelectable() && (n->tabIndex() == highestSuitableTabIndex))
    01372                     return n;
    01373             }
    01374
    01375             assert(false); // should never get here
    01376             return 0;
    01377         }
    01378     }
    01379 }
    01380
    01381 int DocumentImpl::nodeAbsIndex(NodeImpl *node)
    01382 {
    01383     assert(node->getDocument() == this);
    01384
    01385     int absIndex = 0;
    01386     for (NodeImpl *n = node; n && n != this; n = n->traversePreviousNode())
    01387         absIndex++;
    01388     return absIndex;
    01389 }
    01390
    01391 NodeImpl *DocumentImpl::nodeWithAbsIndex(int absIndex)
    01392 {
    01393     NodeImpl *n = this;
    01394     for (int i = 0; n && (i < absIndex); i++) {
    01395         n = n->traverseNextNode();
    01396     }
    01397     return n;
    01398 }
    01399
    01400 void DocumentImpl::processHttpEquiv(const DOMString &equiv, const DOMString &content)
    01401 {
    01402     assert(!equiv.isNull() && !content.isNull());
    01403
    01404     KHTMLView *v = getDocument()->view();
    01405
    01406     if(strcasecmp(equiv, "refresh") == 0 && v->part()->metaRefreshEnabled())
    01407     {
    01408         // get delay and url
    01409         QString str = content.string().stripWhiteSpace();
    01410         int pos = str.find(QRegExp("[;,]"));
    01411         if ( pos == -1 )
    01412             pos = str.find(QRegExp("[ \t]"));
    01413
    01414         if (pos == -1) // There can be no url (David)
    01415         {
    01416             bool ok = false;
    01417             int delay = 0;
    01418             delay = content.implementation()->toInt(&ok);
    01419             if(ok) v->part()->scheduleRedirection(delay, v->part()->url().url() );
    01420         } else {
    01421             int delay = 0;
    01422             int fract = pos;
    01423             bool ok = false;
    01424             if ( (fract = str.find('.') ) < 0 || fract > pos)
    01425                 fract = pos;
    01426             DOMStringImpl* s = content.implementation()->substring(0, fract);
    01427             delay = s->toInt(&ok);
    01428             delete s;
    01429
    01430             pos++;
    01431             while(pos < (int)str.length() && str[pos].isSpace()) pos++;
    01432             str = str.mid(pos);
    01433             if(str.find("url", 0,  false ) == 0)  str = str.mid(3);
    01434             str = str.stripWhiteSpace();
    01435             if ( str.length() && str[0] == '=' ) str = str.mid( 1 ).stripWhiteSpace();
    01436             while(str.length() &&
    01437                   (str[str.length()-1] == ';' || str[str.length()-1] == ','))
    01438                 str.setLength(str.length()-1);
    01439             str = parseURL( DOMString(str) ).string();
    01440             if ( ok  || !fract)
    01441                 v->part()->scheduleRedirection(delay, getDocument()->completeURL( str ));
    01442         }
    01443     }
    01444     else if(strcasecmp(equiv, "expires") == 0)
    01445     {
    01446         bool relative = false;
    01447         QString str = content.string().stripWhiteSpace();
    01448         time_t expire_date = KRFCDate::parseDate(str);
    01449         if (!expire_date)
    01450         {
    01451             expire_date = str.toULong();
    01452             relative = true;
    01453         }
    01454         if (!expire_date)
    01455             expire_date = 1; // expire now
    01456         if (m_docLoader)
    01457             m_docLoader->setExpireDate(expire_date, relative);
    01458     }
    01459     else if(strcasecmp(equiv, "pragma") == 0 || strcasecmp(equiv, "cache-control") == 0)
    01460     {
    01461         QString str = content.string().lower().stripWhiteSpace();
    01462         KURL url = v->part()->url();
    01463         if ((str == "no-cache") && url.protocol().startsWith("http"))
    01464         {
    01465            KIO::http_update_cache(url, true, 0);
    01466         }
    01467     }
    01468     else if( (strcasecmp(equiv, "set-cookie") == 0))
    01469     {
    01470         // ### make setCookie work on XML documents too; e.g. in case of <html:meta .....>
    01471         HTMLDocumentImpl *d = static_cast<HTMLDocumentImpl *>(this);
    01472         d->setCookie(content);
    01473     }
    01474 }
    01475
    01476 bool DocumentImpl::prepareMouseEvent( bool readonly, int _x, int _y, MouseEvent *ev )
    01477 {
    01478     if ( m_render ) {
    01479         assert(m_render->isRoot());
    01480         RenderObject::NodeInfo renderInfo(readonly, ev->type == MousePress);
    01481         bool isInside = m_render->nodeAtPoint(renderInfo, _x, _y, 0, 0);
    01482         ev->innerNode = renderInfo.innerNode();
    01483
    01484         if (renderInfo.URLElement()) {
    01485             assert(renderInfo.URLElement()->isElementNode());
    01486             ElementImpl* e =  static_cast<ElementImpl*>(renderInfo.URLElement());
    01487             DOMString href = khtml::parseURL(e->getAttribute(ATTR_HREF));
    01488             DOMString target = e->getAttribute(ATTR_TARGET);
    01489
    01490             if (!target.isNull() && !href.isNull()) {
    01491                 ev->target = target;
    01492                 ev->url = href;
    01493             }
    01494             else
    01495                 ev->url = href;
    01496 //            qDebug("url: *%s*", ev->url.string().latin1());
    01497         }
    01498
    01499         if (!readonly)
    01500             updateRendering();
    01501
    01502         return isInside;
    01503     }
    01504
    01505
    01506     return false;
    01507 }
    01508
    01509 // DOM Section 1.1.1
    01510 bool DocumentImpl::childAllowed( NodeImpl *newChild )
    01511 {
    01512     // Documents may contain a maximum of one Element child
    01513     if (newChild->nodeType() == Node::ELEMENT_NODE) {
    01514         NodeImpl *c;
    01515         for (c = firstChild(); c; c = c->nextSibling()) {
    01516             if (c->nodeType() == Node::ELEMENT_NODE)
    01517                 return false;
    01518         }
    01519     }
    01520
    01521     // Documents may contain a maximum of one DocumentType child
    01522     if (newChild->nodeType() == Node::DOCUMENT_TYPE_NODE) {
    01523         NodeImpl *c;
    01524         for (c = firstChild(); c; c = c->nextSibling()) {
    01525             if (c->nodeType() == Node::DOCUMENT_TYPE_NODE)
    01526                 return false;
    01527         }
    01528     }
    01529
    01530     return childTypeAllowed(newChild->nodeType());
    01531 }
    01532
    01533 bool DocumentImpl::childTypeAllowed( unsigned short type )
    01534 {
    01535     switch (type) {
    01536         case Node::ELEMENT_NODE:
    01537         case Node::PROCESSING_INSTRUCTION_NODE:
    01538         case Node::COMMENT_NODE:
    01539         case Node::DOCUMENT_TYPE_NODE:
    01540             return true;
    01541             break;
    01542         default:
    01543             return false;
    01544     }
    01545 }
    01546
    01547 NodeImpl *DocumentImpl::cloneNode ( bool /*deep*/ )
    01548 {
    01549     // Spec says cloning Document nodes is "implementation dependent"
    01550     // so we do not support it...
    01551     return 0;
    01552 }
    01553
    01554 NodeImpl::Id DocumentImpl::attrId(DOMStringImpl* _namespaceURI, DOMStringImpl *_name, bool readonly, int* pExceptioncode)
    01555 {
    01556     // Each document maintains a mapping of attrname -> id for every attr name
    01557     // encountered in the document.
    01558     // For attrnames without a prefix (no qualified element name) and without matching
    01559     // namespace, the value defined in misc/htmlattrs.h is used.
    01560     NodeImpl::Id id = 0;
    01561
    01562     // First see if it's a HTML attribute name
    01563     QConstString n(_name->s, _name->l);
    01564     if (!_namespaceURI || !strcasecmp(_namespaceURI, XHTML_NAMESPACE)) {
    01565         // we're in HTML namespace if we know the tag.
    01566         // xhtml is lower case - case sensitive, easy to implement
    01567         if ( htmlMode() == XHtml && (id = khtml::getAttrID(n.string().ascii(), _name->l)) )
    01568             return id;
    01569         // compatibility: upper case - case insensitive
    01570         if ( htmlMode() != XHtml && (id = khtml::getAttrID(n.string().lower().ascii(), _name->l )) )
    01571             return id;
    01572
    01573         // ok, the fast path didn't work out, we need the full check
    01574     }
    01575
    01576     // now lets find out the namespace
    01577     if (_namespaceURI) {
    01578         DOMString nsU(_namespaceURI);
    01579         bool found = false;
    01580         // ### yeah, this is lame. use a dictionary / map instead
    01581         for (unsigned short ns = 0; ns < m_namespaceURICount; ++ns)
    01582             if (nsU == DOMString(m_namespaceURIs[ns])) {
    01583                 id |= ns << 16;
    01584                 found = true;
    01585                 break;
    01586             }
    01587
    01588         if (!found && !readonly) {
    01589             // something new, add it
    01590             if (m_namespaceURICount >= m_namespaceURIAlloc) {
    01591                 m_namespaceURIAlloc += 32;
    01592                 DOMStringImpl **newURIs = new DOMStringImpl* [m_namespaceURIAlloc];
    01593                 for (unsigned short i = 0; i < m_namespaceURICount; i++)
    01594                     newURIs[i] = m_namespaceURIs[i];
    01595                 delete [] m_namespaceURIs;
    01596                 m_namespaceURIs = newURIs;
    01597             }
    01598             m_namespaceURIs[m_namespaceURICount++] = _namespaceURI;
    01599             _namespaceURI->ref();
    01600             id |= m_namespaceURICount << 16;
    01601         }
    01602     }
    01603
    01604     // Look in the m_attrNames array for the name
    01605     // ### yeah, this is lame. use a dictionary / map instead
    01606     DOMString nme(n.string());
    01607     // compatibility mode has to store upper case
    01608     if (htmlMode() != XHtml) nme = nme.upper();
    01609     for (id = 0; id < m_attrNameCount; id++)
    01610         if (DOMString(m_attrNames[id]) == nme)
    01611             return ATTR_LAST_ATTR+id;
    01612
    01613     // unknown
    01614     if (readonly) return 0;
    01615
    01616     if (pExceptioncode && !Element::khtmlValidQualifiedName(_name)) {
    01617         *pExceptioncode = DOMException::INVALID_CHARACTER_ERR;
    01618         return 0;
    01619     }
    01620
    01621     // Name not found in m_attrNames, so let's add it
    01622     // ### yeah, this is lame. use a dictionary / map instead
    01623     if (m_attrNameCount+1 > m_attrNameAlloc) {
    01624         m_attrNameAlloc += 100;
    01625         DOMStringImpl **newNames = new DOMStringImpl* [m_attrNameAlloc];
    01626         if (m_attrNames) {
    01627             unsigned short i;
    01628             for (i = 0; i < m_attrNameCount; i++)
    01629                 newNames[i] = m_attrNames[i];
    01630             delete [] m_attrNames;
    01631         }
    01632         m_attrNames = newNames;
    01633     }
    01634
    01635     id = m_attrNameCount++;
    01636     m_attrNames[id] = nme.implementation();
    01637     m_attrNames[id]->ref();
    01638
    01639     return ATTR_LAST_ATTR+id;
    01640 }
    01641
    01642 DOMString DocumentImpl::attrName(NodeImpl::Id _id) const
    01643 {
    01644     if (_id >= ATTR_LAST_ATTR)
    01645         return m_attrNames[_id-ATTR_LAST_ATTR];
    01646     else {
    01647         // ### put them in a cache
    01648         if (getDocument()->htmlMode() == DocumentImpl::XHtml)
    01649             return getAttrName(_id).lower();
    01650         else
    01651             return getAttrName(_id);
    01652     }
    01653 }
    01654
    01655 NodeImpl::Id DocumentImpl::tagId(DOMStringImpl* _namespaceURI, DOMStringImpl *_name, bool readonly, int *pExceptioncode)
    01656 {
    01657     if (!_name || !_name->l) return 0;
    01658     // Each document maintains a mapping of tag name -> id for every tag name encountered
    01659     // in the document.
    01660     NodeImpl::Id id = 0;
    01661
    01662     // First see if it's a HTML element name
    01663     QConstString n(_name->s, _name->l);
    01664     if (!_namespaceURI || !strcasecmp(_namespaceURI, XHTML_NAMESPACE)) {
    01665         // we're in HTML namespace if we know the tag.
    01666         // xhtml is lower case - case sensitive, easy to implement
    01667         if ( htmlMode() == XHtml && (id = khtml::getTagID(n.string().ascii(), _name->l)) )
    01668             return id;
    01669         // compatibility: upper case - case insensitive
    01670         if ( htmlMode() != XHtml && (id = khtml::getTagID(n.string().lower().ascii(), _name->l )) )
    01671             return id;
    01672
    01673         // ok, the fast path didn't work out, we need the full check
    01674     }
    01675
    01676     // now lets find out the namespace
    01677     if (_namespaceURI) {
    01678         DOMString nsU(_namespaceURI);
    01679         bool found = false;
    01680         // ### yeah, this is lame. use a dictionary / map instead
    01681         for (unsigned short ns = 0; ns < m_namespaceURICount; ++ns)
    01682             if (nsU == DOMString(m_namespaceURIs[ns])) {
    01683                 id |= ns << 16;
    01684                 found = true;
    01685                 break;
    01686             }
    01687
    01688         if (!found && !readonly) {
    01689             // something new, add it
    01690             if (m_namespaceURICount >= m_namespaceURIAlloc) {
    01691                 m_namespaceURIAlloc += 32;
    01692                 DOMStringImpl **newURIs = new DOMStringImpl* [m_namespaceURIAlloc];
    01693                 for (unsigned short i = 0; i < m_namespaceURICount; i++)
    01694                     newURIs[i] = m_namespaceURIs[i];
    01695                 delete [] m_namespaceURIs;
    01696                 m_namespaceURIs = newURIs;
    01697             }
    01698             m_namespaceURIs[m_namespaceURICount++] = _namespaceURI;
    01699             _namespaceURI->ref();
    01700             id |= m_namespaceURICount << 16;
    01701         }
    01702     }
    01703
    01704     // Look in the m_elementNames array for the name
    01705     //DOMString nme(n.string());
    01706     DOMString nme( _name );
    01707     // ### yeah, this is lame. use a dictionary / map instead
    01708     // compatibility mode has to store upper case
    01709     if (htmlMode() != XHtml) nme = nme.upper();
    01710     for (id = 0; id < m_elementNameCount; id++)
    01711         if (DOMString(m_elementNames[id]) == nme)
    01712             return ID_LAST_TAG+id;
    01713
    01714     // unknown
    01715     if (readonly) return 0;
    01716
    01717     if (pExceptioncode && !Element::khtmlValidQualifiedName(_name)) {
    01718         *pExceptioncode = DOMException::INVALID_CHARACTER_ERR;
    01719         return 0;
    01720     }
    01721
    01722     // Name not found in m_elementNames, so let's add it
    01723     if (m_elementNameCount+1 > m_elementNameAlloc) {
    01724         m_elementNameAlloc += 100;
    01725         DOMStringImpl **newNames = new DOMStringImpl* [m_elementNameAlloc];
    01726         // ### yeah, this is lame. use a dictionary / map instead
    01727         if (m_elementNames) {
    01728             unsigned short i;
    01729             for (i = 0; i < m_elementNameCount; i++)
    01730                 newNames[i] = m_elementNames[i];
    01731             delete [] m_elementNames;
    01732         }
    01733         m_elementNames = newNames;
    01734     }
    01735
    01736     id = m_elementNameCount++;
    01737     m_elementNames[id] = nme.implementation();
    01738     m_elementNames[id]->ref();
    01739
    01740     return ID_LAST_TAG+id;
    01741 }
    01742
    01743 DOMString DocumentImpl::tagName(NodeImpl::Id _id) const
    01744 {
    01745     if (_id >= ID_LAST_TAG)
    01746         return m_elementNames[_id-ID_LAST_TAG];
    01747     else {
    01748         // ### put them in a cache
    01749         if (getDocument()->htmlMode() == DocumentImpl::XHtml)
    01750             return getTagName(_id).lower();
    01751         else
    01752             return getTagName(_id);
    01753     }
    01754 }
    01755
    01756
    01757 DOMStringImpl* DocumentImpl::namespaceURI(NodeImpl::Id _id) const
    01758 {
    01759     if (_id < ID_LAST_TAG)
    01760         return htmlMode() == XHtml ? m_namespaceURIs[0] : 0;
    01761
    01762     unsigned short ns = _id >> 16;
    01763
    01764     if (!ns) return 0;
    01765
    01766     return m_namespaceURIs[ns-1];
    01767 }
    01768
    01769 StyleSheetListImpl* DocumentImpl::styleSheets()
    01770 {
    01771     return m_styleSheets;
    01772 }
    01773
    01774 void DocumentImpl::updateStyleSelector()
    01775 {
    01776     recalcStyleSelector();
    01777     recalcStyle(Force);
    01778 #if 0
    01779
    01780     m_styleSelectorDirty = true;
    01781 #endif
    01782     if ( renderer() ) {
    01783         renderer()->setLayouted( false );
    01784         renderer()->setMinMaxKnown( false );
    01785     }
    01786 }
    01787
    01788
    01789 QStringList DocumentImpl::availableStyleSheets() const
    01790 {
    01791     return m_availableSheets;
    01792 }
    01793
    01794 void DocumentImpl::recalcStyleSelector()
    01795 {
    01796     if ( !m_render || !attached() ) return;
    01797
    01798     QPtrList<StyleSheetImpl> oldStyleSheets = m_styleSheets->styleSheets;
    01799     m_styleSheets->styleSheets.clear();
    01800     m_availableSheets.clear();
    01801     NodeImpl *n;
    01802     for (n = this; n; n = n->traverseNextNode()) {
    01803         StyleSheetImpl *sheet = 0;
    01804
    01805         if (n->nodeType() == Node::PROCESSING_INSTRUCTION_NODE)
    01806         {
    01807             // Processing instruction (XML documents only)
    01808             ProcessingInstructionImpl* pi = static_cast<ProcessingInstructionImpl*>(n);
    01809             sheet = pi->sheet();
    01810             if (!sheet && !pi->localHref().isEmpty())
    01811             {
    01812                 // Processing instruction with reference to an element in this document - e.g.
    01813                 // <?xml-stylesheet href="#mystyle">, with the element
    01814                 // <foo id="mystyle">heading { color: red; }</foo> at some location in
    01815                 // the document
    01816                 ElementImpl* elem = getElementById(pi->localHref());
    01817                 if (elem) {
    01818                     DOMString sheetText("");
    01819                     NodeImpl *c;
    01820                     for (c = elem->firstChild(); c; c = c->nextSibling()) {
    01821                         if (c->nodeType() == Node::TEXT_NODE || c->nodeType() == Node::CDATA_SECTION_NODE)
    01822                             sheetText += c->nodeValue();
    01823                     }
    01824
    01825                     CSSStyleSheetImpl *cssSheet = new CSSStyleSheetImpl(this);
    01826                     cssSheet->parseString(sheetText);
    01827                     pi->setStyleSheet(cssSheet);
    01828                     sheet = cssSheet;
    01829                 }
    01830             }
    01831
    01832         }
    01833         else if (n->id() == ID_LINK || n->id() == ID_STYLE) {
    01834             ElementImpl *e = static_cast<ElementImpl *>(n);
    01835             QString title = e->getAttribute( ATTR_TITLE ).string();
    01836             if (n->id() == ID_LINK) {
    01837                 // <LINK> element
    01838                 HTMLLinkElementImpl* l = static_cast<HTMLLinkElementImpl*>(n);
    01839                 // awful hack to ensure that we ignore the title attribute for non-stylesheets
    01840                 // ### make that nicer!
    01841                 if (!(l->sheet() || l->isLoading()))
    01842                     title = QString::null;
    01843             }
    01844             else {
    01845                 HTMLStyleElementImpl* s = static_cast<HTMLStyleElementImpl*>(n);
    01846                 // awful hack to ensure that we ignore the title attribute for non-stylesheets
    01847                 // ### make that nicer!
    01848                 if (!(s->sheet() || s->isLoading()))
    01849                     title = QString::null;
    01850             }
    01851
    01852             QString sheetUsed = view()->part()->d->m_sheetUsed;
    01853             if ( n->id() == ID_LINK )
    01854                 sheet = static_cast<HTMLLinkElementImpl*>(n)->sheet();
    01855             else
    01856                 // <STYLE> element
    01857                 sheet = static_cast<HTMLStyleElementImpl*>(n)->sheet();
    01858
    01859             if ( !title.isEmpty() ) {
    01860                 if ( sheetUsed.isEmpty() )
    01861                     sheetUsed = view()->part()->d->m_sheetUsed = title;
    01862                 if ( !m_availableSheets.contains( title ) )
    01863                     m_availableSheets.append( title );
    01864
    01865                 if ( title != sheetUsed )
    01866                     sheet = 0; // this stylesheet wasn't selected
    01867             }
    01868         }
    01869         else if (n->id() == ID_BODY) {
    01870             // <BODY> element (doesn't contain styles as such but vlink="..." and friends
    01871             // are treated as style declarations)
    01872             sheet = static_cast<HTMLBodyElementImpl*>(n)->sheet();
    01873         }
    01874         if (sheet) {
    01875             sheet->ref();
    01876             m_styleSheets->styleSheets.append(sheet);
    01877         }
    01878
    01879         // For HTML documents, stylesheets are not allowed within/after the <BODY> tag. So we
    01880         // can stop searching here.
    01881         if (isHTMLDocument() && n->id() == ID_BODY)
    01882             break;
    01883     }
    01884
    01885     // De-reference all the stylesheets in the old list
    01886     QPtrListIterator<StyleSheetImpl> it(oldStyleSheets);
    01887     for (; it.current(); ++it)
    01888         it.current()->deref();
    01889
    01890     // Create a new style selector
    01891     delete m_styleSelector;
    01892     QString usersheet = m_usersheet;
    01893     if ( m_view && m_view->mediaType() == "print" )
    01894         usersheet += m_printSheet;
    01895     m_styleSelector = new CSSStyleSelector( this, usersheet, m_styleSheets, m_url,
    01896                                             pMode == Strict );
    01897
    01898     m_styleSelectorDirty = false;
    01899 }
    01900
    01901 void DocumentImpl::setFocusNode(NodeImpl *newFocusNode)
    01902 {
    01903     // don't process focus changes while detaching
    01904     if( !m_render ) return;
    01905     // Make sure newFocusNode is actually in this document
    01906     if (newFocusNode && (newFocusNode->getDocument() != this))
    01907         return;
    01908
    01909     if (m_focusNode != newFocusNode) {
    01910         NodeImpl *oldFocusNode = m_focusNode;
    01911         // Set focus on the new node
    01912         m_focusNode = newFocusNode;
    01913         // Remove focus from the existing focus node (if any)
    01914         if (oldFocusNode) {
    01915             if (oldFocusNode->active())
    01916                 oldFocusNode->setActive(false);
    01917
    01918             oldFocusNode->setFocus(false);
    01919             oldFocusNode->dispatchHTMLEvent(EventImpl::BLUR_EVENT,false,false);
    01920             oldFocusNode->dispatchUIEvent(EventImpl::DOMFOCUSOUT_EVENT);
    01921             if ((oldFocusNode == this) && oldFocusNode->hasOneRef()) {
    01922                 oldFocusNode->deref(); // deletes this
    01923                 return;
    01924             }
    01925             else {
    01926                 oldFocusNode->deref();
    01927             }
    01928         }
    01929
    01930         if (m_focusNode) {
    01931             m_focusNode->ref();
    01932             m_focusNode->dispatchHTMLEvent(EventImpl::FOCUS_EVENT,false,false);
    01933             if (m_focusNode != newFocusNode) return;
    01934             m_focusNode->dispatchUIEvent(EventImpl::DOMFOCUSIN_EVENT);
    01935             if (m_focusNode != newFocusNode) return;
    01936             m_focusNode->setFocus();
    01937             if (m_focusNode != newFocusNode) return;
    01938
    01939             // eww, I suck. set the qt focus correctly
    01940             // ### find a better place in the code for this
    01941             if (view()) {
    01942                 if (!m_focusNode->renderer() || !m_focusNode->renderer()->isWidget())
    01943                     view()->setFocus();
    01944                 else if (static_cast<RenderWidget*>(m_focusNode->renderer())->widget())
    01945                     static_cast<RenderWidget*>(m_focusNode->renderer())->widget()->setFocus();
    01946             }
    01947         }
    01948
    01949         updateRendering();
    01950     }
    01951 }
    01952
    01953 void DocumentImpl::attachNodeIterator(NodeIteratorImpl *ni)
    01954 {
    01955     m_nodeIterators.append(ni);
    01956 }
    01957
    01958 void DocumentImpl::detachNodeIterator(NodeIteratorImpl *ni)
    01959 {
    01960     m_nodeIterators.remove(ni);
    01961 }
    01962
    01963 void DocumentImpl::notifyBeforeNodeRemoval(NodeImpl *n)
    01964 {
    01965     QPtrListIterator<NodeIteratorImpl> it(m_nodeIterators);
    01966     for (; it.current(); ++it)
    01967         it.current()->notifyBeforeNodeRemoval(n);
    01968 }
    01969
    01970 bool DocumentImpl::isURLAllowed(const QString& url) const
    01971 {
    01972     KHTMLView *w = view();
    01973
    01974     KURL newURL(completeURL(url));
    01975     newURL.setRef(QString::null);
    01976
    01977     // Prohibit non-file URLs if we are asked to.
    01978     if (!w || w->part()->onlyLocalReferences() && newURL.protocol() != "file")
    01979         return false;
    01980
    01981     // do we allow this suburl ?
    01982     if ( !kapp || !kapp->authorizeURLAction("redirect", w->part()->url(), newURL) )
    01983         return false;
    01984
    01985     // We allow one level of self-reference because some sites depend on that.
    01986     // But we don't allow more than one.
    01987     bool foundSelfReference = false;
    01988     for (KHTMLPart *part = w->part(); part; part = part->parentPart()) {
    01989         KURL partURL = part->url();
    01990         partURL.setRef(QString::null);
    01991         if (partURL == newURL) {
    01992             if (foundSelfReference)
    01993                 return false;
    01994             foundSelfReference = true;
    01995         }
    01996     }
    01997
    01998     return true;
    01999 }
    02000
    02001 AbstractViewImpl *DocumentImpl::defaultView() const
    02002 {
    02003     return m_defaultView;
    02004 }
    02005
    02006 EventImpl *DocumentImpl::createEvent(const DOMString &eventType, int &exceptioncode)
    02007 {
    02008     if (eventType == "UIEvents")
    02009         return new UIEventImpl();
    02010     else if (eventType == "MouseEvents")
    02011         return new MouseEventImpl();
    02012     else if (eventType == "MutationEvents")
    02013         return new MutationEventImpl();
    02014     else if (eventType == "HTMLEvents")
    02015         return new EventImpl();
    02016     else {
    02017         exceptioncode = DOMException::NOT_SUPPORTED_ERR;
    02018         return 0;
    02019     }
    02020 }
    02021
    02022 CSSStyleDeclarationImpl *DocumentImpl::getOverrideStyle(ElementImpl */*elt*/, DOMStringImpl */*pseudoElt*/)
    02023 {
    02024     return 0; // ###
    02025 }
    02026
    02027 void DocumentImpl::defaultEventHandler(EventImpl *evt)
    02028 {
    02029     // if any html event listeners are registered on the window, then dispatch them here
    02030     QPtrListIterator<RegisteredEventListener> it(m_windowEventListeners);
    02031     Event ev(evt);
    02032     for (; it.current(); ++it) {
    02033         if (it.current()->id == evt->id()) {
    02034             evt->setCurrentTarget(this);
    02035             it.current()->listener->handleEvent(ev);
    02036             return;
    02037         }
    02038     }
    02039 }
    02040
    02041 void DocumentImpl::setWindowEventListener(int id, EventListener *listener)
    02042 {
    02043     // If we already have it we don't want removeWindowEventListener to delete it
    02044     if (listener)
    02045         listener->ref();
    02046     removeWindowEventListener(id);
    02047     if (listener) {
    02048         RegisteredEventListener *rl = new RegisteredEventListener(static_cast<EventImpl::EventId>(id),listener,false);
    02049         m_windowEventListeners.append(rl);
    02050         listener->deref();
    02051     }
    02052 }
    02053
    02054 EventListener *DocumentImpl::getWindowEventListener(int id)
    02055 {
    02056     QPtrListIterator<RegisteredEventListener> it(m_windowEventListeners);
    02057     for (; it.current(); ++it) {
    02058         if (it.current()->id == id) {
    02059             return it.current()->listener;
    02060         }
    02061     }
    02062
    02063     return 0;
    02064 }
    02065
    02066 void DocumentImpl::removeWindowEventListener(int id)
    02067 {
    02068     QPtrListIterator<RegisteredEventListener> it(m_windowEventListeners);
    02069     for (; it.current(); ++it) {
    02070         if (it.current()->id == id) {
    02071             m_windowEventListeners.removeRef(it.current());
    02072             return;
    02073         }
    02074     }
    02075 }
    02076
    02077 EventListener *DocumentImpl::createHTMLEventListener(QString code)
    02078 {
    02079     return view()->part()->createHTMLEventListener(code);
    02080 }
    02081
    02082 void DocumentImpl::setDecoderCodec(const QTextCodec *codec)
    02083 {
    02084     m_decoderMibEnum = codec->mibEnum();
    02085 }
    02086
    02087 // ----------------------------------------------------------------------------
    02088
    02089 DocumentFragmentImpl::DocumentFragmentImpl(DocumentPtr *doc) : NodeBaseImpl(doc)
    02090 {
    02091 }
    02092
    02093 DocumentFragmentImpl::DocumentFragmentImpl(const DocumentFragmentImpl &other)
    02094     : NodeBaseImpl(other)
    02095 {
    02096 }
    02097
    02098 DOMString DocumentFragmentImpl::nodeName() const
    02099 {
    02100   return "#document-fragment";
    02101 }
    02102
    02103 unsigned short DocumentFragmentImpl::nodeType() const
    02104 {
    02105     return Node::DOCUMENT_FRAGMENT_NODE;
    02106 }
    02107
    02108 // DOM Section 1.1.1
    02109 bool DocumentFragmentImpl::childTypeAllowed( unsigned short type )
    02110 {
    02111     switch (type) {
    02112         case Node::ELEMENT_NODE:
    02113         case Node::PROCESSING_INSTRUCTION_NODE:
    02114         case Node::COMMENT_NODE:
    02115         case Node::TEXT_NODE:
    02116         case Node::CDATA_SECTION_NODE:
    02117         case Node::ENTITY_REFERENCE_NODE:
    02118             return true;
    02119             break;
    02120         default:
    02121             return false;
    02122     }
    02123 }
    02124
    02125 NodeImpl *DocumentFragmentImpl::cloneNode ( bool deep )
    02126 {
    02127     DocumentFragmentImpl *clone = new DocumentFragmentImpl( docPtr() );
    02128     if (deep)
    02129         cloneChildNodes(clone);
    02130     return clone;
    02131 }
    02132
    02133
    02134 // ----------------------------------------------------------------------------
    02135
    02136 DocumentTypeImpl::DocumentTypeImpl(DOMImplementationImpl *implementation, DocumentPtr *doc,
    02137                                    const DOMString &qualifiedName, const DOMString &publicId,
    02138                                    const DOMString &systemId)
    02139     : NodeImpl(doc), m_implementation(implementation),
    02140       m_qualifiedName(qualifiedName), m_publicId(publicId), m_systemId(systemId)
    02141 {
    02142     m_implementation->ref();
    02143
    02144     m_entities = 0;
    02145     m_notations = 0;
    02146
    02147     // if doc is 0, it is not attached to a document and / or
    02148     // therefore does not provide entities or notations. (DOM Level 3)
    02149 }
    02150
    02151 DocumentTypeImpl::~DocumentTypeImpl()
    02152 {
    02153     m_implementation->deref();
    02154     if (m_entities)
    02155         m_entities->deref();
    02156     if (m_notations)
    02157         m_notations->deref();
    02158 }
    02159
    02160 void DocumentTypeImpl::copyFrom(const DocumentTypeImpl& other)
    02161 {
    02162     m_qualifiedName = other.m_qualifiedName;
    02163     m_publicId = other.m_publicId;
    02164     m_systemId = other.m_systemId;
    02165     m_subset = other.m_subset;
    02166 }
    02167
    02168 DOMString DocumentTypeImpl::nodeName() const
    02169 {
    02170     return name();
    02171 }
    02172
    02173 unsigned short DocumentTypeImpl::nodeType() const
    02174 {
    02175     return Node::DOCUMENT_TYPE_NODE;
    02176 }
    02177
    02178 // DOM Section 1.1.1
    02179 bool DocumentTypeImpl::childTypeAllowed( unsigned short /*type*/ )
    02180 {
    02181     return false;
    02182 }
    02183
    02184 NodeImpl *DocumentTypeImpl::cloneNode ( bool /*deep*/ )
    02185 {
    02186     // Spec says cloning Document nodes is "implementation dependent"
    02187     // so we do not support it...
    02188     return 0;
    02189 }
    02190
    02191 #include "dom_docimpl.moc"

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:33:41 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001