b49b5be8704f2d89a0ff90abe5be193f296b916d
[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 "FramePrivate.h"
31
32 #include "ApplyStyleCommand.h"
33 #include "CSSComputedStyleDeclaration.h"
34 #include "CSSPropertyNames.h"
35 #include "Cache.h"
36 #include "CachedCSSStyleSheet.h"
37 #include "DOMImplementation.h"
38 #include "DocLoader.h"
39 #include "DOMWindow.h"
40 #include "EditingText.h"
41 #include "EventNames.h"
42 #include "FloatRect.h"
43 #include "Frame.h"
44 #include "GraphicsContext.h"
45 #include "HTMLDocument.h"
46 #include "HTMLFormElement.h"
47 #include "HTMLGenericFormElement.h"
48 #include "HTMLNames.h"
49 #include "MouseEventWithHitTestResults.h"
50 #include "NodeList.h"
51 #include "Plugin.h"
52 #include "RenderCanvas.h"
53 #include "RenderTheme.h"
54 #include "SegmentedString.h"
55 #include "TextIterator.h"
56 #include "TransferJob.h"
57 #include "TypingCommand.h"
58 #include "cssstyleselector.h"
59 #include "dom2_eventsimpl.h"
60 #include "html_imageimpl.h"
61 #include "html_objectimpl.h"
62 #include "htmlediting.h"
63 #include "kjs_window.h"
64 #include "markup.h"
65 #include "render_frames.h"
66 #include "visible_units.h"
67 #include "xml_tokenizer.h"
68 #include "xmlhttprequest.h"
69 #include <math.h>
70 #include <sys/types.h>
71
72 #if !WIN32
73 #include <unistd.h>
74 #endif
75
76 #if SVG_SUPPORT
77 #include "SVGNames.h"
78 #include "XLinkNames.h"
79 #include "SVGDocumentExtensions.h"
80 #endif
81
82 using namespace std;
83 using namespace KJS;
84
85 namespace WebCore {
86
87 using namespace EventNames;
88 using namespace HTMLNames;
89
90 const double caretBlinkFrequency = 0.5;
91 const double autoscrollInterval = 0.1;
92
93 class UserStyleSheetLoader : public CachedObjectClient {
94 public:
95     UserStyleSheetLoader(Frame* frame, const String& url, DocLoader* dl)
96         : m_frame(frame)
97         , m_cachedSheet(Cache::requestStyleSheet(dl, url))
98     {
99         m_cachedSheet->ref(this);
100     }
101     ~UserStyleSheetLoader()
102     {
103         m_cachedSheet->deref(this);
104     }
105 private:
106     virtual void setStyleSheet(const String& /*URL*/, const String& sheet)
107     {
108         m_frame->setUserStyleSheet(sheet.deprecatedString());
109     }
110     Frame* m_frame;
111     CachedCSSStyleSheet* m_cachedSheet;
112 };
113
114 #if !NDEBUG
115 struct FrameCounter { 
116     static int count; 
117     ~FrameCounter() { if (count != 0) fprintf(stderr, "LEAK: %d Frame\n", count); }
118 };
119 int FrameCounter::count = 0;
120 static FrameCounter frameCounter;
121 #endif
122
123 static inline Frame* parentFromOwnerRenderer(RenderPart* ownerRenderer)
124 {
125     if (!ownerRenderer)
126         return 0;
127     return ownerRenderer->node()->document()->frame();
128 }
129
130 Frame::Frame(Page* page, RenderPart* ownerRenderer) 
131     : d(new FramePrivate(page, parentFromOwnerRenderer(ownerRenderer), this, ownerRenderer))
132 {
133     AtomicString::init();
134     Cache::init();
135     EventNames::init();
136     HTMLNames::init();
137     QualifiedName::init();
138
139 #if SVG_SUPPORT
140     SVGNames::init();
141     XLinkNames::init();
142 #endif
143
144     // FIXME: Frames were originally created with a refcount of 1, leave this
145     // ref call here until we can straighten that out.
146     ref();
147 #if !NDEBUG
148     ++FrameCounter::count;
149 #endif
150
151     if (ownerRenderer)
152         ownerRenderer->setFrame(this);
153 }
154
155 Frame::~Frame()
156 {
157     ASSERT(!d->m_lifeSupportTimer.isActive());
158
159 #if !NDEBUG
160     --FrameCounter::count;
161 #endif
162
163     cancelRedirection();
164
165     if (!d->m_bComplete)
166         closeURL();
167
168     clear(false);
169
170     if (d->m_jscript && d->m_jscript->haveInterpreter())
171         if (Window* w = Window::retrieveWindow(this)) {
172             w->disconnectFrame();
173             // Must clear the window pointer, otherwise we will not
174             // garbage-collect collect the window (inside the call to
175             // delete d below).
176             w = 0;
177         }
178
179     if (d->m_domWindow)
180         d->m_domWindow->disconnectFrame();
181             
182     setOpener(0);
183     HashSet<Frame*> openedBy = d->m_openedFrames;
184     HashSet<Frame*>::iterator end = openedBy.end();
185     for (HashSet<Frame*>::iterator it = openedBy.begin(); it != end; ++it)
186         (*it)->setOpener(0);
187
188     if (d->m_ownerRenderer)
189         d->m_ownerRenderer->setFrame(0);
190     ASSERT(!d->m_ownerRenderer);
191
192     if (d->m_view) {
193         d->m_view->hide();
194         d->m_view->m_frame = 0;
195     }
196   
197     ASSERT(!d->m_lifeSupportTimer.isActive());
198
199     delete d->m_userStyleSheetLoader;
200     delete d;
201     d = 0;
202 }
203
204 bool Frame::didOpenURL(const KURL& url)
205 {
206   if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad) {
207     // A redirect was shceduled before the document was created. This can happen
208     // when one frame changes another frame's location.
209     return false;
210   }
211   
212   cancelRedirection();
213   
214   // clear last edit command
215   d->m_lastEditCommand = EditCommandPtr();
216   
217   closeURL();
218
219   if (d->m_request.reload)
220      d->m_cachePolicy = KIO::CC_Refresh;
221   else
222      d->m_cachePolicy = KIO::CC_Verify;
223
224   if (d->m_request.doPost() && url.protocol().startsWith("http")) {
225       d->m_job = new TransferJob(this, "POST", url, d->m_request.postData);
226       d->m_job->addMetaData("content-type", d->m_request.contentType());
227   } else
228       d->m_job = new TransferJob(this, "GET", url);
229
230   d->m_bComplete = false;
231   d->m_bLoadingMainResource = true;
232   d->m_bLoadEventEmitted = false;
233
234   d->m_kjsStatusBarText = String();
235   d->m_kjsDefaultStatusBarText = String();
236
237   d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled();
238   d->m_bJavaEnabled = d->m_settings->isJavaEnabled();
239   d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled();
240
241   // initializing d->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
242   // data arrives) (Simon)
243   d->m_url = url;
244   if (d->m_url.protocol().startsWith("http") && !d->m_url.host().isEmpty() && d->m_url.path().isEmpty())
245     d->m_url.setPath("/");
246   d->m_workingURL = d->m_url;
247
248   started();
249
250   return true;
251 }
252
253 void Frame::didExplicitOpen()
254 {
255   d->m_bComplete = false;
256   d->m_bLoadEventEmitted = false;
257     
258   // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
259   // from a subsequent window.document.open / window.document.write call. 
260   // Cancelling redirection here works for all cases because document.open 
261   // implicitly precedes document.write.
262   cancelRedirection(); 
263 }
264
265 void Frame::stopLoading(bool sendUnload)
266 {
267   if (d->m_doc && d->m_doc->tokenizer())
268     d->m_doc->tokenizer()->stopParsing();
269     
270   if (d->m_job)
271   {
272     d->m_job->kill();
273     d->m_job = 0;
274   }
275
276   if (sendUnload) {
277     if (d->m_doc) {
278       if (d->m_bLoadEventEmitted && !d->m_bUnloadEventEmitted) {
279         d->m_doc->dispatchWindowEvent(unloadEvent, false, false);
280         if (d->m_doc)
281           d->m_doc->updateRendering();
282         d->m_bUnloadEventEmitted = true;
283       }
284     }
285     
286     if (d->m_doc && !d->m_doc->inPageCache())
287       d->m_doc->removeAllEventListenersFromAllNodes();
288   }
289
290   d->m_bComplete = true; // to avoid calling completed() in finishedParsing() (David)
291   d->m_bLoadingMainResource = false;
292   d->m_bLoadEventEmitted = true; // don't want that one either
293   d->m_cachePolicy = KIO::CC_Verify; // Why here?
294
295   if (d->m_doc && d->m_doc->parsing()) {
296     finishedParsing();
297     d->m_doc->setParsing(false);
298   }
299   
300   d->m_workingURL = KURL();
301
302   if (Document *doc = d->m_doc.get()) {
303     if (DocLoader *docLoader = doc->docLoader())
304       Cache::loader()->cancelRequests(docLoader);
305       XMLHttpRequest::cancelRequests(doc);
306   }
307
308   // tell all subframes to stop as well
309   for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
310       child->stopLoading(sendUnload);
311
312   d->m_bPendingChildRedirection = false;
313
314   cancelRedirection();
315 }
316
317 BrowserExtension *Frame::browserExtension() const
318 {
319   return d->m_extension;
320 }
321
322 FrameView* Frame::view() const
323 {
324     return d->m_view.get();
325 }
326
327 void Frame::setView(FrameView* view)
328 {
329     d->m_view = view;
330 }
331
332 bool Frame::jScriptEnabled() const
333 {
334     return d->m_bJScriptEnabled;
335 }
336
337 KJSProxy *Frame::jScript()
338 {
339     if (!d->m_bJScriptEnabled)
340         return 0;
341
342     if (!d->m_jscript)
343         d->m_jscript = new KJSProxy(this);
344
345     return d->m_jscript;
346 }
347
348 static bool getString(JSValue* result, DeprecatedString& string)
349 {
350     if (!result)
351         return false;
352     JSLock lock;
353     UString ustring;
354     if (!result->getString(ustring))
355         return false;
356     string = ustring;
357     return true;
358 }
359
360 void Frame::replaceContentsWithScriptResult(const KURL& url)
361 {
362     JSValue* ret = executeScript(0, KURL::decode_string(url.url().mid(strlen("javascript:"))));
363     DeprecatedString scriptResult;
364     if (getString(ret, scriptResult)) {
365         begin();
366         write(scriptResult);
367         end();
368     }
369 }
370
371 JSValue* Frame::executeScript(Node* n, const DeprecatedString& script, bool forceUserGesture)
372 {
373   KJSProxy *proxy = jScript();
374
375   if (!proxy)
376     return 0;
377
378   d->m_runningScripts++;
379   // If forceUserGesture is true, then make the script interpreter
380   // treat it as if triggered by a user gesture even if there is no
381   // current DOM event being processed.
382   JSValue* ret = proxy->evaluate(forceUserGesture ? DeprecatedString::null : d->m_url.url(), 0, script, n);
383   d->m_runningScripts--;
384
385   if (!d->m_runningScripts)
386       submitFormAgain();
387
388   Document::updateDocumentsRendering();
389
390   return ret;
391 }
392
393 bool Frame::javaEnabled() const
394 {
395     return d->m_settings->isJavaEnabled();
396 }
397
398 bool Frame::pluginsEnabled() const
399 {
400     return d->m_bPluginsEnabled;
401 }
402
403 void Frame::setAutoloadImages(bool enable)
404 {
405   if (d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable)
406     return;
407
408   if (d->m_doc)
409     d->m_doc->docLoader()->setAutoloadImages(enable);
410 }
411
412 bool Frame::autoloadImages() const
413 {
414   if (d->m_doc)
415     return d->m_doc->docLoader()->autoloadImages();
416
417   return true;
418 }
419
420 void Frame::clear(bool clearWindowProperties)
421 {
422   if (d->m_bCleared)
423     return;
424   d->m_bCleared = true;
425   d->m_mousePressNode = 0;
426
427   if (d->m_doc) {
428     d->m_doc->cancelParsing();
429     d->m_doc->detach();
430   }
431
432   // Moving past doc so that onUnload works.
433   if (clearWindowProperties && d->m_jscript)
434     d->m_jscript->clear();
435
436   if (d->m_view)
437     d->m_view->clear();
438
439   // do not drop the document before the jscript and view are cleared, as some destructors
440   // might still try to access the document.
441   d->m_doc = 0;
442   d->m_decoder = 0;
443
444   d->m_plugins.clear();
445
446   d->m_scheduledRedirection = noRedirectionScheduled;
447   d->m_delayRedirect = 0;
448   d->m_redirectURL = DeprecatedString::null;
449   d->m_redirectReferrer = DeprecatedString::null;
450   d->m_redirectLockHistory = true;
451   d->m_redirectUserGesture = false;
452   d->m_bHTTPRefresh = false;
453   d->m_bFirstData = true;
454
455   d->m_bMousePressed = false;
456
457   if (!d->m_haveEncoding)
458     d->m_encoding = DeprecatedString::null;
459 }
460
461 Document *Frame::document() const
462 {
463     if (d)
464         return d->m_doc.get();
465     return 0;
466 }
467
468 void Frame::setDocument(Document* newDoc)
469 {
470     if (d) {
471         if (d->m_doc)
472             d->m_doc->detach();
473         d->m_doc = newDoc;
474         if (newDoc)
475             newDoc->attach();
476     }
477 }
478
479 void Frame::receivedFirstData()
480 {
481     begin(d->m_workingURL);
482
483     d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy);
484     d->m_workingURL = KURL();
485
486     // When the first data arrives, the metadata has just been made available
487     DeprecatedString qData;
488
489     // Support for http-refresh
490     qData = d->m_job->queryMetaData("http-refresh").deprecatedString();
491     if (!qData.isEmpty()) {
492       double delay;
493       int pos = qData.find(';');
494       if (pos == -1)
495         pos = qData.find(',');
496
497       if (pos == -1) {
498         delay = qData.stripWhiteSpace().toDouble();
499         // We want a new history item if the refresh timeout > 1 second
500         scheduleRedirection(delay, d->m_url.url(), delay <= 1);
501       } else {
502         int end_pos = qData.length();
503         delay = qData.left(pos).stripWhiteSpace().toDouble();
504         while (qData[++pos] == ' ');
505         if (qData.find("url", pos, false) == pos) {
506           pos += 3;
507           while (qData[pos] == ' ' || qData[pos] == '=')
508               pos++;
509           if (qData[pos] == '"') {
510               pos++;
511               int index = end_pos-1;
512               while (index > pos) {
513                 if (qData[index] == '"')
514                     break;
515                 index--;
516               }
517               if (index > pos)
518                 end_pos = index;
519           }
520         }
521         // We want a new history item if the refresh timeout > 1 second
522         scheduleRedirection(delay, d->m_doc->completeURL(qData.mid(pos, end_pos)), delay <= 1);
523       }
524       d->m_bHTTPRefresh = true;
525     }
526
527     // Support for http last-modified
528     d->m_lastModified = d->m_job->queryMetaData("modified");
529 }
530
531 void Frame::receivedAllData(TransferJob* job)
532 {
533     d->m_job = 0;
534
535     if (job->error()) {
536         checkCompleted();
537         return;
538     }
539
540     d->m_workingURL = KURL();
541
542     if (d->m_doc->parsing())
543         end(); // will call completed()
544 }
545
546 void Frame::childBegin()
547 {
548     // We need to do this when the child is created so as to avoid the parent thining the child
549     // is complete before it has even started loading.
550     // FIXME: do we really still need this?
551     d->m_bComplete = false;
552 }
553
554 void Frame::setResourceRequest(const ResourceRequest& request)
555 {
556     d->m_request = request;
557 }
558
559 const ResourceRequest& Frame::resourceRequest() const
560 {
561     return d->m_request;
562 }
563
564 void Frame::begin(const KURL& url)
565 {
566   if (d->m_workingURL.isEmpty())
567     createEmptyDocument(); // Creates an empty document if we don't have one already
568
569   clear();
570   partClearedInBegin();
571
572   d->m_bCleared = false;
573   d->m_bComplete = false;
574   d->m_bLoadEventEmitted = false;
575   d->m_bLoadingMainResource = true;
576
577   KURL ref(url);
578   ref.setUser(DeprecatedString());
579   ref.setPass(DeprecatedString());
580   ref.setRef(DeprecatedString());
581   d->m_referrer = ref.url();
582   d->m_url = url;
583   KURL baseurl;
584
585   // We don't need KDE chained URI handling or window caption setting
586   if (!d->m_url.isEmpty())
587     baseurl = d->m_url;
588
589   if (DOMImplementation::isXMLMIMEType(d->m_request.m_responseMIMEType))
590     d->m_doc = DOMImplementation::instance()->createDocument(d->m_view.get());
591   else
592     d->m_doc = DOMImplementation::instance()->createHTMLDocument(d->m_view.get());
593
594   if (!d->m_doc->attached())
595     d->m_doc->attach();
596   d->m_doc->setURL(d->m_url.url());
597   // We prefer m_baseURL over d->m_url because d->m_url changes when we are
598   // about to load a new page.
599   d->m_doc->setBaseURL(baseurl.url());
600   if (d->m_decoder)
601     d->m_doc->setDecoder(d->m_decoder.get());
602
603   updatePolicyBaseURL();
604
605   setAutoloadImages(d->m_settings->autoLoadImages());
606   const KURL& userStyleSheet = d->m_settings->userStyleSheetLocation();
607
608   if (!userStyleSheet.isEmpty())
609     setUserStyleSheetLocation(KURL(userStyleSheet));
610
611   restoreDocumentState();
612
613   d->m_doc->implicitOpen();
614   // clear widget
615   if (d->m_view)
616     d->m_view->resizeContents(0, 0);
617 }
618
619 void Frame::write(const char* str, int len)
620 {
621     if (!d->m_decoder) {
622         d->m_decoder = new Decoder;
623         if (!d->m_encoding.isNull())
624             d->m_decoder->setEncodingName(d->m_encoding.latin1(),
625                 d->m_haveEncoding ? Decoder::UserChosenEncoding : Decoder::EncodingFromHTTPHeader);
626         else
627             d->m_decoder->setEncodingName(settings()->encoding().latin1(), Decoder::DefaultEncoding);
628
629         if (d->m_doc)
630             d->m_doc->setDecoder(d->m_decoder.get());
631     }
632   if (len == 0)
633     return;
634
635   if (len == -1)
636     len = strlen(str);
637
638   DeprecatedString decoded = d->m_decoder->decode(str, len);
639
640   if (decoded.isEmpty())
641     return;
642
643   if (d->m_bFirstData) {
644       // determine the parse mode
645       d->m_doc->determineParseMode(decoded);
646       d->m_bFirstData = false;
647
648       // ### this is still quite hacky, but should work a lot better than the old solution
649       if (d->m_decoder->visuallyOrdered()) d->m_doc->setVisuallyOrdered();
650       d->m_doc->recalcStyle(Node::Force);
651   }
652
653   if (Tokenizer* t = d->m_doc->tokenizer())
654       t->write(decoded, true);
655 }
656
657 void Frame::write(const DeprecatedString& str)
658 {
659   if (str.isNull())
660     return;
661
662   if (d->m_bFirstData) {
663       // determine the parse mode
664       d->m_doc->setParseMode(Document::Strict);
665       d->m_bFirstData = false;
666   }
667   Tokenizer* t = d->m_doc->tokenizer();
668   if (t)
669     t->write(str, true);
670 }
671
672 void Frame::end()
673 {
674     d->m_bLoadingMainResource = false;
675     endIfNotLoading();
676 }
677
678 void Frame::endIfNotLoading()
679 {
680     if (d->m_bLoadingMainResource)
681         return;
682
683     // make sure nothing's left in there...
684     if (d->m_doc) {
685         if (d->m_decoder)
686             write(d->m_decoder->flush());
687         d->m_doc->finishParsing();
688     } else
689         // WebKit partially uses WebCore when loading non-HTML docs.  In these cases doc==nil, but
690         // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
691         // become true.  An example is when a subframe is a pure text doc, and that subframe is the
692         // last one to complete.
693         checkCompleted();
694 }
695
696 void Frame::stop()
697 {
698     if (d->m_doc) {
699         if (d->m_doc->tokenizer())
700             d->m_doc->tokenizer()->stopParsing();
701         d->m_doc->finishParsing();
702     } else
703         // WebKit partially uses WebCore when loading non-HTML docs.  In these cases doc==nil, but
704         // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
705         // become true.  An example is when a subframe is a pure text doc, and that subframe is the
706         // last one to complete.
707         checkCompleted();
708 }
709
710 void Frame::gotoAnchor()
711 {
712     // If our URL has no ref, then we have no place we need to jump to.
713     if (!d->m_url.hasRef())
714         return;
715
716     DeprecatedString ref = d->m_url.encodedHtmlRef();
717     if (!gotoAnchor(ref)) {
718         // Can't use htmlRef() here because it doesn't know which encoding to use to decode.
719         // Decoding here has to match encoding in completeURL, which means it has to use the
720         // page's encoding rather than UTF-8.
721         if (d->m_decoder)
722             gotoAnchor(KURL::decode_string(ref, d->m_decoder->encoding()));
723     }
724 }
725
726 void Frame::finishedParsing()
727 {
728   RefPtr<Frame> protector(this);
729   checkCompleted();
730
731   if (!d->m_view)
732     return; // We are being destroyed by something checkCompleted called.
733
734   // check if the scrollbars are really needed for the content
735   // if not, remove them, relayout, and repaint
736
737   d->m_view->restoreScrollBar();
738   gotoAnchor();
739 }
740
741 void Frame::loadDone()
742 {
743     if (d->m_doc)
744         checkCompleted();
745 }
746
747 void Frame::checkCompleted()
748 {
749   // Any frame that hasn't completed yet ?
750   for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
751       if (!child->d->m_bComplete)
752           return;
753
754   // Have we completed before?
755   if (d->m_bComplete)
756       return;
757
758   // Are we still parsing?
759   if (d->m_doc && d->m_doc->parsing())
760       return;
761
762   // Still waiting for images/scripts from the loader ?
763   int requests = 0;
764   if (d->m_doc && d->m_doc->docLoader())
765       requests = Cache::loader()->numRequests(d->m_doc->docLoader());
766
767   if (requests > 0)
768       return;
769
770   // OK, completed.
771   // Now do what should be done when we are really completed.
772   d->m_bComplete = true;
773
774   checkEmitLoadEvent(); // if we didn't do it before
775
776   if (d->m_scheduledRedirection != noRedirectionScheduled) {
777       // Do not start redirection for frames here! That action is
778       // deferred until the parent emits a completed signal.
779       if (!tree()->parent())
780           startRedirectionTimer();
781
782       completed(true);
783   } else {
784       completed(d->m_bPendingChildRedirection);
785   }
786 }
787
788 void Frame::checkEmitLoadEvent()
789 {
790     if (d->m_bLoadEventEmitted || !d->m_doc || d->m_doc->parsing())
791         return;
792
793     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
794         if (!child->d->m_bComplete) // still got a frame running -> too early
795             return;
796
797     // All frames completed -> set their domain to the frameset's domain
798     // This must only be done when loading the frameset initially (#22039),
799     // not when following a link in a frame (#44162).
800     if (d->m_doc) {
801         String domain = d->m_doc->domain();
802         for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
803             if (child->d->m_doc)
804                 child->d->m_doc->setDomain(domain);
805     }
806
807     d->m_bLoadEventEmitted = true;
808     d->m_bUnloadEventEmitted = false;
809     if (d->m_doc)
810         d->m_doc->implicitClose();
811 }
812
813 const KHTMLSettings *Frame::settings() const
814 {
815   return d->m_settings;
816 }
817
818 KURL Frame::baseURL() const
819 {
820     if (!d->m_doc)
821         return KURL();
822     return d->m_doc->baseURL();
823 }
824
825 String Frame::baseTarget() const
826 {
827     if (!d->m_doc)
828         return DeprecatedString();
829     return d->m_doc->baseTarget();
830 }
831
832 KURL Frame::completeURL(const DeprecatedString& url)
833 {
834     if (!d->m_doc)
835         return url;
836
837     return KURL(d->m_doc->completeURL(url));
838 }
839
840 void Frame::scheduleRedirection(double delay, const DeprecatedString& url, bool doLockHistory)
841 {
842     if (delay < 0 || delay > INT_MAX / 1000)
843       return;
844     if (d->m_scheduledRedirection == noRedirectionScheduled || delay <= d->m_delayRedirect)
845     {
846        d->m_scheduledRedirection = redirectionScheduled;
847        d->m_delayRedirect = delay;
848        d->m_redirectURL = url;
849        d->m_redirectReferrer = DeprecatedString::null;
850        d->m_redirectLockHistory = doLockHistory;
851        d->m_redirectUserGesture = false;
852
853        stopRedirectionTimer();
854        if (d->m_bComplete)
855          startRedirectionTimer();
856     }
857 }
858
859 void Frame::scheduleLocationChange(const DeprecatedString& url, const DeprecatedString& referrer, bool lockHistory, bool userGesture)
860 {
861     // Handle a location change of a page with no document as a special case.
862     // This may happen when a frame changes the location of another frame.
863     d->m_scheduledRedirection = d->m_doc ? locationChangeScheduled : locationChangeScheduledDuringLoad;
864     
865     // If a redirect was scheduled during a load, then stop the current load.
866     // Otherwise when the current load transitions from a provisional to a 
867     // committed state, pending redirects may be cancelled. 
868     if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad) {
869         stopLoading(true);   
870     }
871     
872     d->m_delayRedirect = 0;
873     d->m_redirectURL = url;
874     d->m_redirectReferrer = referrer;
875     d->m_redirectLockHistory = lockHistory;
876     d->m_redirectUserGesture = userGesture;
877     stopRedirectionTimer();
878     if (d->m_bComplete)
879         startRedirectionTimer();
880 }
881
882 bool Frame::isScheduledLocationChangePending() const
883 {
884     switch (d->m_scheduledRedirection) {
885         case noRedirectionScheduled:
886         case redirectionScheduled:
887             return false;
888         case historyNavigationScheduled:
889         case locationChangeScheduled:
890         case locationChangeScheduledDuringLoad:
891             return true;
892     }
893     return false;
894 }
895
896 void Frame::scheduleHistoryNavigation(int steps)
897 {
898     // navigation will always be allowed in the 0 steps case, which is OK because
899     // that's supposed to force a reload.
900     if (!canGoBackOrForward(steps)) {
901         cancelRedirection();
902         return;
903     }
904
905     d->m_scheduledRedirection = historyNavigationScheduled;
906     d->m_delayRedirect = 0;
907     d->m_redirectURL = DeprecatedString::null;
908     d->m_redirectReferrer = DeprecatedString::null;
909     d->m_scheduledHistoryNavigationSteps = steps;
910     stopRedirectionTimer();
911     if (d->m_bComplete)
912         startRedirectionTimer();
913 }
914
915 void Frame::cancelRedirection(bool cancelWithLoadInProgress)
916 {
917     if (d) {
918         d->m_cancelWithLoadInProgress = cancelWithLoadInProgress;
919         d->m_scheduledRedirection = noRedirectionScheduled;
920         stopRedirectionTimer();
921     }
922 }
923
924 void Frame::changeLocation(const DeprecatedString& URL, const DeprecatedString& referrer, bool lockHistory, bool userGesture)
925 {
926     if (URL.find("javascript:", 0, false) == 0) {
927         DeprecatedString script = KURL::decode_string(URL.mid(11));
928         JSValue* result = executeScript(0, script, userGesture);
929         DeprecatedString scriptResult;
930         if (getString(result, scriptResult)) {
931             begin(url());
932             write(scriptResult);
933             end();
934         }
935         return;
936     }
937
938     ResourceRequest request(completeURL(URL));
939     request.setLockHistory(lockHistory);
940     if (!referrer.isEmpty())
941         request.setReferrer(referrer);
942
943     urlSelected(request, "_self");
944 }
945
946 void Frame::redirectionTimerFired(Timer<Frame>*)
947 {
948     if (d->m_scheduledRedirection == historyNavigationScheduled) {
949         d->m_scheduledRedirection = noRedirectionScheduled;
950
951         // Special case for go(0) from a frame -> reload only the frame
952         // go(i!=0) from a frame navigates into the history of the frame only,
953         // in both IE and NS (but not in Mozilla).... we can't easily do that
954         // in Konqueror...
955         if (d->m_scheduledHistoryNavigationSteps == 0) // add && parent() to get only frames, but doesn't matter
956             openURL(url()); /// ## need args.reload=true?
957         else {
958             if (d->m_extension) {
959                 d->m_extension->goBackOrForward(d->m_scheduledHistoryNavigationSteps);
960             }
961         }
962         return;
963     }
964
965     DeprecatedString URL = d->m_redirectURL;
966     DeprecatedString referrer = d->m_redirectReferrer;
967     bool lockHistory = d->m_redirectLockHistory;
968     bool userGesture = d->m_redirectUserGesture;
969
970     d->m_scheduledRedirection = noRedirectionScheduled;
971     d->m_delayRedirect = 0;
972     d->m_redirectURL = DeprecatedString::null;
973     d->m_redirectReferrer = DeprecatedString::null;
974
975     changeLocation(URL, referrer, lockHistory, userGesture);
976 }
977
978 void Frame::receivedRedirect(TransferJob*, const KURL& url)
979 {
980     d->m_workingURL = url;
981 }
982
983 DeprecatedString Frame::encoding() const
984 {
985     if (d->m_haveEncoding && !d->m_encoding.isEmpty())
986         return d->m_encoding;
987
988     if (d->m_decoder && d->m_decoder->encoding().isValid())
989         return d->m_decoder->encodingName();
990
991     return settings()->encoding();
992 }
993
994 void Frame::setUserStyleSheetLocation(const KURL& url)
995 {
996     delete d->m_userStyleSheetLoader;
997     d->m_userStyleSheetLoader = 0;
998     if (d->m_doc && d->m_doc->docLoader())
999         d->m_userStyleSheetLoader = new UserStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
1000 }
1001
1002 void Frame::setUserStyleSheet(const String& styleSheet)
1003 {
1004     delete d->m_userStyleSheetLoader;
1005     d->m_userStyleSheetLoader = 0;
1006     if (d->m_doc)
1007         d->m_doc->setUserStyleSheet(styleSheet);
1008 }
1009
1010 bool Frame::gotoAnchor(const String& name)
1011 {
1012   if (!d->m_doc)
1013     return false;
1014
1015   Node *n = d->m_doc->getElementById(AtomicString(name));
1016   if (!n) {
1017     HTMLCollection *anchors =
1018         new HTMLCollection(d->m_doc.get(), HTMLCollection::DOC_ANCHORS);
1019     anchors->ref();
1020     n = anchors->namedItem(name, !d->m_doc->inCompatMode());
1021     anchors->deref();
1022   }
1023
1024   d->m_doc->setCSSTarget(n); // Setting to null will clear the current target.
1025   
1026   // Implement the rule that "" and "top" both mean top of page as in other browsers.
1027   if (!n && !(name.isEmpty() || name.lower() == "top"))
1028       return false;
1029
1030   // We need to update the layout before scrolling, otherwise we could
1031   // really mess things up if an anchor scroll comes at a bad moment.
1032   if (d->m_doc) {
1033     d->m_doc->updateRendering();
1034     // Only do a layout if changes have occurred that make it necessary.      
1035     if (d->m_view && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout()) {
1036       d->m_view->layout();
1037     }
1038   }
1039   
1040   // Scroll nested layers and frames to reveal the anchor.
1041   RenderObject *renderer;
1042   IntRect rect;
1043   if (n) {
1044       renderer = n->renderer();
1045       rect = n->getRect();
1046   } else {
1047     // If there's no node, we should scroll to the top of the document.
1048       renderer = d->m_doc->renderer();
1049       rect = IntRect();
1050   }
1051
1052   if (renderer) {
1053     // Align to the top and to the closest side (this matches other browsers).
1054     renderer->enclosingLayer()->scrollRectToVisible(rect, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways);
1055   }
1056   
1057   return true;
1058 }
1059
1060 void Frame::setStandardFont(const String& name)
1061 {
1062     d->m_settings->setStdFontName(AtomicString(name));
1063 }
1064
1065 void Frame::setFixedFont(const String& name)
1066 {
1067     d->m_settings->setFixedFontName(AtomicString(name));
1068 }
1069
1070 String Frame::selectedText() const
1071 {
1072     return plainText(selection().toRange().get());
1073 }
1074
1075 bool Frame::hasSelection() const
1076 {
1077     return d->m_selection.isCaretOrRange();
1078 }
1079
1080 SelectionController& Frame::selection() const
1081 {
1082     return d->m_selection;
1083 }
1084
1085 TextGranularity Frame::selectionGranularity() const
1086 {
1087     return d->m_selectionGranularity;
1088 }
1089
1090 void Frame::setSelectionGranularity(TextGranularity granularity) const
1091 {
1092     d->m_selectionGranularity = granularity;
1093 }
1094
1095 SelectionController& Frame::dragCaret() const
1096 {
1097     return d->m_dragCaret;
1098 }
1099
1100 const Selection& Frame::mark() const
1101 {
1102     return d->m_mark;
1103 }
1104
1105 void Frame::setMark(const Selection& s)
1106 {
1107     d->m_mark = s;
1108 }
1109
1110 void Frame::setSelection(const SelectionController& s, bool closeTyping, bool keepTypingStyle)
1111 {
1112     if (d->m_selection == s) {
1113         return;
1114     }
1115     
1116     clearCaretRectIfNeeded();
1117
1118     SelectionController oldSelection = d->m_selection;
1119
1120     d->m_selection = s;
1121     if (!s.isNone())
1122         setFocusNodeIfNeeded();
1123     
1124     selectionLayoutChanged();
1125
1126     // Always clear the x position used for vertical arrow navigation.
1127     // It will be restored by the vertical arrow navigation code if necessary.
1128     d->m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation;
1129
1130     if (closeTyping)
1131         TypingCommand::closeTyping(lastEditCommand());
1132
1133     if (!keepTypingStyle)
1134         clearTypingStyle();
1135     
1136     respondToChangedSelection(oldSelection, closeTyping);
1137 }
1138
1139 void Frame::setDragCaret(const SelectionController& dragCaret)
1140 {
1141     if (d->m_dragCaret != dragCaret) {
1142         d->m_dragCaret.needsCaretRepaint();
1143         d->m_dragCaret = dragCaret;
1144         d->m_dragCaret.needsCaretRepaint();
1145     }
1146 }
1147
1148 void Frame::invalidateSelection()
1149 {
1150     clearCaretRectIfNeeded();
1151     d->m_selection.setNeedsLayout();
1152     selectionLayoutChanged();
1153 }
1154
1155 void Frame::setCaretVisible(bool flag)
1156 {
1157     if (d->m_caretVisible == flag)
1158         return;
1159     clearCaretRectIfNeeded();
1160     if (flag)
1161         setFocusNodeIfNeeded();
1162     d->m_caretVisible = flag;
1163     selectionLayoutChanged();
1164 }
1165
1166
1167 void Frame::clearCaretRectIfNeeded()
1168 {
1169     if (d->m_caretPaint) {
1170         d->m_caretPaint = false;
1171         d->m_selection.needsCaretRepaint();
1172     }        
1173 }
1174
1175 // Helper function that tells whether a particular node is an element that has an entire
1176 // Frame and FrameView, a <frame>, <iframe>, or <object>.
1177 static bool isFrameElement(const Node *n)
1178 {
1179     if (!n)
1180         return false;
1181     RenderObject *renderer = n->renderer();
1182     if (!renderer || !renderer->isWidget())
1183         return false;
1184     Widget *widget = static_cast<RenderWidget *>(renderer)->widget();
1185     return widget && widget->isFrameView();
1186 }
1187
1188 void Frame::setFocusNodeIfNeeded()
1189 {
1190     if (!document() || d->m_selection.isNone() || !d->m_isFocused)
1191         return;
1192
1193     Node *startNode = d->m_selection.start().node();
1194     Node *target = startNode ? startNode->rootEditableElement() : 0;
1195     
1196     if (target) {
1197         RenderObject* renderer = target->renderer();
1198
1199         // Walk up the render tree to search for a node to focus.
1200         // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
1201         while (renderer) {
1202             // We don't want to set focus on a subframe when selecting in a parent frame,
1203             // so add the !isFrameElement check here. There's probably a better way to make this
1204             // work in the long term, but this is the safest fix at this time.
1205             if (target && target->isMouseFocusable() && !isFrameElement(target)) {
1206                 document()->setFocusNode(target);
1207                 return;
1208             }
1209             renderer = renderer->parent();
1210             if (renderer)
1211                 target = renderer->element();
1212         }
1213         document()->setFocusNode(0);
1214     }
1215 }
1216
1217 void Frame::selectionLayoutChanged()
1218 {
1219     // kill any caret blink timer now running
1220     d->m_caretBlinkTimer.stop();
1221
1222     // see if a new caret blink timer needs to be started
1223     if (d->m_caretVisible && d->m_caretBlinks && 
1224         d->m_selection.isCaret() && d->m_selection.start().node()->isContentEditable()) {
1225         d->m_caretBlinkTimer.startRepeating(caretBlinkFrequency);
1226         d->m_caretPaint = true;
1227         d->m_selection.needsCaretRepaint();
1228     }
1229
1230     if (d->m_doc)
1231         d->m_doc->updateSelection();
1232 }
1233
1234 void Frame::setXPosForVerticalArrowNavigation(int x)
1235 {
1236     d->m_xPosForVerticalArrowNavigation = x;
1237 }
1238
1239 int Frame::xPosForVerticalArrowNavigation() const
1240 {
1241     return d->m_xPosForVerticalArrowNavigation;
1242 }
1243
1244 void Frame::caretBlinkTimerFired(Timer<Frame>*)
1245 {
1246     // Might be better to turn the timer off during some of these circumstances
1247     // and assert rather then letting the timer fire and do nothing here.
1248     // Could do that in selectionLayoutChanged.
1249
1250     if (!d->m_caretVisible)
1251         return;
1252     if (!d->m_caretBlinks)
1253         return;
1254     if (!d->m_selection.isCaret())
1255         return;
1256     bool caretPaint = d->m_caretPaint;
1257     if (d->m_bMousePressed && caretPaint)
1258         return;
1259     d->m_caretPaint = !caretPaint;
1260     d->m_selection.needsCaretRepaint();
1261 }
1262
1263 void Frame::paintCaret(GraphicsContext* p, const IntRect& rect) const
1264 {
1265     if (d->m_caretPaint)
1266         d->m_selection.paintCaret(p, rect);
1267 }
1268
1269 void Frame::paintDragCaret(GraphicsContext* p, const IntRect& rect) const
1270 {
1271     d->m_dragCaret.paintCaret(p, rect);
1272 }
1273
1274 void Frame::urlSelected(const DeprecatedString& url, const String& target)
1275 {
1276     urlSelected(ResourceRequest(completeURL(url)), target);
1277 }
1278
1279 void Frame::urlSelected(const ResourceRequest& request, const String& _target)
1280 {
1281   String target = _target;
1282   if (target.isEmpty() && d->m_doc)
1283     target = d->m_doc->baseTarget();
1284
1285   const KURL& url = request.url();
1286
1287   if (url.url().startsWith("javascript:", false)) {
1288     executeScript(0, KURL::decode_string(url.url().mid(11)), true);
1289     return;
1290   }
1291
1292   if (!url.isValid())
1293     // ### ERROR HANDLING
1294     return;
1295
1296   ResourceRequest requestCopy = request;
1297   requestCopy.frameName = target;
1298
1299   if (d->m_bHTTPRefresh)
1300     d->m_bHTTPRefresh = false;
1301
1302   if (!d->m_referrer.isEmpty())
1303     requestCopy.setReferrer(d->m_referrer);
1304
1305   urlSelected(requestCopy);
1306 }
1307
1308 bool Frame::requestFrame(RenderPart* renderer, const String& urlParam, const AtomicString& frameName)
1309 {
1310     DeprecatedString _url = urlParam.deprecatedString();
1311     // Support for <frame src="javascript:string">
1312     KURL scriptURL;
1313     KURL url;
1314     if (_url.startsWith("javascript:", false)) {
1315         scriptURL = _url;
1316         url = "about:blank";
1317     } else
1318         url = completeURL(_url);
1319
1320     Frame* frame = tree()->child(frameName);
1321     if (frame) {
1322         ResourceRequest request(url);
1323         request.setReferrer(d->m_referrer);
1324         request.reload = (d->m_cachePolicy == KIO::CC_Reload) || (d->m_cachePolicy == KIO::CC_Refresh);
1325         frame->openURLRequest(request);
1326     } else
1327         frame = loadSubframe(renderer, url, frameName, d->m_referrer);
1328     
1329     if (!frame)
1330         return false;
1331
1332     if (!scriptURL.isEmpty())
1333         frame->replaceContentsWithScriptResult(scriptURL);
1334
1335     return true;
1336 }
1337
1338 bool Frame::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName,
1339                           const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
1340 {
1341     KURL completedURL;
1342     if (!url.isEmpty())
1343         completedURL = completeURL(url.deprecatedString());
1344     
1345     if (url.isEmpty() && mimeType.isEmpty())
1346         return true;
1347     
1348     bool useFallback;
1349     if (shouldUsePlugin(renderer->element(), completedURL, mimeType, renderer->hasFallbackContent(), useFallback))
1350         return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
1351
1352     // FIXME: ok to always make a new one? when does the old frame get removed?
1353     return loadSubframe(renderer, completedURL, frameName, d->m_referrer);
1354 }
1355
1356 bool Frame::shouldUsePlugin(Node* element, const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
1357 {
1358     useFallback = false;
1359     ObjectContentType objectType = objectContentType(url, mimeType);
1360
1361     // if an object's content can't be handled and it has no fallback, let
1362     // it be handled as a plugin to show the broken plugin icon
1363     if (objectType == ObjectContentNone && hasFallback)
1364         useFallback = true;
1365
1366     return objectType == ObjectContentNone || objectType == ObjectContentPlugin;
1367 }
1368
1369
1370 bool Frame::loadPlugin(RenderPart *renderer, const KURL& url, const String& mimeType, 
1371                        const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
1372 {
1373     if (useFallback) {
1374         checkEmitLoadEvent();
1375         return false;
1376     }
1377
1378     Plugin* plugin = createPlugin(url, paramNames, paramValues, mimeType);
1379     if (!plugin) {
1380         checkEmitLoadEvent();
1381         return false;
1382     }
1383     d->m_plugins.append(plugin);
1384     
1385     if (renderer && plugin->view())
1386         renderer->setWidget(plugin->view());
1387     
1388     checkEmitLoadEvent();
1389     
1390     return true;
1391 }
1392
1393 Frame* Frame::loadSubframe(RenderPart* renderer, const KURL& url, const String& name, const String& referrer)
1394 {
1395     Frame* frame = createFrame(url, name, renderer, referrer);
1396     if (!frame)  {
1397         checkEmitLoadEvent();
1398         return 0;
1399     }
1400     
1401     frame->childBegin();
1402     
1403     if (renderer && frame->view())
1404         renderer->setWidget(frame->view());
1405     
1406     checkEmitLoadEvent();
1407     
1408     // In these cases, the synchronous load would have finished
1409     // before we could connect the signals, so make sure to send the 
1410     // completed() signal for the child by hand
1411     // FIXME: In this case the Frame will have finished loading before 
1412     // it's being added to the child list. It would be a good idea to
1413     // create the child first, then invoke the loader separately.
1414     if (url.isEmpty() || url == "about:blank") {
1415         frame->completed(false);
1416         frame->checkCompleted();
1417     }
1418
1419     return frame;
1420 }
1421
1422 void Frame::clearRecordedFormValues()
1423 {
1424     d->m_formAboutToBeSubmitted = 0;
1425     d->m_formValuesAboutToBeSubmitted.clear();
1426 }
1427
1428 void Frame::recordFormValue(const String& name, const String& value, PassRefPtr<HTMLFormElement> element)
1429 {
1430     d->m_formAboutToBeSubmitted = element;
1431     d->m_formValuesAboutToBeSubmitted.set(name, value);
1432 }
1433
1434 void Frame::submitFormAgain()
1435 {
1436     FramePrivate::SubmitForm* form = d->m_submitForm;
1437     d->m_submitForm = 0;
1438     if (d->m_doc && !d->m_doc->parsing() && form)
1439         submitForm(form->submitAction, form->submitUrl, form->submitFormData,
1440             form->target, form->submitContentType, form->submitBoundary);
1441     delete form;
1442 }
1443
1444 void Frame::submitForm(const char *action, const String& url, const FormData& formData, const String& _target, const String& contentType, const String& boundary)
1445 {
1446   KURL u = completeURL(url.deprecatedString());
1447
1448   if (!u.isValid())
1449     // ### ERROR HANDLING!
1450     return;
1451
1452   DeprecatedString urlstring = u.url();
1453   if (urlstring.startsWith("javascript:", false)) {
1454     urlstring = KURL::decode_string(urlstring);
1455     d->m_executingJavaScriptFormAction = true;
1456     executeScript(0, urlstring.mid(11));
1457     d->m_executingJavaScriptFormAction = false;
1458     return;
1459   }
1460
1461   ResourceRequest request;
1462
1463   if (!d->m_referrer.isEmpty())
1464      request.setReferrer(d->m_referrer);
1465
1466   request.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
1467
1468   // Handle mailto: forms
1469   if (u.protocol() == "mailto") {
1470       // 1)  Check for attach= and strip it
1471       DeprecatedString q = u.query().mid(1);
1472       DeprecatedStringList nvps = DeprecatedStringList::split("&", q);
1473       bool triedToAttach = false;
1474
1475       for (DeprecatedStringList::Iterator nvp = nvps.begin(); nvp != nvps.end(); ++nvp) {
1476          DeprecatedStringList pair = DeprecatedStringList::split("=", *nvp);
1477          if (pair.count() >= 2) {
1478             if (pair.first().lower() == "attach") {
1479                nvp = nvps.remove(nvp);
1480                triedToAttach = true;
1481             }
1482          }
1483       }
1484
1485
1486       // 2)  Append body=
1487       DeprecatedString bodyEnc;
1488       if (contentType.lower() == "multipart/form-data")
1489          // FIXME: is this correct?  I suspect not
1490          bodyEnc = KURL::encode_string(formData.flattenToString());
1491       else if (contentType.lower() == "text/plain") {
1492          // Convention seems to be to decode, and s/&/\n/
1493          DeprecatedString tmpbody = formData.flattenToString();
1494          tmpbody.replace('&', '\n');
1495          tmpbody.replace('+', ' ');
1496          tmpbody = KURL::decode_string(tmpbody);  // Decode the rest of it
1497          bodyEnc = KURL::encode_string(tmpbody);  // Recode for the URL
1498       } else
1499          bodyEnc = KURL::encode_string(formData.flattenToString());
1500
1501       nvps.append(String::sprintf("body=%s", bodyEnc.latin1()).deprecatedString());
1502       q = nvps.join("&");
1503       u.setQuery(q);
1504   } 
1505
1506   if (strcmp(action, "get") == 0) {
1507     if (u.protocol() != "mailto")
1508        u.setQuery(formData.flattenToString());
1509     request.setDoPost(false);
1510   } else {
1511     request.postData = formData;
1512     request.setDoPost(true);
1513
1514     // construct some user headers if necessary
1515     if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
1516       request.setContentType("Content-Type: application/x-www-form-urlencoded");
1517     else // contentType must be "multipart/form-data"
1518       request.setContentType("Content-Type: " + contentType + "; boundary=" + boundary);
1519   }
1520
1521   if (d->m_doc->parsing() || d->m_runningScripts > 0) {
1522     if (d->m_submitForm)
1523         return;
1524     d->m_submitForm = new FramePrivate::SubmitForm;
1525     d->m_submitForm->submitAction = action;
1526     d->m_submitForm->submitUrl = url;
1527     d->m_submitForm->submitFormData = formData;
1528     d->m_submitForm->target = _target;
1529     d->m_submitForm->submitContentType = contentType;
1530     d->m_submitForm->submitBoundary = boundary;
1531   } else {
1532       request.setURL(u);
1533       submitForm(request);
1534   }
1535 }
1536
1537 void Frame::parentCompleted()
1538 {
1539     if (d->m_scheduledRedirection != noRedirectionScheduled && !d->m_redirectionTimer.isActive())
1540         startRedirectionTimer();
1541 }
1542
1543 void Frame::childCompleted(bool complete)
1544 {
1545     if (complete && !tree()->parent())
1546         d->m_bPendingChildRedirection = true;
1547     checkCompleted();
1548 }
1549
1550 int Frame::zoomFactor() const
1551 {
1552   return d->m_zoomFactor;
1553 }
1554
1555 void Frame::setZoomFactor(int percent)
1556 {  
1557   if (d->m_zoomFactor == percent)
1558       return;
1559
1560   d->m_zoomFactor = percent;
1561
1562   if (d->m_doc)
1563       d->m_doc->recalcStyle(Node::Force);
1564
1565   for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
1566       child->setZoomFactor(d->m_zoomFactor);
1567
1568   if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout())
1569       view()->layout();
1570 }
1571
1572 void Frame::setJSStatusBarText(const String& text)
1573 {
1574     d->m_kjsStatusBarText = text;
1575     setStatusBarText(d->m_kjsStatusBarText);
1576 }
1577
1578 void Frame::setJSDefaultStatusBarText(const String& text)
1579 {
1580     d->m_kjsDefaultStatusBarText = text;
1581     setStatusBarText(d->m_kjsDefaultStatusBarText);
1582 }
1583
1584 String Frame::jsStatusBarText() const
1585 {
1586     return d->m_kjsStatusBarText;
1587 }
1588
1589 String Frame::jsDefaultStatusBarText() const
1590 {
1591    return d->m_kjsDefaultStatusBarText;
1592 }
1593
1594 DeprecatedString Frame::referrer() const
1595 {
1596     return d->m_referrer;
1597 }
1598
1599 String Frame::lastModified() const
1600 {
1601     return d->m_lastModified;
1602 }
1603
1604 void Frame::reparseConfiguration()
1605 {
1606     setAutoloadImages(d->m_settings->autoLoadImages());
1607         
1608     d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled();
1609     d->m_bJavaEnabled = d->m_settings->isJavaEnabled();
1610     d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled();
1611
1612     const KURL& userStyleSheetLocation = d->m_settings->userStyleSheetLocation();
1613     if (!userStyleSheetLocation.isEmpty())
1614         setUserStyleSheetLocation(userStyleSheetLocation);
1615     else
1616         setUserStyleSheet(String());
1617
1618     // FIXME: It's not entirely clear why the following is needed.
1619     // The document automatically does this as required when you set the style sheet.
1620     // But we had problems when this code was removed. Details are in
1621     // <http://bugzilla.opendarwin.org/show_bug.cgi?id=8079>.
1622     if (d->m_doc)
1623         d->m_doc->updateStyleSelector();
1624 }
1625
1626 bool Frame::shouldDragAutoNode(Node *node, const IntPoint& point) const
1627 {
1628     // No KDE impl yet
1629     return false;
1630 }
1631
1632 bool Frame::isPointInsideSelection(const IntPoint& point)
1633 {
1634     // Treat a collapsed selection like no selection.
1635     if (!d->m_selection.isRange())
1636         return false;
1637     if (!document()->renderer()) 
1638         return false;
1639     
1640     RenderObject::NodeInfo nodeInfo(true, true);
1641     document()->renderer()->layer()->hitTest(nodeInfo, point);
1642     Node *innerNode = nodeInfo.innerNode();
1643     if (!innerNode || !innerNode->renderer())
1644         return false;
1645     
1646     Position pos(innerNode->renderer()->positionForPoint(point).deepEquivalent());
1647     if (pos.isNull())
1648         return false;
1649
1650     Node *n = d->m_selection.start().node();
1651     while (n) {
1652         if (n == pos.node()) {
1653             if ((n == d->m_selection.start().node() && pos.offset() < d->m_selection.start().offset()) ||
1654                 (n == d->m_selection.end().node() && pos.offset() > d->m_selection.end().offset())) {
1655                 return false;
1656             }
1657             return true;
1658         }
1659         if (n == d->m_selection.end().node())
1660             break;
1661         n = n->traverseNextNode();
1662     }
1663
1664    return false;
1665 }
1666
1667 void Frame::selectClosestWordFromMouseEvent(const PlatformMouseEvent& mouse, Node *innerNode)
1668 {
1669     SelectionController selection;
1670
1671     if (innerNode && innerNode->renderer() && mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
1672         IntPoint vPoint = view()->viewportToContents(mouse.pos());
1673         VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
1674         if (pos.isNotNull()) {
1675             selection.moveTo(pos);
1676             selection.expandUsingGranularity(WordGranularity);
1677         }
1678     }
1679     
1680     if (selection.isRange()) {
1681         d->m_selectionGranularity = WordGranularity;
1682         d->m_beganSelectingText = true;
1683     }
1684     
1685     if (shouldChangeSelection(selection))
1686         setSelection(selection);
1687 }
1688
1689 void Frame::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
1690 {
1691     if (event.event().button() == LeftButton) {
1692         if (selection().isRange())
1693             // A double-click when range is already selected
1694             // should not change the selection.  So, do not call
1695             // selectClosestWordFromMouseEvent, but do set
1696             // m_beganSelectingText to prevent handleMouseReleaseEvent
1697             // from setting caret selection.
1698             d->m_beganSelectingText = true;
1699         else
1700             selectClosestWordFromMouseEvent(event.event(), event.targetNode());
1701     }
1702 }
1703
1704 void Frame::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
1705 {
1706     Node *innerNode = event.targetNode();
1707     
1708     if (event.event().button() == LeftButton && innerNode && innerNode->renderer() &&
1709         mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
1710         SelectionController selection;
1711         IntPoint vPoint = view()->viewportToContents(event.event().pos());
1712         VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
1713         if (pos.isNotNull()) {
1714             selection.moveTo(pos);
1715             selection.expandUsingGranularity(ParagraphGranularity);
1716         }
1717         if (selection.isRange()) {
1718             d->m_selectionGranularity = ParagraphGranularity;
1719             d->m_beganSelectingText = true;
1720         }
1721         
1722         if (shouldChangeSelection(selection))
1723             setSelection(selection);
1724     }
1725 }
1726
1727 void Frame::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
1728 {
1729     Node *innerNode = event.targetNode();
1730     
1731     if (event.event().button() == LeftButton) {
1732         if (innerNode && innerNode->renderer() &&
1733             mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
1734             SelectionController sel;
1735             
1736             // Extend the selection if the Shift key is down, unless the click is in a link.
1737             bool extendSelection = event.event().shiftKey() && !event.isOverLink();
1738
1739             // Don't restart the selection when the mouse is pressed on an
1740             // existing selection so we can allow for text dragging.
1741             IntPoint vPoint = view()->viewportToContents(event.event().pos());
1742             if (!extendSelection && isPointInsideSelection(vPoint))
1743                 return;
1744
1745             VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(vPoint));
1746             if (visiblePos.isNull())
1747                 visiblePos = VisiblePosition(innerNode, innerNode->caretMinOffset(), DOWNSTREAM);
1748             Position pos = visiblePos.deepEquivalent();
1749             
1750             sel = selection();
1751             if (extendSelection && sel.isCaretOrRange()) {
1752                 sel.clearModifyBias();
1753                 
1754                 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection 
1755                 // was created right-to-left
1756                 Position start = sel.start();
1757                 short before = Range::compareBoundaryPoints(pos.node(), pos.offset(), start.node(), start.offset());
1758                 if (before <= 0)
1759                     sel.setBaseAndExtent(pos.node(), pos.offset(), sel.end().node(), sel.end().offset());
1760                 else
1761                     sel.setBaseAndExtent(start.node(), start.offset(), pos.node(), pos.offset());
1762
1763                 if (d->m_selectionGranularity != CharacterGranularity)
1764                     sel.expandUsingGranularity(d->m_selectionGranularity);
1765                 d->m_beganSelectingText = true;
1766             } else {
1767                 sel = SelectionController(visiblePos);
1768                 d->m_selectionGranularity = CharacterGranularity;
1769             }
1770             
1771             if (shouldChangeSelection(sel))
1772                 setSelection(sel);
1773         }
1774     }
1775 }
1776
1777 void Frame::handleMousePressEvent(const MouseEventWithHitTestResults& event)
1778 {
1779     Node *innerNode = event.targetNode();
1780
1781     d->m_mousePressNode = innerNode;
1782     d->m_dragStartPos = event.event().pos();
1783
1784     if (event.event().button() == LeftButton || event.event().button() == MiddleButton) {
1785         d->m_bMousePressed = true;
1786         d->m_beganSelectingText = false;
1787
1788         if (event.event().clickCount() == 2) {
1789             handleMousePressEventDoubleClick(event);
1790             return;
1791         }
1792         if (event.event().clickCount() >= 3) {
1793             handleMousePressEventTripleClick(event);
1794             return;
1795         }
1796         handleMousePressEventSingleClick(event);
1797     }
1798 }
1799
1800 void Frame::handleMouseMoveEvent(const MouseEventWithHitTestResults& event)
1801 {
1802     // Mouse not pressed. Do nothing.
1803     if (!d->m_bMousePressed)
1804         return;
1805
1806     Node *innerNode = event.targetNode();
1807
1808     if (event.event().button() != 0 || !innerNode || !innerNode->renderer() || !mouseDownMayStartSelect() || !innerNode->renderer()->shouldSelect())
1809         return;
1810
1811     // handle making selection
1812     IntPoint vPoint = view()->viewportToContents(event.event().pos());
1813     VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
1814
1815     // Don't modify the selection if we're not on a node.
1816     if (pos.isNull())
1817         return;
1818
1819     // Restart the selection if this is the first mouse move. This work is usually
1820     // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
1821     SelectionController sel = selection();
1822     sel.clearModifyBias();
1823     
1824     if (!d->m_beganSelectingText) {
1825         d->m_beganSelectingText = true;
1826         sel.moveTo(pos);
1827     }
1828
1829     sel.setExtent(pos);
1830     if (d->m_selectionGranularity != CharacterGranularity)
1831         sel.expandUsingGranularity(d->m_selectionGranularity);
1832
1833     if (shouldChangeSelection(sel))
1834         setSelection(sel);
1835 }
1836
1837 void Frame::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
1838 {
1839     stopAutoscrollTimer();
1840     
1841     // Used to prevent mouseMoveEvent from initiating a drag before
1842     // the mouse is pressed again.
1843     d->m_bMousePressed = false;
1844   
1845     // Clear the selection if the mouse didn't move after the last mouse press.
1846     // We do this so when clicking on the selection, the selection goes away.
1847     // However, if we are editing, place the caret.
1848     if (mouseDownMayStartSelect() && !d->m_beganSelectingText
1849             && d->m_dragStartPos == event.event().pos()
1850             && d->m_selection.isRange()) {
1851         SelectionController selection;
1852         Node *node = event.targetNode();
1853         if (node && node->isContentEditable() && node->renderer()) {
1854             IntPoint vPoint = view()->viewportToContents(event.event().pos());
1855             VisiblePosition pos = node->renderer()->positionForPoint(vPoint);
1856             selection.moveTo(pos);
1857         }
1858         if (shouldChangeSelection(selection))
1859             setSelection(selection);
1860     }
1861     selectFrameElementInParentIfFullySelected();
1862 }
1863
1864 void Frame::selectAll()
1865 {
1866     if (!d->m_doc)
1867         return;
1868     
1869     Node *startNode = d->m_selection.start().node();
1870     Node *root = startNode && startNode->isContentEditable() ? startNode->rootEditableElement() : d->m_doc->documentElement();
1871     
1872     selectContentsOfNode(root);
1873     selectFrameElementInParentIfFullySelected();
1874 }
1875
1876 bool Frame::selectContentsOfNode(Node* node)
1877 {
1878     SelectionController sel = SelectionController(Selection::selectionFromContentsOfNode(node));    
1879     if (shouldChangeSelection(sel)) {
1880         setSelection(sel);
1881         return true;
1882     }
1883     return false;
1884 }
1885
1886 bool Frame::shouldChangeSelection(const SelectionController& newselection) const
1887 {
1888     return shouldChangeSelection(d->m_selection, newselection, newselection.affinity(), false);
1889 }
1890
1891 bool Frame::shouldBeginEditing(const Range *range) const
1892 {
1893     return true;
1894 }
1895
1896 bool Frame::shouldEndEditing(const Range *range) const
1897 {
1898     return true;
1899 }
1900
1901 bool Frame::isContentEditable() const 
1902 {
1903     if (!d->m_doc)
1904         return false;
1905     return d->m_doc->inDesignMode();
1906 }
1907
1908 void Frame::textFieldDidBeginEditing(Element* input)
1909 {
1910 }
1911
1912 void Frame::textFieldDidEndEditing(Element* input)
1913 {
1914 }
1915
1916 void Frame::textDidChangeInTextField(Element* input)
1917 {
1918 }
1919
1920 bool Frame::doTextFieldCommandFromEvent(Element* input, const PlatformKeyboardEvent* evt)
1921 {
1922     return false;
1923 }
1924
1925 void Frame::textWillBeDeletedInTextField(Element* input)
1926 {
1927 }
1928
1929 EditCommandPtr Frame::lastEditCommand()
1930 {
1931     return d->m_lastEditCommand;
1932 }
1933
1934 void dispatchEditableContentChangedEvent(Node* root)
1935 {
1936     if (!root)
1937         return;
1938         
1939     ExceptionCode ec = 0;
1940     RefPtr<Event> evt = new Event(khtmlEditableContentChangedEvent, false, false);
1941     EventTargetNodeCast(root)->dispatchEvent(evt, ec, true);
1942 }
1943
1944 void Frame::appliedEditing(EditCommandPtr& cmd)
1945 {
1946     SelectionController sel(cmd.endingSelection());
1947     if (shouldChangeSelection(sel))
1948         setSelection(sel, false);
1949     
1950     dispatchEditableContentChangedEvent(!selection().isNone() ? selection().start().node()->rootEditableElement() : 0);
1951
1952     // Now set the typing style from the command. Clear it when done.
1953     // This helps make the case work where you completely delete a piece
1954     // of styled text and then type a character immediately after.
1955     // That new character needs to take on the style of the just-deleted text.
1956     // FIXME: Improve typing style.
1957     // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
1958     if (cmd.typingStyle()) {
1959         setTypingStyle(cmd.typingStyle());
1960         cmd.setTypingStyle(0);
1961     }
1962
1963     // Command will be equal to last edit command only in the case of typing
1964     if (d->m_lastEditCommand == cmd) {
1965         assert(cmd.isTypingCommand());
1966     }
1967     else {
1968         // Only register a new undo command if the command passed in is
1969         // different from the last command
1970         registerCommandForUndo(cmd);
1971         d->m_lastEditCommand = cmd;
1972     }
1973     respondToChangedContents();
1974 }
1975
1976 void Frame::unappliedEditing(EditCommandPtr& cmd)
1977 {
1978     SelectionController sel(cmd.startingSelection());
1979     if (shouldChangeSelection(sel))
1980         setSelection(sel, true);
1981     
1982     dispatchEditableContentChangedEvent(!selection().isNone() ? selection().start().node()->rootEditableElement() : 0);
1983         
1984     registerCommandForRedo(cmd);
1985     respondToChangedContents();
1986     d->m_lastEditCommand = EditCommandPtr::emptyCommand();
1987 }
1988
1989 void Frame::reappliedEditing(EditCommandPtr& cmd)
1990 {
1991     SelectionController sel(cmd.endingSelection());
1992     if (shouldChangeSelection(sel))
1993         setSelection(sel, true);
1994     
1995     dispatchEditableContentChangedEvent(!selection().isNone() ? selection().start().node()->rootEditableElement() : 0);
1996         
1997     registerCommandForUndo(cmd);
1998     respondToChangedContents();
1999     d->m_lastEditCommand = EditCommandPtr::emptyCommand();
2000 }
2001
2002 CSSMutableStyleDeclaration *Frame::typingStyle() const
2003 {
2004     return d->m_typingStyle.get();
2005 }
2006
2007 void Frame::setTypingStyle(CSSMutableStyleDeclaration *style)
2008 {
2009     d->m_typingStyle = style;
2010 }
2011
2012 void Frame::clearTypingStyle()
2013 {
2014     d->m_typingStyle = 0;
2015 }
2016
2017 JSValue* Frame::executeScript(const String& filename, int baseLine, Node* n, const DeprecatedString& script)
2018 {
2019   // FIXME: This is missing stuff that the other executeScript has.
2020   // --> d->m_runningScripts and submitFormAgain.
2021   // Why is that OK?
2022   KJSProxy *proxy = jScript();
2023   if (!proxy)
2024     return 0;
2025   JSValue* ret = proxy->evaluate(filename, baseLine, script, n);
2026   Document::updateDocumentsRendering();
2027   return ret;
2028 }
2029
2030 Frame *Frame::opener()
2031 {
2032     return d->m_opener;
2033 }
2034
2035 void Frame::setOpener(Frame* opener)
2036 {
2037     if (d->m_opener)
2038         d->m_opener->d->m_openedFrames.remove(this);
2039     if (opener)
2040         opener->d->m_openedFrames.add(this);
2041     d->m_opener = opener;
2042 }
2043
2044 bool Frame::openedByJS()
2045 {
2046     return d->m_openedByJS;
2047 }
2048
2049 void Frame::setOpenedByJS(bool _openedByJS)
2050 {
2051     d->m_openedByJS = _openedByJS;
2052 }
2053
2054 bool Frame::tabsToLinks() const
2055 {
2056     return true;
2057 }
2058
2059 bool Frame::tabsToAllControls() const
2060 {
2061     return true;
2062 }
2063
2064 void Frame::copyToPasteboard()
2065 {
2066     issueCopyCommand();
2067 }
2068
2069 void Frame::cutToPasteboard()
2070 {
2071     issueCutCommand();
2072 }
2073
2074 void Frame::pasteFromPasteboard()
2075 {
2076     issuePasteCommand();
2077 }
2078
2079 void Frame::pasteAndMatchStyle()
2080 {
2081     issuePasteAndMatchStyleCommand();
2082 }
2083
2084 void Frame::transpose()
2085 {
2086     issueTransposeCommand();
2087 }
2088
2089 void Frame::redo()
2090 {
2091     issueRedoCommand();
2092 }
2093
2094 void Frame::undo()
2095 {
2096     issueUndoCommand();
2097 }
2098
2099
2100 void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction editingAction)
2101 {
2102     if (!style || style->length() == 0) {
2103         clearTypingStyle();
2104         return;
2105     }
2106
2107     // Calculate the current typing style.
2108     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
2109     if (typingStyle()) {
2110         typingStyle()->merge(mutableStyle.get());
2111         mutableStyle = typingStyle();
2112     }
2113
2114     Node *node = VisiblePosition(selection().start(), selection().affinity()).deepEquivalent().node();
2115     CSSComputedStyleDeclaration computedStyle(node);
2116     computedStyle.diff(mutableStyle.get());
2117     
2118     // Handle block styles, substracting these from the typing style.
2119     RefPtr<CSSMutableStyleDeclaration> blockStyle = mutableStyle->copyBlockProperties();
2120     blockStyle->diff(mutableStyle.get());
2121     if (document() && blockStyle->length() > 0) {
2122         EditCommandPtr cmd(new ApplyStyleCommand(document(), blockStyle.get(), editingAction));
2123         cmd.apply();
2124     }
2125     
2126     // Set the remaining style as the typing style.
2127     d->m_typingStyle = mutableStyle.release();
2128 }
2129
2130 void Frame::applyStyle(CSSStyleDeclaration *style, EditAction editingAction)
2131 {
2132     switch (selection().state()) {
2133         case Selection::NONE:
2134             // do nothing
2135             break;
2136         case Selection::CARET: {
2137             computeAndSetTypingStyle(style, editingAction);
2138             break;
2139         }
2140         case Selection::RANGE:
2141             if (document() && style) {
2142                 EditCommandPtr cmd(new ApplyStyleCommand(document(), style, editingAction));
2143                 cmd.apply();
2144             }
2145             break;
2146     }
2147 }
2148
2149 void Frame::applyParagraphStyle(CSSStyleDeclaration *style, EditAction editingAction)
2150 {
2151     switch (selection().state()) {
2152         case Selection::NONE:
2153             // do nothing
2154             break;
2155         case Selection::CARET:
2156         case Selection::RANGE:
2157             if (document() && style) {
2158                 EditCommandPtr cmd(new ApplyStyleCommand(document(), style, editingAction, ApplyStyleCommand::ForceBlockProperties));
2159                 cmd.apply();
2160             }
2161             break;
2162     }
2163 }
2164
2165 static void updateState(CSSMutableStyleDeclaration *desiredStyle, CSSComputedStyleDeclaration *computedStyle, bool& atStart, Frame::TriState& state)
2166 {
2167     DeprecatedValueListConstIterator<CSSProperty> end;
2168     for (DeprecatedValueListConstIterator<CSSProperty> it = desiredStyle->valuesIterator(); it != end; ++it) {
2169         int propertyID = (*it).id();
2170         String desiredProperty = desiredStyle->getPropertyValue(propertyID);
2171         String computedProperty = computedStyle->getPropertyValue(propertyID);
2172         Frame::TriState propertyState = equalIgnoringCase(desiredProperty, computedProperty)
2173             ? Frame::trueTriState : Frame::falseTriState;
2174         if (atStart) {
2175             state = propertyState;
2176             atStart = false;
2177         } else if (state != propertyState) {
2178             state = Frame::mixedTriState;
2179             break;
2180         }
2181     }
2182 }
2183
2184 Frame::TriState Frame::selectionHasStyle(CSSStyleDeclaration *style) const
2185 {
2186     bool atStart = true;
2187     TriState state = falseTriState;
2188
2189     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
2190
2191     if (!d->m_selection.isRange()) {
2192         Node* nodeToRemove;
2193         RefPtr<CSSComputedStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
2194         if (!selectionStyle)
2195             return falseTriState;
2196         updateState(mutableStyle.get(), selectionStyle.get(), atStart, state);
2197         if (nodeToRemove) {
2198             ExceptionCode ec = 0;
2199             nodeToRemove->remove(ec);
2200             assert(ec == 0);
2201         }
2202     } else {
2203         for (Node* node = d->m_selection.start().node(); node; node = node->traverseNextNode()) {
2204             RefPtr<CSSComputedStyleDeclaration> computedStyle = new CSSComputedStyleDeclaration(node);
2205             if (computedStyle)
2206                 updateState(mutableStyle.get(), computedStyle.get(), atStart, state);
2207             if (state == mixedTriState)
2208                 break;
2209             if (node == d->m_selection.end().node())
2210                 break;
2211         }
2212     }
2213
2214     return state;
2215 }
2216
2217 bool Frame::selectionStartHasStyle(CSSStyleDeclaration *style) const
2218 {
2219     Node* nodeToRemove;
2220     RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
2221     if (!selectionStyle)
2222         return false;
2223
2224     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
2225
2226     bool match = true;
2227     DeprecatedValueListConstIterator<CSSProperty> end;
2228     for (DeprecatedValueListConstIterator<CSSProperty> it = mutableStyle->valuesIterator(); it != end; ++it) {
2229         int propertyID = (*it).id();
2230         if (!equalIgnoringCase(mutableStyle->getPropertyValue(propertyID), selectionStyle->getPropertyValue(propertyID))) {
2231             match = false;
2232             break;
2233         }
2234     }
2235
2236     if (nodeToRemove) {
2237         ExceptionCode ec = 0;
2238         nodeToRemove->remove(ec);
2239         assert(ec == 0);
2240     }
2241
2242     return match;
2243 }
2244
2245 String Frame::selectionStartStylePropertyValue(int stylePropertyID) const
2246 {
2247     Node *nodeToRemove;
2248     RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
2249     if (!selectionStyle)
2250         return String();
2251
2252     String value = selectionStyle->getPropertyValue(stylePropertyID);
2253
2254     if (nodeToRemove) {
2255         ExceptionCode ec = 0;
2256         nodeToRemove->remove(ec);
2257         assert(ec == 0);
2258     }
2259
2260     return value;
2261 }
2262
2263 CSSComputedStyleDeclaration *Frame::selectionComputedStyle(Node *&nodeToRemove) const
2264 {
2265     nodeToRemove = 0;
2266
2267     if (!document())
2268         return 0;
2269
2270     if (d->m_selection.isNone())
2271         return 0;
2272
2273     RefPtr<Range> range(d->m_selection.toRange());
2274     Position pos = range->editingStartPosition();
2275
2276     Element *elem = pos.element();
2277     if (!elem)
2278         return 0;
2279     
2280     RefPtr<Element> styleElement = elem;
2281     ExceptionCode ec = 0;
2282
2283     if (d->m_typingStyle) {
2284         styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
2285         assert(ec == 0);
2286
2287         styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
2288         assert(ec == 0);
2289         
2290         styleElement->appendChild(document()->createEditingTextNode(""), ec);
2291         assert(ec == 0);
2292
2293         if (elem->renderer() && elem->renderer()->canHaveChildren()) {
2294             elem->appendChild(styleElement, ec);
2295         } else {
2296             Node *parent = elem->parent();
2297             Node *next = elem->nextSibling();
2298
2299             if (next) {
2300                 parent->insertBefore(styleElement, next, ec);
2301             } else {
2302                 parent->appendChild(styleElement, ec);
2303             }
2304         }
2305         assert(ec == 0);
2306
2307         nodeToRemove = styleElement.get();
2308     }
2309
2310     return new CSSComputedStyleDeclaration(styleElement);
2311 }
2312
2313 void Frame::applyEditingStyleToBodyElement() const
2314 {
2315     if (!d->m_doc)
2316         return;
2317         
2318     RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
2319     unsigned len = list->length();
2320     for (unsigned i = 0; i < len; i++) {
2321         applyEditingStyleToElement(static_cast<Element *>(list->item(i)));    
2322     }
2323 }
2324
2325 void Frame::removeEditingStyleFromBodyElement() const
2326 {
2327     if (!d->m_doc)
2328         return;
2329         
2330     RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
2331     unsigned len = list->length();
2332     for (unsigned i = 0; i < len; i++) {
2333         removeEditingStyleFromElement(static_cast<Element *>(list->item(i)));    
2334     }
2335 }
2336
2337 void Frame::applyEditingStyleToElement(Element *element) const
2338 {
2339     if (!element || !element->isHTMLElement())
2340         return;
2341     
2342     static_cast<HTMLElement *>(element)->setContentEditable("true");
2343 }
2344
2345 void Frame::removeEditingStyleFromElement(Element *element) const
2346 {
2347     if (!element || !element->isHTMLElement())
2348         return;
2349         
2350     static_cast<HTMLElement *>(element)->setContentEditable("false");        
2351 }
2352
2353
2354 bool Frame::isCharacterSmartReplaceExempt(const QChar&, bool)
2355 {
2356     // no smart replace
2357     return true;
2358 }
2359
2360 #if !NDEBUG
2361 static HashSet<Frame*> lifeSupportSet;
2362 #endif
2363
2364 void Frame::endAllLifeSupport()
2365 {
2366 #if !NDEBUG
2367     HashSet<Frame*> lifeSupportCopy = lifeSupportSet;
2368     HashSet<Frame*>::iterator end = lifeSupportCopy.end();
2369     for (HashSet<Frame*>::iterator it = lifeSupportCopy.begin(); it != end; ++it)
2370         (*it)->endLifeSupport();
2371 #endif
2372 }
2373
2374 void Frame::keepAlive()
2375 {
2376     if (d->m_lifeSupportTimer.isActive())
2377         return;
2378     ref();
2379 #if !NDEBUG
2380     lifeSupportSet.add(this);
2381 #endif
2382     d->m_lifeSupportTimer.startOneShot(0);
2383 }
2384
2385 void Frame::endLifeSupport()
2386 {
2387     if (!d->m_lifeSupportTimer.isActive())
2388         return;
2389     d->m_lifeSupportTimer.stop();
2390 #if !NDEBUG
2391     lifeSupportSet.remove(this);
2392 #endif
2393     deref();
2394 }
2395
2396 void Frame::lifeSupportTimerFired(Timer<Frame>*)
2397 {
2398 #if !NDEBUG
2399     lifeSupportSet.remove(this);
2400 #endif
2401     deref();
2402 }
2403
2404 // Workaround for the fact that it's hard to delete a frame.
2405 // Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
2406 // Can't do this implicitly as part of every setSelection call because in some contexts it might not be good
2407 // for the focus to move to another frame. So instead we call it from places where we are selecting with the
2408 // mouse or the keyboard after setting the selection.
2409 void Frame::selectFrameElementInParentIfFullySelected()
2410 {
2411     // Find the parent frame; if there is none, then we have nothing to do.
2412     Frame *parent = tree()->parent();
2413     if (!parent)
2414         return;
2415     FrameView *parentView = parent->view();
2416     if (!parentView)
2417         return;
2418
2419     // Check if the selection contains the entire frame contents; if not, then there is nothing to do.
2420     if (!d->m_selection.isRange())
2421         return;
2422     if (!isStartOfDocument(VisiblePosition(d->m_selection.start(), d->m_selection.affinity())))
2423         return;
2424     if (!isEndOfDocument(VisiblePosition(d->m_selection.end(), d->m_selection.affinity())))
2425         return;
2426
2427     // Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
2428     Document *doc = document();
2429     if (!doc)
2430         return;
2431     Element *ownerElement = doc->ownerElement();
2432     if (!ownerElement)
2433         return;
2434     Node *ownerElementParent = ownerElement->parentNode();
2435     if (!ownerElementParent)
2436         return;
2437         
2438     // This method's purpose is it to make it easier to select iframes (in order to delete them).  Don't do anything if the iframe isn't deletable.
2439     if (!ownerElementParent->isContentEditable())
2440         return;
2441
2442     // Create compute positions before and after the element.
2443     unsigned ownerElementNodeIndex = ownerElement->nodeIndex();
2444     VisiblePosition beforeOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex, SEL_DEFAULT_AFFINITY));
2445     VisiblePosition afterOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex + 1, VP_UPSTREAM_IF_POSSIBLE));
2446
2447     // Focus on the parent frame, and then select from before this element to after.
2448     if (parent->shouldChangeSelection(SelectionController(beforeOwnerElement, afterOwnerElement))) {
2449         parentView->setFocus();
2450         parent->setSelection(SelectionController(beforeOwnerElement, afterOwnerElement));
2451     }
2452 }
2453
2454 void Frame::handleFallbackContent()
2455 {
2456     Element* owner = ownerElement();
2457     if (!owner || !owner->hasTagName(objectTag))
2458         return;
2459     static_cast<HTMLObjectElement *>(owner)->renderFallbackContent();
2460 }
2461
2462 void Frame::setSettings(KHTMLSettings *settings)
2463 {
2464     d->m_settings = settings;
2465 }
2466
2467 void Frame::provisionalLoadStarted()
2468 {
2469     // we don't want to wait until we get an actual http response back
2470     // to cancel pending redirects, otherwise they might fire before
2471     // that happens.
2472     cancelRedirection(true);
2473 }
2474
2475 bool Frame::userGestureHint()
2476 {
2477     Frame *rootFrame = this;
2478     while (rootFrame->tree()->parent())
2479         rootFrame = rootFrame->tree()->parent();
2480
2481     if (rootFrame->jScript())
2482         return rootFrame->jScript()->interpreter()->wasRunByUserGesture();
2483
2484     return true; // If JavaScript is disabled, a user gesture must have initiated the navigation
2485 }
2486
2487 RenderObject *Frame::renderer() const
2488 {
2489     Document *doc = document();
2490     return doc ? doc->renderer() : 0;
2491 }
2492
2493 Element* Frame::ownerElement()
2494 {
2495     RenderPart* ownerElementRenderer = d->m_ownerRenderer;
2496     if (!ownerElementRenderer)
2497         return 0;
2498     return static_cast<Element*>(ownerElementRenderer->element());
2499 }
2500
2501 RenderPart* Frame::ownerRenderer()
2502 {
2503     return d->m_ownerRenderer;
2504 }
2505
2506 IntRect Frame::selectionRect() const
2507 {
2508     RenderCanvas *root = static_cast<RenderCanvas *>(renderer());
2509     if (!root)
2510         return IntRect();
2511
2512     return root->selectionRect();
2513 }
2514
2515 // returns FloatRect because going through IntRect would truncate any floats
2516 FloatRect Frame::visibleSelectionRect() const
2517 {
2518     if (!d->m_view)
2519         return FloatRect();
2520     
2521     return intersection(selectionRect(), d->m_view->visibleContentRect());
2522 }
2523
2524 bool Frame::isFrameSet() const
2525 {
2526     Document* document = d->m_doc.get();
2527     if (!document || !document->isHTMLDocument())
2528         return false;
2529     Node *body = static_cast<HTMLDocument *>(document)->body();
2530     return body && body->renderer() && body->hasTagName(framesetTag);
2531 }
2532
2533 bool Frame::openURL(const KURL& URL)
2534 {
2535     ASSERT_NOT_REACHED();
2536     return true;
2537 }
2538
2539 void Frame::didNotOpenURL(const KURL& URL)
2540 {
2541     if (d->m_submittedFormURL == URL)
2542         d->m_submittedFormURL = KURL();
2543 }
2544
2545 // Scans logically forward from "start", including any child frames
2546 static HTMLFormElement *scanForForm(Node *start)
2547 {
2548     Node *n;
2549     for (n = start; n; n = n->traverseNextNode()) {
2550         if (n->hasTagName(formTag))
2551             return static_cast<HTMLFormElement *>(n);
2552         else if (n->isHTMLElement() && static_cast<HTMLElement*>(n)->isGenericFormElement())
2553             return static_cast<HTMLGenericFormElement*>(n)->form();
2554         else if (n->hasTagName(frameTag) || n->hasTagName(iframeTag)) {
2555             Node *childDoc = static_cast<HTMLFrameElement *>(n)->contentDocument();
2556             if (HTMLFormElement *frameResult = scanForForm(childDoc))
2557                 return frameResult;
2558         }
2559     }
2560     return 0;
2561 }
2562
2563 // We look for either the form containing the current focus, or for one immediately after it
2564 HTMLFormElement *Frame::currentForm() const
2565 {
2566     // start looking either at the active (first responder) node, or where the selection is
2567     Node *start = d->m_doc ? d->m_doc->focusNode() : 0;
2568     if (!start)
2569         start = selection().start().node();
2570     
2571     // try walking up the node tree to find a form element
2572     Node *n;
2573     for (n = start; n; n = n->parentNode()) {
2574         if (n->hasTagName(formTag))
2575             return static_cast<HTMLFormElement *>(n);
2576         else if (n->isHTMLElement()
2577                    && static_cast<HTMLElement *>(n)->isGenericFormElement())
2578             return static_cast<HTMLGenericFormElement *>(n)->form();
2579     }
2580     
2581     // try walking forward in the node tree to find a form element
2582     return start ? scanForForm(start) : 0;
2583 }
2584
2585 void Frame::setEncoding(const DeprecatedString& name, bool userChosen)
2586 {
2587     if (!d->m_workingURL.isEmpty())
2588         receivedFirstData();
2589     d->m_encoding = name;
2590     d->m_haveEncoding = userChosen;
2591 }
2592
2593 void Frame::addData(const char *bytes, int length)
2594 {
2595     ASSERT(d->m_workingURL.isEmpty());
2596     ASSERT(d->m_doc);
2597     ASSERT(d->m_doc->parsing());
2598     write(bytes, length);
2599 }
2600
2601 // FIXME: should this go in SelectionController?
2602 void Frame::revealSelection()
2603 {
2604     IntRect rect;
2605     
2606     switch (selection().state()) {
2607         case Selection::NONE:
2608             return;
2609             
2610         case Selection::CARET:
2611             rect = selection().caretRect();
2612             break;
2613             
2614         case Selection::RANGE:
2615             rect = selectionRect();
2616             break;
2617     }
2618     
2619     Position start = selection().start();
2620     Position end = selection().end();
2621     ASSERT(start.node());
2622     if (start.node() && start.node()->renderer()) {
2623         RenderLayer *layer = start.node()->renderer()->enclosingLayer();
2624         if (layer) {
2625             ASSERT(!end.node() || !end.node()->renderer() 
2626                    || (end.node()->renderer()->enclosingLayer() == layer));
2627             layer->scrollRectToVisible(rect);
2628         }
2629     }
2630 }
2631
2632 // FIXME: should this be here?
2633 bool Frame::scrollOverflow(KWQScrollDirection direction, KWQScrollGranularity granularity)
2634 {
2635     if (!document()) {
2636         return false;
2637     }
2638     
2639     Node *node = document()->focusNode();
2640     if (node == 0) {
2641         node = d->m_mousePressNode.get();
2642     }
2643     
2644     if (node != 0) {
2645         RenderObject *r = node->renderer();
2646         if (r != 0) {
2647             return r->scroll(direction, granularity);
2648         }
2649     }
2650     
2651     return false;
2652 }
2653
2654 void Frame::handleAutoscroll(RenderLayer* layer)
2655 {
2656     if (d->m_autoscrollTimer.isActive())
2657         return;
2658     d->m_autoscrollLayer = layer;
2659     startAutoscrollTimer();
2660 }
2661
2662 void Frame::autoscrollTimerFired(Timer<Frame>*)
2663 {
2664     bool isStillDown = PlatformMouseEvent::isMouseButtonDown(LeftButton);  
2665     if (!isStillDown){
2666         stopAutoscrollTimer();
2667         return;
2668     }
2669     if (d->m_autoscrollLayer) {
2670         d->m_autoscrollLayer->autoscroll();
2671     } 
2672 }
2673
2674 void Frame::startAutoscrollTimer()
2675 {
2676     d->m_autoscrollTimer.startRepeating(autoscrollInterval);
2677 }
2678
2679 void Frame::stopAutoscrollTimer()
2680 {
2681     d->m_autoscrollTimer.stop();
2682 }
2683
2684 // FIXME: why is this here instead of on the FrameView?
2685 void Frame::paint(GraphicsContext* p, const IntRect& rect)
2686 {
2687 #if !NDEBUG
2688     bool fillWithRed;
2689     if (p->printing())
2690         fillWithRed = false; // Printing, don't fill with red (can't remember why).
2691     else if (!document() || document()->ownerElement())
2692         fillWithRed = false; // Subframe, don't fill with red.
2693     else if (view() && view()->isTransparent())
2694         fillWithRed = false; // Transparent, don't fill with red.
2695     else if (d->m_drawSelectionOnly)
2696         fillWithRed = false; // Selections are transparent, don't fill with red.
2697     else if (d->m_elementToDraw)
2698         fillWithRed = false; // Element images are transparent, don't fill with red.
2699     else
2700         fillWithRed = true;
2701     
2702     if (fillWithRed)
2703         p->fillRect(rect, Color(0xFF, 0, 0));
2704 #endif
2705     
2706     if (renderer()) {
2707         // d->m_elementToDraw is used to draw only one element
2708         RenderObject *eltRenderer = d->m_elementToDraw ? d->m_elementToDraw->renderer() : 0;
2709         renderer()->layer()->paint(p, rect, d->m_drawSelectionOnly, eltRenderer);
2710
2711 #if __APPLE__
2712         // Regions may have changed as a result of the visibility/z-index of element changing.
2713         if (renderer()->document()->dashboardRegionsDirty())
2714             renderer()->canvas()->view()->updateDashboardRegions();
2715 #endif
2716     } else
2717         LOG_ERROR("called Frame::paint with nil renderer");
2718 }
2719
2720 void Frame::adjustPageHeight(float *newBottom, float oldTop, float oldBottom, float bottomLimit)
2721 {
2722     RenderCanvas *root = static_cast<RenderCanvas *>(document()->renderer());
2723     if (root) {
2724         // Use a printer device, with painting disabled for the pagination phase
2725         GraphicsContext painter(true);
2726         painter.setPaintingDisabled(true);
2727         
2728         root->setTruncatedAt((int)floorf(oldBottom));
2729         IntRect dirtyRect(0, (int)floorf(oldTop),
2730                         root->docWidth(), (int)ceilf(oldBottom-oldTop));
2731         root->layer()->paint(&painter, dirtyRect);
2732         *newBottom = root->bestTruncatedAt();
2733         if (*newBottom == 0)
2734             *newBottom = oldBottom;
2735     } else
2736         *newBottom = oldBottom;
2737 }
2738
2739 PausedTimeouts *Frame::pauseTimeouts()
2740 {
2741 #if SVG_SUPPORT
2742     if (d->m_doc && d->m_doc->svgExtensions())
2743         d->m_doc->accessSVGExtensions()->pauseAnimations();
2744 #endif
2745
2746     if (d->m_doc && d->m_jscript) {
2747         if (Window *w = Window::retrieveWindow(this))
2748             return w->pauseTimeouts();
2749     }
2750     return 0;
2751 }
2752
2753 void Frame::resumeTimeouts(PausedTimeouts *t)
2754 {
2755 #if SVG_SUPPORT
2756     if (d->m_doc && d->m_doc->svgExtensions())
2757         d->m_doc->accessSVGExtensions()->unpauseAnimations();
2758 #endif
2759
2760     if (d->m_doc && d->m_jscript && d->m_bJScriptEnabled) {
2761         if (Window *w = Window::retrieveWindow(this))
2762             w->resumeTimeouts(t);
2763     }
2764 }
2765
2766 bool Frame::canCachePage()
2767 {
2768     // Only save page state if:
2769     // 1.  We're not a frame or frameset.
2770     // 2.  The page has no unload handler.
2771     // 3.  The page has no password fields.
2772     // 4.  The URL for the page is not https.
2773     // 5.  The page has no applets.
2774     if (tree()->childCount() || d->m_plugins.size() ||
2775         tree()->parent() ||
2776         d->m_url.protocol().startsWith("https") || 
2777         (d->m_doc && (d->m_doc->applets()->length() != 0 ||
2778                       d->m_doc->hasWindowEventListener(unloadEvent) ||
2779                       d->m_doc->hasPasswordField()))) {
2780         return false;
2781     }
2782     return true;
2783 }
2784
2785 void Frame::saveWindowProperties(KJS::SavedProperties *windowProperties)
2786 {
2787     Window *window = Window::retrieveWindow(this);
2788     if (window)
2789         window->saveProperties(*windowProperties);
2790 }
2791
2792 void Frame::saveLocationProperties(SavedProperties *locationProperties)
2793 {
2794     Window *window = Window::retrieveWindow(this);
2795     if (window) {
2796         JSLock lock;
2797         Location *location = window->location();
2798         location->saveProperties(*locationProperties);
2799     }
2800 }
2801
2802 void Frame::restoreWindowProperties(SavedProperties *windowProperties)
2803 {
2804     Window *window = Window::retrieveWindow(this);
2805     if (window)
2806         window->restoreProperties(*windowProperties);
2807 }
2808
2809 void Frame::restoreLocationProperties(SavedProperties *locationProperties)
2810 {
2811     Window *window = Window::retrieveWindow(this);
2812     if (window) {
2813         JSLock lock;
2814         Location *location = window->location();
2815         location->restoreProperties(*locationProperties);
2816     }
2817 }
2818
2819 void Frame::saveInterpreterBuiltins(SavedBuiltins& interpreterBuiltins)
2820 {
2821     if (jScript())
2822         jScript()->interpreter()->saveBuiltins(interpreterBuiltins);
2823 }
2824
2825 void Frame::restoreInterpreterBuiltins(const SavedBuiltins& interpreterBuiltins)
2826 {
2827     if (jScript())
2828         jScript()->interpreter()->restoreBuiltins(interpreterBuiltins);
2829 }
2830
2831 Frame *Frame::frameForWidget(const Widget *widget)
2832 {
2833     ASSERT_ARG(widget, widget);
2834     
2835     Node *node = nodeForWidget(widget);
2836     if (node)
2837         return frameForNode(node);
2838     
2839     // Assume all widgets are either form controls, or FrameViews.
2840     ASSERT(widget->isFrameView());
2841     return static_cast<const FrameView *>(widget)->frame();
2842 }
2843
2844 Frame *Frame::frameForNode(Node *node)
2845 {
2846     ASSERT_ARG(node, node);
2847     return node->document()->frame();
2848 }
2849
2850 Node* Frame::nodeForWidget(const Widget* widget)
2851 {
2852     ASSERT_ARG(widget, widget);
2853     WidgetClient* client = widget->client();
2854     if (!client)
2855         return 0;
2856     return client->element(const_cast<Widget*>(widget));
2857 }
2858
2859 void Frame::clearDocumentFocus(Widget *widget)
2860 {
2861     Node *node = nodeForWidget(widget);
2862     ASSERT(node);
2863     node->document()->setFocusNode(0);
2864 }
2865
2866 void Frame::updatePolicyBaseURL()
2867 {
2868     if (tree()->parent() && tree()->parent()->document())
2869         setPolicyBaseURL(tree()->parent()->document()->policyBaseURL());
2870     else
2871         setPolicyBaseURL(d->m_url.url());
2872 }
2873
2874 void Frame::setPolicyBaseURL(const String& s)
2875 {
2876     if (document())
2877         document()->setPolicyBaseURL(s);
2878     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
2879         child->setPolicyBaseURL(s);
2880 }
2881
2882 void Frame::forceLayout()
2883 {
2884     FrameView *v = d->m_view.get();
2885     if (v) {
2886         v->layout();
2887         // We cannot unschedule a pending relayout, since the force can be called with
2888         // a tiny rectangle from a drawRect update.  By unscheduling we in effect
2889         // "validate" and stop the necessary full repaint from occurring.  Basically any basic
2890         // append/remove DHTML is broken by this call.  For now, I have removed the optimization
2891         // until we have a better invalidation stategy. -dwh
2892         //v->unscheduleRelayout();
2893     }
2894 }
2895
2896 void Frame::forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth)
2897 {
2898     // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
2899     // the state of things before and after the layout
2900     RenderCanvas *root = static_cast<RenderCanvas *>(document()->renderer());
2901     if (root) {
2902         // This magic is basically copied from khtmlview::print
2903         int pageW = (int)ceilf(minPageWidth);
2904         root->setWidth(pageW);
2905         root->setNeedsLayoutAndMinMaxRecalc();
2906         forceLayout();
2907         
2908         // If we don't fit in the minimum page width, we'll lay out again. If we don't fit in the
2909         // maximum page width, we will lay out to the maximum page width and clip extra content.
2910         // FIXME: We are assuming a shrink-to-fit printing implementation.  A cropping
2911         // implementation should not do this!
2912         int rightmostPos = root->rightmostPosition();
2913         if (rightmostPos > minPageWidth) {
2914             pageW = min(rightmostPos, (int)ceilf(maxPageWidth));
2915             root->setWidth(pageW);
2916             root->setNeedsLayoutAndMinMaxRecalc();
2917             forceLayout();
2918         }
2919     }
2920 }
2921
2922 void Frame::sendResizeEvent()
2923 {
2924     if (Document* doc = document())
2925         doc->dispatchWindowEvent(EventNames::resizeEvent, false, false);
2926 }
2927
2928 void Frame::sendScrollEvent()
2929 {
2930     FrameView *v = d->m_view.get();
2931     if (v) {
2932         Document *doc = document();
2933         if (!doc)
2934             return;
2935         doc->dispatchHTMLEvent(scrollEvent, true, false);
2936     }
2937 }
2938
2939 bool Frame::scrollbarsVisible()
2940 {
2941     if (!view())
2942         return false;
2943     
2944     if (view()->hScrollBarMode() == ScrollBarAlwaysOff || view()->vScrollBarMode() == ScrollBarAlwaysOff)
2945         return false;
2946     
2947     return true;
2948 }
2949
2950 void Frame::addMetaData(const String& key, const String& value)
2951 {
2952     d->m_job->addMetaData(key, value);
2953 }
2954
2955 // This does the same kind of work that Frame::openURL does, except it relies on the fact
2956 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
2957 void Frame::scrollToAnchor(const KURL& URL)
2958 {
2959     d->m_url = URL;
2960     started();
2961     
2962     gotoAnchor();
2963     
2964     // It's important to model this as a load that starts and immediately finishes.
2965     // Otherwise, the parent frame may think we never finished loading.
2966     d->m_bComplete = false;
2967     checkCompleted();
2968 }
2969
2970 bool Frame::closeURL()
2971 {
2972     saveDocumentState();
2973     stopLoading(true);
2974     clearUndoRedoOperations();
2975     return true;
2976 }
2977
2978 bool Frame::canMouseDownStartSelect(Node* node)
2979 {
2980     if (!node || !node->renderer())
2981         return true;
2982     
2983     // Check to see if -webkit-user-select has been set to none
2984     if (!node->renderer()->canSelect())
2985         return false;
2986     
2987     // Some controls and images can't start a select on a mouse down.
2988     for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) {
2989         if (curr->style()->userSelect() == SELECT_IGNORE)
2990             return false;
2991     }
2992     
2993     return true;
2994 }
2995
2996 void Frame::handleMouseReleaseDoubleClickEvent(const MouseEventWithHitTestResults& event)
2997 {
2998     passWidgetMouseDownEventToWidget(event, true);
2999 }
3000
3001 bool Frame::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event, bool isDoubleClick)
3002 {
3003     // Figure out which view to send the event to.
3004     RenderObject *target = event.targetNode() ? event.targetNode()->renderer() : 0;
3005     if (!target)
3006         return false;
3007     
3008     Widget* widget = RenderLayer::gScrollBar;
3009     if (!widget) {
3010         if (!target->isWidget())
3011             return false;
3012         widget = static_cast<RenderWidget *>(target)->widget();
3013     }
3014     
3015     // Doubleclick events don't exist in Cocoa.  Since passWidgetMouseDownEventToWidget will
3016     // just pass _currentEvent down to the widget,  we don't want to call it for events that
3017     // don't correspond to Cocoa events.  The mousedown/ups will have already been passed on as
3018     // part of the pressed/released handling.
3019     if (!isDoubleClick)
3020         return passMouseDownEventToWidget(widget);
3021     return true;
3022 }
3023
3024 bool Frame::passWidgetMouseDownEventToWidget(RenderWidget *renderWidget)
3025 {
3026     return passMouseDownEventToWidget(renderWidget->widget());
3027 }
3028
3029 void Frame::clearTimers(FrameView *view)
3030 {
3031     if (view) {
3032         view->unscheduleRelayout();
3033         if (view->frame()) {
3034             Document* document = view->frame()->document();
3035             if (document && document->renderer() && document->renderer()->layer())
3036                 document->renderer()->layer()->suspendMarquees();
3037         }
3038     }
3039 }
3040
3041 void Frame::clearTimers()
3042 {
3043     clearTimers(d->m_view.get());
3044 }
3045
3046 // FIXME: selection controller?
3047 void Frame::centerSelectionInVisibleArea() const
3048 {
3049     IntRect rect;
3050     
3051     switch (selection().state()) {
3052         case Selection::NONE:
3053             return;
3054             
3055         case Selection::CARET:
3056             rect = selection().caretRect();
3057             break;
3058             
3059         case Selection::RANGE:
3060             rect = selectionRect();
3061             break;
3062     }
3063     
3064     Position start = selection().start();
3065     Position end = selection().end();
3066     ASSERT(start.node());
3067     if (start.node() && start.node()->renderer()) {
3068         RenderLayer *layer = start.node()->renderer()->enclosingLayer();
3069         if (layer) {
3070             ASSERT(!end.node() || !end.node()->renderer() 
3071                    || (end.node()->renderer()->enclosingLayer() == layer));
3072             layer->scrollRectToVisible(rect, RenderLayer::gAlignCenterAlways, RenderLayer::gAlignCenterAlways);
3073         }
3074     }
3075 }
3076
3077 RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const
3078 {
3079     nodeToRemove = 0;
3080     
3081     if (!document())
3082         return 0;
3083     if (d->m_selection.isNone())
3084         return 0;
3085     
3086     Position pos = VisiblePosition(d->m_selection.start(), d->m_selection.affinity()).deepEquivalent();
3087     if (!pos.inRenderedContent())
3088         return 0;
3089     Node *node = pos.node();
3090     if (!node)
3091         return 0;
3092     
3093     if (!d->m_typingStyle)
3094         return node->renderer()->style();
3095     
3096     ExceptionCode ec = 0;
3097     RefPtr<Element> styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
3098     ASSERT(ec == 0);
3099     
3100     styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
3101     ASSERT(ec == 0);
3102     
3103     styleElement->appendChild(document()->createEditingTextNode(""), ec);
3104     ASSERT(ec == 0);
3105     
3106     node->parentNode()->appendChild(styleElement, ec);
3107     ASSERT(ec == 0);
3108     
3109     nodeToRemove = styleElement.get();    
3110     return styleElement->renderer()->style();
3111 }
3112
3113 void Frame::setMediaType(const String& type)
3114 {
3115     if (d->m_view)
3116         d->m_view->setMediaType(type);
3117 }
3118
3119 void Frame::setSelectionFromNone()
3120 {
3121     // Put the caret someplace if the selection is empty and the part is editable.
3122     // This has the effect of flashing the caret in a contentEditable view automatically 
3123     // without requiring the programmer to set a selection explicitly.
3124     Document *doc = document();
3125     if (doc && selection().isNone() && isContentEditable()) {
3126         Node *node = doc->documentElement();
3127         while (node) {
3128             // Look for a block flow, but skip over the HTML element, since we really
3129             // want to get at least as far as the the BODY element in a document.
3130             if (node->isBlockFlow() && node->hasTagName(htmlTag))
3131                 break;
3132             node = node->traverseNextNode();
3133         }
3134         if (node)
3135             setSelection(SelectionController(Position(node, 0), DOWNSTREAM));
3136     }
3137 }
3138
3139 bool Frame::displaysWithFocusAttributes() const
3140 {
3141     return d->m_isFocused;
3142 }
3143
3144 void Frame::setDisplaysWithFocusAttributes(bool flag)
3145 {
3146     if (d->m_isFocused == flag)
3147         return;
3148     
3149     d->m_isFocused = flag;
3150
3151     // This method does the job of updating the view based on whether the view is "active".
3152     // This involves three kinds of drawing updates:
3153
3154     // 1. The background color used to draw behind selected content (active | inactive color)
3155     if (d->m_view)
3156         d->m_view->updateContents(enclosingIntRect(visibleSelectionRect()));
3157
3158     // 2. Caret blinking (blinks | does not blink)
3159     if (flag)
3160         setSelectionFromNone();
3161     setCaretVisible(flag);
3162     
3163     // 3. The drawing of a focus ring around links in web pages.
3164     Document *doc = document();
3165     if (doc) {
3166         Node *node = doc->focusNode();
3167         if (node) {
3168             node->setChanged();
3169             if (node->renderer() && node->renderer()->style()->hasAppearance())
3170                 theme()->stateChanged(node->renderer(), FocusState);
3171         }
3172     }
3173 }
3174
3175 void Frame::setWindowHasFocus(bool flag)
3176 {
3177     if (d->m_windowHasFocus == flag)
3178         return;
3179     d->m_windowHasFocus = flag;
3180     
3181     if (Document *doc = document())
3182         doc->dispatchWindowEvent(flag ? focusEvent : blurEvent, false, false);
3183 }
3184
3185 QChar Frame::backslashAsCurrencySymbol() const
3186 {
3187     Document *doc = document();
3188     if (!doc)
3189         return '\\';
3190     Decoder *decoder = doc->decoder();
3191     if (!decoder)
3192         return '\\';
3193
3194     return decoder->encoding().backslashAsCurrencySymbol();
3195 }
3196
3197 bool Frame::markedTextUsesUnderlines() const
3198 {
3199     return d->m_markedTextUsesUnderlines;
3200 }
3201
3202 DeprecatedValueList<MarkedTextUnderline> Frame::markedTextUnderlines() const
3203 {
3204     return d->m_markedTextUnderlines;
3205 }
3206
3207 unsigned Frame::highlightAllMatchesForString(const String& target, bool caseFlag)
3208 {
3209     if (target.isEmpty())
3210         return 0;
3211     
3212     RefPtr<Range> searchRange(rangeOfContents(document()));
3213     
3214     int exception = 0;
3215     unsigned matchCount = 0;
3216     do {
3217         RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, caseFlag));
3218         if (resultRange->collapsed(exception))
3219             break;
3220         
3221         // A non-collapsed result range can in some funky whitespace cases still not
3222         // advance the range's start position (4509328). Break to avoid infinite loop.
3223         VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
3224         if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
3225             break;
3226
3227         ++matchCount;
3228         document()->addMarker(resultRange.get(), DocumentMarker::TextMatch);        
3229         
3230         setStart(searchRange.get(), newStart);
3231     } while (true);
3232     
3233     return matchCount;
3234 }
3235
3236 void Frame::prepareForUserAction()
3237 {
3238     // Reset the multiple form submission protection code.
3239     // We'll let you submit the same form twice if you do two separate user actions.
3240     d->m_submittedFormURL = KURL();
3241 }
3242
3243 Node *Frame::mousePressNode()
3244 {
3245     return d->m_mousePressNode.get();
3246 }
3247
3248 bool Frame::isComplete() const
3249 {
3250     return d->m_bComplete;
3251 }
3252
3253 bool Frame::isLoadingMainResource() const
3254 {
3255     return d->m_bLoadingMainResource;
3256 }
3257
3258 FrameTree* Frame::tree() const
3259 {
3260     return &d->m_treeNode;
3261 }
3262
3263 DOMWindow* Frame::domWindow() const
3264 {
3265     if (!d->m_domWindow)
3266         d->m_domWindow = new DOMWindow(const_cast<Frame*>(this));
3267
3268     return d->m_domWindow.get();
3269 }
3270
3271 KURL Frame::url() const
3272 {
3273     return d->m_url;
3274 }
3275
3276 void Frame::startRedirectionTimer()
3277 {
3278     d->m_redirectionTimer.startOneShot(d->m_delayRedirect);
3279 }
3280
3281 void Frame::stopRedirectionTimer()
3282 {
3283     d->m_redirectionTimer.stop();
3284 }
3285
3286 void Frame::frameDetached()
3287 {
3288 }
3289
3290 void Frame::updateBaseURLForEmptyDocument()
3291 {
3292     Element* owner = ownerElement();
3293     // FIXME: Should embed be included?
3294     if (owner && (owner->hasTagName(iframeTag) || owner->hasTagName(objectTag) || owner->hasTagName(embedTag)))
3295         d->m_doc->setBaseURL(tree()->parent()->d->m_doc->baseURL());
3296 }
3297
3298 Page* Frame::page() const
3299 {
3300     return d->m_page;
3301 }
3302
3303 void Frame::completed(bool complete)
3304 {
3305     ref();
3306     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
3307         child->parentCompleted();
3308     if (Frame* parent = tree()->parent())
3309         parent->childCompleted(complete);
3310     submitFormAgain();
3311     deref();
3312 }
3313
3314 void Frame::setStatusBarText(const String&)
3315 {
3316 }
3317
3318 void Frame::started()
3319 {
3320     for (Frame* frame = this; frame; frame = frame->tree()->parent())
3321         frame->d->m_bComplete = false;
3322 }
3323
3324 void Frame::disconnectOwnerRenderer()
3325 {
3326     d->m_ownerRenderer = 0;
3327 }
3328
3329 } // namespace WebCore