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