Reviewed by Darin Adler.
[WebKit-https.git] / WebCore / khtml / khtml_part.cpp
1 /* This file is part of the KDE project
2  *
3  * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
4  *                     1999 Lars Knoll <knoll@kde.org>
5  *                     1999 Antti Koivisto <koivisto@kde.org>
6  *                     2000 Simon Hausmann <hausmann@kde.org>
7  *                     2000 Stefan Schimanski <1Stein@gmx.de>
8  *                     2001 George Staikos <staikos@kde.org>
9  * Copyright (C) 2004 Apple Computer, Inc.
10  * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com>
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public License
23  * along with this library; see the file COPYING.LIB.  If not, write to
24  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25  * Boston, MA 02111-1307, USA.
26  */
27
28 #include "config.h"
29 #include "khtml_part.h"
30
31 #define QT_NO_CLIPBOARD
32 #define QT_NO_DRAGANDDROP
33
34 #include "css/csshelper.h"
35 #include "css/cssproperties.h"
36 #include "css/cssstyleselector.h"
37 #include "css/css_computedstyle.h"
38 #include "css/css_valueimpl.h"
39 #include "dom/dom_string.h"
40 #include "editing/markup.h"
41 #include "editing/htmlediting.h"
42 #include "editing/SelectionController.h"
43 #include "editing/visible_position.h"
44 #include "editing/visible_text.h"
45 #include "editing/visible_units.h"
46 #include "html/html_documentimpl.h"
47 #include "html/html_baseimpl.h"
48 #include "html/html_miscimpl.h"
49 #include "html/html_imageimpl.h"
50 #include "html/html_objectimpl.h"
51 #include "rendering/render_block.h"
52 #include "rendering/render_text.h"
53 #include "rendering/render_frames.h"
54 #include "misc/loader.h"
55 #include "xml/dom2_eventsimpl.h"
56 #include "xml/dom2_rangeimpl.h"
57 #include "xml/EventNames.h"
58 #include "xml/xml_tokenizer.h"
59 #if SVG_SUPPORT
60 #include "SVGNames.h"
61 #include "XLinkNames.h"
62 #endif
63
64 using namespace DOM;
65 using namespace HTMLNames;
66
67 #include "khtmlview.h"
68 #include "ecma/kjs_proxy.h"
69 #include "ecma/xmlhttprequest.h"
70 #include "khtml_settings.h"
71 #include "khtmlpart_p.h"
72
73 #include <sys/types.h>
74 #include <assert.h>
75 #include <unistd.h>
76
77 #include <kstandarddirs.h>
78 #include <kio/job.h>
79 #include <kio/global.h>
80 #include <kdebug.h>
81 #include <klocale.h>
82 #include <kcharsets.h>
83 #include <kglobalsettings.h>
84 #if !defined(QT_NO_DRAGANDDROP)
85 #include <kmultipledrag.h>
86 #endif
87
88 #include <qfile.h>
89 #include <qptrlist.h>
90
91 #include <CoreServices/CoreServices.h>
92
93 using namespace DOM::EventNames;
94
95 using khtml::ApplyStyleCommand;
96 using khtml::CHARACTER;
97 using khtml::ChildFrame;
98 using khtml::Decoder;
99 using khtml::DocLoader;
100 using khtml::EAffinity;
101 using khtml::EditAction;
102 using khtml::EditCommandPtr;
103 using khtml::ETextGranularity;
104 using khtml::FormData;
105 using khtml::InlineTextBox;
106 using khtml::isEndOfDocument;
107 using khtml::isStartOfDocument;
108 using khtml::PARAGRAPH;
109 using khtml::plainText;
110 using khtml::RenderObject;
111 using khtml::RenderText;
112 using khtml::RenderLayer;
113 using khtml::RenderWidget;
114 using khtml::SelectionController;
115 using khtml::Tokenizer;
116 using khtml::TypingCommand;
117 using khtml::VisiblePosition;
118 using khtml::WORD;
119
120 using KParts::BrowserInterface;
121
122 const int CARET_BLINK_FREQUENCY = 500;
123
124 namespace khtml {
125     class PartStyleSheetLoader : public CachedObjectClient
126     {
127     public:
128         PartStyleSheetLoader(KHTMLPart *part, DOM::DOMString url, DocLoader* dl)
129         {
130             m_part = part;
131             m_cachedSheet = Cache::requestStyleSheet(dl, url );
132             if (m_cachedSheet)
133                 m_cachedSheet->ref( this );
134         }
135         virtual ~PartStyleSheetLoader()
136         {
137             if ( m_cachedSheet ) m_cachedSheet->deref(this);
138         }
139         virtual void setStyleSheet(const DOM::DOMString&, const DOM::DOMString &sheet)
140         {
141           if ( m_part )
142             m_part->setUserStyleSheet( sheet.qstring() );
143
144             delete this;
145         }
146         QGuardedPtr<KHTMLPart> m_part;
147         khtml::CachedCSSStyleSheet *m_cachedSheet;
148     };
149 }
150
151 FrameList::Iterator FrameList::find( const QString &name )
152 {
153     Iterator it = begin();
154     Iterator e = end();
155
156     for (; it!=e; ++it )
157         if ( (*it).m_name==name )
158             break;
159
160     return it;
161 }
162
163 KHTMLPart::KHTMLPart(QWidget *parentWidget, const char *widgetname, QObject *parent, const char *name)
164     : KParts::ReadOnlyPart(parent, name), d(0)
165 {
166 }
167
168 void KHTMLPart::init(KHTMLView *view)
169 {
170   AtomicString::init();
171   QualifiedName::init();
172   EventNames::init();
173   HTMLNames::init(); // FIXME: We should make this happen only when HTML is used.
174 #if SVG_SUPPORT
175   KSVG::SVGNames::init();
176   XLinkNames::init();
177 #endif
178
179   frameCount = 0;
180
181   d = new KHTMLPartPrivate(parent());
182
183   d->m_view = view;
184   setWidget( d->m_view );
185   
186   d->m_extension = new KHTMLPartBrowserExtension( this );
187   d->m_hostExtension = new KHTMLPartBrowserHostExtension( this );
188
189   d->m_bSecurityInQuestion = false;
190   d->m_bMousePressed = false;
191
192   // The java, javascript, and plugin settings will be set after the settings
193   // have been initialized.
194   d->m_bJScriptEnabled = true;
195   d->m_bJavaEnabled = true;
196   d->m_bPluginsEnabled = true;
197
198   connect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
199            this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
200   connect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
201            this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
202   connect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
203            this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
204
205   connect( &d->m_redirectionTimer, SIGNAL( timeout() ),
206            this, SLOT( slotRedirect() ) );
207
208   connect(&d->m_lifeSupportTimer, SIGNAL(timeout()), this, SLOT(slotEndLifeSupport()));
209 }
210
211 KHTMLPart::~KHTMLPart()
212 {
213   stopAutoScroll();
214   cancelRedirection();
215
216   if (!d->m_bComplete)
217     closeURL();
218
219   disconnect( khtml::Cache::loader(), SIGNAL( requestStarted( khtml::DocLoader*, khtml::CachedObject* ) ),
220            this, SLOT( slotLoaderRequestStarted( khtml::DocLoader*, khtml::CachedObject* ) ) );
221   disconnect( khtml::Cache::loader(), SIGNAL( requestDone( khtml::DocLoader*, khtml::CachedObject *) ),
222            this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
223   disconnect( khtml::Cache::loader(), SIGNAL( requestFailed( khtml::DocLoader*, khtml::CachedObject *) ),
224            this, SLOT( slotLoaderRequestDone( khtml::DocLoader*, khtml::CachedObject *) ) );
225
226   clear();
227
228   if ( d->m_view )
229   {
230     d->m_view->hide();
231     d->m_view->viewport()->hide();
232     d->m_view->m_part = 0;
233   }
234   
235   delete d->m_hostExtension;
236
237   delete d; d = 0;
238 }
239
240 bool KHTMLPart::restoreURL( const KURL &url )
241 {
242   kdDebug( 6050 ) << "KHTMLPart::restoreURL " << url.url() << endl;
243
244   cancelRedirection();
245
246   /*
247    * That's not a good idea as it will call closeURL() on all
248    * child frames, preventing them from further loading. This
249    * method gets called from restoreState() in case of a full frameset
250    * restoral, and restoreState() calls closeURL() before restoring
251    * anyway.
252   kdDebug( 6050 ) << "closing old URL" << endl;
253   closeURL();
254   */
255
256   d->m_bComplete = false;
257   d->m_bLoadEventEmitted = false;
258   d->m_workingURL = url;
259
260   // set the java(script) flags according to the current host.
261   d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled(url.host());
262   d->m_bJavaEnabled = d->m_settings->isJavaEnabled(url.host());
263   d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled(url.host());
264
265   m_url = url;
266
267   emit started( 0L );
268
269   return true;
270 }
271
272
273 bool KHTMLPart::didOpenURL(const KURL &url)
274 {
275   kdDebug( 6050 ) << "KHTMLPart(" << this << ")::openURL " << url.url() << endl;
276
277   if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad) {
278     // We're about to get a redirect that happened before the document was
279     // created.  This can happen when one frame may change the location of a 
280     // sibling.
281     return false;
282   }
283   
284   cancelRedirection();
285   
286   // clear last edit command
287   d->m_lastEditCommand = EditCommandPtr();
288   KWQ(this)->clearUndoRedoOperations();
289   
290
291   KParts::URLArgs args( d->m_extension->urlArgs() );
292
293
294   if (!d->m_restored)
295   {
296     kdDebug( 6050 ) << "closing old URL" << endl;
297     closeURL();
298   }
299
300
301   if (d->m_restored)
302      d->m_cachePolicy = KIO::CC_Cache;
303   else if (args.reload)
304      d->m_cachePolicy = KIO::CC_Refresh;
305   else
306      d->m_cachePolicy = KIO::CC_Verify;
307
308   if ( args.doPost() && (url.protocol().startsWith("http")) )
309   {
310       d->m_job = KIO::http_post( url, args.postData, false );
311       d->m_job->addMetaData("content-type", args.contentType() );
312   }
313   else
314   {
315       d->m_job = KIO::get( url, false, false );
316       d->m_job->addMetaData("cache", KIO::getCacheControlString(d->m_cachePolicy));
317   }
318
319   d->m_job->addMetaData(args.metaData());
320
321   connect( d->m_job, SIGNAL( result( KIO::Job * ) ),
322            SLOT( slotFinished( KIO::Job * ) ) );
323
324   connect( d->m_job, SIGNAL(redirection(KIO::Job*, const KURL&) ),
325            SLOT( slotRedirection(KIO::Job*,const KURL&) ) );
326
327   d->m_bComplete = false;
328   d->m_bLoadingMainResource = true;
329   d->m_bLoadEventEmitted = false;
330
331   // delete old status bar msg's from kjs (if it _was_ activated on last URL)
332   if( d->m_bJScriptEnabled )
333   {
334      d->m_kjsStatusBarText = QString::null;
335      d->m_kjsDefaultStatusBarText = QString::null;
336   }
337
338   // set the javascript flags according to the current url
339   d->m_bJavaEnabled = d->m_settings->isJavaEnabled(url.host());
340   d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled(url.host());
341
342   // initializing m_url to the new url breaks relative links when opening such a link after this call and _before_ begin() is called (when the first
343   // data arrives) (Simon)
344   m_url = url;
345   if(m_url.protocol().startsWith("http") && !m_url.host().isEmpty() && m_url.path().isEmpty())
346     m_url.setPath("/");
347   // copy to m_workingURL after fixing m_url above
348   d->m_workingURL = m_url;
349
350   kdDebug( 6050 ) << "KHTMLPart::openURL now (before started) m_url = " << m_url.url() << endl;
351
352   connect( d->m_job, SIGNAL( speed( KIO::Job*, unsigned long ) ),
353            this, SLOT( slotJobSpeed( KIO::Job*, unsigned long ) ) );
354
355   connect( d->m_job, SIGNAL( percent( KIO::Job*, unsigned long ) ),
356            this, SLOT( slotJobPercent( KIO::Job*, unsigned long ) ) );
357
358   emit started( 0L );
359
360   return true;
361 }
362
363 void KHTMLPart::didExplicitOpen()
364 {
365   d->m_bComplete = false;
366   d->m_bLoadEventEmitted = false;
367     
368   // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
369   // from a subsequent window.document.open / window.document.write call. 
370   // Cancelling redirection here works for all cases because document.open 
371   // implicitly precedes document.write.
372   cancelRedirection(); 
373 }
374
375 void KHTMLPart::stopLoading(bool sendUnload)
376 {
377   if (d->m_doc && d->m_doc->tokenizer())
378     d->m_doc->tokenizer()->stopParsing();
379     
380   if ( d->m_job )
381   {
382     d->m_job->kill();
383     d->m_job = 0;
384   }
385
386   if (sendUnload) {
387     if ( d->m_doc && d->m_doc->isHTMLDocument() ) {
388       HTMLDocumentImpl* hdoc = static_cast<HTMLDocumentImpl*>( d->m_doc );
389       
390       if ( hdoc->body() && d->m_bLoadEventEmitted && !d->m_bUnloadEventEmitted ) {
391         hdoc->body()->dispatchWindowEvent( unloadEvent, false, false );
392         if ( d->m_doc )
393           d->m_doc->updateRendering();
394         d->m_bUnloadEventEmitted = true;
395       }
396     }
397     
398     if (d->m_doc && !d->m_doc->inPageCache())
399       d->m_doc->removeAllEventListenersFromAllNodes();
400   }
401
402   d->m_bComplete = true; // to avoid emitting completed() in slotFinishedParsing() (David)
403   d->m_bLoadingMainResource = false;
404   d->m_bLoadEventEmitted = true; // don't want that one either
405   d->m_cachePolicy = KIO::CC_Verify; // Why here?
406
407   if ( d->m_doc && d->m_doc->parsing() )
408   {
409     kdDebug( 6050 ) << " was still parsing... calling end " << endl;
410     slotFinishedParsing();
411     d->m_doc->setParsing(false);
412   }
413   
414   d->m_workingURL = KURL();
415
416   if (DocumentImpl *doc = d->m_doc) {
417     if (DocLoader *docLoader = doc->docLoader())
418       khtml::Cache::loader()->cancelRequests(docLoader);
419     KJS::XMLHttpRequest::cancelRequests(doc);
420   }
421
422   // tell all subframes to stop as well
423   ConstFrameIt it = d->m_frames.begin();
424   ConstFrameIt end = d->m_frames.end();
425   for (; it != end; ++it ) {
426       KParts::ReadOnlyPart *part = (*it).m_part;
427       if (part) {
428           KHTMLPart *khtml_part = static_cast<KHTMLPart *>(part);
429
430           if (khtml_part->inherits("KHTMLPart"))
431               khtml_part->stopLoading(sendUnload);
432           else
433               part->closeURL();
434       }
435   }
436
437   d->m_bPendingChildRedirection = false;
438
439   // Stop any started redirections as well!! (DA)
440   cancelRedirection();
441 }
442
443 bool KHTMLPart::closeURL()
444 {    
445   stopLoading(true);
446
447   return true;
448 }
449
450 KParts::BrowserExtension *KHTMLPart::browserExtension() const
451 {
452   return d->m_extension;
453 }
454
455 KHTMLView *KHTMLPart::view() const
456 {
457   return d->m_view;
458 }
459
460 void KHTMLPart::setJScriptEnabled( bool enable )
461 {
462   if ( !enable && jScriptEnabled() && d->m_jscript ) {
463     d->m_jscript->clear();
464   }
465   d->m_bJScriptForce = enable;
466   d->m_bJScriptOverride = true;
467 }
468
469 bool KHTMLPart::jScriptEnabled() const
470 {
471   if ( d->m_bJScriptOverride )
472       return d->m_bJScriptForce;
473   return d->m_bJScriptEnabled;
474 }
475
476 void KHTMLPart::setMetaRefreshEnabled( bool enable )
477 {
478   d->m_metaRefreshEnabled = enable;
479 }
480
481 bool KHTMLPart::metaRefreshEnabled() const
482 {
483   return d->m_metaRefreshEnabled;
484 }
485
486 KJSProxyImpl *KHTMLPart::jScript()
487 {
488     if (!jScriptEnabled())
489         return 0;
490
491     if (!d->m_jscript)
492         d->m_jscript = new KJSProxyImpl(this);
493
494     return d->m_jscript;
495 }
496
497 void KHTMLPart::replaceContentsWithScriptResult( const KURL &url )
498 {
499   QString script = KURL::decode_string(url.url().mid(strlen("javascript:")));
500   QVariant ret = executeScript(script);
501   
502   if (ret.type() == QVariant::String) {
503     begin();
504     write(ret.asString());
505     end();
506   }
507 }
508
509 QVariant KHTMLPart::executeScript( const QString &script, bool forceUserGesture )
510 {
511     return executeScript( 0, script, forceUserGesture );
512 }
513
514 //Enable this to see all JS scripts being executed
515 //#define KJS_VERBOSE
516
517 QVariant KHTMLPart::executeScript( DOM::NodeImpl *n, const QString &script, bool forceUserGesture )
518 {
519 #ifdef KJS_VERBOSE
520   kdDebug(6070) << "KHTMLPart::executeScript n=" << n.nodeName().qstring().latin1() << "(" << (n.isNull() ? 0 : n.nodeType()) << ") " << script << endl;
521 #endif
522   KJSProxyImpl *proxy = jScript();
523
524   if (!proxy)
525     return QVariant();
526   d->m_runningScripts++;
527   // If forceUserGesture is true, then make the script interpreter
528   // treat it as if triggered by a user gesture even if there is no
529   // current DOM event being processed.
530   QVariant ret = proxy->evaluate( forceUserGesture ? QString::null : m_url.url(), 0, script, n );
531   d->m_runningScripts--;
532   if (!d->m_runningScripts && d->m_doc && !d->m_doc->parsing() && d->m_submitForm )
533       submitFormAgain();
534     DocumentImpl::updateDocumentsRendering();
535
536 #ifdef KJS_VERBOSE
537   kdDebug(6070) << "KHTMLPart::executeScript - done" << endl;
538 #endif
539   return ret;
540 }
541
542 bool KHTMLPart::scheduleScript(DOM::NodeImpl *n, const QString& script)
543 {
544     //kdDebug(6050) << "KHTMLPart::scheduleScript "<< script << endl;
545
546     d->scheduledScript = script;
547     d->scheduledScriptNode = n;
548
549     return true;
550 }
551
552 QVariant KHTMLPart::executeScheduledScript()
553 {
554   if( d->scheduledScript.isEmpty() )
555     return QVariant();
556
557   //kdDebug(6050) << "executing delayed " << d->scheduledScript << endl;
558
559   QVariant ret = executeScript( d->scheduledScriptNode.get(), d->scheduledScript );
560   d->scheduledScript = QString();
561   d->scheduledScriptNode = 0;
562
563   return ret;
564 }
565
566 void KHTMLPart::setJavaEnabled( bool enable )
567 {
568   d->m_bJavaForce = enable;
569   d->m_bJavaOverride = true;
570 }
571
572 bool KHTMLPart::javaEnabled() const
573 {
574 #ifndef Q_WS_QWS
575   if( d->m_bJavaOverride )
576       return d->m_bJavaForce;
577   return d->m_bJavaEnabled;
578 #else
579   return false;
580 #endif
581 }
582
583 KJavaAppletContext *KHTMLPart::javaContext()
584 {
585 #ifndef Q_WS_QWS
586   return d->m_javaContext;
587 #else
588   return 0;
589 #endif
590 }
591
592 KJavaAppletContext *KHTMLPart::createJavaContext()
593 {
594 #ifndef Q_WS_QWS
595   if (!d->m_javaContext)
596       d->m_javaContext = new KJavaAppletContext(this);
597
598   return d->m_javaContext;
599 #else
600   return 0;
601 #endif
602 }
603
604 void KHTMLPart::setPluginsEnabled( bool enable )
605 {
606   d->m_bPluginsForce = enable;
607   d->m_bPluginsOverride = true;
608 }
609
610 bool KHTMLPart::pluginsEnabled() const
611 {
612   if ( d->m_bPluginsOverride )
613       return d->m_bPluginsForce;
614   return d->m_bPluginsEnabled;
615 }
616
617
618 void KHTMLPart::slotDebugDOMTree()
619 {
620   if ( d->m_doc && d->m_doc->firstChild() )
621     qDebug("%s", createMarkup(d->m_doc->firstChild()).latin1());
622 }
623
624 void KHTMLPart::slotDebugRenderTree()
625 {
626 #ifndef NDEBUG
627   if ( d->m_doc )
628     d->m_doc->renderer()->printTree();
629 #endif
630 }
631
632 void KHTMLPart::setAutoloadImages( bool enable )
633 {
634   if ( d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable )
635     return;
636
637   if ( d->m_doc )
638     d->m_doc->docLoader()->setAutoloadImages( enable );
639
640 }
641
642 bool KHTMLPart::autoloadImages() const
643 {
644   if ( d->m_doc )
645     return d->m_doc->docLoader()->autoloadImages();
646
647   return true;
648 }
649
650 void KHTMLPart::clear()
651 {
652   if ( d->m_bCleared )
653     return;
654   d->m_bCleared = true;
655
656   d->m_bClearing = true;
657
658
659   d->m_mousePressNode = 0;
660
661
662   if ( d->m_doc )
663     d->m_doc->detach();
664
665   // Moving past doc so that onUnload works.
666   if ( d->m_jscript )
667     d->m_jscript->clear();
668
669   if ( d->m_view )
670     d->m_view->clear();
671
672   // do not dereference the document before the jscript and view are cleared, as some destructors
673   // might still try to access the document.
674   if ( d->m_doc )
675     d->m_doc->deref();
676   d->m_doc = 0;
677
678   d->m_decoder = 0;
679
680   {
681     ConstFrameIt it = d->m_frames.begin();
682     ConstFrameIt end = d->m_frames.end();
683     for(; it != end; ++it )
684     {
685       if ( (*it).m_part )
686       {
687         disconnectChild(&*it);
688         (*it).m_part->deref();
689       }
690     }
691   }
692   d->m_frames.clear();
693
694   {
695     ConstFrameIt it = d->m_objects.begin();
696     ConstFrameIt end = d->m_objects.end();
697     for(; it != end; ++it )
698     {
699       if ( (*it).m_part )
700       {
701         (*it).m_part->deref();
702       }
703     }
704   }
705   d->m_objects.clear();
706
707 #ifndef Q_WS_QWS
708   delete d->m_javaContext;
709   d->m_javaContext = 0;
710 #endif
711
712   d->m_scheduledRedirection = noRedirectionScheduled;
713   d->m_delayRedirect = 0;
714   d->m_redirectURL = QString::null;
715   d->m_redirectReferrer = QString::null;
716   d->m_redirectLockHistory = true;
717   d->m_redirectUserGesture = false;
718   d->m_bHTTPRefresh = false;
719   d->m_bClearing = false;
720   d->m_frameNameId = 1;
721   d->m_bFirstData = true;
722
723   d->m_bMousePressed = false;
724
725 #ifndef QT_NO_CLIPBOARD
726   connect( kapp->clipboard(), SIGNAL( selectionChanged()), SLOT( slotClearSelection()));
727 #endif
728
729
730   if ( !d->m_haveEncoding )
731     d->m_encoding = QString::null;
732 #ifdef SPEED_DEBUG
733   d->m_parsetime.restart();
734 #endif
735 }
736
737 bool KHTMLPart::openFile()
738 {
739   return true;
740 }
741
742 DOM::DocumentImpl *KHTMLPart::xmlDocImpl() const
743 {
744     if ( d )
745         return d->m_doc;
746     return 0;
747 }
748
749 void KHTMLPart::replaceDocImpl(DocumentImpl* newDoc)
750 {
751     if (d) {
752         if (d->m_doc) {
753             d->m_doc->detach();
754             d->m_doc->deref();
755         }
756         d->m_doc = newDoc;
757         if (newDoc) {
758             newDoc->ref();
759             newDoc->attach();
760         }
761     }
762 }
763
764 /*bool KHTMLPart::isSSLInUse() const
765 {
766   return d->m_ssl_in_use;
767 }*/
768
769 void KHTMLPart::receivedFirstData()
770 {
771     // Leave indented one extra for easier merging.
772     
773       //kdDebug( 6050 ) << "begin!" << endl;
774
775     begin( d->m_workingURL, d->m_extension->urlArgs().xOffset, d->m_extension->urlArgs().yOffset );
776
777
778     d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy);
779     d->m_workingURL = KURL();
780
781
782     // When the first data arrives, the metadata has just been made available
783     QString qData;
784
785     // Support for http-refresh
786     qData = d->m_job->queryMetaData("http-refresh");
787     if( !qData.isEmpty() && d->m_metaRefreshEnabled )
788     {
789       kdDebug(6050) << "HTTP Refresh Request: " << qData << endl;
790       double delay;
791       int pos = qData.find( ';' );
792       if ( pos == -1 )
793         pos = qData.find( ',' );
794
795       if( pos == -1 )
796       {
797         delay = qData.stripWhiteSpace().toDouble();
798         // We want a new history item if the refresh timeout > 1 second
799         scheduleRedirection( delay, m_url.url(), delay <= 1);
800       }
801       else
802       {
803         int end_pos = qData.length();
804         delay = qData.left(pos).stripWhiteSpace().toDouble();
805         while ( qData[++pos] == ' ' );
806         if ( qData.find( "url", pos, false ) == pos )
807         {
808           pos += 3;
809           while (qData[pos] == ' ' || qData[pos] == '=' )
810               pos++;
811           if ( qData[pos] == '"' )
812           {
813               pos++;
814               int index = end_pos-1;
815               while( index > pos )
816               {
817                 if ( qData[index] == '"' )
818                     break;
819                 index--;
820               }
821               if ( index > pos )
822                 end_pos = index;
823           }
824         }
825         // We want a new history item if the refresh timeout > 1 second
826         scheduleRedirection( delay, d->m_doc->completeURL( qData.mid( pos, end_pos ) ), delay <= 1);
827       }
828       d->m_bHTTPRefresh = true;
829     }
830
831     // Support for http last-modified
832     d->m_lastModified = d->m_job->queryMetaData("modified");
833     //kdDebug() << "KHTMLPart::slotData metadata modified: " << d->m_lastModified << endl;
834 }
835
836
837 void KHTMLPart::slotFinished( KIO::Job * job )
838 {
839   if (job->error())
840   {
841     d->m_job = 0L;
842     // TODO: what else ?
843     checkCompleted();
844     return;
845   }
846   //kdDebug( 6050 ) << "slotFinished" << endl;
847
848
849   if ( d->m_doc && d->m_doc->docLoader()->expireDate() && m_url.protocol().lower().startsWith("http"))
850       KIO::http_update_cache(m_url, false, d->m_doc->docLoader()->expireDate());
851
852   d->m_workingURL = KURL();
853   d->m_job = 0L;
854
855   if (d->m_doc->parsing())
856       end(); //will emit completed()
857 }
858
859 void KHTMLPart::childBegin()
860 {
861     // We need to do this when the child is created so as to avoid the bogus state of the parent's
862     // child->m_bCompleted being false but the child's m_bComplete being true.  If the child gets
863     // an error early on, we had trouble where checkingComplete on the child was a NOP because
864     // it thought it was already complete, and thus the parent was never signaled, and never set
865     // its child->m_bComplete.
866     d->m_bComplete = false;
867 }
868
869 void KHTMLPart::begin( const KURL &url, int xOffset, int yOffset )
870 {
871   // If we aren't loading an actual URL, then we need to make sure
872   // that we have at least an empty document. createEmptyDocument will
873   // do that if we don't have a document already.
874   if (d->m_workingURL.isEmpty()) {
875     KWQ(this)->createEmptyDocument();
876   }
877
878   clear();
879
880   KWQ(this)->partClearedInBegin();
881
882   // Only do this after clearing the part, so that JavaScript can
883   // clean up properly if it was on for the last load.
884   d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled(url.host());
885
886   d->m_bCleared = false;
887   d->m_bComplete = false;
888   d->m_bLoadEventEmitted = false;
889   d->m_bLoadingMainResource = true;
890
891   KParts::URLArgs args( d->m_extension->urlArgs() );
892   args.xOffset = xOffset;
893   args.yOffset = yOffset;
894   d->m_extension->setURLArgs( args );
895
896   KURL ref(url);
897   ref.setUser(QSTRING_NULL);
898   ref.setPass(QSTRING_NULL);
899   ref.setRef(QSTRING_NULL);
900   d->m_referrer = ref.url();
901   m_url = url;
902   KURL baseurl;
903
904   // We don't need KDE chained URI handling or window caption setting
905   if (!m_url.isEmpty())
906     baseurl = m_url;
907
908   if (DOMImplementationImpl::isXMLMIMEType(args.serviceType))
909     d->m_doc = DOMImplementationImpl::instance()->createDocument( d->m_view );
910   else
911     d->m_doc = DOMImplementationImpl::instance()->createHTMLDocument( d->m_view );
912
913   d->m_doc->ref();
914   if (!d->m_doc->attached())
915     d->m_doc->attach( );
916   d->m_doc->setURL( m_url.url() );
917   // We prefer m_baseURL over m_url because m_url changes when we are
918   // about to load a new page.
919   d->m_doc->setBaseURL( baseurl.url() );
920   if (d->m_decoder)
921     d->m_doc->setDecoder(d->m_decoder.get());
922   d->m_doc->docLoader()->setShowAnimations( d->m_settings->showAnimations() );
923
924   KWQ(this)->updatePolicyBaseURL();
925
926   setAutoloadImages( d->m_settings->autoLoadImages() );
927   QString userStyleSheet = d->m_settings->userStyleSheet();
928
929   if ( !userStyleSheet.isEmpty() )
930     setUserStyleSheet( KURL( userStyleSheet ) );
931
932   KWQ(this)->restoreDocumentState();
933
934   d->m_doc->implicitOpen();
935   // clear widget
936   if (d->m_view)
937     d->m_view->resizeContents( 0, 0 );
938   connect(d->m_doc,SIGNAL(finishedParsing()),this,SLOT(slotFinishedParsing()));
939 }
940
941 void KHTMLPart::write( const char *str, int len )
942 {
943     if ( !d->m_decoder ) {
944         d->m_decoder = new Decoder;
945         if (!d->m_encoding.isNull())
946             d->m_decoder->setEncoding(d->m_encoding.latin1(),
947                 d->m_haveEncoding ? Decoder::UserChosenEncoding : Decoder::EncodingFromHTTPHeader);
948         else
949             d->m_decoder->setEncoding(settings()->encoding().latin1(), Decoder::DefaultEncoding);
950
951         if (d->m_doc)
952             d->m_doc->setDecoder(d->m_decoder.get());
953     }
954   if ( len == 0 )
955     return;
956
957   if ( len == -1 )
958     len = strlen( str );
959
960   QString decoded = d->m_decoder->decode( str, len );
961
962   if(decoded.isEmpty()) return;
963
964   if(d->m_bFirstData) {
965       // determine the parse mode
966       d->m_doc->determineParseMode( decoded );
967       d->m_bFirstData = false;
968
969       // ### this is still quite hacky, but should work a lot better than the old solution
970       if(d->m_decoder->visuallyOrdered()) d->m_doc->setVisuallyOrdered();
971       d->m_doc->recalcStyle( NodeImpl::Force );
972   }
973
974   if (Tokenizer* t = d->m_doc->tokenizer())
975       t->write( decoded, true );
976 }
977
978 void KHTMLPart::write( const QString &str )
979 {
980   if ( str.isNull() )
981     return;
982
983   if(d->m_bFirstData) {
984       // determine the parse mode
985       d->m_doc->setParseMode( DocumentImpl::Strict );
986       d->m_bFirstData = false;
987   }
988   Tokenizer* t = d->m_doc->tokenizer();
989   if(t)
990     t->write( str, true );
991 }
992
993 void KHTMLPart::end()
994 {
995     d->m_bLoadingMainResource = false;
996     endIfNotLoading();
997 }
998
999 void KHTMLPart::endIfNotLoading()
1000 {
1001     if (d->m_bLoadingMainResource)
1002         return;
1003
1004     // make sure nothing's left in there...
1005     if (d->m_decoder)
1006         write(d->m_decoder->flush());
1007     if (d->m_doc)
1008         d->m_doc->finishParsing();
1009     else
1010         // WebKit partially uses WebCore when loading non-HTML docs.  In these cases doc==nil, but
1011         // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
1012         // become true.  An example is when a subframe is a pure text doc, and that subframe is the
1013         // last one to complete.
1014         checkCompleted();
1015 }
1016
1017 void KHTMLPart::stop()
1018 {
1019     // make sure nothing's left in there...
1020     if (d->m_doc) {
1021         if (d->m_doc->tokenizer())
1022             d->m_doc->tokenizer()->stopParsing();
1023         d->m_doc->finishParsing();
1024     } else {
1025         // WebKit partially uses WebCore when loading non-HTML docs.  In these cases doc==nil, but
1026         // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
1027         // become true.  An example is when a subframe is a pure text doc, and that subframe is the
1028         // last one to complete.
1029         checkCompleted();
1030     }
1031 }
1032
1033
1034 void KHTMLPart::stopAnimations()
1035 {
1036   if ( d->m_doc )
1037     d->m_doc->docLoader()->setShowAnimations( KHTMLSettings::KAnimationDisabled );
1038
1039   ConstFrameIt it = d->m_frames.begin();
1040   ConstFrameIt end = d->m_frames.end();
1041   for (; it != end; ++it )
1042     if ( !( *it ).m_part.isNull() && ( *it ).m_part->inherits( "KHTMLPart" ) ) {
1043       KParts::ReadOnlyPart* p = ( *it ).m_part;
1044       static_cast<KHTMLPart*>( p )->stopAnimations();
1045     }
1046 }
1047
1048 void KHTMLPart::gotoAnchor()
1049 {
1050     // If our URL has no ref, then we have no place we need to jump to.
1051     if (!m_url.hasRef())
1052         return;
1053
1054     QString ref = m_url.encodedHtmlRef();
1055     if (!gotoAnchor(ref)) {
1056         // Can't use htmlRef() here because it doesn't know which encoding to use to decode.
1057         // Decoding here has to match encoding in completeURL, which means it has to use the
1058         // page's encoding rather than UTF-8.
1059         if (d->m_decoder)
1060             gotoAnchor(KURL::decode_string(ref, d->m_decoder->codec()));
1061     }
1062 }
1063
1064 void KHTMLPart::slotFinishedParsing()
1065 {
1066   d->m_doc->setParsing(false);
1067
1068   if (!d->m_view)
1069     return; // We are probably being destructed.
1070
1071   RefPtr<KHTMLPart> protector(this);
1072   checkCompleted();
1073
1074   if (!d->m_view)
1075     return; // We are being destroyed by something checkCompleted called.
1076
1077   // check if the scrollbars are really needed for the content
1078   // if not, remove them, relayout, and repaint
1079
1080   d->m_view->restoreScrollBar();
1081   gotoAnchor();
1082 }
1083
1084 void KHTMLPart::slotLoaderRequestStarted( khtml::DocLoader* dl, khtml::CachedObject *obj )
1085 {
1086 }
1087
1088 void KHTMLPart::slotLoaderRequestDone( khtml::DocLoader* dl, khtml::CachedObject *obj )
1089 {
1090   // We really only need to call checkCompleted when our own resources are done loading.
1091   // So we should check that d->m_doc->docLoader() == dl here.
1092   // That might help with performance by skipping some unnecessary work, but it's too
1093   // risky to make that change right now (2005-02-07), because we might be accidentally
1094   // depending on the extra checkCompleted calls.
1095   if (d->m_doc) {
1096     checkCompleted();
1097   }
1098 }
1099
1100
1101 void KHTMLPart::checkCompleted()
1102 {
1103 //   kdDebug( 6050 ) << "KHTMLPart::checkCompleted() parsing: " << d->m_doc->parsing() << endl;
1104 //   kdDebug( 6050 ) << "                           complete: " << d->m_bComplete << endl;
1105
1106
1107   // Any frame that hasn't completed yet ?
1108   ConstFrameIt it = d->m_frames.begin();
1109   ConstFrameIt end = d->m_frames.end();
1110   for (; it != end; ++it )
1111     if ( !(*it).m_bCompleted )
1112       return;
1113
1114   // Have we completed before?
1115   if ( d->m_bComplete )
1116     return;
1117
1118   // Are we still parsing?
1119   if ( d->m_doc && d->m_doc->parsing() )
1120     return;
1121
1122   // Still waiting for images/scripts from the loader ?
1123   int requests = 0;
1124   if ( d->m_doc && d->m_doc->docLoader() )
1125     requests = khtml::Cache::loader()->numRequests( d->m_doc->docLoader() );
1126
1127   if ( requests > 0 )
1128     return;
1129
1130   // OK, completed.
1131   // Now do what should be done when we are really completed.
1132   d->m_bComplete = true;
1133
1134   checkEmitLoadEvent(); // if we didn't do it before
1135
1136
1137   if ( d->m_scheduledRedirection != noRedirectionScheduled )
1138   {
1139     // Do not start redirection for frames here! That action is
1140     // deferred until the parent emits a completed signal.
1141     if ( parentPart() == 0 )
1142       d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
1143
1144     emit completed( true );
1145   }
1146   else
1147   {
1148     if ( d->m_bPendingChildRedirection )
1149       emit completed ( true );
1150     else
1151       emit completed();
1152   }
1153
1154
1155 #ifdef SPEED_DEBUG
1156   kdDebug(6050) << "DONE: " <<d->m_parsetime.elapsed() << endl;
1157 #endif
1158 }
1159
1160 void KHTMLPart::checkEmitLoadEvent()
1161 {
1162   if ( d->m_bLoadEventEmitted || !d->m_doc || d->m_doc->parsing() ) return;
1163
1164   ConstFrameIt it = d->m_frames.begin();
1165   ConstFrameIt end = d->m_frames.end();
1166   for (; it != end; ++it )
1167     if ( !(*it).m_bCompleted ) // still got a frame running -> too early
1168       return;
1169
1170
1171   // All frames completed -> set their domain to the frameset's domain
1172   // This must only be done when loading the frameset initially (#22039),
1173   // not when following a link in a frame (#44162).
1174   if ( d->m_doc )
1175   {
1176     DOMString domain = d->m_doc->domain();
1177     ConstFrameIt it = d->m_frames.begin();
1178     ConstFrameIt end = d->m_frames.end();
1179     for (; it != end; ++it )
1180     {
1181       KParts::ReadOnlyPart *p = (*it).m_part;
1182       if ( p && p->inherits( "KHTMLPart" ))
1183       {
1184         KHTMLPart* htmlFrame = static_cast<KHTMLPart *>(p);
1185         if (htmlFrame->d->m_doc)
1186         {
1187           kdDebug() << "KHTMLPart::checkCompleted setting frame domain to " << domain.qstring() << endl;
1188           htmlFrame->d->m_doc->setDomain( domain );
1189         }
1190       }
1191     }
1192   }
1193
1194   d->m_bLoadEventEmitted = true;
1195   d->m_bUnloadEventEmitted = false;
1196   if (d->m_doc)
1197     d->m_doc->implicitClose();
1198 }
1199
1200 const KHTMLSettings *KHTMLPart::settings() const
1201 {
1202   return d->m_settings;
1203 }
1204
1205 #ifndef KDE_NO_COMPAT
1206 KURL KHTMLPart::baseURL() const
1207 {
1208   if ( !d->m_doc ) return KURL();
1209
1210   return d->m_doc->baseURL();
1211 }
1212
1213 QString KHTMLPart::baseTarget() const
1214 {
1215   if ( !d->m_doc ) return QString::null;
1216
1217   return d->m_doc->baseTarget();
1218 }
1219 #endif
1220
1221 KURL KHTMLPart::completeURL( const QString &url )
1222 {
1223   if ( !d->m_doc ) return url;
1224
1225
1226   return KURL( d->m_doc->completeURL( url ) );
1227 }
1228
1229 void KHTMLPart::scheduleRedirection( double delay, const QString &url, bool doLockHistory)
1230 {
1231     kdDebug(6050) << "KHTMLPart::scheduleRedirection delay=" << delay << " url=" << url << endl;
1232     if (delay < 0 || delay > INT_MAX / 1000)
1233       return;
1234     if ( d->m_scheduledRedirection == noRedirectionScheduled || delay <= d->m_delayRedirect )
1235     {
1236        d->m_scheduledRedirection = redirectionScheduled;
1237        d->m_delayRedirect = delay;
1238        d->m_redirectURL = url;
1239        d->m_redirectReferrer = QString::null;
1240        d->m_redirectLockHistory = doLockHistory;
1241        d->m_redirectUserGesture = false;
1242
1243        d->m_redirectionTimer.stop();
1244        if ( d->m_bComplete )
1245          d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
1246     }
1247 }
1248
1249 void KHTMLPart::scheduleLocationChange(const QString &url, const QString &referrer, bool lockHistory, bool userGesture)
1250 {
1251     // Handle a location change of a page with no document as a special case.
1252     // This may happen when a frame changes the location of another frame.
1253     d->m_scheduledRedirection = d->m_doc ? locationChangeScheduled : locationChangeScheduledDuringLoad;
1254     
1255     // If a redirect was scheduled during a load, then stop the current load.
1256     // Otherwise when the current load transitions from a provisional to a 
1257     // committed state, pending redirects may be cancelled. 
1258     if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad) {
1259         stopLoading(true);   
1260     }
1261     
1262     d->m_delayRedirect = 0;
1263     d->m_redirectURL = url;
1264     d->m_redirectReferrer = referrer;
1265     d->m_redirectLockHistory = lockHistory;
1266     d->m_redirectUserGesture = userGesture;
1267     d->m_redirectionTimer.stop();
1268     if (d->m_bComplete)
1269         d->m_redirectionTimer.start(0, true);
1270 }
1271
1272 bool KHTMLPart::isScheduledLocationChangePending() const
1273 {
1274     switch (d->m_scheduledRedirection) {
1275         case noRedirectionScheduled:
1276         case redirectionScheduled:
1277             return false;
1278         case historyNavigationScheduled:
1279         case locationChangeScheduled:
1280         case locationChangeScheduledDuringLoad:
1281             return true;
1282     }
1283     return false;
1284 }
1285
1286 void KHTMLPart::scheduleHistoryNavigation( int steps )
1287 {
1288     // navigation will always be allowed in the 0 steps case, which is OK because
1289     // that's supposed to force a reload.
1290     if (!KWQ(this)->canGoBackOrForward(steps)) {
1291         cancelRedirection();
1292         return;
1293     }
1294
1295     d->m_scheduledRedirection = historyNavigationScheduled;
1296     d->m_delayRedirect = 0;
1297     d->m_redirectURL = QString::null;
1298     d->m_redirectReferrer = QString::null;
1299     d->m_scheduledHistoryNavigationSteps = steps;
1300     d->m_redirectionTimer.stop();
1301     if (d->m_bComplete)
1302         d->m_redirectionTimer.start(0, true);
1303 }
1304
1305 void KHTMLPart::cancelRedirection(bool cancelWithLoadInProgress)
1306 {
1307     if (d) {
1308         d->m_cancelWithLoadInProgress = cancelWithLoadInProgress;
1309         d->m_scheduledRedirection = noRedirectionScheduled;
1310         d->m_redirectionTimer.stop();
1311     }
1312 }
1313
1314 void KHTMLPart::changeLocation(const QString &URL, const QString &referrer, bool lockHistory, bool userGesture)
1315 {
1316     if (URL.find("javascript:", 0, false) == 0) {
1317         QString script = KURL::decode_string(URL.mid(11));
1318         QVariant result = executeScript(script, userGesture);
1319         if (result.type() == QVariant::String) {
1320             begin(url());
1321             write(result.asString());
1322             end();
1323         }
1324         return;
1325     }
1326
1327     KParts::URLArgs args;
1328
1329     args.setLockHistory(lockHistory);
1330     if (!referrer.isEmpty())
1331         args.metaData()["referrer"] = referrer;
1332
1333     urlSelected(URL, 0, 0, "_self", args);
1334 }
1335
1336 void KHTMLPart::slotRedirect()
1337 {
1338     if (d->m_scheduledRedirection == historyNavigationScheduled) {
1339         d->m_scheduledRedirection = noRedirectionScheduled;
1340
1341         // Special case for go(0) from a frame -> reload only the frame
1342         // go(i!=0) from a frame navigates into the history of the frame only,
1343         // in both IE and NS (but not in Mozilla).... we can't easily do that
1344         // in Konqueror...
1345         if (d->m_scheduledHistoryNavigationSteps == 0) // add && parentPart() to get only frames, but doesn't matter
1346             openURL( url() ); /// ## need args.reload=true?
1347         else {
1348             if (d->m_extension) {
1349                 BrowserInterface *interface = d->m_extension->browserInterface();
1350                 if (interface)
1351                     interface->callMethod( "goHistory(int)", d->m_scheduledHistoryNavigationSteps );
1352             }
1353         }
1354         return;
1355     }
1356
1357     QString URL = d->m_redirectURL;
1358     QString referrer = d->m_redirectReferrer;
1359     bool lockHistory = d->m_redirectLockHistory;
1360     bool userGesture = d->m_redirectUserGesture;
1361
1362     d->m_scheduledRedirection = noRedirectionScheduled;
1363     d->m_delayRedirect = 0;
1364     d->m_redirectURL = QString::null;
1365     d->m_redirectReferrer = QString::null;
1366
1367     changeLocation(URL, referrer, lockHistory, userGesture);
1368 }
1369
1370 void KHTMLPart::slotRedirection(KIO::Job*, const KURL& url)
1371 {
1372     d->m_workingURL = url;
1373 }
1374
1375 QString KHTMLPart::encoding() const
1376 {
1377     if(d->m_haveEncoding && !d->m_encoding.isEmpty())
1378         return d->m_encoding;
1379
1380     if(d->m_decoder && d->m_decoder->encoding())
1381         return QString(d->m_decoder->encoding());
1382
1383     return(settings()->encoding());
1384 }
1385
1386 void KHTMLPart::setUserStyleSheet(const KURL &url)
1387 {
1388   if ( d->m_doc && d->m_doc->docLoader() )
1389     (void) new khtml::PartStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
1390 }
1391
1392 void KHTMLPart::setUserStyleSheet(const QString &styleSheet)
1393 {
1394   if ( d->m_doc )
1395     d->m_doc->setUserStyleSheet( styleSheet );
1396 }
1397
1398 bool KHTMLPart::gotoAnchor( const QString &name )
1399 {
1400   if (!d->m_doc)
1401     return false;
1402
1403   NodeImpl *n = d->m_doc->getElementById(name);
1404   if (!n) {
1405     HTMLCollectionImpl *anchors =
1406         new HTMLCollectionImpl( d->m_doc, HTMLCollectionImpl::DOC_ANCHORS);
1407     anchors->ref();
1408     n = anchors->namedItem(name, !d->m_doc->inCompatMode());
1409     anchors->deref();
1410   }
1411
1412   d->m_doc->setCSSTarget(n); // Setting to null will clear the current target.
1413   
1414   // Implement the rule that "" and "top" both mean top of page as in other browsers.
1415   if (!n && !(name.isEmpty() || name.lower() == "top")) {
1416     kdDebug(6050) << "KHTMLPart::gotoAnchor node '" << name << "' not found" << endl;
1417     return false;
1418   }
1419
1420   // We need to update the layout before scrolling, otherwise we could
1421   // really mess things up if an anchor scroll comes at a bad moment.
1422   if ( d->m_doc ) {
1423     d->m_doc->updateRendering();
1424     // Only do a layout if changes have occurred that make it necessary.      
1425     if ( d->m_view && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout() ) {
1426       d->m_view->layout();
1427     }
1428   }
1429   
1430   // Scroll nested layers and frames to reveal the anchor.
1431   RenderObject *renderer;
1432   QRect rect;
1433   if (n) {
1434       renderer = n->renderer();
1435       rect = n->getRect();
1436   } else {
1437     // If there's no node, we should scroll to the top of the document.
1438       renderer = d->m_doc->renderer();
1439       rect = QRect();
1440   }
1441
1442   if (renderer) {
1443     // Align to the top and to the closest side (this matches other browsers).
1444     renderer->enclosingLayer()->scrollRectToVisible(rect, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways);
1445   }
1446   
1447   return true;
1448 }
1449
1450 void KHTMLPart::setStandardFont( const QString &name )
1451 {
1452     d->m_settings->setStdFontName(name);
1453 }
1454
1455 void KHTMLPart::setFixedFont( const QString &name )
1456 {
1457     d->m_settings->setFixedFontName(name);
1458 }
1459
1460
1461 QCursor KHTMLPart::urlCursor() const
1462 {
1463   // Don't load the link cursor until it's actually used.
1464   // Also, we don't need setURLCursor.
1465   // This speeds up startup time.
1466   return KCursor::handCursor();
1467 }
1468
1469 bool KHTMLPart::onlyLocalReferences() const
1470 {
1471   return d->m_onlyLocalReferences;
1472 }
1473
1474 void KHTMLPart::setOnlyLocalReferences(bool enable)
1475 {
1476   d->m_onlyLocalReferences = enable;
1477 }
1478
1479 QString KHTMLPart::selectedText() const
1480 {
1481     return plainText(selection().toRange().get());
1482 }
1483
1484 bool KHTMLPart::hasSelection() const
1485 {
1486     return d->m_selection.isCaretOrRange();
1487 }
1488
1489 const SelectionController &KHTMLPart::selection() const
1490 {
1491     return d->m_selection;
1492 }
1493
1494 ETextGranularity KHTMLPart::selectionGranularity() const
1495 {
1496     return d->m_selectionGranularity;
1497 }
1498
1499 void KHTMLPart::setSelectionGranularity(ETextGranularity granularity) const
1500 {
1501     d->m_selectionGranularity = granularity;
1502 }
1503
1504 const SelectionController &KHTMLPart::dragCaret() const
1505 {
1506     return d->m_dragCaret;
1507 }
1508
1509 const SelectionController &KHTMLPart::mark() const
1510 {
1511     return d->m_mark;
1512 }
1513
1514 void KHTMLPart::setMark(const SelectionController &s)
1515 {
1516     d->m_mark = s;
1517 }
1518
1519 void KHTMLPart::setSelection(const SelectionController &s, bool closeTyping, bool keepTypingStyle)
1520 {
1521     if (d->m_selection == s) {
1522         return;
1523     }
1524     
1525     clearCaretRectIfNeeded();
1526
1527     SelectionController oldSelection = d->m_selection;
1528
1529     d->m_selection = s;
1530     if (!s.isNone())
1531         setFocusNodeIfNeeded();
1532     
1533     selectionLayoutChanged();
1534
1535     // Always clear the x position used for vertical arrow navigation.
1536     // It will be restored by the vertical arrow navigation code if necessary.
1537     d->m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation;
1538
1539     if (closeTyping)
1540         TypingCommand::closeTyping(lastEditCommand());
1541
1542     if (!keepTypingStyle)
1543         clearTypingStyle();
1544     
1545     KWQ(this)->respondToChangedSelection(oldSelection, closeTyping);
1546 }
1547
1548 void KHTMLPart::setDragCaret(const SelectionController &dragCaret)
1549 {
1550     if (d->m_dragCaret != dragCaret) {
1551         d->m_dragCaret.needsCaretRepaint();
1552         d->m_dragCaret = dragCaret;
1553         d->m_dragCaret.needsCaretRepaint();
1554     }
1555 }
1556
1557 void KHTMLPart::clearSelection()
1558 {
1559     setSelection(SelectionController());
1560 }
1561
1562 void KHTMLPart::invalidateSelection()
1563 {
1564     clearCaretRectIfNeeded();
1565     d->m_selection.setNeedsLayout();
1566     selectionLayoutChanged();
1567 }
1568
1569 void KHTMLPart::setCaretVisible(bool flag)
1570 {
1571     if (d->m_caretVisible == flag)
1572         return;
1573     clearCaretRectIfNeeded();
1574     if (flag)
1575         setFocusNodeIfNeeded();
1576     d->m_caretVisible = flag;
1577     selectionLayoutChanged();
1578 }
1579
1580
1581 void KHTMLPart::clearCaretRectIfNeeded()
1582 {
1583     if (d->m_caretPaint) {
1584         d->m_caretPaint = false;
1585         d->m_selection.needsCaretRepaint();
1586     }        
1587 }
1588
1589 // Helper function that tells whether a particular node is an element that has an entire
1590 // KHTMLPart and KHTMLView, a <frame>, <iframe>, or <object>.
1591 static bool isFrame(const NodeImpl *n)
1592 {
1593     if (!n)
1594         return false;
1595     RenderObject *renderer = n->renderer();
1596     if (!renderer || !renderer->isWidget())
1597         return false;
1598     QWidget *widget = static_cast<RenderWidget *>(renderer)->widget();
1599     return widget && widget->inherits("KHTMLView");
1600 }
1601
1602 void KHTMLPart::setFocusNodeIfNeeded()
1603 {
1604     if (!xmlDocImpl() || d->m_selection.isNone() || !d->m_isFocused)
1605         return;
1606
1607     NodeImpl *startNode = d->m_selection.start().node();
1608     NodeImpl *target = startNode ? startNode->rootEditableElement() : 0;
1609     
1610     if (target) {
1611         for ( ; target; target = target->parentNode()) {
1612             // We don't want to set focus on a subframe when selecting in a parent frame,
1613             // so add the !isFrame check here. There's probably a better way to make this
1614             // work in the long term, but this is the safest fix at this time.
1615             if (target->isMouseFocusable() && !isFrame(target)) {
1616                 xmlDocImpl()->setFocusNode(target);
1617                 return;
1618             }
1619         }
1620         xmlDocImpl()->setFocusNode(0);
1621     }
1622 }
1623
1624 void KHTMLPart::selectionLayoutChanged()
1625 {
1626     // kill any caret blink timer now running
1627     if (d->m_caretBlinkTimer >= 0) {
1628         killTimer(d->m_caretBlinkTimer);
1629         d->m_caretBlinkTimer = -1;
1630     }
1631
1632     // see if a new caret blink timer needs to be started
1633     if (d->m_caretVisible && d->m_caretBlinks && 
1634         d->m_selection.isCaret() && d->m_selection.start().node()->isContentEditable()) {
1635         d->m_caretBlinkTimer = startTimer(CARET_BLINK_FREQUENCY);
1636         d->m_caretPaint = true;
1637         d->m_selection.needsCaretRepaint();
1638     }
1639
1640     if (d->m_doc)
1641         d->m_doc->updateSelection();
1642 }
1643
1644 void KHTMLPart::setXPosForVerticalArrowNavigation(int x)
1645 {
1646     d->m_xPosForVerticalArrowNavigation = x;
1647 }
1648
1649 int KHTMLPart::xPosForVerticalArrowNavigation() const
1650 {
1651     return d->m_xPosForVerticalArrowNavigation;
1652 }
1653
1654 void KHTMLPart::timerEvent(QTimerEvent *e)
1655 {
1656     if (e->timerId() == d->m_caretBlinkTimer && 
1657         d->m_caretVisible && 
1658         d->m_caretBlinks && 
1659         d->m_selection.isCaret()) {
1660         if (d->m_bMousePressed) {
1661             if (!d->m_caretPaint) {
1662                 d->m_caretPaint = true;
1663                 d->m_selection.needsCaretRepaint();
1664             }
1665         }
1666         else {
1667             d->m_caretPaint = !d->m_caretPaint;
1668             d->m_selection.needsCaretRepaint();
1669         }
1670     }
1671 }
1672
1673 void KHTMLPart::paintCaret(QPainter *p, const QRect &rect) const
1674 {
1675     if (d->m_caretPaint)
1676         d->m_selection.paintCaret(p, rect);
1677 }
1678
1679 void KHTMLPart::paintDragCaret(QPainter *p, const QRect &rect) const
1680 {
1681     d->m_dragCaret.paintCaret(p, rect);
1682 }
1683
1684
1685 void KHTMLPart::urlSelected( const QString &url, int button, int state, const QString &_target,
1686                              KParts::URLArgs args )
1687 {
1688   bool hasTarget = false;
1689
1690   QString target = _target;
1691   if ( target.isEmpty() && d->m_doc )
1692     target = d->m_doc->baseTarget();
1693   if ( !target.isEmpty() )
1694       hasTarget = true;
1695
1696   if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
1697   {
1698     executeScript( KURL::decode_string( url.right( url.length() - 11) ), true );
1699     return;
1700   }
1701
1702   KURL cURL = completeURL(url);
1703
1704   if ( !cURL.isValid() )
1705     // ### ERROR HANDLING
1706     return;
1707
1708   //kdDebug( 6000 ) << "urlSelected: complete URL:" << cURL.url() << " target = " << target << endl;
1709
1710
1711   args.frameName = target;
1712
1713   if ( d->m_bHTTPRefresh )
1714   {
1715     d->m_bHTTPRefresh = false;
1716     args.metaData()["cache"] = "refresh";
1717   }
1718
1719
1720   if (!d->m_referrer.isEmpty())
1721     args.metaData()["referrer"] = d->m_referrer;
1722   KWQ(this)->urlSelected(cURL, button, state, args);
1723 }
1724
1725
1726 bool KHTMLPart::requestFrame( khtml::RenderPart *frame, const QString &url, const QString &frameName,
1727                               const QStringList &paramNames, const QStringList &paramValues, bool isIFrame )
1728 {
1729 //  kdDebug( 6050 ) << "childRequest( ..., " << url << ", " << frameName << " )" << endl;
1730   FrameIt it = d->m_frames.find( frameName );
1731   if ( it == d->m_frames.end() )
1732   {
1733     khtml::ChildFrame child;
1734 //    kdDebug( 6050 ) << "inserting new frame into frame map " << frameName << endl;
1735     child.m_name = frameName;
1736     it = d->m_frames.append( child );
1737   }
1738
1739   (*it).m_type = isIFrame ? khtml::ChildFrame::IFrame : khtml::ChildFrame::Frame;
1740   (*it).m_frame = frame;
1741   (*it).m_paramValues = paramNames;
1742   (*it).m_paramNames = paramValues;
1743
1744   // Support for <frame src="javascript:string">
1745   if ( url.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 )
1746   {
1747     if (!processObjectRequest(&(*it), "about:blank", "text/html" ))
1748       return false;
1749
1750     KHTMLPart *newPart = static_cast<KHTMLPart *>(&*(*it).m_part); 
1751     newPart->replaceContentsWithScriptResult( url );
1752
1753     return true;
1754   }
1755
1756   return requestObject( &(*it), completeURL( url ));
1757 }
1758
1759 QString KHTMLPart::requestFrameName()
1760 {
1761     return KWQ(this)->generateFrameName();
1762 }
1763
1764 bool KHTMLPart::requestObject( khtml::RenderPart *frame, const QString &url, const QString &serviceType,
1765                                const QStringList &paramNames, const QStringList &paramValues )
1766 {
1767   khtml::ChildFrame child;
1768   QValueList<khtml::ChildFrame>::Iterator it = d->m_objects.append( child );
1769   (*it).m_frame = frame;
1770   (*it).m_type = khtml::ChildFrame::Object;
1771   (*it).m_paramNames = paramNames;
1772   (*it).m_paramValues = paramValues;
1773   (*it).m_hasFallbackContent = frame->hasFallbackContent();
1774
1775   KURL completedURL;
1776   if (!url.isEmpty())
1777     completedURL = completeURL(url);
1778
1779   KParts::URLArgs args;
1780   args.serviceType = serviceType;
1781   return requestObject( &(*it), completedURL, args );
1782 }
1783
1784 bool KHTMLPart::requestObject( khtml::ChildFrame *child, const KURL &url, const KParts::URLArgs &_args )
1785 {
1786   if ( child->m_bPreloaded )
1787   {
1788     // kdDebug(6005) << "KHTMLPart::requestObject preload" << endl;
1789     if ( child->m_frame && child->m_part && child->m_part->widget() )
1790       child->m_frame->setWidget( child->m_part->widget() );
1791
1792     child->m_bPreloaded = false;
1793     return true;
1794   }
1795
1796   KParts::URLArgs args( _args );
1797
1798
1799   if ( child->m_part && !args.reload && urlcmp( child->m_part->url().url(), url.url(), true, true ) )
1800     args.serviceType = child->m_serviceType;
1801
1802   child->m_args = args;
1803   child->m_args.reload = (d->m_cachePolicy == KIO::CC_Reload) || (d->m_cachePolicy == KIO::CC_Refresh);
1804   child->m_serviceName = QString::null;
1805   if (!d->m_referrer.isEmpty() && !child->m_args.metaData().contains( "referrer" ))
1806     child->m_args.metaData()["referrer"] = d->m_referrer;
1807
1808
1809   // We want a KHTMLPart if the HTML says <frame src=""> or <frame src="about:blank">
1810   if ((url.isEmpty() || url.url() == "about:blank") && args.serviceType.isEmpty())
1811     args.serviceType = QString::fromLatin1( "text/html" );
1812
1813   return processObjectRequest( child, url, args.serviceType );
1814 }
1815
1816 bool KHTMLPart::processObjectRequest( khtml::ChildFrame *child, const KURL &_url, const QString &mimetype )
1817 {
1818   //kdDebug( 6050 ) << "KHTMLPart::processObjectRequest trying to create part for " << mimetype << endl;
1819
1820   // IMPORTANT: create a copy of the url here, because it is just a reference, which was likely to be given
1821   // by an emitting frame part (emit openURLRequest( blahurl, ... ) . A few lines below we delete the part
1822   // though -> the reference becomes invalid -> crash is likely
1823   KURL url( _url );
1824
1825   // khtmlrun called us this way to indicate a loading error
1826   if ( d->m_onlyLocalReferences || ( url.isEmpty() && mimetype.isEmpty() ) )
1827   {
1828       checkEmitLoadEvent();
1829       child->m_bCompleted = true;
1830       return true;
1831   }
1832
1833   if (child->m_bNotify)
1834   {
1835       child->m_bNotify = false;
1836       if ( !child->m_args.lockHistory() )
1837           emit d->m_extension->openURLNotify();
1838   }
1839
1840   if ( child->m_part )
1841   {
1842     KHTMLPart *part = static_cast<KHTMLPart *>(&*child->m_part);
1843     if (part && part->inherits("KHTMLPart")) {
1844       KParts::URLArgs args;
1845       if (!d->m_referrer.isEmpty())
1846         args.metaData()["referrer"] = d->m_referrer;
1847       KWQ(part)->openURLRequest(url, args);
1848     }
1849   }
1850   else
1851   {
1852     KParts::ReadOnlyPart *part = KWQ(this)->createPart(*child, url, mimetype);
1853     KHTMLPart *khtml_part = static_cast<KHTMLPart *>(part);
1854     if (khtml_part && khtml_part->inherits("KHTMLPart"))
1855       khtml_part->childBegin();
1856
1857     if (!part) {
1858         checkEmitLoadEvent();
1859         return false;
1860     }
1861
1862     //CRITICAL STUFF
1863     if ( child->m_part )
1864     {
1865       disconnectChild(child);
1866       child->m_part->deref();
1867     }
1868
1869     child->m_serviceType = mimetype;
1870     if ( child->m_frame && part->widget() )
1871       child->m_frame->setWidget( part->widget() );
1872
1873
1874     child->m_part = part;
1875     assert( ((void*) child->m_part) != 0);
1876
1877     connectChild(child);
1878
1879   }
1880
1881   checkEmitLoadEvent();
1882   // Some JS code in the load event may have destroyed the part
1883   // In that case, abort
1884   if ( !child->m_part )
1885     return false;
1886
1887   if ( child->m_bPreloaded )
1888   {
1889     if ( child->m_frame && child->m_part )
1890       child->m_frame->setWidget( child->m_part->widget() );
1891
1892     child->m_bPreloaded = false;
1893     return true;
1894   }
1895
1896   child->m_args.reload = (d->m_cachePolicy == KIO::CC_Reload) || (d->m_cachePolicy == KIO::CC_Refresh);
1897
1898   // make sure the part has a way to find out about the mimetype.
1899   // we actually set it in child->m_args in requestObject already,
1900   // but it's useless if we had to use a KHTMLRun instance, as the
1901   // point the run object is to find out exactly the mimetype.
1902   child->m_args.serviceType = mimetype;
1903
1904   child->m_bCompleted = false;
1905   if ( child->m_extension )
1906     child->m_extension->setURLArgs( child->m_args );
1907
1908   // In these cases, the synchronous load would have finished
1909   // before we could connect the signals, so make sure to send the 
1910   // completed() signal for the child by hand
1911   // FIXME: In this case the KHTMLPart will have finished loading before 
1912   // it's being added to the child list.  It would be a good idea to
1913   // create the child first, then invoke the loader separately  
1914   if (url.isEmpty() || url.url() == "about:blank") {
1915       ReadOnlyPart *readOnlyPart = child->m_part;
1916       KHTMLPart *part = static_cast<KHTMLPart *>(readOnlyPart);
1917       if (part && part->inherits("KHTMLPart")) {
1918           part->completed();
1919           part->checkCompleted();
1920       }
1921   }
1922       return true;
1923 }
1924
1925
1926 void KHTMLPart::submitFormAgain()
1927 {
1928   if( d->m_doc && !d->m_doc->parsing() && d->m_submitForm)
1929     KHTMLPart::submitForm( d->m_submitForm->submitAction, d->m_submitForm->submitUrl, d->m_submitForm->submitFormData, d->m_submitForm->target, d->m_submitForm->submitContentType, d->m_submitForm->submitBoundary );
1930
1931   delete d->m_submitForm;
1932   d->m_submitForm = 0;
1933   disconnect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
1934 }
1935
1936 void KHTMLPart::submitForm( const char *action, const QString &url, const FormData &formData, const QString &_target, const QString& contentType, const QString& boundary )
1937 {
1938   kdDebug(6000) << this << ": KHTMLPart::submitForm target=" << _target << " url=" << url << endl;
1939   KURL u = completeURL( url );
1940
1941   if ( !u.isValid() )
1942   {
1943     // ### ERROR HANDLING!
1944     return;
1945   }
1946
1947
1948   QString urlstring = u.url();
1949
1950   if ( urlstring.find( QString::fromLatin1( "javascript:" ), 0, false ) == 0 ) {
1951     urlstring = KURL::decode_string(urlstring);
1952     d->m_executingJavaScriptFormAction = true;
1953     executeScript( urlstring.right( urlstring.length() - 11) );
1954     d->m_executingJavaScriptFormAction = false;
1955     return;
1956   }
1957
1958
1959   KParts::URLArgs args;
1960
1961   if (!d->m_referrer.isEmpty())
1962      args.metaData()["referrer"] = d->m_referrer;
1963
1964   args.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
1965
1966   // Handle mailto: forms
1967   if (u.protocol() == "mailto") {
1968       // 1)  Check for attach= and strip it
1969       QString q = u.query().mid(1);
1970       QStringList nvps = QStringList::split("&", q);
1971       bool triedToAttach = false;
1972
1973       for (QStringList::Iterator nvp = nvps.begin(); nvp != nvps.end(); ++nvp) {
1974          QStringList pair = QStringList::split("=", *nvp);
1975          if (pair.count() >= 2) {
1976             if (pair.first().lower() == "attach") {
1977                nvp = nvps.remove(nvp);
1978                triedToAttach = true;
1979             }
1980          }
1981       }
1982
1983
1984       // 2)  Append body=
1985       QString bodyEnc;
1986       if (contentType.lower() == "multipart/form-data") {
1987          // FIXME: is this correct?  I suspect not
1988          bodyEnc = KURL::encode_string(formData.flattenToString());
1989       } else if (contentType.lower() == "text/plain") {
1990          // Convention seems to be to decode, and s/&/\n/
1991          QString tmpbody = formData.flattenToString();
1992          tmpbody.replace('&', '\n');
1993          tmpbody.replace('+', ' ');
1994          tmpbody = KURL::decode_string(tmpbody);  // Decode the rest of it
1995          bodyEnc = KURL::encode_string(tmpbody);  // Recode for the URL
1996       } else {
1997          bodyEnc = KURL::encode_string(formData.flattenToString());
1998       }
1999
2000       nvps.append(QString("body=%1").arg(bodyEnc));
2001       q = nvps.join("&");
2002       u.setQuery(q);
2003   } 
2004
2005   if ( strcmp( action, "get" ) == 0 ) {
2006     if (u.protocol() != "mailto")
2007        u.setQuery( formData.flattenToString() );
2008     args.setDoPost( false );
2009   }
2010   else {
2011     args.postData = formData;
2012     args.setDoPost( true );
2013
2014     // construct some user headers if necessary
2015     if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
2016       args.setContentType( "Content-Type: application/x-www-form-urlencoded" );
2017     else // contentType must be "multipart/form-data"
2018       args.setContentType( "Content-Type: " + contentType + "; boundary=" + boundary );
2019   }
2020
2021   if ( d->m_doc->parsing() || d->m_runningScripts > 0 ) {
2022     if( d->m_submitForm ) {
2023       kdDebug(6000) << "KHTMLPart::submitForm ABORTING!" << endl;
2024       return;
2025     }
2026     d->m_submitForm = new KHTMLPartPrivate::SubmitForm;
2027     d->m_submitForm->submitAction = action;
2028     d->m_submitForm->submitUrl = url;
2029     d->m_submitForm->submitFormData = formData;
2030     d->m_submitForm->target = _target;
2031     d->m_submitForm->submitContentType = contentType;
2032     d->m_submitForm->submitBoundary = boundary;
2033     connect(this, SIGNAL(completed()), this, SLOT(submitFormAgain()));
2034   }
2035   else
2036   {
2037     KWQ(this)->submitForm( u, args);
2038   }
2039 }
2040
2041
2042 void KHTMLPart::slotParentCompleted()
2043 {
2044   if ( d->m_scheduledRedirection != noRedirectionScheduled && !d->m_redirectionTimer.isActive() )
2045   {
2046     // kdDebug(6050) << this << ": Child redirection -> " << d->m_redirectURL << endl;
2047     d->m_redirectionTimer.start( (int)(1000 * d->m_delayRedirect), true );
2048   }
2049 }
2050
2051 void KHTMLPart::slotChildStarted( KIO::Job *job )
2052 {
2053   khtml::ChildFrame *child = childFrame( sender() );
2054
2055   assert( child );
2056
2057   child->m_bCompleted = false;
2058
2059   if ( d->m_bComplete )
2060   {
2061     d->m_bComplete = false;
2062     emit started( job );
2063   }
2064 }
2065
2066 void KHTMLPart::slotChildCompleted()
2067 {
2068   slotChildCompleted( false );
2069 }
2070
2071 void KHTMLPart::slotChildCompleted( bool complete )
2072 {
2073   khtml::ChildFrame *child = childFrame( sender() );
2074
2075   assert( child );
2076
2077   child->m_bCompleted = true;
2078   child->m_args = KParts::URLArgs();
2079
2080   if ( complete && parentPart() == 0 )
2081     d->m_bPendingChildRedirection = true;
2082
2083   checkCompleted();
2084 }
2085
2086
2087 khtml::ChildFrame *KHTMLPart::childFrame( const QObject *obj )
2088 {
2089     assert( obj->inherits( "KParts::ReadOnlyPart" ) );
2090     const ReadOnlyPart *part = static_cast<const ReadOnlyPart *>( obj );
2091
2092     FrameIt it = d->m_frames.begin();
2093     FrameIt end = d->m_frames.end();
2094     for (; it != end; ++it )
2095       if ( static_cast<ReadOnlyPart *>((*it).m_part) == part )
2096         return &(*it);
2097
2098     it = d->m_objects.begin();
2099     end = d->m_objects.end();
2100     for (; it != end; ++it )
2101       if ( static_cast<ReadOnlyPart *>((*it).m_part) == part )
2102         return &(*it);
2103
2104     return 0L;
2105 }
2106
2107 KHTMLPart *KHTMLPart::findFrame( const QString &f )
2108 {
2109
2110   // ### http://www.w3.org/TR/html4/appendix/notes.html#notes-frames
2111   ConstFrameIt it = d->m_frames.find( f );
2112   if ( it == d->m_frames.end() )
2113   {
2114     //kdDebug() << "KHTMLPart::findFrame frame " << f << " not found" << endl;
2115     return 0L;
2116   }
2117   else {
2118     KParts::ReadOnlyPart *p = (*it).m_part;
2119     if ( p && p->inherits( "KHTMLPart" ))
2120     {
2121       //kdDebug() << "KHTMLPart::findFrame frame " << f << " is a KHTMLPart, ok" << endl;
2122       return (KHTMLPart*)p;
2123     }
2124     else
2125     {
2126       return 0L;
2127     }
2128   }
2129 }
2130
2131
2132 bool KHTMLPart::frameExists( const QString &frameName )
2133 {
2134   ConstFrameIt it = d->m_frames.find( frameName );
2135   if ( it == d->m_frames.end() )
2136     return false;
2137
2138   // WABA: We only return true if the child actually has a frame
2139   // set. Otherwise we might find our preloaded-selve.
2140   // This happens when we restore the frameset.
2141   return (!(*it).m_frame.isNull());
2142 }
2143
2144 KHTMLPart *KHTMLPart::parentPart() const
2145 {
2146   if ( !parent() || !parent()->inherits( "KHTMLPart" ) )
2147     return 0L;
2148
2149   return (KHTMLPart *)parent();
2150 }
2151
2152 int KHTMLPart::zoomFactor() const
2153 {
2154   return d->m_zoomFactor;
2155 }
2156
2157 // ### make the list configurable ?
2158 static const int zoomSizes[] = { 20, 40, 60, 80, 90, 95, 100, 105, 110, 120, 140, 160, 180, 200, 250, 300 };
2159 static const int zoomSizeCount = (sizeof(zoomSizes) / sizeof(int));
2160 static const int minZoom = 20;
2161 static const int maxZoom = 300;
2162
2163 void KHTMLPart::slotIncZoom()
2164 {
2165   int zoomFactor = d->m_zoomFactor;
2166
2167   if (zoomFactor < maxZoom) {
2168     // find the entry nearest to the given zoomsizes
2169     for (int i = 0; i < zoomSizeCount; ++i)
2170       if (zoomSizes[i] > zoomFactor) {
2171         zoomFactor = zoomSizes[i];
2172         break;
2173       }
2174     setZoomFactor(zoomFactor);
2175   }
2176 }
2177
2178 void KHTMLPart::slotDecZoom()
2179 {
2180     int zoomFactor = d->m_zoomFactor;
2181     if (zoomFactor > minZoom) {
2182       // find the entry nearest to the given zoomsizes
2183       for (int i = zoomSizeCount-1; i >= 0; --i)
2184         if (zoomSizes[i] < zoomFactor) {
2185           zoomFactor = zoomSizes[i];
2186           break;
2187         }
2188       setZoomFactor(zoomFactor);
2189     }
2190 }
2191
2192 void KHTMLPart::setZoomFactor (int percent)
2193 {
2194   
2195   if (d->m_zoomFactor == percent) return;
2196   d->m_zoomFactor = percent;
2197
2198   if(d->m_doc) {
2199     d->m_doc->recalcStyle( NodeImpl::Force );
2200   }
2201
2202   ConstFrameIt it = d->m_frames.begin();
2203   ConstFrameIt end = d->m_frames.end();
2204   for (; it != end; ++it )
2205     if ( !( *it ).m_part.isNull() && ( *it ).m_part->inherits( "KHTMLPart" ) ) {
2206       KParts::ReadOnlyPart* p = ( *it ).m_part;
2207       static_cast<KHTMLPart*>( p )->setZoomFactor(d->m_zoomFactor);
2208     }
2209
2210
2211   if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout())
2212     view()->layout();
2213 }
2214
2215 void KHTMLPart::setJSStatusBarText( const QString &text )
2216 {
2217    d->m_kjsStatusBarText = text;
2218    emit setStatusBarText( d->m_kjsStatusBarText );
2219 }
2220
2221 void KHTMLPart::setJSDefaultStatusBarText( const QString &text )
2222 {
2223    d->m_kjsDefaultStatusBarText = text;
2224    emit setStatusBarText( d->m_kjsDefaultStatusBarText );
2225 }
2226
2227 QString KHTMLPart::jsStatusBarText() const
2228 {
2229     return d->m_kjsStatusBarText;
2230 }
2231
2232 QString KHTMLPart::jsDefaultStatusBarText() const
2233 {
2234    return d->m_kjsDefaultStatusBarText;
2235 }
2236
2237 QString KHTMLPart::referrer() const
2238 {
2239    return d->m_referrer;
2240 }
2241
2242 QString KHTMLPart::lastModified() const
2243 {
2244   return d->m_lastModified;
2245 }
2246
2247
2248 void KHTMLPart::reparseConfiguration()
2249 {
2250   setAutoloadImages( d->m_settings->autoLoadImages() );
2251   if (d->m_doc)
2252      d->m_doc->docLoader()->setShowAnimations( d->m_settings->showAnimations() );
2253
2254   d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled(m_url.host());
2255   d->m_bJavaEnabled = d->m_settings->isJavaEnabled(m_url.host());
2256   d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled(m_url.host());
2257
2258   QString userStyleSheet = d->m_settings->userStyleSheet();
2259   if ( !userStyleSheet.isEmpty() )
2260     setUserStyleSheet( KURL( userStyleSheet ) );
2261   else
2262     setUserStyleSheet( QString() );
2263
2264   if(d->m_doc) d->m_doc->updateStyleSelector();
2265 }
2266
2267 QStringList KHTMLPart::frameNames() const
2268 {
2269   QStringList res;
2270
2271   ConstFrameIt it = d->m_frames.begin();
2272   ConstFrameIt end = d->m_frames.end();
2273   for (; it != end; ++it )
2274     if (!(*it).m_bPreloaded)
2275       res += (*it).m_name;
2276
2277   return res;
2278 }
2279
2280 QPtrList<KParts::ReadOnlyPart> KHTMLPart::frames() const
2281 {
2282   QPtrList<KParts::ReadOnlyPart> res;
2283
2284   ConstFrameIt it = d->m_frames.begin();
2285   ConstFrameIt end = d->m_frames.end();
2286   for (; it != end; ++it )
2287     if (!(*it).m_bPreloaded)
2288       res.append( (*it).m_part );
2289
2290   return res;
2291 }
2292
2293 KHTMLPart *KHTMLPart::childFrameNamed(const QString &name) const
2294 {
2295   FrameList::Iterator it = d->m_frames.find(name);
2296   if (it != d->m_frames.end())
2297     return static_cast<KHTMLPart *>(&*(*it).m_part);
2298   return NULL;
2299 }
2300
2301
2302
2303 void KHTMLPart::setDNDEnabled( bool b )
2304 {
2305   d->m_bDnd = b;
2306 }
2307
2308 bool KHTMLPart::dndEnabled() const
2309 {
2310   return d->m_bDnd;
2311 }
2312
2313 bool KHTMLPart::shouldDragAutoNode(DOM::NodeImpl *node, int x, int y) const
2314 {
2315     // No KDE impl yet
2316     return false;
2317 }
2318
2319 void KHTMLPart::customEvent( QCustomEvent *event )
2320 {
2321   if ( khtml::MousePressEvent::test( event ) )
2322   {
2323     khtmlMousePressEvent( static_cast<khtml::MousePressEvent *>( event ) );
2324     return;
2325   }
2326
2327   if ( khtml::MouseDoubleClickEvent::test( event ) )
2328   {
2329     khtmlMouseDoubleClickEvent( static_cast<khtml::MouseDoubleClickEvent *>( event ) );
2330     return;
2331   }
2332
2333   if ( khtml::MouseMoveEvent::test( event ) )
2334   {
2335     khtmlMouseMoveEvent( static_cast<khtml::MouseMoveEvent *>( event ) );
2336     return;
2337   }
2338
2339   if ( khtml::MouseReleaseEvent::test( event ) )
2340   {
2341     khtmlMouseReleaseEvent( static_cast<khtml::MouseReleaseEvent *>( event ) );
2342     return;
2343   }
2344
2345   if ( khtml::DrawContentsEvent::test( event ) )
2346   {
2347     khtmlDrawContentsEvent( static_cast<khtml::DrawContentsEvent *>( event ) );
2348     return;
2349   }
2350
2351   KParts::ReadOnlyPart::customEvent( event );
2352 }
2353
2354 bool KHTMLPart::isPointInsideSelection(int x, int y)
2355 {
2356     // Treat a collapsed selection like no selection.
2357     if (!d->m_selection.isRange())
2358         return false;
2359     if (!xmlDocImpl()->renderer()) 
2360         return false;
2361     
2362     RenderObject::NodeInfo nodeInfo(true, true);
2363     xmlDocImpl()->renderer()->layer()->hitTest(nodeInfo, x, y);
2364     NodeImpl *innerNode = nodeInfo.innerNode();
2365     if (!innerNode || !innerNode->renderer())
2366         return false;
2367     
2368     Position pos(innerNode->renderer()->positionForCoordinates(x, y).deepEquivalent());
2369     if (pos.isNull())
2370         return false;
2371
2372     NodeImpl *n = d->m_selection.start().node();
2373     while (n) {
2374         if (n == pos.node()) {
2375             if ((n == d->m_selection.start().node() && pos.offset() < d->m_selection.start().offset()) ||
2376                 (n == d->m_selection.end().node() && pos.offset() > d->m_selection.end().offset())) {
2377                 return false;
2378             }
2379             return true;
2380         }
2381         if (n == d->m_selection.end().node())
2382             break;
2383         n = n->traverseNextNode();
2384     }
2385
2386    return false;
2387 }
2388
2389 void KHTMLPart::selectClosestWordFromMouseEvent(QMouseEvent *mouse, NodeImpl *innerNode, int x, int y)
2390 {
2391     SelectionController selection;
2392
2393     if (innerNode && innerNode->renderer() && mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
2394         VisiblePosition pos(innerNode->renderer()->positionForCoordinates(x, y));
2395         if (pos.isNotNull()) {
2396             selection.moveTo(pos);
2397             selection.expandUsingGranularity(WORD);
2398         }
2399     }
2400     
2401     if (selection.isRange()) {
2402         d->m_selectionGranularity = WORD;
2403         d->m_beganSelectingText = true;
2404     }
2405     
2406     if (shouldChangeSelection(selection)) {
2407         setSelection(selection);
2408         startAutoScroll();
2409     }
2410 }
2411
2412 void KHTMLPart::handleMousePressEventDoubleClick(khtml::MousePressEvent *event)
2413 {
2414     if (event->qmouseEvent()->button() == LeftButton) {
2415         if (selection().isRange()) {
2416             // A double-click when range is already selected
2417             // should not change the selection.  So, do not call
2418             // selectClosestWordFromMouseEvent, but do set
2419             // m_beganSelectingText to prevent khtmlMouseReleaseEvent
2420             // from setting caret selection.
2421             d->m_beganSelectingText = true;
2422         } else {
2423             selectClosestWordFromMouseEvent(event->qmouseEvent(), event->innerNode(), event->x(), event->y());
2424         }
2425     }
2426 }
2427
2428 void KHTMLPart::handleMousePressEventTripleClick(khtml::MousePressEvent *event)
2429 {
2430     QMouseEvent *mouse = event->qmouseEvent();
2431     NodeImpl *innerNode = event->innerNode();
2432     
2433     if (mouse->button() == LeftButton && innerNode && innerNode->renderer() &&
2434         mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
2435         SelectionController selection;
2436         VisiblePosition pos(innerNode->renderer()->positionForCoordinates(event->x(), event->y()));
2437         if (pos.isNotNull()) {
2438             selection.moveTo(pos);
2439             selection.expandUsingGranularity(PARAGRAPH);
2440         }
2441         if (selection.isRange()) {
2442             d->m_selectionGranularity = PARAGRAPH;
2443             d->m_beganSelectingText = true;
2444         }
2445         
2446         if (shouldChangeSelection(selection)) {
2447             setSelection(selection);
2448             startAutoScroll();
2449         }
2450     }
2451 }
2452
2453 void KHTMLPart::handleMousePressEventSingleClick(khtml::MousePressEvent *event)
2454 {
2455     QMouseEvent *mouse = event->qmouseEvent();
2456     NodeImpl *innerNode = event->innerNode();
2457     
2458     if (mouse->button() == LeftButton) {
2459         if (innerNode && innerNode->renderer() &&
2460             mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
2461             SelectionController sel;
2462             
2463             // Extend the selection if the Shift key is down, unless the click is in a link.
2464             bool extendSelection = (mouse->state() & ShiftButton) && (event->url().isNull());
2465
2466             // Don't restart the selection when the mouse is pressed on an
2467             // existing selection so we can allow for text dragging.
2468             if (!extendSelection && isPointInsideSelection(event->x(), event->y())) {
2469                 return;
2470             }
2471
2472             VisiblePosition visiblePos(innerNode->renderer()->positionForCoordinates(event->x(), event->y()));
2473             if (visiblePos.isNull())
2474                 visiblePos = VisiblePosition(innerNode, innerNode->caretMinOffset(), khtml::DOWNSTREAM);
2475             Position pos = visiblePos.deepEquivalent();
2476             
2477             sel = selection();
2478             if (extendSelection && sel.isCaretOrRange()) {
2479                 sel.clearModifyBias();
2480                 
2481                 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection 
2482                 // was created right-to-left
2483                 Position start = sel.start();
2484                 short before = RangeImpl::compareBoundaryPoints(pos.node(), pos.offset(), start.node(), start.offset());
2485                 if (before <= 0) {
2486                     sel.setBaseAndExtent(pos, visiblePos.affinity(), sel.end(), sel.endAffinity());
2487                 } else {
2488                     sel.setBaseAndExtent(start, sel.startAffinity(), pos, visiblePos.affinity());
2489                 }
2490
2491                 if (d->m_selectionGranularity != CHARACTER) {
2492                     sel.expandUsingGranularity(d->m_selectionGranularity);
2493                 }
2494                 d->m_beganSelectingText = true;
2495             } else {
2496                 sel = SelectionController(visiblePos);
2497                 d->m_selectionGranularity = CHARACTER;
2498             }
2499             
2500             if (shouldChangeSelection(sel)) {
2501                 setSelection(sel);
2502                 startAutoScroll();
2503             }
2504         }
2505     }
2506 }
2507
2508 void KHTMLPart::khtmlMousePressEvent(khtml::MousePressEvent *event)
2509 {
2510     DOM::DOMString url = event->url();
2511     QMouseEvent *mouse = event->qmouseEvent();
2512     NodeImpl *innerNode = event->innerNode();
2513
2514     d->m_mousePressNode = innerNode;
2515     d->m_dragStartPos = mouse->pos();
2516
2517     if (!event->url().isNull()) {
2518         d->m_strSelectedURL = d->m_strSelectedURLTarget = QString::null;
2519     }
2520     else {
2521         d->m_strSelectedURL = event->url().qstring();
2522         d->m_strSelectedURLTarget = event->target().qstring();
2523     }
2524
2525
2526     if (mouse->button() == LeftButton || mouse->button() == MidButton) {
2527         d->m_bMousePressed = true;
2528
2529 #ifdef KHTML_NO_SELECTION
2530         d->m_dragLastPos = mouse->globalPos();
2531 #else
2532         d->m_beganSelectingText = false;
2533
2534         if (mouse->clickCount() == 2) {
2535             handleMousePressEventDoubleClick(event);
2536             return;
2537         }
2538         
2539         if (mouse->clickCount() >= 3) {
2540             handleMousePressEventTripleClick(event);
2541             return;
2542         }
2543
2544         handleMousePressEventSingleClick(event);
2545 #endif // KHTML_NO_SELECTION
2546     }
2547 }
2548
2549 void KHTMLPart::khtmlMouseDoubleClickEvent( khtml::MouseDoubleClickEvent *event)
2550 {
2551 }
2552
2553
2554 void KHTMLPart::handleMouseMoveEventSelection(khtml::MouseMoveEvent *event)
2555 {
2556     // Mouse not pressed. Do nothing.
2557     if (!d->m_bMousePressed)
2558         return;
2559
2560 #ifdef KHTML_NO_SELECTION
2561     if (d->m_doc && d->m_view) {
2562         QPoint diff( mouse->globalPos() - d->m_dragLastPos );
2563                 
2564         if (abs(diff.x()) > 64 || abs(diff.y()) > 64) {
2565             d->m_view->scrollBy(-diff.x(), -diff.y());
2566             d->m_dragLastPos = mouse->globalPos();
2567         }
2568     }
2569     return;   
2570 #else
2571
2572     QMouseEvent *mouse = event->qmouseEvent();
2573     NodeImpl *innerNode = event->innerNode();
2574
2575     if (mouse->state() != LeftButton || !innerNode || !innerNode->renderer() ||
2576         !mouseDownMayStartSelect() || !innerNode->renderer()->shouldSelect())
2577         return;
2578
2579     // handle making selection
2580     VisiblePosition pos(innerNode->renderer()->positionForCoordinates(event->x(), event->y()));
2581
2582     // Don't modify the selection if we're not on a node.
2583     if (pos.isNull())
2584         return;
2585
2586     // Restart the selection if this is the first mouse move. This work is usually
2587     // done in khtmlMousePressEvent, but not if the mouse press was on an existing selection.
2588     SelectionController sel = selection();
2589     sel.clearModifyBias();
2590     
2591     if (!d->m_beganSelectingText) {
2592         d->m_beganSelectingText = true;
2593         sel.moveTo(pos);
2594     }
2595
2596     sel.setExtent(pos);
2597     if (d->m_selectionGranularity != CHARACTER)
2598         sel.expandUsingGranularity(d->m_selectionGranularity);
2599
2600     if (shouldChangeSelection(sel))
2601         setSelection(sel);
2602
2603 #endif // KHTML_NO_SELECTION
2604 }
2605
2606 void KHTMLPart::khtmlMouseMoveEvent(khtml::MouseMoveEvent *event)
2607 {
2608     handleMouseMoveEventSelection(event);               
2609 }
2610
2611 void KHTMLPart::khtmlMouseReleaseEvent( khtml::MouseReleaseEvent *event )
2612 {
2613     if (d->m_bMousePressed)
2614         stopAutoScroll();
2615         
2616     // Used to prevent mouseMoveEvent from initiating a drag before
2617     // the mouse is pressed again.
2618     d->m_bMousePressed = false;
2619
2620 #ifndef QT_NO_CLIPBOARD
2621     QMouseEvent *_mouse = event->qmouseEvent();
2622     if ((d->m_guiProfile == BrowserViewGUI) && (_mouse->button() == MidButton) && (event->url().isNull())) {
2623         QClipboard *cb = QApplication::clipboard();
2624         cb->setSelectionMode(true);
2625         QCString plain("plain");
2626         QString url = cb->text(plain).stripWhiteSpace();
2627         KURL u(url);
2628         if (u.isMalformed()) {
2629             // some half-baked guesses for incomplete urls
2630             // (the same code is in libkonq/konq_dirpart.cc)
2631             if (url.startsWith("ftp.")) {
2632                 url.prepend("ftp://");
2633                 u = url;
2634             }
2635             else {
2636                 url.prepend("http://");
2637                 u = url;
2638             }
2639         }
2640         if (u.isValid()) {
2641             QString savedReferrer = d->m_referrer;
2642             d->m_referrer = QString::null; // Disable referrer.
2643             urlSelected(url, 0,0, "_top");
2644             d->m_referrer = savedReferrer; // Restore original referrer.
2645         }
2646     }
2647 #endif
2648   
2649 #ifndef KHTML_NO_SELECTION
2650         
2651     // Clear the selection if the mouse didn't move after the last mouse press.
2652     // We do this so when clicking on the selection, the selection goes away.
2653     // However, if we are editing, place the caret.
2654     if (mouseDownMayStartSelect() && !d->m_beganSelectingText
2655             && d->m_dragStartPos.x() == event->qmouseEvent()->x()
2656             && d->m_dragStartPos.y() == event->qmouseEvent()->y()
2657             && d->m_selection.isRange()) {
2658         SelectionController selection;
2659         NodeImpl *node = event->innerNode();
2660         if (node && node->isContentEditable() && node->renderer()) {
2661             VisiblePosition pos = node->renderer()->positionForCoordinates(event->x(), event->y());
2662             selection.moveTo(pos);
2663         }
2664         if (shouldChangeSelection(selection)) {
2665             setSelection(selection);
2666         }
2667     }
2668
2669 #ifndef QT_NO_CLIPBOARD
2670     // get selected text and paste to the clipboard
2671     QString text = selectedText();
2672     text.replace(QRegExp(QChar(0xa0)), " ");
2673     QClipboard *cb = QApplication::clipboard();
2674     cb->setSelectionMode(true);
2675     disconnect(kapp->clipboard(), SIGNAL(selectionChanged()), this, SLOT(slotClearSelection()));
2676     cb->setText(text);
2677     connect(kapp->clipboard(), SIGNAL(selectionChanged()), SLOT(slotClearSelection()));
2678     cb->setSelectionMode(false);
2679 #endif // QT_NO_CLIPBOARD
2680
2681     selectFrameElementInParentIfFullySelected();
2682
2683 #endif // KHTML_NO_SELECTION
2684 }
2685
2686 void KHTMLPart::khtmlDrawContentsEvent( khtml::DrawContentsEvent * )
2687 {
2688 }
2689
2690
2691 void KHTMLPart::startAutoScroll()
2692 {
2693 }
2694
2695 void KHTMLPart::stopAutoScroll()
2696 {
2697 }
2698
2699
2700 void KHTMLPart::selectAll()
2701 {
2702     if (!d->m_doc)
2703         return;
2704     
2705     NodeImpl *startNode = d->m_selection.start().node();
2706     NodeImpl *root = startNode && startNode->isContentEditable() ? startNode->rootEditableElement() : d->m_doc->documentElement();
2707     
2708     selectContentsOfNode(root);
2709     selectFrameElementInParentIfFullySelected();
2710 }
2711
2712 bool KHTMLPart::selectContentsOfNode(NodeImpl* node)
2713 {
2714     SelectionController sel = SelectionController(Position(node, 0), khtml::DOWNSTREAM, Position(node, node->maxDeepOffset()), khtml::DOWNSTREAM);    
2715     if (shouldChangeSelection(sel)) {
2716         setSelection(sel);
2717         return true;
2718     }
2719     return false;
2720 }
2721
2722 bool KHTMLPart::shouldChangeSelection(const SelectionController &newselection) const
2723 {
2724     return KWQ(this)->shouldChangeSelection(d->m_selection, newselection, newselection.startAffinity(), false);
2725 }
2726
2727 bool KHTMLPart::shouldBeginEditing(const RangeImpl *range) const
2728 {
2729     return true;
2730 }
2731
2732 bool KHTMLPart::shouldEndEditing(const RangeImpl *range) const
2733 {
2734     return true;
2735 }
2736
2737 bool KHTMLPart::isContentEditable() const 
2738 {
2739     if (!d->m_doc)
2740         return false;
2741     return d->m_doc->inDesignMode();
2742 }
2743
2744 EditCommandPtr KHTMLPart::lastEditCommand()
2745 {
2746     return d->m_lastEditCommand;
2747 }
2748
2749 void KHTMLPart::appliedEditing(EditCommandPtr &cmd)
2750 {
2751     if (shouldChangeSelection(cmd.endingSelection())) {
2752         setSelection(cmd.endingSelection(), false);
2753     }
2754
2755     // Now set the typing style from the command. Clear it when done.
2756     // This helps make the case work where you completely delete a piece
2757     // of styled text and then type a character immediately after.
2758     // That new character needs to take on the style of the just-deleted text.
2759     // FIXME: Improve typing style.
2760     // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
2761     if (cmd.typingStyle()) {
2762         setTypingStyle(cmd.typingStyle());
2763         cmd.setTypingStyle(0);
2764     }
2765
2766     // Command will be equal to last edit command only in the case of typing
2767     if (d->m_lastEditCommand == cmd) {
2768         assert(cmd.isTypingCommand());
2769     }
2770     else {
2771         // Only register a new undo command if the command passed in is
2772         // different from the last command
2773         KWQ(this)->registerCommandForUndo(cmd);
2774         d->m_lastEditCommand = cmd;
2775     }
2776     KWQ(this)->respondToChangedContents();
2777 }
2778
2779 void KHTMLPart::unappliedEditing(EditCommandPtr &cmd)
2780 {
2781     if (shouldChangeSelection(cmd.startingSelection())) {
2782         setSelection(cmd.startingSelection(), true);
2783     }
2784     KWQ(this)->registerCommandForRedo(cmd);
2785     KWQ(this)->respondToChangedContents();
2786     d->m_lastEditCommand = EditCommandPtr::emptyCommand();
2787 }
2788
2789 void KHTMLPart::reappliedEditing(EditCommandPtr &cmd)
2790 {
2791     if (shouldChangeSelection(cmd.endingSelection())) {
2792         setSelection(cmd.endingSelection(), true);
2793     }
2794     KWQ(this)->registerCommandForUndo(cmd);
2795     KWQ(this)->respondToChangedContents();
2796     d->m_lastEditCommand = EditCommandPtr::emptyCommand();
2797 }
2798
2799 CSSMutableStyleDeclarationImpl *KHTMLPart::typingStyle() const
2800 {
2801     return d->m_typingStyle;
2802 }
2803
2804 void KHTMLPart::setTypingStyle(CSSMutableStyleDeclarationImpl *style)
2805 {
2806     if (d->m_typingStyle == style)
2807         return;
2808         
2809     CSSMutableStyleDeclarationImpl *old = d->m_typingStyle;
2810     d->m_typingStyle = style;
2811     if (d->m_typingStyle)
2812         d->m_typingStyle->ref();
2813     if (old)
2814         old->deref();
2815 }
2816
2817 void KHTMLPart::clearTypingStyle()
2818 {
2819     setTypingStyle(0);
2820 }
2821
2822
2823 QVariant KHTMLPart::executeScript(QString filename, int baseLine, NodeImpl *n, const QString &script)
2824 {
2825 #ifdef KJS_VERBOSE
2826   kdDebug(6070) << "executeScript: filename=" << filename << " baseLine=" << baseLine << " script=" << script << endl;
2827 #endif
2828   KJSProxyImpl *proxy = jScript();
2829
2830   if (!proxy)
2831     return QVariant();
2832   QVariant ret = proxy->evaluate(filename,baseLine,script, n );
2833   DocumentImpl::updateDocumentsRendering();
2834   return ret;
2835 }
2836
2837 void KHTMLPart::slotPartRemoved(KParts::Part *part)
2838 {
2839     if (part == d->m_activeFrame)
2840         d->m_activeFrame = 0;
2841 }
2842
2843 DOM::EventListener *KHTMLPart::createHTMLEventListener(const DOMString& code, NodeImpl *node)
2844 {
2845     if (KJSProxyImpl *proxy = jScript())
2846         return proxy->createHTMLEventHandler(code, node);
2847     return 0;
2848 }
2849
2850 KHTMLPart *KHTMLPart::opener()
2851 {
2852     return d->m_opener;
2853 }
2854
2855 void KHTMLPart::setOpener(KHTMLPart *_opener)
2856 {
2857     d->m_opener = _opener;
2858 }
2859
2860 bool KHTMLPart::openedByJS()
2861 {
2862     return d->m_openedByJS;
2863 }
2864
2865 void KHTMLPart::setOpenedByJS(bool _openedByJS)
2866 {
2867     d->m_openedByJS = _openedByJS;
2868 }
2869
2870 void KHTMLPart::preloadStyleSheet(const QString &url, const QString &stylesheet)
2871 {
2872     khtml::Cache::preloadStyleSheet(url, stylesheet);
2873 }
2874
2875 void KHTMLPart::preloadScript(const QString &url, const QString &script)
2876 {
2877     khtml::Cache::preloadScript(url, script);
2878 }
2879
2880
2881 bool KHTMLPart::restored() const
2882 {
2883   return d->m_restored;
2884 }
2885
2886 void KHTMLPart::incrementFrameCount()
2887 {
2888   frameCount++;
2889   if (parentPart()) {
2890     parentPart()->incrementFrameCount();
2891   }
2892 }
2893
2894 void KHTMLPart::decrementFrameCount()
2895 {
2896   frameCount--;
2897   if (parentPart()) {
2898     parentPart()->decrementFrameCount();
2899   }
2900 }
2901
2902 int KHTMLPart::topLevelFrameCount()
2903 {
2904   if (parentPart()) {
2905     return parentPart()->topLevelFrameCount();
2906   }
2907
2908   return frameCount;
2909 }
2910
2911 bool KHTMLPart::tabsToLinks() const
2912 {
2913     return true;
2914 }
2915
2916 bool KHTMLPart::tabsToAllControls() const
2917 {
2918     return true;
2919 }
2920
2921 void KHTMLPart::copyToPasteboard()
2922 {
2923     KWQ(this)->issueCopyCommand();
2924 }
2925
2926 void KHTMLPart::cutToPasteboard()
2927 {
2928     KWQ(this)->issueCutCommand();
2929 }
2930
2931 void KHTMLPart::pasteFromPasteboard()
2932 {
2933     KWQ(this)->issuePasteCommand();
2934 }
2935
2936 void KHTMLPart::pasteAndMatchStyle()
2937 {
2938     KWQ(this)->issuePasteAndMatchStyleCommand();
2939 }
2940
2941 void KHTMLPart::transpose()
2942 {
2943     KWQ(this)->issueTransposeCommand();
2944 }
2945
2946 void KHTMLPart::redo()
2947 {
2948     KWQ(this)->issueRedoCommand();
2949 }
2950
2951 void KHTMLPart::undo()
2952 {
2953     KWQ(this)->issueUndoCommand();
2954 }
2955
2956
2957 void KHTMLPart::computeAndSetTypingStyle(CSSStyleDeclarationImpl *style, EditAction editingAction)
2958 {
2959     if (!style || style->length() == 0) {
2960         clearTypingStyle();
2961         return;
2962     }
2963
2964     // Calculate the current typing style.
2965     CSSMutableStyleDeclarationImpl *mutableStyle = style->makeMutable();
2966     mutableStyle->ref();
2967     if (typingStyle()) {
2968         typingStyle()->merge(mutableStyle);
2969         mutableStyle->deref();
2970         mutableStyle = typingStyle();
2971         mutableStyle->ref();
2972     }
2973
2974     NodeImpl *node = VisiblePosition(selection().start(), selection().startAffinity()).deepEquivalent().node();
2975     CSSComputedStyleDeclarationImpl computedStyle(node);
2976     computedStyle.diff(mutableStyle);
2977     
2978     // Handle block styles, substracting these from the typing style.
2979     CSSMutableStyleDeclarationImpl *blockStyle = mutableStyle->copyBlockProperties();
2980     blockStyle->ref();
2981     blockStyle->diff(mutableStyle);
2982     if (xmlDocImpl() && blockStyle->length() > 0) {
2983         EditCommandPtr cmd(new ApplyStyleCommand(xmlDocImpl(), blockStyle, editingAction));
2984         cmd.apply();
2985     }
2986     blockStyle->deref();
2987     
2988     // Set the remaining style as the typing style.
2989     setTypingStyle(mutableStyle);
2990     mutableStyle->deref();
2991 }
2992
2993 void KHTMLPart::applyStyle(CSSStyleDeclarationImpl *style, EditAction editingAction)
2994 {
2995     switch (selection().state()) {
2996         case SelectionController::NONE:
2997             // do nothing
2998             break;
2999         case SelectionController::CARET: {
3000             computeAndSetTypingStyle(style, editingAction);
3001             break;
3002         }
3003         case SelectionController::RANGE:
3004             if (xmlDocImpl() && style) {
3005                 EditCommandPtr cmd(new ApplyStyleCommand(xmlDocImpl(), style, editingAction));
3006                 cmd.apply();
3007             }
3008             break;
3009     }
3010 }
3011
3012 void KHTMLPart::applyParagraphStyle(CSSStyleDeclarationImpl *style, EditAction editingAction)
3013 {
3014     switch (selection().state()) {
3015         case SelectionController::NONE:
3016             // do nothing
3017             break;
3018         case SelectionController::CARET:
3019         case SelectionController::RANGE:
3020             if (xmlDocImpl() && style) {
3021                 EditCommandPtr cmd(new ApplyStyleCommand(xmlDocImpl(), style, editingAction, ApplyStyleCommand::ForceBlockProperties));
3022                 cmd.apply();
3023             }
3024             break;
3025     }
3026 }
3027
3028 static void updateState(CSSMutableStyleDeclarationImpl *desiredStyle, CSSComputedStyleDeclarationImpl *computedStyle, bool &atStart, KHTMLPart::TriState &state)
3029 {
3030     QValueListConstIterator<CSSProperty> end;
3031     for (QValueListConstIterator<CSSProperty> it = desiredStyle->valuesIterator(); it != end; ++it) {
3032         int propertyID = (*it).id();
3033         DOMString desiredProperty = desiredStyle->getPropertyValue(propertyID);
3034         DOMString computedProperty = computedStyle->getPropertyValue(propertyID);
3035         KHTMLPart::TriState propertyState = strcasecmp(desiredProperty, computedProperty) == 0
3036             ? KHTMLPart::trueTriState : KHTMLPart::falseTriState;
3037         if (atStart) {
3038             state = propertyState;
3039             atStart = false;
3040         } else if (state != propertyState) {
3041             state = KHTMLPart::mixedTriState;
3042             break;
3043         }
3044     }
3045 }
3046
3047 KHTMLPart::TriState KHTMLPart::selectionHasStyle(CSSStyleDeclarationImpl *style) const
3048 {
3049     bool atStart = true;
3050     TriState state = falseTriState;
3051
3052     CSSMutableStyleDeclarationImpl *mutableStyle = style->makeMutable();
3053     RefPtr<CSSStyleDeclarationImpl> protectQueryStyle(mutableStyle);
3054
3055     if (!d->m_selection.isRange()) {
3056         NodeImpl *nodeToRemove;
3057         CSSComputedStyleDeclarationImpl *selectionStyle = selectionComputedStyle(nodeToRemove);
3058         if (!selectionStyle)
3059             return falseTriState;
3060         selectionStyle->ref();
3061         updateState(mutableStyle, selectionStyle, atStart, state);
3062         selectionStyle->deref();
3063         if (nodeToRemove) {
3064             int exceptionCode = 0;
3065             nodeToRemove->remove(exceptionCode);
3066             assert(exceptionCode == 0);
3067         }
3068     } else {
3069         for (NodeImpl *node = d->m_selection.start().node(); node; node = node->traverseNextNode()) {
3070             CSSComputedStyleDeclarationImpl *computedStyle = new CSSComputedStyleDeclarationImpl(node);
3071             if (computedStyle) {
3072                 computedStyle->ref();
3073                 updateState(mutableStyle, computedStyle, atStart, state);
3074                 computedStyle->deref();
3075             }
3076             if (state == mixedTriState)
3077                 break;
3078             if (node == d->m_selection.end().node())
3079                 break;
3080         }
3081     }
3082
3083     return state;
3084 }
3085
3086 bool KHTMLPart::selectionStartHasStyle(CSSStyleDeclarationImpl *style) const
3087 {
3088     NodeImpl *nodeToRemove;
3089     CSSStyleDeclarationImpl *selectionStyle = selectionComputedStyle(nodeToRemove);
3090     if (!selectionStyle)
3091         return false;
3092
3093     CSSMutableStyleDeclarationImpl *mutableStyle = style->makeMutable();
3094
3095     RefPtr<CSSStyleDeclarationImpl> protectSelectionStyle(selectionStyle);
3096     RefPtr<CSSStyleDeclarationImpl> protectQueryStyle(mutableStyle);
3097
3098     bool match = true;
3099     QValueListConstIterator<CSSProperty> end;
3100     for (QValueListConstIterator<CSSProperty> it = mutableStyle->valuesIterator(); it != end; ++it) {
3101         int propertyID = (*it).id();
3102         DOMString desiredProperty = mutableStyle->getPropertyValue(propertyID);
3103         DOMString selectionProperty = selectionStyle->getPropertyValue(propertyID);
3104         if (strcasecmp(selectionProperty, desiredProperty) != 0) {
3105             match = false;
3106             break;
3107         }
3108     }
3109
3110     if (nodeToRemove) {
3111         int exceptionCode = 0;
3112         nodeToRemove->remove(exceptionCode);
3113         assert(exceptionCode == 0);
3114     }
3115
3116     return match;
3117 }
3118
3119 DOMString KHTMLPart::selectionStartStylePropertyValue(int stylePropertyID) const
3120 {
3121     NodeImpl *nodeToRemove;
3122     CSSStyleDeclarationImpl *selectionStyle = selectionComputedStyle(nodeToRemove);
3123     if (!selectionStyle)
3124         return DOMString();
3125
3126     selectionStyle->ref();
3127     DOMString value = selectionStyle->getPropertyValue(stylePropertyID);
3128     selectionStyle->deref();
3129
3130     if (nodeToRemove) {
3131         int exceptionCode = 0;
3132         nodeToRemove->remove(exceptionCode);
3133         assert(exceptionCode == 0);
3134     }
3135
3136     return value;
3137 }
3138
3139 CSSComputedStyleDeclarationImpl *KHTMLPart::selectionComputedStyle(NodeImpl *&nodeToRemove) const
3140 {
3141     nodeToRemove = 0;
3142
3143     if (!xmlDocImpl())
3144         return 0;
3145
3146     if (d->m_selection.isNone())
3147         return 0;
3148
3149     RefPtr<RangeImpl> range(d->m_selection.toRange());
3150     Position pos = range->editingStartPosition();
3151
3152     ElementImpl *elem = pos.element();
3153     if (!elem)
3154         return 0;
3155     
3156     ElementImpl *styleElement = elem;
3157     int exceptionCode = 0;
3158
3159     if (d->m_typingStyle) {
3160         styleElement = xmlDocImpl()->createElementNS(xhtmlNamespaceURI, "span", exceptionCode);
3161         assert(exceptionCode == 0);
3162
3163         styleElement->ref();
3164         
3165         styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), exceptionCode);
3166         assert(exceptionCode == 0);
3167         
3168         TextImpl *text = xmlDocImpl()->createEditingTextNode("");
3169         styleElement->appendChild(text, exceptionCode);
3170         assert(exceptionCode == 0);
3171
3172         if (elem->renderer() && elem->renderer()->canHaveChildren()) {
3173             elem->appendChild(styleElement, exceptionCode);
3174         } else {
3175             NodeImpl *parent = elem->parent();
3176             NodeImpl *next = elem->nextSibling();
3177
3178             if (next) {
3179                 parent->insertBefore(styleElement, next, exceptionCode);
3180             } else {
3181                 parent->appendChild(styleElement, exceptionCode);
3182             }
3183         }
3184         assert(exceptionCode == 0);
3185
3186         styleElement->deref();
3187
3188         nodeToRemove = styleElement;
3189     }
3190
3191     return new CSSComputedStyleDeclarationImpl(styleElement);
3192 }
3193
3194 static CSSMutableStyleDeclarationImpl *editingStyle()
3195 {
3196     static CSSMutableStyleDeclarationImpl *editingStyle = 0;
3197     if (!editingStyle) {
3198         editingStyle = new CSSMutableStyleDeclarationImpl;
3199         int exceptionCode;
3200         editingStyle->setCssText("word-wrap: break-word; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;", exceptionCode);
3201     }
3202     return editingStyle;
3203 }
3204
3205 void KHTMLPart::applyEditingStyleToBodyElement() const
3206 {
3207     if (!d->m_doc)
3208         return;
3209         
3210     RefPtr<NodeListImpl> list = d->m_doc->getElementsByTagName("body");
3211     unsigned len = list->length();
3212     for (unsigned i = 0; i < len; i++) {
3213         applyEditingStyleToElement(static_cast<ElementImpl *>(list->item(i)));    
3214     }
3215 }
3216
3217 void KHTMLPart::removeEditingStyleFromBodyElement() const
3218 {
3219     if (!d->m_doc)
3220         return;
3221         
3222     RefPtr<NodeListImpl> list = d->m_doc->getElementsByTagName("body");
3223     unsigned len = list->length();
3224     for (unsigned i = 0; i < len; i++) {
3225         removeEditingStyleFromElement(static_cast<ElementImpl *>(list->item(i)));    
3226     }
3227 }
3228
3229 void KHTMLPart::applyEditingStyleToElement(ElementImpl *element) const
3230 {
3231     if (!element || !element->isHTMLElement())
3232         return;
3233         
3234     RenderObject *renderer = element->renderer();
3235     if (!renderer || !renderer->isBlockFlow())
3236         return;
3237     
3238     CSSMutableStyleDeclarationImpl *currentStyle = static_cast<HTMLElementImpl *>(element)->getInlineStyleDecl();
3239     CSSMutableStyleDeclarationImpl *mergeStyle = editingStyle();
3240     if (mergeStyle) {
3241         currentStyle->merge(mergeStyle);
3242         element->setAttribute(styleAttr, currentStyle->cssText());
3243     }
3244 }
3245
3246 void KHTMLPart::removeEditingStyleFromElement(ElementImpl *element) const
3247 {
3248     if (!element || !element->isHTMLElement())
3249         return;
3250         
3251     RenderObject *renderer = element->renderer();
3252     if (!renderer || !renderer->isBlockFlow())
3253         return;
3254     
3255     CSSMutableStyleDeclarationImpl *currentStyle = static_cast<HTMLElementImpl *>(element)->getInlineStyleDecl();
3256     bool changed = false;
3257     changed |= !currentStyle->removeProperty(CSS_PROP_WORD_WRAP, false).isNull();
3258     changed |= !currentStyle->removeProperty(CSS_PROP__KHTML_NBSP_MODE, false).isNull();
3259     changed |= !currentStyle->removeProperty(CSS_PROP__KHTML_LINE_BREAK, false).isNull();
3260     if (changed)
3261         currentStyle->setChanged();
3262
3263     element->setAttribute(styleAttr, currentStyle->cssText());
3264 }
3265
3266
3267 bool KHTMLPart::isCharacterSmartReplaceExempt(const QChar &, bool)
3268 {
3269     // no smart replace
3270     return true;
3271 }
3272
3273 void KHTMLPart::connectChild(const khtml::ChildFrame *child) const
3274 {
3275     ReadOnlyPart *part = child->m_part;
3276     if (part && child->m_type != ChildFrame::Object)
3277     {
3278         connect( part, SIGNAL( started( KIO::Job *) ),
3279                  this, SLOT( slotChildStarted( KIO::Job *) ) );
3280         connect( part, SIGNAL( completed() ),
3281                  this, SLOT( slotChildCompleted() ) );
3282         connect( part, SIGNAL( completed(bool) ),
3283                  this, SLOT( slotChildCompleted(bool) ) );
3284         connect( part, SIGNAL( setStatusBarText( const QString & ) ),
3285                  this, SIGNAL( setStatusBarText( const QString & ) ) );
3286         connect( this, SIGNAL( completed() ),
3287                  part, SLOT( slotParentCompleted() ) );
3288         connect( this, SIGNAL( completed(bool) ),
3289                  part, SLOT( slotParentCompleted() ) );
3290     }
3291 }
3292
3293 void KHTMLPart::disconnectChild(const khtml::ChildFrame *child) const
3294 {
3295     ReadOnlyPart *part = child->m_part;
3296     if (part && child->m_type != ChildFrame::Object)
3297     {
3298         disconnect( part, SIGNAL( started( KIO::Job *) ),
3299                     this, SLOT( slotChildStarted( KIO::Job *) ) );
3300         disconnect( part, SIGNAL( completed() ),
3301                     this, SLOT( slotChildCompleted() ) );
3302         disconnect( part, SIGNAL( completed(bool) ),
3303                     this, SLOT( slotChildCompleted(bool) ) );
3304         disconnect( part, SIGNAL( setStatusBarText( const QString & ) ),
3305                     this, SIGNAL( setStatusBarText( const QString & ) ) );
3306         disconnect( this, SIGNAL( completed() ),
3307                     part, SLOT( slotParentCompleted() ) );
3308         disconnect( this, SIGNAL( completed(bool) ),
3309                     part, SLOT( slotParentCompleted() ) );
3310     }
3311 }
3312
3313 void KHTMLPart::keepAlive()
3314 {
3315     if (d->m_lifeSupportTimer.isActive())
3316         return;
3317     ref();
3318     d->m_lifeSupportTimer.start(0, true);
3319 }
3320
3321 void KHTMLPart::slotEndLifeSupport()
3322 {
3323     d->m_lifeSupportTimer.stop();
3324     deref();
3325 }
3326
3327 // Workaround for the fact that it's hard to delete a frame.
3328 // Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
3329 // Can't do this implicitly as part of every setSelection call because in some contexts it might not be good
3330 // for the focus to move to another frame. So instead we call it from places where we are selecting with the
3331 // mouse or the keyboard after setting the selection.
3332 void KHTMLPart::selectFrameElementInParentIfFullySelected()
3333 {
3334     // Find the parent frame; if there is none, then we have nothing to do.
3335     KHTMLPart *parent = parentPart();
3336     if (!parent)
3337         return;
3338     KHTMLView *parentView = parent->view();
3339     if (!parentView)
3340         return;
3341
3342     // Check if the selection contains the entire frame contents; if not, then there is nothing to do.
3343     if (!d->m_selection.isRange())
3344         return;
3345     if (!isStartOfDocument(VisiblePosition(d->m_selection.start(), d->m_selection.startAffinity())))
3346         return;
3347     if (!isEndOfDocument(VisiblePosition(d->m_selection.end(), d->m_selection.endAffinity())))
3348         return;
3349
3350     // Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
3351     DocumentImpl *document = xmlDocImpl();
3352     if (!document)
3353         return;
3354     ElementImpl *ownerElement = document->ownerElement();
3355     if (!ownerElement)
3356         return;
3357     NodeImpl *ownerElementParent = ownerElement->parentNode();
3358     if (!ownerElementParent)
3359         return;
3360
3361     // Create compute positions before and after the element.
3362     unsigned ownerElementNodeIndex = ownerElement->nodeIndex();
3363     VisiblePosition beforeOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex, khtml::SEL_DEFAULT_AFFINITY));
3364     VisiblePosition afterOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex + 1, khtml::VP_UPSTREAM_IF_POSSIBLE));
3365
3366     // Focus on the parent frame, and then select from before this element to after.
3367     if (parent->shouldChangeSelection(SelectionController(beforeOwnerElement, afterOwnerElement))) {
3368         parentView->setFocus();
3369         parent->setSelection(SelectionController(beforeOwnerElement, afterOwnerElement));
3370     }
3371 }
3372
3373 void KHTMLPart::handleFallbackContent()
3374 {
3375     KHTMLPart *parent = parentPart();
3376     if (!parent)
3377         return;
3378     ChildFrame *childFrame = parent->childFrame(this);
3379     if (!childFrame || childFrame->m_type != ChildFrame::Object)
3380         return;
3381     khtml::RenderPart *renderPart = childFrame->m_frame;
3382     if (!renderPart)
3383         return;
3384     NodeImpl *node = renderPart->element();
3385     if (!node || !node->hasTagName(objectTag))
3386         return;
3387     static_cast<HTMLObjectElementImpl *>(node)->renderFallbackContent();
3388 }