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