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