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