khtml Library API Documentation

html_documentimpl.cpp

00001 
00024 #include "html/html_documentimpl.h"
00025 #include "html/html_imageimpl.h"
00026 #include "html/html_headimpl.h"
00027 #include "html/html_baseimpl.h"
00028 #include "html/htmltokenizer.h"
00029 #include "html/html_miscimpl.h"
00030 
00031 #include "khtmlview.h"
00032 #include "khtml_part.h"
00033 #include "khtmlpart_p.h"
00034 #include "khtml_settings.h"
00035 #include "misc/htmlattrs.h"
00036 #include "misc/htmlhashes.h"
00037 
00038 #include "xml/xml_tokenizer.h"
00039 #include "xml/dom2_eventsimpl.h"
00040 
00041 #include "khtml_factory.h"
00042 #include "rendering/render_object.h"
00043 
00044 #include <dcopclient.h>
00045 #include <kapplication.h>
00046 #include <kdebug.h>
00047 #include <kurl.h>
00048 #include <kglobal.h>
00049 #include <kcharsets.h>
00050 #include <kglobalsettings.h>
00051 
00052 #include "css/cssproperties.h"
00053 #include "css/cssstyleselector.h"
00054 #include "css/css_stylesheetimpl.h"
00055 #include <stdlib.h>
00056 #include <qptrstack.h>
00057 
00058 template class QPtrStack<DOM::NodeImpl>;
00059 
00060 using namespace DOM;
00061 using namespace khtml;
00062 
00063 
00064 HTMLDocumentImpl::HTMLDocumentImpl(DOMImplementationImpl *_implementation, KHTMLView *v)
00065   : DocumentImpl(_implementation, v)
00066 {
00067 //    kdDebug( 6090 ) << "HTMLDocumentImpl constructor this = " << this << endl;
00068     bodyElement = 0;
00069     htmlElement = 0;
00070 
00071 /* dynamic history stuff to be fixed later (pfeiffer)
00072     connect( KHTMLFactory::vLinks(), SIGNAL( inserted( const QString& )),
00073              SLOT( slotHistoryChanged() ));
00074     connect( KHTMLFactory::vLinks(), SIGNAL( removed( const QString& )),
00075              SLOT( slotHistoryChanged() ));
00076 */
00077     connect( KHTMLFactory::vLinks(), SIGNAL( cleared()),
00078              SLOT( slotHistoryChanged() ));
00079 }
00080 
00081 HTMLDocumentImpl::~HTMLDocumentImpl()
00082 {
00083 }
00084 
00085 DOMString HTMLDocumentImpl::referrer() const
00086 {
00087     if ( view() )
00088         return view()->part()->pageReferrer();
00089     return DOMString();
00090 }
00091 
00092 DOMString HTMLDocumentImpl::domain() const
00093 {
00094     if ( m_domain.isEmpty() ) // not set yet (we set it on demand to save time and space)
00095         m_domain = KURL(URL()).host(); // Initially set to the host
00096     return m_domain;
00097 }
00098 
00099 void HTMLDocumentImpl::setDomain(const DOMString &newDomain)
00100 {
00101     if ( m_domain.isEmpty() ) // not set yet (we set it on demand to save time and space)
00102         m_domain = KURL(URL()).host().lower(); // Initially set to the host
00103 
00104     if ( m_domain.isEmpty() /*&& view() && view()->part()->openedByJS()*/ )
00105         m_domain = newDomain.lower();
00106 
00107     // Both NS and IE specify that changing the domain is only allowed when
00108     // the new domain is a suffix of the old domain.
00109     int oldLength = m_domain.length();
00110     int newLength = newDomain.length();
00111     if ( newLength < oldLength ) // e.g. newDomain=kde.org (7) and m_domain=www.kde.org (11)
00112     {
00113         DOMString test = m_domain.copy();
00114         DOMString reference = newDomain.lower();
00115         if ( test[oldLength - newLength - 1] == '.' ) // Check that it's a subdomain, not e.g. "de.org"
00116         {
00117             test.remove( 0, oldLength - newLength ); // now test is "kde.org" from m_domain
00118             if ( test == reference )                 // and we check that it's the same thing as newDomain
00119                 m_domain = reference;
00120         }
00121     }
00122 }
00123 
00124 DOMString HTMLDocumentImpl::lastModified() const
00125 {
00126     if ( view() )
00127         return view()->part()->lastModified();
00128     return DOMString();
00129 }
00130 
00131 DOMString HTMLDocumentImpl::cookie() const
00132 {
00133     long windowId = 0;
00134     KHTMLView *v = view ();
00135 
00136     if ( v && v->topLevelWidget() )
00137       windowId = v->topLevelWidget()->winId();
00138 
00139     QCString replyType;
00140     QByteArray params, reply;
00141     QDataStream stream(params, IO_WriteOnly);
00142     stream << URL() << windowId;
00143     if (!kapp->dcopClient()->call("kcookiejar", "kcookiejar",
00144                                   "findDOMCookies(QString,long int)", params,
00145                                   replyType, reply))
00146     {
00147        kdWarning(6010) << "Can't communicate with cookiejar!" << endl;
00148        return DOMString();
00149     }
00150 
00151     QDataStream stream2(reply, IO_ReadOnly);
00152     if(replyType != "QString") {
00153          kdError(6010) << "DCOP function findDOMCookies(...) returns "
00154                        << replyType << ", expected QString" << endl;
00155          return DOMString();
00156     }
00157 
00158     QString result;
00159     stream2 >> result;
00160     return DOMString(result);
00161 }
00162 
00163 void HTMLDocumentImpl::setCookie( const DOMString & value )
00164 {
00165     long windowId = 0;
00166     KHTMLView *v = view ();
00167 
00168     if ( v && v->topLevelWidget() )
00169       windowId = v->topLevelWidget()->winId();
00170 
00171     QByteArray params;
00172     QDataStream stream(params, IO_WriteOnly);
00173     QString fake_header("Set-Cookie: ");
00174     fake_header.append(value.string());
00175     fake_header.append("\n");
00176     stream << URL() << fake_header.utf8() << windowId;
00177     if (!kapp->dcopClient()->send("kcookiejar", "kcookiejar",
00178                                   "addCookies(QString,QCString,long int)", params))
00179     {
00180          // Maybe it wasn't running (e.g. we're opening local html files)
00181          KApplication::startServiceByDesktopName( "kcookiejar");
00182          if (!kapp->dcopClient()->send("kcookiejar", "kcookiejar",
00183                                        "addCookies(QString,QCString,long int)", params))
00184              kdWarning(6010) << "Can't communicate with cookiejar!" << endl;
00185     }
00186 }
00187 
00188 
00189 
00190 HTMLElementImpl *HTMLDocumentImpl::body()
00191 {
00192     NodeImpl *de = documentElement();
00193     if (!de)
00194         return 0;
00195 
00196     // try to prefer a FRAMESET element over BODY
00197     NodeImpl* body = 0;
00198     for (NodeImpl* i = de->firstChild(); i; i = i->nextSibling()) {
00199         if (i->id() == ID_FRAMESET)
00200             return static_cast<HTMLElementImpl*>(i);
00201 
00202         if (i->id() == ID_BODY)
00203             body = i;
00204     }
00205     return static_cast<HTMLElementImpl *>(body);
00206 }
00207 
00208 void HTMLDocumentImpl::setBody(HTMLElementImpl *_body)
00209 {
00210     int exceptioncode = 0;
00211     HTMLElementImpl *b = body();
00212     if ( !_body && !b ) return;
00213     if ( !_body )
00214         documentElement()->removeChild( b, exceptioncode );
00215     else if ( !b )
00216         documentElement()->appendChild( _body, exceptioncode );
00217     else
00218         documentElement()->replaceChild( _body, b, exceptioncode );
00219 }
00220 
00221 Tokenizer *HTMLDocumentImpl::createTokenizer()
00222 {
00223     return new HTMLTokenizer(docPtr(),m_view);
00224 }
00225 
00226 // --------------------------------------------------------------------------
00227 // not part of the DOM
00228 // --------------------------------------------------------------------------
00229 
00230 bool HTMLDocumentImpl::childAllowed( NodeImpl *newChild )
00231 {
00232     // ### support comments. etc as a child
00233     return (newChild->id() == ID_HTML || newChild->id() == ID_COMMENT);
00234 }
00235 
00236 ElementImpl *HTMLDocumentImpl::createElement( const DOMString &name, int* pExceptioncode )
00237 {
00238     ElementImpl* e = createHTMLElement( name );
00239     if ( e )
00240         return e;
00241     return DOM::DocumentImpl::createElement( name, pExceptioncode );
00242 }
00243 
00244 void HTMLDocumentImpl::slotHistoryChanged()
00245 {
00246     if ( true || !m_render ) // disabled for now
00247         return;
00248 
00249     recalcStyle( Force );
00250     m_render->repaint();
00251 }
00252 
00253 HTMLMapElementImpl* HTMLDocumentImpl::getMap(const DOMString& _url)
00254 {
00255     QString url = _url.string();
00256     QString s;
00257     int pos = url.find('#');
00258     //kdDebug(0) << "map pos of #:" << pos << endl;
00259     s = QString(_url.unicode() + pos + 1, _url.length() - pos - 1);
00260 
00261     QMapConstIterator<QString,HTMLMapElementImpl*> it = mapMap.find(s);
00262 
00263     if (it != mapMap.end())
00264         return *it;
00265     else
00266         return 0;
00267 }
00268 
00269 static bool isTransitional(const QString &spec, int start)
00270 {
00271     if((spec.find("TRANSITIONAL", start, false ) != -1 ) ||
00272        (spec.find("LOOSE", start, false ) != -1 ) ||
00273        (spec.find("FRAMESET", start, false ) != -1 ) ||
00274        (spec.find("LATIN1", start, false ) != -1 ) ||
00275        (spec.find("SYMBOLS", start, false ) != -1 ) ||
00276        (spec.find("SPECIAL", start, false ) != -1 ) ) {
00277         //kdDebug() << "isTransitional" << endl;
00278         return true;
00279     }
00280     return false;
00281 }
00282 
00283 void HTMLDocumentImpl::close()
00284 {
00285     bool doload = !parsing() && m_tokenizer;
00286 
00287     DocumentImpl::close();
00288 
00289     HTMLElementImpl* b = body();
00290     if (b && doload) {
00291         // According to dom the load event must not bubble
00292         // but other browsers execute in a frameset document
00293         // the first(IE)/last(Moz/Konq) registered onload on a <frame> and the
00294         // first(IE)/last(Moz/Konq) registered onload on a <frameset>.
00295 
00296         // The body has the listener for <frame onload>
00297         b->dispatchWindowEvent(EventImpl::LOAD_EVENT, false, false);
00298 
00299         b = body(); // the onload code could have changed it (e.g. document.open/write/close)
00300 
00301         // The document has the listener for <frameset onload>
00302         if (b && b->id() == ID_FRAMESET)
00303             getDocument()->dispatchWindowEvent(EventImpl::LOAD_EVENT, false, false);
00304 
00305         // don't update rendering if we're going to redirect anyway
00306         if ( view() && ( view()->part()->d->m_redirectURL.isNull() ||
00307                          view()->part()->d->m_delayRedirect > 1 ) )
00308         updateRendering();
00309     }
00310 }
00311 
00312 
00313 void HTMLDocumentImpl::determineParseMode( const QString &str )
00314 {
00315     //kdDebug() << "DocumentImpl::determineParseMode str=" << str<< endl;
00316     // determines the parse mode for HTML
00317     // quite some hints here are inspired by the mozilla code.
00318     int oldPMode = pMode;
00319 
00320     // default parsing mode is Loose
00321     pMode = Compat;
00322     hMode = Html3;
00323 
00324     ParseMode systemId = Unknown;
00325     ParseMode publicId = Unknown;
00326 
00327     int pos = 0;
00328     int doctype = str.find("!doctype", 0, false);
00329     if( doctype > 2 ) {
00330         pos = doctype - 2;
00331         // Store doctype name
00332         int start = doctype + 9;
00333         while ( start < (int)str.length() && str[start].isSpace() )
00334             start++;
00335         int espace = str.find(' ',start);
00336         QString name = str.mid(start,espace-start);
00337         //kdDebug() << "DocumentImpl::determineParseMode setName: " << name << endl;
00338         m_doctype->setName( name );
00339     }
00340 
00341     // get the first tag (or the doctype tag)
00342     int start = str.find('<', pos);
00343     int stop = str.find('>', pos);
00344     if( start > -1 && stop > start ) {
00345         QString spec = str.mid( start + 1, stop - start - 1 );
00346         //kdDebug() << "DocumentImpl::determineParseMode dtd=" << spec<< endl;
00347         start = 0;
00348         int quote = -1;
00349         if( doctype != -1 ) {
00350             while( (quote = spec.find( "\"", start )) != -1 ) {
00351                 int quote2 = spec.find( "\"", quote+1 );
00352                 if(quote2 < 0) quote2 = spec.length();
00353                 QString val = spec.mid( quote+1, quote2 - quote-1 );
00354                 //kdDebug() << "DocumentImpl::determineParseMode val = " << val << endl;
00355                 // find system id
00356                 pos = val.find("http://www.w3.org/tr/", 0, false);
00357                 if ( pos != -1 ) {
00358                     // loose or strict dtd?
00359                     if ( val.find("strict.dtd", pos, false) != -1 )
00360                         systemId = Strict;
00361                     else if (isTransitional(val, pos))
00362                         systemId = Transitional;
00363                 }
00364 
00365                 // find public id
00366                 pos = val.find("//dtd", 0, false );
00367                 if ( pos != -1 ) {
00368                     if( val.find( "xhtml", pos+6, false ) != -1 ) {
00369                         hMode = XHtml;
00370                         publicId = isTransitional(val, pos) ? Transitional : Strict;
00371                     } else if ( val.find( "15445:1999", pos+6 ) != -1 ) {
00372                         hMode = Html4;
00373                         publicId = Strict;
00374                     } else {
00375                         int tagPos = val.find( "html", pos+6, false );
00376                         if( tagPos == -1 )
00377                             tagPos = val.find( "hypertext markup", pos+6, false );
00378                         if ( tagPos != -1 ) {
00379                             tagPos = val.find(QRegExp("[0-9]"), tagPos );
00380                             int version = val.mid( tagPos, 1 ).toInt();
00381                             //kdDebug() << "DocumentImpl::determineParseMode tagPos = " << tagPos << " version=" << version << endl;
00382                             if( version > 3 ) {
00383                                 hMode = Html4;
00384                                 publicId = isTransitional( val, tagPos ) ? Transitional : Strict;
00385                             }
00386                         }
00387                     }
00388                 }
00389                 start = quote2 + 1;
00390             }
00391         }
00392 
00393         if( systemId == publicId )
00394             pMode = publicId;
00395         else if ( systemId == Unknown )
00396             pMode = hMode == Html4 ? Compat : publicId;
00397         else if ( publicId == Transitional && systemId == Strict ) {
00398             pMode = hMode == Html3 ? Compat : Strict;
00399         } else
00400             pMode = Compat;
00401 
00402         if ( hMode == XHtml )
00403             pMode = Strict;
00404     }
00405 //     kdDebug() << "DocumentImpl::determineParseMode: publicId =" << publicId << " systemId = " << systemId << endl;
00406 //     kdDebug() << "DocumentImpl::determineParseMode: htmlMode = " << hMode<< endl;
00407 //     if( pMode == Strict )
00408 //         kdDebug(6020) << " using strict parseMode" << endl;
00409 //     else if (pMode == Compat )
00410 //         kdDebug(6020) << " using compatibility parseMode" << endl;
00411 //     else
00412 //         kdDebug(6020) << " using transitional parseMode" << endl;
00413 
00414     if ( pMode != oldPMode && styleSelector() )
00415     recalcStyleSelector();
00416 }
00417 
00418 #include "html_documentimpl.moc"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:16:34 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001