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