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