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