2007-10-20 Rodney Dawes <dobey@wayofthemonkey.com>
[WebKit-https.git] / WebCore / page / Frame.cpp
1 /*
2  * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3  *                     1999 Lars Knoll <knoll@kde.org>
4  *                     1999 Antti Koivisto <koivisto@kde.org>
5  *                     2000 Simon Hausmann <hausmann@kde.org>
6  *                     2000 Stefan Schimanski <1Stein@gmx.de>
7  *                     2001 George Staikos <staikos@kde.org>
8  * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
9  * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com>
10  * Copyright (C) 2007 Trolltech ASA
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., 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27
28 #include "config.h"
29 #include "Frame.h"
30 #include "FramePrivate.h"
31
32 #include "ApplyStyleCommand.h"
33 #include "BeforeUnloadEvent.h"
34 #include "CSSComputedStyleDeclaration.h"
35 #include "CSSProperty.h"
36 #include "CSSPropertyNames.h"
37 #include "CachedCSSStyleSheet.h"
38 #include "DOMWindow.h"
39 #include "DocLoader.h"
40 #include "DocumentType.h"
41 #include "EditingText.h"
42 #include "EditorClient.h"
43 #include "EventNames.h"
44 #include "FocusController.h"
45 #include "FrameLoader.h"
46 #include "FrameView.h"
47 #include "GraphicsContext.h"
48 #include "HitTestResult.h"
49 #include "HTMLDocument.h"
50 #include "HTMLFormElement.h"
51 #include "HTMLFrameElementBase.h"
52 #include "HTMLGenericFormElement.h"
53 #include "HTMLNames.h"
54 #include "HTMLTableCellElement.h"
55 #include "Logging.h"
56 #include "MediaFeatureNames.h"
57 #include "NodeList.h"
58 #include "Page.h"
59 #include "RegularExpression.h"
60 #include "RenderPart.h"
61 #include "RenderTableCell.h"
62 #include "RenderTextControl.h"
63 #include "RenderTheme.h"
64 #include "RenderView.h"
65 #include "Settings.h"
66 #include "SystemTime.h"
67 #include "TextIterator.h"
68 #include "TextResourceDecoder.h"
69 #include "XMLNames.h"
70 #include "bindings/NP_jsobject.h"
71 #include "bindings/npruntime_impl.h"
72 #include "bindings/runtime_root.h"
73 #include "kjs_proxy.h"
74 #include "kjs_window.h"
75 #include "visible_units.h"
76
77 #if ENABLE(SVG)
78 #include "SVGDocument.h"
79 #include "SVGDocumentExtensions.h"
80 #include "SVGNames.h"
81 #include "XLinkNames.h"
82 #endif
83
84 using namespace std;
85
86 using KJS::JSLock;
87
88 namespace WebCore {
89
90 using namespace EventNames;
91 using namespace HTMLNames;
92
93 static const double caretBlinkFrequency = 0.5;
94
95 double Frame::s_currentPaintTimeStamp = 0.0;
96
97 class UserStyleSheetLoader : public CachedResourceClient {
98 public:
99     UserStyleSheetLoader(PassRefPtr<Document> document, const String& url)
100         : m_document(document)
101         , m_cachedSheet(m_document->docLoader()->requestUserCSSStyleSheet(url, ""))
102     {
103         m_document->addPendingSheet();
104         m_cachedSheet->ref(this);
105     }
106     ~UserStyleSheetLoader()
107     {
108         if (!m_cachedSheet->isLoaded())
109             m_document->removePendingSheet();        
110         m_cachedSheet->deref(this);
111     }
112 private:
113     virtual void setCSSStyleSheet(const String& /*URL*/, const String& /*charset*/, const String& sheet)
114     {
115         m_document->removePendingSheet();
116         if (Frame* frame = m_document->frame())
117             frame->setUserStyleSheet(sheet);
118     }
119     RefPtr<Document> m_document;
120     CachedCSSStyleSheet* m_cachedSheet;
121 };
122
123 #ifndef NDEBUG
124 WTFLogChannel LogWebCoreFrameLeaks =  { 0x00000000, "", WTFLogChannelOn };
125
126 struct FrameCounter { 
127     static int count; 
128     ~FrameCounter() 
129     { 
130         if (count)
131             LOG(WebCoreFrameLeaks, "LEAK: %d Frame\n", count);
132     }
133 };
134 int FrameCounter::count = 0;
135 static FrameCounter frameCounter;
136 #endif
137
138 static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
139 {
140     if (!ownerElement)
141         return 0;
142     return ownerElement->document()->frame();
143 }
144
145 Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient) 
146     : d(new FramePrivate(page, parentFromOwnerElement(ownerElement), this, ownerElement, frameLoaderClient))
147 {
148     AtomicString::init();
149     EventNames::init();
150     HTMLNames::init();
151     QualifiedName::init();
152     MediaFeatureNames::init();
153
154 #if ENABLE(SVG)
155     SVGNames::init();
156     XLinkNames::init();
157 #endif
158
159     XMLNames::init();
160
161     if (!ownerElement)
162         page->setMainFrame(this);
163     else {
164         // FIXME: Frames were originally created with a refcount of 1.
165         // Leave this ref call here until we can straighten that out.
166         ref();
167         page->incrementFrameCount();
168         ownerElement->m_contentFrame = this;
169     }
170
171 #ifndef NDEBUG
172     ++FrameCounter::count;
173 #endif
174 }
175
176 Frame::~Frame()
177 {
178     setView(0);
179     loader()->clearRecordedFormValues();
180
181 #if PLATFORM(MAC)
182     setBridge(0);
183 #endif
184     
185     loader()->cancelAndClear();
186     
187     // FIXME: We should not be doing all this work inside the destructor
188
189     ASSERT(!d->m_lifeSupportTimer.isActive());
190
191 #ifndef NDEBUG
192     --FrameCounter::count;
193 #endif
194
195     if (d->m_jscript && d->m_jscript->haveInterpreter())
196         static_cast<KJS::Window*>(d->m_jscript->interpreter()->globalObject())->disconnectFrame();
197
198     disconnectOwnerElement();
199     
200     if (d->m_domWindow)
201         d->m_domWindow->disconnectFrame();
202             
203     if (d->m_view) {
204         d->m_view->hide();
205         d->m_view->clearFrame();
206     }
207   
208     ASSERT(!d->m_lifeSupportTimer.isActive());
209
210     delete d->m_userStyleSheetLoader;
211     delete d;
212     d = 0;
213 }
214
215 void Frame::init()
216 {
217     d->m_loader->init();
218 }
219
220 FrameLoader* Frame::loader() const
221 {
222     return d->m_loader;
223 }
224
225 FrameView* Frame::view() const
226 {
227     return d->m_view.get();
228 }
229
230 void Frame::setView(FrameView* view)
231 {
232     // Detach the document now, so any onUnload handlers get run - if
233     // we wait until the view is destroyed, then things won't be
234     // hooked up enough for some JavaScript calls to work.
235     if (!view && d->m_doc && d->m_doc->attached() && !d->m_doc->inPageCache()) {
236         // FIXME: We don't call willRemove here. Why is that OK?
237         d->m_doc->detach();
238         if (d->m_view)
239             d->m_view->unscheduleRelayout();
240     }
241     eventHandler()->clear();
242
243     d->m_view = view;
244
245     // Only one form submission is allowed per view of a part.
246     // Since this part may be getting reused as a result of being
247     // pulled from the back/forward cache, reset this flag.
248     loader()->resetMultipleFormSubmissionProtection();
249 }
250
251 KJSProxy *Frame::scriptProxy()
252 {
253     Settings* settings = this->settings();
254     if (!settings || !settings->isJavaScriptEnabled())
255         return 0;
256
257     if (!d->m_jscript)
258         d->m_jscript = new KJSProxy(this);
259
260     return d->m_jscript;
261 }
262
263 Document *Frame::document() const
264 {
265     if (d)
266         return d->m_doc.get();
267     return 0;
268 }
269
270 void Frame::setDocument(PassRefPtr<Document> newDoc)
271 {
272     if (d->m_doc && d->m_doc->attached() && !d->m_doc->inPageCache()) {
273         // FIXME: We don't call willRemove here. Why is that OK?
274         d->m_doc->detach();
275     }
276
277     d->m_doc = newDoc;
278     if (d->m_doc && d->m_isActive)
279         setUseSecureKeyboardEntry(d->m_doc->useSecureKeyboardEntryWhenActive());
280         
281     if (d->m_doc && !d->m_doc->attached())
282         d->m_doc->attach();
283     
284     // Remove the cached 'document' property, which is now stale.
285     if (d->m_jscript)
286         d->m_jscript->clearDocumentWrapper();
287 }
288
289 Settings* Frame::settings() const
290 {
291     return d->m_page ? d->m_page->settings() : 0;
292 }
293
294 void Frame::setUserStyleSheetLocation(const KURL& url)
295 {
296     delete d->m_userStyleSheetLoader;
297     d->m_userStyleSheetLoader = 0;
298     if (d->m_doc && d->m_doc->docLoader())
299         d->m_userStyleSheetLoader = new UserStyleSheetLoader(d->m_doc, url.url());
300 }
301
302 void Frame::setUserStyleSheet(const String& styleSheet)
303 {
304     delete d->m_userStyleSheetLoader;
305     d->m_userStyleSheetLoader = 0;
306     if (d->m_doc)
307         d->m_doc->setUserStyleSheet(styleSheet);
308 }
309
310 String Frame::selectedText() const
311 {
312     return plainText(selectionController()->toRange().get());
313 }
314
315 IntRect Frame::firstRectForRange(Range* range) const
316 {
317     int extraWidthToEndOfLine = 0;
318     ExceptionCode ec = 0;
319     ASSERT(range->startContainer(ec));
320     ASSERT(range->endContainer(ec));
321     IntRect startCaretRect = range->startContainer(ec)->renderer()->caretRect(range->startOffset(ec), DOWNSTREAM, &extraWidthToEndOfLine);
322     ASSERT(!ec);
323     IntRect endCaretRect = range->endContainer(ec)->renderer()->caretRect(range->endOffset(ec), UPSTREAM);
324     ASSERT(!ec);
325     
326     if (startCaretRect.y() == endCaretRect.y()) {
327         // start and end are on the same line
328         return IntRect(min(startCaretRect.x(), endCaretRect.x()), 
329                        startCaretRect.y(), 
330                        abs(endCaretRect.x() - startCaretRect.x()),
331                        max(startCaretRect.height(), endCaretRect.height()));
332     }
333     
334     // start and end aren't on the same line, so go from start to the end of its line
335     return IntRect(startCaretRect.x(), 
336                    startCaretRect.y(),
337                    startCaretRect.width() + extraWidthToEndOfLine,
338                    startCaretRect.height());
339 }
340
341 SelectionController* Frame::selectionController() const
342 {
343     return &d->m_selectionController;
344 }
345
346 Editor* Frame::editor() const
347 {
348     return &d->m_editor;
349 }
350
351 TextGranularity Frame::selectionGranularity() const
352 {
353     return d->m_selectionGranularity;
354 }
355
356 void Frame::setSelectionGranularity(TextGranularity granularity) const
357 {
358     d->m_selectionGranularity = granularity;
359 }
360
361 SelectionController* Frame::dragCaretController() const
362 {
363     return d->m_page->dragCaretController();
364 }
365
366
367 // Either get cached regexp or build one that matches any of the labels.
368 // The regexp we build is of the form:  (STR1|STR2|STRN)
369 static RegularExpression *regExpForLabels(const Vector<String>& labels)
370 {
371     // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being
372     // the same across calls.  We can't do that.
373
374     static RegularExpression wordRegExp = RegularExpression("\\w");
375     DeprecatedString pattern("(");
376     unsigned int numLabels = labels.size();
377     unsigned int i;
378     for (i = 0; i < numLabels; i++) {
379         DeprecatedString label = labels[i].deprecatedString();
380
381         bool startsWithWordChar = false;
382         bool endsWithWordChar = false;
383         if (label.length() != 0) {
384             startsWithWordChar = wordRegExp.search(label.at(0)) >= 0;
385             endsWithWordChar = wordRegExp.search(label.at(label.length() - 1)) >= 0;
386         }
387         
388         if (i != 0)
389             pattern.append("|");
390         // Search for word boundaries only if label starts/ends with "word characters".
391         // If we always searched for word boundaries, this wouldn't work for languages
392         // such as Japanese.
393         if (startsWithWordChar) {
394             pattern.append("\\b");
395         }
396         pattern.append(label);
397         if (endsWithWordChar) {
398             pattern.append("\\b");
399         }
400     }
401     pattern.append(")");
402     return new RegularExpression(pattern, false);
403 }
404
405 String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell)
406 {
407     RenderTableCell* cellRenderer = static_cast<RenderTableCell*>(cell->renderer());
408
409     if (cellRenderer && cellRenderer->isTableCell()) {
410         RenderTableCell* cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer);
411
412         if (cellAboveRenderer) {
413             HTMLTableCellElement* aboveCell =
414                 static_cast<HTMLTableCellElement*>(cellAboveRenderer->element());
415
416             if (aboveCell) {
417                 // search within the above cell we found for a match
418                 for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
419                     if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
420                         // For each text chunk, run the regexp
421                         DeprecatedString nodeString = n->nodeValue().deprecatedString();
422                         int pos = regExp->searchRev(nodeString);
423                         if (pos >= 0)
424                             return nodeString.mid(pos, regExp->matchedLength());
425                     }
426                 }
427             }
428         }
429     }
430     // Any reason in practice to search all cells in that are above cell?
431     return String();
432 }
433
434 String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element)
435 {
436     RegularExpression* regExp = regExpForLabels(labels);
437     // We stop searching after we've seen this many chars
438     const unsigned int charsSearchedThreshold = 500;
439     // This is the absolute max we search.  We allow a little more slop than
440     // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
441     const unsigned int maxCharsSearched = 600;
442     // If the starting element is within a table, the cell that contains it
443     HTMLTableCellElement* startingTableCell = 0;
444     bool searchedCellAbove = false;
445
446     // walk backwards in the node tree, until another element, or form, or end of tree
447     int unsigned lengthSearched = 0;
448     Node* n;
449     for (n = element->traversePreviousNode();
450          n && lengthSearched < charsSearchedThreshold;
451          n = n->traversePreviousNode())
452     {
453         if (n->hasTagName(formTag)
454             || (n->isHTMLElement()
455                 && static_cast<HTMLElement*>(n)->isGenericFormElement()))
456         {
457             // We hit another form element or the start of the form - bail out
458             break;
459         } else if (n->hasTagName(tdTag) && !startingTableCell) {
460             startingTableCell = static_cast<HTMLTableCellElement*>(n);
461         } else if (n->hasTagName(trTag) && startingTableCell) {
462             String result = searchForLabelsAboveCell(regExp, startingTableCell);
463             if (!result.isEmpty())
464                 return result;
465             searchedCellAbove = true;
466         } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
467             // For each text chunk, run the regexp
468             DeprecatedString nodeString = n->nodeValue().deprecatedString();
469             // add 100 for slop, to make it more likely that we'll search whole nodes
470             if (lengthSearched + nodeString.length() > maxCharsSearched)
471                 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
472             int pos = regExp->searchRev(nodeString);
473             if (pos >= 0)
474                 return nodeString.mid(pos, regExp->matchedLength());
475             else
476                 lengthSearched += nodeString.length();
477         }
478     }
479
480     // If we started in a cell, but bailed because we found the start of the form or the
481     // previous element, we still might need to search the row above us for a label.
482     if (startingTableCell && !searchedCellAbove) {
483          return searchForLabelsAboveCell(regExp, startingTableCell);
484     }
485     return String();
486 }
487
488 String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element)
489 {
490     DeprecatedString name = element->getAttribute(nameAttr).deprecatedString();
491     // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
492     name.replace(RegularExpression("[[:digit:]]"), " ");
493     name.replace('_', ' ');
494     
495     RegularExpression* regExp = regExpForLabels(labels);
496     // Use the largest match we can find in the whole name string
497     int pos;
498     int length;
499     int bestPos = -1;
500     int bestLength = -1;
501     int start = 0;
502     do {
503         pos = regExp->search(name, start);
504         if (pos != -1) {
505             length = regExp->matchedLength();
506             if (length >= bestLength) {
507                 bestPos = pos;
508                 bestLength = length;
509             }
510             start = pos+1;
511         }
512     } while (pos != -1);
513
514     if (bestPos != -1)
515         return name.mid(bestPos, bestLength);
516     return String();
517 }
518
519 const Selection& Frame::mark() const
520 {
521     return d->m_mark;
522 }
523
524 void Frame::setMark(const Selection& s)
525 {
526     ASSERT(!s.base().node() || s.base().node()->document() == document());
527     ASSERT(!s.extent().node() || s.extent().node()->document() == document());
528     ASSERT(!s.start().node() || s.start().node()->document() == document());
529     ASSERT(!s.end().node() || s.end().node()->document() == document());
530
531     d->m_mark = s;
532 }
533
534 void Frame::notifyRendererOfSelectionChange(bool userTriggered)
535 {
536     RenderObject* renderer = 0;
537     if (selectionController()->rootEditableElement())
538         renderer = selectionController()->rootEditableElement()->shadowAncestorNode()->renderer();
539
540     // If the current selection is in a textfield or textarea, notify the renderer that the selection has changed
541     if (renderer && (renderer->isTextArea() || renderer->isTextField()))
542         static_cast<RenderTextControl*>(renderer)->selectionChanged(userTriggered);
543 }
544
545 void Frame::invalidateSelection()
546 {
547     selectionController()->setNeedsLayout();
548     selectionLayoutChanged();
549 }
550
551 void Frame::setCaretVisible(bool flag)
552 {
553     if (d->m_caretVisible == flag)
554         return;
555     clearCaretRectIfNeeded();
556     d->m_caretVisible = flag;
557     selectionLayoutChanged();
558 }
559
560 void Frame::clearCaretRectIfNeeded()
561 {
562     if (d->m_caretPaint) {
563         d->m_caretPaint = false;
564         selectionController()->invalidateCaretRect();
565     }
566 }
567
568 // Helper function that tells whether a particular node is an element that has an entire
569 // Frame and FrameView, a <frame>, <iframe>, or <object>.
570 static bool isFrameElement(const Node *n)
571 {
572     if (!n)
573         return false;
574     RenderObject *renderer = n->renderer();
575     if (!renderer || !renderer->isWidget())
576         return false;
577     Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
578     return widget && widget->isFrameView();
579 }
580
581 void Frame::setFocusedNodeIfNeeded()
582 {
583     if (!document() || selectionController()->isNone() || !d->m_isActive)
584         return;
585
586     Node* target = selectionController()->rootEditableElement();
587     if (target) {
588         RenderObject* renderer = target->renderer();
589
590         // Walk up the render tree to search for a node to focus.
591         // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
592         while (renderer) {
593             // We don't want to set focus on a subframe when selecting in a parent frame,
594             // so add the !isFrameElement check here. There's probably a better way to make this
595             // work in the long term, but this is the safest fix at this time.
596             if (target && target->isMouseFocusable() && !isFrameElement(target)) {
597                 page()->focusController()->setFocusedNode(target, this);
598                 return;
599             }
600             renderer = renderer->parent();
601             if (renderer)
602                 target = renderer->element();
603         }
604         document()->setFocusedNode(0);
605     }
606 }
607
608 void Frame::selectionLayoutChanged()
609 {
610     bool caretRectChanged = selectionController()->recomputeCaretRect();
611
612     bool shouldBlink = d->m_caretVisible
613         && selectionController()->isCaret() && selectionController()->isContentEditable();
614
615     // If the caret moved, stop the blink timer so we can restart with a
616     // black caret in the new location.
617     if (caretRectChanged || !shouldBlink)
618         d->m_caretBlinkTimer.stop();
619
620     // Start blinking with a black caret. Be sure not to restart if we're
621     // already blinking in the right location.
622     if (shouldBlink && !d->m_caretBlinkTimer.isActive()) {
623         d->m_caretBlinkTimer.startRepeating(caretBlinkFrequency);
624         if (!d->m_caretPaint) {
625             d->m_caretPaint = true;
626             selectionController()->invalidateCaretRect();
627         }
628     }
629
630     if (d->m_doc)
631         d->m_doc->updateSelection();
632 }
633
634 void Frame::caretBlinkTimerFired(Timer<Frame>*)
635 {
636     ASSERT(d->m_caretVisible);
637     ASSERT(selectionController()->isCaret());
638     bool caretPaint = d->m_caretPaint;
639     if (selectionController()->isCaretBlinkingSuspended() && caretPaint)
640         return;
641     d->m_caretPaint = !caretPaint;
642     selectionController()->invalidateCaretRect();
643 }
644
645 void Frame::paintCaret(GraphicsContext* p, const IntRect& rect) const
646 {
647     if (d->m_caretPaint && d->m_caretVisible)
648         selectionController()->paintCaret(p, rect);
649 }
650
651 void Frame::paintDragCaret(GraphicsContext* p, const IntRect& rect) const
652 {
653     SelectionController* dragCaretController = d->m_page->dragCaretController();
654     ASSERT(dragCaretController->selection().isCaret());
655     if (dragCaretController->selection().start().node()->document()->frame() == this)
656         dragCaretController->paintCaret(p, rect);
657 }
658
659 int Frame::zoomFactor() const
660 {
661   return d->m_zoomFactor;
662 }
663
664 void Frame::setZoomFactor(int percent)
665 {  
666   if (d->m_zoomFactor == percent)
667       return;
668
669 #if ENABLE(SVG)
670     if (d->m_doc && d->m_doc->isSVGDocument()) {
671         if (!static_cast<SVGDocument*>(d->m_doc.get())->zoomAndPanEnabled())
672             return;
673         d->m_zoomFactor = percent;
674         if (d->m_doc->renderer())
675             d->m_doc->renderer()->repaint();
676         return;
677     }
678 #endif
679   d->m_zoomFactor = percent;
680   if (d->m_doc)
681       d->m_doc->recalcStyle(Node::Force);
682
683   for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
684       child->setZoomFactor(d->m_zoomFactor);
685
686   if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout())
687       view()->layout();
688 }
689
690 void Frame::setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize)
691 {
692     if (!d->m_doc)
693         return;
694
695     d->m_doc->setPrinting(printing);
696     view()->setMediaType(printing ? "print" : "screen");
697     d->m_doc->updateStyleSelector();
698     forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth, adjustViewSize);
699
700     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
701         child->setPrinting(printing, minPageWidth, maxPageWidth, adjustViewSize);
702 }
703
704 void Frame::setJSStatusBarText(const String& text)
705 {
706     d->m_kjsStatusBarText = text;
707     if (d->m_page)
708         d->m_page->chrome()->setStatusbarText(this, d->m_kjsStatusBarText);
709 }
710
711 void Frame::setJSDefaultStatusBarText(const String& text)
712 {
713     d->m_kjsDefaultStatusBarText = text;
714     if (d->m_page)
715         d->m_page->chrome()->setStatusbarText(this, d->m_kjsDefaultStatusBarText);
716 }
717
718 String Frame::jsStatusBarText() const
719 {
720     return d->m_kjsStatusBarText;
721 }
722
723 String Frame::jsDefaultStatusBarText() const
724 {
725    return d->m_kjsDefaultStatusBarText;
726 }
727
728 void Frame::reparseConfiguration()
729 {
730     if (d->m_doc)
731         d->m_doc->docLoader()->setAutoLoadImages(d->m_page && d->m_page->settings()->loadsImagesAutomatically());
732         
733     const KURL userStyleSheetLocation = d->m_page ? d->m_page->settings()->userStyleSheetLocation() : KURL();
734     if (!userStyleSheetLocation.isEmpty())
735         setUserStyleSheetLocation(userStyleSheetLocation);
736     else
737         setUserStyleSheet(String());
738
739     // FIXME: It's not entirely clear why the following is needed.
740     // The document automatically does this as required when you set the style sheet.
741     // But we had problems when this code was removed. Details are in
742     // <http://bugs.webkit.org/show_bug.cgi?id=8079>.
743     if (d->m_doc)
744         d->m_doc->updateStyleSelector();
745 }
746
747 bool Frame::shouldChangeSelection(const Selection& newSelection) const
748 {
749     return shouldChangeSelection(selectionController()->selection(), newSelection, newSelection.affinity(), false);
750 }
751
752 bool Frame::shouldChangeSelection(const Selection& oldSelection, const Selection& newSelection, EAffinity affinity, bool stillSelecting) const
753 {
754     return editor()->client()->shouldChangeSelectedRange(oldSelection.toRange().get(), newSelection.toRange().get(),
755                                                          affinity, stillSelecting);
756 }
757
758 bool Frame::shouldDeleteSelection(const Selection& selection) const
759 {
760     return editor()->client()->shouldDeleteRange(selection.toRange().get());
761 }
762
763 bool Frame::isContentEditable() const 
764 {
765     if (d->m_editor.clientIsEditable())
766         return true;
767     if (!d->m_doc)
768         return false;
769     return d->m_doc->inDesignMode();
770 }
771
772 #if !PLATFORM(MAC)
773
774 void Frame::setUseSecureKeyboardEntry(bool)
775 {
776 }
777
778 #endif
779
780 void Frame::updateSecureKeyboardEntryIfActive()
781 {
782     if (d->m_isActive)
783         setUseSecureKeyboardEntry(d->m_doc->useSecureKeyboardEntryWhenActive());
784 }
785
786 CSSMutableStyleDeclaration *Frame::typingStyle() const
787 {
788     return d->m_typingStyle.get();
789 }
790
791 void Frame::setTypingStyle(CSSMutableStyleDeclaration *style)
792 {
793     d->m_typingStyle = style;
794 }
795
796 void Frame::clearTypingStyle()
797 {
798     d->m_typingStyle = 0;
799 }
800
801 void Frame::transpose()
802 {
803     issueTransposeCommand();
804 }
805
806 void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction editingAction)
807 {
808     if (!style || style->length() == 0) {
809         clearTypingStyle();
810         return;
811     }
812
813     // Calculate the current typing style.
814     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
815     if (typingStyle()) {
816         typingStyle()->merge(mutableStyle.get());
817         mutableStyle = typingStyle();
818     }
819
820     Node *node = selectionController()->selection().visibleStart().deepEquivalent().node();
821     CSSComputedStyleDeclaration computedStyle(node);
822     computedStyle.diff(mutableStyle.get());
823     
824     // Handle block styles, substracting these from the typing style.
825     RefPtr<CSSMutableStyleDeclaration> blockStyle = mutableStyle->copyBlockProperties();
826     blockStyle->diff(mutableStyle.get());
827     if (document() && blockStyle->length() > 0)
828         applyCommand(new ApplyStyleCommand(document(), blockStyle.get(), editingAction));
829     
830     // Set the remaining style as the typing style.
831     d->m_typingStyle = mutableStyle.release();
832 }
833
834 static void updateState(CSSMutableStyleDeclaration *desiredStyle, CSSComputedStyleDeclaration *computedStyle, bool& atStart, Frame::TriState& state)
835 {
836     DeprecatedValueListConstIterator<CSSProperty> end;
837     for (DeprecatedValueListConstIterator<CSSProperty> it = desiredStyle->valuesIterator(); it != end; ++it) {
838         int propertyID = (*it).id();
839         String desiredProperty = desiredStyle->getPropertyValue(propertyID);
840         String computedProperty = computedStyle->getPropertyValue(propertyID);
841         Frame::TriState propertyState = equalIgnoringCase(desiredProperty, computedProperty)
842             ? Frame::trueTriState : Frame::falseTriState;
843         if (atStart) {
844             state = propertyState;
845             atStart = false;
846         } else if (state != propertyState) {
847             state = Frame::mixedTriState;
848             break;
849         }
850     }
851 }
852
853 Frame::TriState Frame::selectionHasStyle(CSSStyleDeclaration *style) const
854 {
855     bool atStart = true;
856     TriState state = falseTriState;
857
858     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
859
860     if (!selectionController()->isRange()) {
861         Node* nodeToRemove;
862         RefPtr<CSSComputedStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
863         if (!selectionStyle)
864             return falseTriState;
865         updateState(mutableStyle.get(), selectionStyle.get(), atStart, state);
866         if (nodeToRemove) {
867             ExceptionCode ec = 0;
868             nodeToRemove->remove(ec);
869             ASSERT(ec == 0);
870         }
871     } else {
872         for (Node* node = selectionController()->start().node(); node; node = node->traverseNextNode()) {
873             RefPtr<CSSComputedStyleDeclaration> computedStyle = new CSSComputedStyleDeclaration(node);
874             if (computedStyle)
875                 updateState(mutableStyle.get(), computedStyle.get(), atStart, state);
876             if (state == mixedTriState)
877                 break;
878             if (node == selectionController()->end().node())
879                 break;
880         }
881     }
882
883     return state;
884 }
885
886 String Frame::selectionStartStylePropertyValue(int stylePropertyID) const
887 {
888     Node *nodeToRemove;
889     RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
890     if (!selectionStyle)
891         return String();
892
893     String value = selectionStyle->getPropertyValue(stylePropertyID);
894
895     if (nodeToRemove) {
896         ExceptionCode ec = 0;
897         nodeToRemove->remove(ec);
898         ASSERT(ec == 0);
899     }
900
901     return value;
902 }
903
904 CSSComputedStyleDeclaration *Frame::selectionComputedStyle(Node *&nodeToRemove) const
905 {
906     nodeToRemove = 0;
907
908     if (!document())
909         return 0;
910
911     if (selectionController()->isNone())
912         return 0;
913
914     RefPtr<Range> range(selectionController()->toRange());
915     Position pos = range->editingStartPosition();
916
917     Element *elem = pos.element();
918     if (!elem)
919         return 0;
920     
921     RefPtr<Element> styleElement = elem;
922     ExceptionCode ec = 0;
923
924     if (d->m_typingStyle) {
925         styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
926         ASSERT(ec == 0);
927
928         styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
929         ASSERT(ec == 0);
930         
931         styleElement->appendChild(document()->createEditingTextNode(""), ec);
932         ASSERT(ec == 0);
933
934         if (elem->renderer() && elem->renderer()->canHaveChildren()) {
935             elem->appendChild(styleElement, ec);
936         } else {
937             Node *parent = elem->parent();
938             Node *next = elem->nextSibling();
939
940             if (next) {
941                 parent->insertBefore(styleElement, next, ec);
942             } else {
943                 parent->appendChild(styleElement, ec);
944             }
945         }
946         ASSERT(ec == 0);
947
948         nodeToRemove = styleElement.get();
949     }
950
951     return new CSSComputedStyleDeclaration(styleElement);
952 }
953
954 void Frame::textFieldDidBeginEditing(Element* e)
955 {
956     if (editor()->client())
957         editor()->client()->textFieldDidBeginEditing(e);
958 }
959
960 void Frame::textFieldDidEndEditing(Element* e)
961 {
962     if (editor()->client())
963         editor()->client()->textFieldDidEndEditing(e);
964 }
965
966 void Frame::textDidChangeInTextField(Element* e)
967 {
968     if (editor()->client())
969         editor()->client()->textDidChangeInTextField(e);
970 }
971
972 bool Frame::doTextFieldCommandFromEvent(Element* e, KeyboardEvent* ke)
973 {
974     if (editor()->client())
975         return editor()->client()->doTextFieldCommandFromEvent(e, ke);
976
977     return false;
978 }
979
980 void Frame::textWillBeDeletedInTextField(Element* input)
981 {
982     if (editor()->client())
983         editor()->client()->textWillBeDeletedInTextField(input);
984 }
985
986 void Frame::textDidChangeInTextArea(Element* e)
987 {
988     if (editor()->client())
989         editor()->client()->textDidChangeInTextArea(e);
990 }
991
992 void Frame::applyEditingStyleToBodyElement() const
993 {
994     if (!d->m_doc)
995         return;
996         
997     RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
998     unsigned len = list->length();
999     for (unsigned i = 0; i < len; i++) {
1000         applyEditingStyleToElement(static_cast<Element*>(list->item(i)));    
1001     }
1002 }
1003
1004 void Frame::removeEditingStyleFromBodyElement() const
1005 {
1006     if (!d->m_doc)
1007         return;
1008         
1009     RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
1010     unsigned len = list->length();
1011     for (unsigned i = 0; i < len; i++) {
1012         removeEditingStyleFromElement(static_cast<Element*>(list->item(i)));    
1013     }
1014 }
1015
1016 void Frame::applyEditingStyleToElement(Element* element) const
1017 {
1018     if (!element)
1019         return;
1020
1021     CSSStyleDeclaration* style = element->style();
1022     ASSERT(style);
1023
1024     ExceptionCode ec = 0;
1025     style->setProperty(CSS_PROP_WORD_WRAP, "break-word", false, ec);
1026     ASSERT(ec == 0);
1027     style->setProperty(CSS_PROP__WEBKIT_NBSP_MODE, "space", false, ec);
1028     ASSERT(ec == 0);
1029     style->setProperty(CSS_PROP__WEBKIT_LINE_BREAK, "after-white-space", false, ec);
1030     ASSERT(ec == 0);
1031 }
1032
1033 void Frame::removeEditingStyleFromElement(Element*) const
1034 {
1035 }
1036
1037 #ifndef NDEBUG
1038 static HashSet<Frame*>& keepAliveSet()
1039 {
1040     static HashSet<Frame*> staticKeepAliveSet;
1041     return staticKeepAliveSet;
1042 }
1043 #endif
1044
1045 void Frame::keepAlive()
1046 {
1047     if (d->m_lifeSupportTimer.isActive())
1048         return;
1049 #ifndef NDEBUG
1050     keepAliveSet().add(this);
1051 #endif
1052     ref();
1053     d->m_lifeSupportTimer.startOneShot(0);
1054 }
1055
1056 #ifndef NDEBUG
1057 void Frame::cancelAllKeepAlive()
1058 {
1059     HashSet<Frame*>::iterator end = keepAliveSet().end();
1060     for (HashSet<Frame*>::iterator it = keepAliveSet().begin(); it != end; ++it) {
1061         Frame* frame = *it;
1062         frame->d->m_lifeSupportTimer.stop();
1063         frame->deref();
1064     }
1065     keepAliveSet().clear();
1066 }
1067 #endif
1068
1069 void Frame::lifeSupportTimerFired(Timer<Frame>*)
1070 {
1071 #ifndef NDEBUG
1072     keepAliveSet().remove(this);
1073 #endif
1074     deref();
1075 }
1076
1077 KJS::Bindings::RootObject* Frame::bindingRootObject()
1078 {
1079     Settings* settings = this->settings();
1080     if (!settings || !settings->isJavaScriptEnabled())
1081         return 0;
1082
1083     if (!d->m_bindingRootObject) {
1084         JSLock lock;
1085         d->m_bindingRootObject = KJS::Bindings::RootObject::create(0, scriptProxy()->interpreter());
1086     }
1087     return d->m_bindingRootObject.get();
1088 }
1089
1090 PassRefPtr<KJS::Bindings::RootObject> Frame::createRootObject(void* nativeHandle, PassRefPtr<KJS::Interpreter> interpreter)
1091 {
1092     RootObjectMap::iterator it = d->m_rootObjects.find(nativeHandle);
1093     if (it != d->m_rootObjects.end())
1094         return it->second;
1095     
1096     RefPtr<KJS::Bindings::RootObject> rootObject = KJS::Bindings::RootObject::create(nativeHandle, interpreter);
1097     
1098     d->m_rootObjects.set(nativeHandle, rootObject);
1099     return rootObject.release();
1100 }
1101
1102 #if USE(NPOBJECT)
1103 NPObject* Frame::windowScriptNPObject()
1104 {
1105     if (!d->m_windowScriptNPObject) {
1106         Settings* settings = this->settings();
1107         if (settings && settings->isJavaScriptEnabled()) {
1108             // JavaScript is enabled, so there is a JavaScript window object.  Return an NPObject bound to the window
1109             // object.
1110             KJS::JSLock lock;
1111             KJS::JSObject* win = KJS::Window::retrieveWindow(this);
1112             ASSERT(win);
1113             KJS::Bindings::RootObject* root = bindingRootObject();
1114             d->m_windowScriptNPObject = _NPN_CreateScriptObject(0, win, root, root);
1115         } else {
1116             // JavaScript is not enabled, so we cannot bind the NPObject to the JavaScript window object.
1117             // Instead, we create an NPObject of a different class, one which is not bound to a JavaScript object.
1118             d->m_windowScriptNPObject = _NPN_CreateNoScriptObject();
1119         }
1120     }
1121
1122     return d->m_windowScriptNPObject;
1123 }
1124 #endif
1125     
1126 void Frame::clearScriptProxy()
1127 {
1128     if (d->m_jscript)
1129         d->m_jscript->clear();
1130 }
1131
1132 void Frame::clearDOMWindow()
1133 {
1134     if (d->m_domWindow)
1135         d->m_domWindow->clear();
1136 }
1137
1138 void Frame::cleanupScriptObjectsForPlugin(void* nativeHandle)
1139 {
1140     RootObjectMap::iterator it = d->m_rootObjects.find(nativeHandle);
1141     
1142     if (it == d->m_rootObjects.end())
1143         return;
1144     
1145     it->second->invalidate();
1146     d->m_rootObjects.remove(it);
1147 }
1148     
1149 void Frame::clearScriptObjects()
1150 {
1151     JSLock lock;
1152
1153     RootObjectMap::const_iterator end = d->m_rootObjects.end();
1154     for (RootObjectMap::const_iterator it = d->m_rootObjects.begin(); it != end; ++it)
1155         it->second->invalidate();
1156
1157     d->m_rootObjects.clear();
1158
1159     if (d->m_bindingRootObject) {
1160         d->m_bindingRootObject->invalidate();
1161         d->m_bindingRootObject = 0;
1162     }
1163
1164 #if USE(NPOBJECT)
1165     if (d->m_windowScriptNPObject) {
1166         // Call _NPN_DeallocateObject() instead of _NPN_ReleaseObject() so that we don't leak if a plugin fails to release the window
1167         // script object properly.
1168         // This shouldn't cause any problems for plugins since they should have already been stopped and destroyed at this point.
1169         _NPN_DeallocateObject(d->m_windowScriptNPObject);
1170         d->m_windowScriptNPObject = 0;
1171     }
1172 #endif
1173
1174     clearPlatformScriptObjects();
1175 }
1176
1177 RenderObject *Frame::renderer() const
1178 {
1179     Document *doc = document();
1180     return doc ? doc->renderer() : 0;
1181 }
1182
1183 HTMLFrameOwnerElement* Frame::ownerElement() const
1184 {
1185     return d->m_ownerElement;
1186 }
1187
1188 RenderPart* Frame::ownerRenderer()
1189 {
1190     HTMLFrameOwnerElement* ownerElement = d->m_ownerElement;
1191     if (!ownerElement)
1192         return 0;
1193     return static_cast<RenderPart*>(ownerElement->renderer());
1194 }
1195
1196 // returns FloatRect because going through IntRect would truncate any floats
1197 FloatRect Frame::selectionRect(bool clipToVisibleContent) const
1198 {
1199     RenderView *root = static_cast<RenderView*>(renderer());
1200     if (!root)
1201         return IntRect();
1202     
1203     IntRect selectionRect = root->selectionRect(clipToVisibleContent);
1204     return clipToVisibleContent ? intersection(selectionRect, d->m_view->visibleContentRect()) : selectionRect;
1205 }
1206
1207 void Frame::selectionTextRects(Vector<FloatRect>& rects, bool clipToVisibleContent) const
1208 {
1209     RenderView *root = static_cast<RenderView*>(renderer());
1210     if (!root)
1211         return;
1212
1213     RefPtr<Range> selectedRange = selectionController()->toRange();
1214
1215     Vector<IntRect> intRects;
1216     selectedRange->addLineBoxRects(intRects, true);
1217
1218     unsigned size = intRects.size();
1219     FloatRect visibleContentRect = d->m_view->visibleContentRect();
1220     for (unsigned i = 0; i < size; ++i)
1221         if (clipToVisibleContent)
1222             rects.append(intersection(intRects[i], visibleContentRect));
1223         else
1224             rects.append(intRects[i]);
1225 }
1226
1227
1228 bool Frame::isFrameSet() const
1229 {
1230     Document* document = d->m_doc.get();
1231     if (!document || !document->isHTMLDocument())
1232         return false;
1233     Node *body = static_cast<HTMLDocument*>(document)->body();
1234     return body && body->renderer() && body->hasTagName(framesetTag);
1235 }
1236
1237 // Scans logically forward from "start", including any child frames
1238 static HTMLFormElement *scanForForm(Node *start)
1239 {
1240     Node *n;
1241     for (n = start; n; n = n->traverseNextNode()) {
1242         if (n->hasTagName(formTag))
1243             return static_cast<HTMLFormElement*>(n);
1244         else if (n->isHTMLElement() && static_cast<HTMLElement*>(n)->isGenericFormElement())
1245             return static_cast<HTMLGenericFormElement*>(n)->form();
1246         else if (n->hasTagName(frameTag) || n->hasTagName(iframeTag)) {
1247             Node *childDoc = static_cast<HTMLFrameElementBase*>(n)->contentDocument();
1248             if (HTMLFormElement *frameResult = scanForForm(childDoc))
1249                 return frameResult;
1250         }
1251     }
1252     return 0;
1253 }
1254
1255 // We look for either the form containing the current focus, or for one immediately after it
1256 HTMLFormElement *Frame::currentForm() const
1257 {
1258     // start looking either at the active (first responder) node, or where the selection is
1259     Node *start = d->m_doc ? d->m_doc->focusedNode() : 0;
1260     if (!start)
1261         start = selectionController()->start().node();
1262     
1263     // try walking up the node tree to find a form element
1264     Node *n;
1265     for (n = start; n; n = n->parentNode()) {
1266         if (n->hasTagName(formTag))
1267             return static_cast<HTMLFormElement*>(n);
1268         else if (n->isHTMLElement()
1269                    && static_cast<HTMLElement*>(n)->isGenericFormElement())
1270             return static_cast<HTMLGenericFormElement*>(n)->form();
1271     }
1272     
1273     // try walking forward in the node tree to find a form element
1274     return start ? scanForForm(start) : 0;
1275 }
1276
1277 // FIXME: should this go in SelectionController?
1278 void Frame::revealSelection(const RenderLayer::ScrollAlignment& alignment) const
1279 {
1280     IntRect rect;
1281     
1282     switch (selectionController()->state()) {
1283         case Selection::NONE:
1284             return;
1285             
1286         case Selection::CARET:
1287             rect = selectionController()->caretRect();
1288             break;
1289             
1290         case Selection::RANGE:
1291             rect = enclosingIntRect(selectionRect(false));
1292             break;
1293     }
1294
1295     Position start = selectionController()->start();
1296
1297     ASSERT(start.node());
1298     if (start.node() && start.node()->renderer()) {
1299         // FIXME: This code only handles scrolling the startContainer's layer, but
1300         // the selection rect could intersect more than just that. 
1301         // See <rdar://problem/4799899>.
1302         if (RenderLayer *layer = start.node()->renderer()->enclosingLayer())
1303             layer->scrollRectToVisible(rect, alignment, alignment);
1304     }
1305 }
1306
1307 void Frame::revealCaret(const RenderLayer::ScrollAlignment& alignment) const
1308 {
1309     if (selectionController()->isNone())
1310         return;
1311
1312     Position extent = selectionController()->extent();
1313     if (extent.node() && extent.node()->renderer()) {
1314         IntRect extentRect = VisiblePosition(extent).caretRect();
1315         RenderLayer* layer = extent.node()->renderer()->enclosingLayer();
1316         if (layer)
1317             layer->scrollRectToVisible(extentRect, alignment, alignment);
1318     }
1319 }
1320
1321 // FIXME: why is this here instead of on the FrameView?
1322 void Frame::paint(GraphicsContext* p, const IntRect& rect)
1323 {
1324 #ifndef NDEBUG
1325     bool fillWithRed;
1326     if (!document() || document()->printing())
1327         fillWithRed = false; // Printing, don't fill with red (can't remember why).
1328     else if (document()->ownerElement())
1329         fillWithRed = false; // Subframe, don't fill with red.
1330     else if (view() && view()->isTransparent())
1331         fillWithRed = false; // Transparent, don't fill with red.
1332     else if (d->m_paintRestriction == PaintRestrictionSelectionOnly || d->m_paintRestriction == PaintRestrictionSelectionOnlyBlackText)
1333         fillWithRed = false; // Selections are transparent, don't fill with red.
1334     else if (d->m_elementToDraw)
1335         fillWithRed = false; // Element images are transparent, don't fill with red.
1336     else
1337         fillWithRed = true;
1338     
1339     if (fillWithRed)
1340         p->fillRect(rect, Color(0xFF, 0, 0));
1341 #endif
1342
1343     bool isTopLevelPainter = !s_currentPaintTimeStamp;
1344     if (isTopLevelPainter)
1345         s_currentPaintTimeStamp = currentTime();
1346     
1347     if (renderer()) {
1348         ASSERT(d->m_view && !d->m_view->needsLayout());
1349         ASSERT(!d->m_isPainting);
1350         
1351         d->m_isPainting = true;
1352         
1353         // d->m_elementToDraw is used to draw only one element
1354         RenderObject *eltRenderer = d->m_elementToDraw ? d->m_elementToDraw->renderer() : 0;
1355         if (d->m_paintRestriction == PaintRestrictionNone)
1356             renderer()->document()->invalidateRenderedRectsForMarkersInRect(rect);
1357         renderer()->layer()->paint(p, rect, d->m_paintRestriction, eltRenderer);
1358         
1359         d->m_isPainting = false;
1360
1361         // Regions may have changed as a result of the visibility/z-index of element changing.
1362         if (renderer()->document()->dashboardRegionsDirty())
1363             renderer()->view()->frameView()->updateDashboardRegions();
1364     } else
1365         LOG_ERROR("called Frame::paint with nil renderer");
1366         
1367     if (isTopLevelPainter)
1368         s_currentPaintTimeStamp = 0;
1369 }
1370
1371 void Frame::setPaintRestriction(PaintRestriction pr)
1372 {
1373     d->m_paintRestriction = pr;
1374 }
1375     
1376 bool Frame::isPainting() const
1377 {
1378     return d->m_isPainting;
1379 }
1380
1381 void Frame::adjustPageHeight(float *newBottom, float oldTop, float oldBottom, float bottomLimit)
1382 {
1383     RenderView *root = static_cast<RenderView*>(document()->renderer());
1384     if (root) {
1385         // Use a context with painting disabled.
1386         GraphicsContext context((PlatformGraphicsContext*)0);
1387         root->setTruncatedAt((int)floorf(oldBottom));
1388         IntRect dirtyRect(0, (int)floorf(oldTop), root->docWidth(), (int)ceilf(oldBottom - oldTop));
1389         root->layer()->paint(&context, dirtyRect);
1390         *newBottom = root->bestTruncatedAt();
1391         if (*newBottom == 0)
1392             *newBottom = oldBottom;
1393     } else
1394         *newBottom = oldBottom;
1395 }
1396
1397 Frame* Frame::frameForWidget(const Widget* widget)
1398 {
1399     ASSERT_ARG(widget, widget);
1400
1401     if (RenderWidget* renderer = RenderWidget::find(widget))
1402         if (Node* node = renderer->node())
1403             return node->document()->frame();
1404
1405     // Assume all widgets are either a FrameView or owned by a RenderWidget.
1406     // FIXME: That assumption is not right for scroll bars!
1407     ASSERT(widget->isFrameView());
1408     return static_cast<const FrameView*>(widget)->frame();
1409 }
1410
1411 void Frame::forceLayout(bool allowSubtree)
1412 {
1413     FrameView *v = d->m_view.get();
1414     if (v) {
1415         v->layout(allowSubtree);
1416         // We cannot unschedule a pending relayout, since the force can be called with
1417         // a tiny rectangle from a drawRect update.  By unscheduling we in effect
1418         // "validate" and stop the necessary full repaint from occurring.  Basically any basic
1419         // append/remove DHTML is broken by this call.  For now, I have removed the optimization
1420         // until we have a better invalidation stategy. -dwh
1421         //v->unscheduleRelayout();
1422     }
1423 }
1424
1425 void Frame::forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth, bool adjustViewSize)
1426 {
1427     // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
1428     // the state of things before and after the layout
1429     RenderView *root = static_cast<RenderView*>(document()->renderer());
1430     if (root) {
1431         // This magic is basically copied from khtmlview::print
1432         int pageW = (int)ceilf(minPageWidth);
1433         root->setWidth(pageW);
1434         root->setNeedsLayoutAndPrefWidthsRecalc();
1435         forceLayout();
1436         
1437         // If we don't fit in the minimum page width, we'll lay out again. If we don't fit in the
1438         // maximum page width, we will lay out to the maximum page width and clip extra content.
1439         // FIXME: We are assuming a shrink-to-fit printing implementation.  A cropping
1440         // implementation should not do this!
1441         int rightmostPos = root->rightmostPosition();
1442         if (rightmostPos > minPageWidth) {
1443             pageW = min(rightmostPos, (int)ceilf(maxPageWidth));
1444             root->setWidth(pageW);
1445             root->setNeedsLayoutAndPrefWidthsRecalc();
1446             forceLayout();
1447         }
1448     }
1449
1450     if (adjustViewSize && view())
1451         view()->adjustViewSize();
1452 }
1453
1454 void Frame::sendResizeEvent()
1455 {
1456     if (Document* doc = document())
1457         doc->dispatchWindowEvent(EventNames::resizeEvent, false, false);
1458 }
1459
1460 void Frame::sendScrollEvent()
1461 {
1462     FrameView* v = d->m_view.get();
1463     if (!v)
1464         return;
1465     v->setWasScrolledByUser(true);
1466     Document* doc = document();
1467     if (!doc)
1468         return;
1469     doc->dispatchHTMLEvent(scrollEvent, true, false);
1470 }
1471
1472 void Frame::clearTimers(FrameView *view)
1473 {
1474     if (view) {
1475         view->unscheduleRelayout();
1476         if (view->frame()) {
1477             Document* document = view->frame()->document();
1478             if (document && document->renderer() && document->renderer()->hasLayer())
1479                 document->renderer()->layer()->suspendMarquees();
1480         }
1481     }
1482 }
1483
1484 void Frame::clearTimers()
1485 {
1486     clearTimers(d->m_view.get());
1487 }
1488
1489 RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const
1490 {
1491     nodeToRemove = 0;
1492     
1493     if (!document())
1494         return 0;
1495     if (selectionController()->isNone())
1496         return 0;
1497     
1498     Position pos = selectionController()->selection().visibleStart().deepEquivalent();
1499     if (!pos.isCandidate())
1500         return 0;
1501     Node *node = pos.node();
1502     if (!node)
1503         return 0;
1504     
1505     if (!d->m_typingStyle)
1506         return node->renderer()->style();
1507     
1508     ExceptionCode ec = 0;
1509     RefPtr<Element> styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
1510     ASSERT(ec == 0);
1511     
1512     String styleText = d->m_typingStyle->cssText() + " display: inline";
1513     styleElement->setAttribute(styleAttr, styleText.impl(), ec);
1514     ASSERT(ec == 0);
1515     
1516     styleElement->appendChild(document()->createEditingTextNode(""), ec);
1517     ASSERT(ec == 0);
1518     
1519     node->parentNode()->appendChild(styleElement, ec);
1520     ASSERT(ec == 0);
1521     
1522     nodeToRemove = styleElement.get();    
1523     return styleElement->renderer() ? styleElement->renderer()->style() : 0;
1524 }
1525
1526 void Frame::setSelectionFromNone()
1527 {
1528     // Put a caret inside the body if the entire frame is editable (either the 
1529     // entire WebView is editable or designMode is on for this document).
1530     Document *doc = document();
1531     if (!doc || !selectionController()->isNone() || !isContentEditable())
1532         return;
1533         
1534     Node* node = doc->documentElement();
1535     while (node && !node->hasTagName(bodyTag))
1536         node = node->traverseNextNode();
1537     if (node)
1538         selectionController()->setSelection(Selection(Position(node, 0), DOWNSTREAM));
1539 }
1540
1541 bool Frame::isActive() const
1542 {
1543     return d->m_isActive;
1544 }
1545
1546 void Frame::setIsActive(bool flag)
1547 {
1548     if (d->m_isActive == flag)
1549         return;
1550     d->m_isActive = flag;
1551
1552     // Because RenderObject::selectionBackgroundColor() and
1553     // RenderObject::selectionForegroundColor() check if the frame is active,
1554     // we have to update places those colors were painted.
1555     if (d->m_view)
1556         d->m_view->updateContents(enclosingIntRect(selectionRect()));
1557
1558     // Caret appears in the active frame.
1559     if (flag)
1560         setSelectionFromNone();
1561     setCaretVisible(flag);
1562
1563     // Because CSSStyleSelector::checkOneSelector() and
1564     // RenderTheme::isFocused() check if the frame is active, we have to
1565     // update style and theme state that depended on those.
1566     if (d->m_doc) {
1567         if (Node* node = d->m_doc->focusedNode()) {
1568             node->setChanged();
1569             if (RenderObject* renderer = node->renderer())
1570                 if (renderer && renderer->style()->hasAppearance())
1571                     theme()->stateChanged(renderer, FocusState);
1572         }
1573     }
1574
1575     // Secure keyboard entry is set by the active frame.
1576     if (d->m_doc->useSecureKeyboardEntryWhenActive())
1577         setUseSecureKeyboardEntry(flag);
1578 }
1579
1580 void Frame::setWindowHasFocus(bool flag)
1581 {
1582     if (d->m_windowHasFocus == flag)
1583         return;
1584     d->m_windowHasFocus = flag;
1585     
1586     if (Document *doc = document())
1587         doc->dispatchWindowEvent(flag ? focusEvent : blurEvent, false, false);
1588 }
1589
1590 bool Frame::inViewSourceMode() const
1591 {
1592     return d->m_inViewSourceMode;
1593 }
1594
1595 void Frame::setInViewSourceMode(bool mode) const
1596 {
1597     d->m_inViewSourceMode = mode;
1598 }
1599
1600 UChar Frame::backslashAsCurrencySymbol() const
1601 {
1602     Document *doc = document();
1603     if (!doc)
1604         return '\\';
1605     TextResourceDecoder *decoder = doc->decoder();
1606     if (!decoder)
1607         return '\\';
1608
1609     return decoder->encoding().backslashAsCurrencySymbol();
1610 }
1611
1612 static bool isInShadowTree(Node* node)
1613 {
1614     for (Node* n = node; n; n = n->parentNode())
1615         if (n->isShadowNode())
1616             return true;
1617     return false;
1618 }
1619
1620 // Searches from the beginning of the document if nothing is selected.
1621 bool Frame::findString(const String& target, bool forward, bool caseFlag, bool wrapFlag, bool startInSelection)
1622 {
1623     if (target.isEmpty() || !document())
1624         return false;
1625     
1626     // Start from an edge of the selection, if there's a selection that's not in shadow content. Which edge
1627     // is used depends on whether we're searching forward or backward, and whether startInSelection is set.
1628     RefPtr<Range> searchRange(rangeOfContents(document()));
1629     Selection selection(selectionController()->selection());
1630     Node* selectionBaseNode = selection.base().node();
1631     
1632     // FIXME 3099526: We don't search in the shadow trees (e.g. text fields and textareas), though we'd like to
1633     // someday. If we don't explicitly skip them here, we'll miss hits in the regular content.
1634     bool selectionIsInMainContent = selectionBaseNode && !isInShadowTree(selectionBaseNode);
1635
1636     if (selectionIsInMainContent) {
1637         if (forward)
1638             setStart(searchRange.get(), startInSelection ? selection.visibleStart() : selection.visibleEnd());
1639         else
1640             setEnd(searchRange.get(), startInSelection ? selection.visibleEnd() : selection.visibleStart());
1641     }
1642     RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, forward, caseFlag));
1643     // If we started in the selection and the found range exactly matches the existing selection, find again.
1644     // Build a selection with the found range to remove collapsed whitespace.
1645     // Compare ranges instead of selection objects to ignore the way that the current selection was made.
1646     if (startInSelection && selectionIsInMainContent && *Selection(resultRange.get()).toRange() == *selection.toRange()) {
1647         searchRange = rangeOfContents(document());
1648         if (forward)
1649             setStart(searchRange.get(), selection.visibleEnd());
1650         else
1651             setEnd(searchRange.get(), selection.visibleStart());
1652         resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
1653     }
1654     
1655     int exception = 0;
1656     
1657     // If we didn't find anything and we're wrapping, search again in the entire document (this will
1658     // redundantly re-search the area already searched in some cases).
1659     if (resultRange->collapsed(exception) && wrapFlag) {
1660         searchRange = rangeOfContents(document());
1661         resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
1662         // We used to return false here if we ended up with the same range that we started with
1663         // (e.g., the selection was already the only instance of this text). But we decided that
1664         // this should be a success case instead, so we'll just fall through in that case.
1665     }
1666
1667     if (resultRange->collapsed(exception))
1668         return false;
1669
1670     selectionController()->setSelection(Selection(resultRange.get(), DOWNSTREAM));
1671     revealSelection();
1672     return true;
1673 }
1674
1675 unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsigned limit)
1676 {
1677     if (target.isEmpty() || !document())
1678         return 0;
1679     
1680     RefPtr<Range> searchRange(rangeOfContents(document()));
1681     
1682     int exception = 0;
1683     unsigned matchCount = 0;
1684     do {
1685         RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, caseFlag));
1686         if (resultRange->collapsed(exception))
1687             break;
1688         
1689         // A non-collapsed result range can in some funky whitespace cases still not
1690         // advance the range's start position (4509328). Break to avoid infinite loop.
1691         VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
1692         if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
1693             break;
1694
1695         ++matchCount;
1696         
1697         document()->addMarker(resultRange.get(), DocumentMarker::TextMatch);        
1698         
1699         // Stop looking if we hit the specified limit. A limit of 0 means no limit.
1700         if (limit > 0 && matchCount >= limit)
1701             break;
1702         
1703         setStart(searchRange.get(), newStart);
1704     } while (true);
1705     
1706     // Do a "fake" paint in order to execute the code that computes the rendered rect for 
1707     // each text match.
1708     Document* doc = document();
1709     if (doc && d->m_view && renderer()) {
1710         doc->updateLayout(); // Ensure layout is up to date.
1711         IntRect visibleRect(enclosingIntRect(d->m_view->visibleContentRect()));
1712         GraphicsContext context((PlatformGraphicsContext*)0);
1713         context.setPaintingDisabled(true);
1714         paint(&context, visibleRect);
1715     }
1716     
1717     return matchCount;
1718 }
1719
1720 bool Frame::markedTextMatchesAreHighlighted() const
1721 {
1722     return d->m_highlightTextMatches;
1723 }
1724
1725 void Frame::setMarkedTextMatchesAreHighlighted(bool flag)
1726 {
1727     if (flag == d->m_highlightTextMatches || !document())
1728         return;
1729     
1730     d->m_highlightTextMatches = flag;
1731     document()->repaintMarkers(DocumentMarker::TextMatch);
1732 }
1733
1734 FrameTree* Frame::tree() const
1735 {
1736     return &d->m_treeNode;
1737 }
1738
1739 DOMWindow* Frame::domWindow() const
1740 {
1741     if (!d->m_domWindow)
1742         d->m_domWindow = new DOMWindow(const_cast<Frame*>(this));
1743
1744     return d->m_domWindow.get();
1745 }
1746
1747 Page* Frame::page() const
1748 {
1749     return d->m_page;
1750 }
1751
1752 EventHandler* Frame::eventHandler() const
1753 {
1754     return &d->m_eventHandler;
1755 }
1756
1757 void Frame::pageDestroyed()
1758 {
1759     if (Frame* parent = tree()->parent())
1760         parent->loader()->checkLoadComplete();
1761
1762     if (d->m_page && d->m_page->focusController()->focusedFrame() == this)
1763         d->m_page->focusController()->setFocusedFrame(0);
1764
1765     // This will stop any JS timers
1766     if (d->m_jscript && d->m_jscript->haveInterpreter())
1767         if (KJS::Window* w = KJS::Window::retrieveWindow(this))
1768             w->disconnectFrame();
1769
1770     d->m_page = 0;
1771 }
1772
1773 void Frame::disconnectOwnerElement()
1774 {
1775     if (d->m_ownerElement) {
1776         d->m_ownerElement->m_contentFrame = 0;
1777         if (d->m_page)
1778             d->m_page->decrementFrameCount();
1779     }
1780     d->m_ownerElement = 0;
1781 }
1782
1783 String Frame::documentTypeString() const
1784 {
1785     if (Document *doc = document())
1786         if (DocumentType *doctype = doc->realDocType())
1787             return doctype->toString();
1788
1789     return String();
1790 }
1791
1792 bool Frame::prohibitsScrolling() const
1793 {
1794     return d->m_prohibitsScrolling;
1795 }
1796
1797 void Frame::setProhibitsScrolling(bool prohibit)
1798 {
1799     d->m_prohibitsScrolling = prohibit;
1800 }
1801
1802 void Frame::focusWindow()
1803 {
1804     if (!page())
1805         return;
1806
1807     // If we're a top level window, bring the window to the front.
1808     if (!tree()->parent())
1809         page()->chrome()->focus();
1810
1811     eventHandler()->focusDocumentView();
1812 }
1813
1814 void Frame::unfocusWindow()
1815 {
1816     if (!page())
1817         return;
1818     
1819     // If we're a top level window, deactivate the window.
1820     if (!tree()->parent())
1821         page()->chrome()->unfocus();
1822 }
1823
1824 bool Frame::shouldClose()
1825 {
1826     Chrome* chrome = page() ? page()->chrome() : 0;
1827     if (!chrome || !chrome->canRunBeforeUnloadConfirmPanel())
1828         return true;
1829
1830     RefPtr<Document> doc = document();
1831     if (!doc)
1832         return true;
1833     HTMLElement* body = doc->body();
1834     if (!body)
1835         return true;
1836
1837     RefPtr<BeforeUnloadEvent> beforeUnloadEvent = new BeforeUnloadEvent;
1838     beforeUnloadEvent->setTarget(doc);
1839     doc->handleWindowEvent(beforeUnloadEvent.get(), false);
1840
1841     if (!beforeUnloadEvent->defaultPrevented() && doc)
1842         doc->defaultEventHandler(beforeUnloadEvent.get());
1843     if (beforeUnloadEvent->result().isNull())
1844         return true;
1845
1846     String text = beforeUnloadEvent->result();
1847     text.replace('\\', backslashAsCurrencySymbol());
1848
1849     return chrome->runBeforeUnloadConfirmPanel(text, this);
1850 }
1851
1852 void Frame::scheduleClose()
1853 {
1854     if (!shouldClose())
1855         return;
1856
1857     Chrome* chrome = page() ? page()->chrome() : 0;
1858     if (chrome)
1859         chrome->closeWindowSoon();
1860 }
1861
1862 void Frame::respondToChangedSelection(const Selection& oldSelection, bool closeTyping)
1863 {
1864     if (document()) {
1865         bool isContinuousSpellCheckingEnabled = editor()->isContinuousSpellCheckingEnabled();
1866         bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled && editor()->isGrammarCheckingEnabled();
1867         if (isContinuousSpellCheckingEnabled) {
1868             Selection newAdjacentWords;
1869             Selection newSelectedSentence;
1870             if (selectionController()->selection().isContentEditable()) {
1871                 VisiblePosition newStart(selectionController()->selection().visibleStart());
1872                 newAdjacentWords = Selection(startOfWord(newStart, LeftWordIfOnBoundary), endOfWord(newStart, RightWordIfOnBoundary));
1873                 if (isContinuousGrammarCheckingEnabled)
1874                     newSelectedSentence = Selection(startOfSentence(newStart), endOfSentence(newStart));
1875             }
1876
1877             // When typing we check spelling elsewhere, so don't redo it here.
1878             // If this is a change in selection resulting from a delete operation,
1879             // oldSelection may no longer be in the document.
1880             if (closeTyping && oldSelection.isContentEditable() && oldSelection.start().node() && oldSelection.start().node()->inDocument()) {
1881                 VisiblePosition oldStart(oldSelection.visibleStart());
1882                 Selection oldAdjacentWords = Selection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));   
1883                 if (oldAdjacentWords != newAdjacentWords) {
1884                     editor()->markMisspellings(oldAdjacentWords);
1885                     if (isContinuousGrammarCheckingEnabled) {
1886                         Selection oldSelectedSentence = Selection(startOfSentence(oldStart), endOfSentence(oldStart));   
1887                         if (oldSelectedSentence != newSelectedSentence)
1888                             editor()->markBadGrammar(oldSelectedSentence);
1889                     }
1890                 }
1891             }
1892
1893             // This only erases markers that are in the first unit (word or sentence) of the selection.
1894             // Perhaps peculiar, but it matches AppKit.
1895             if (RefPtr<Range> wordRange = newAdjacentWords.toRange())
1896                 document()->removeMarkers(wordRange.get(), DocumentMarker::Spelling);
1897             if (RefPtr<Range> sentenceRange = newSelectedSentence.toRange())
1898                 document()->removeMarkers(sentenceRange.get(), DocumentMarker::Grammar);
1899         }
1900
1901         // When continuous spell checking is off, existing markers disappear after the selection changes.
1902         if (!isContinuousSpellCheckingEnabled)
1903             document()->removeMarkers(DocumentMarker::Spelling);
1904         if (!isContinuousGrammarCheckingEnabled)
1905             document()->removeMarkers(DocumentMarker::Grammar);
1906     }
1907
1908     editor()->respondToChangedSelection(oldSelection);
1909 }
1910
1911 VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint)
1912 {
1913     HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, true);
1914     Node* node = result.innerNode();
1915     if (!node)
1916         return VisiblePosition();
1917     RenderObject* renderer = node->renderer();
1918     if (!renderer)
1919         return VisiblePosition();
1920     VisiblePosition visiblePos = renderer->positionForCoordinates(result.localPoint().x(), result.localPoint().y());
1921     if (visiblePos.isNull())
1922         visiblePos = VisiblePosition(Position(node, 0));
1923     return visiblePos;
1924 }
1925     
1926 Document* Frame::documentAtPoint(const IntPoint& point)
1927 {  
1928     if (!view()) 
1929         return 0;
1930     
1931     IntPoint pt = view()->windowToContents(point);
1932     HitTestResult result = HitTestResult(pt);
1933     
1934     if (renderer())
1935         result = eventHandler()->hitTestResultAtPoint(pt, false);
1936     return result.innerNode() ? result.innerNode()->document() : 0;
1937 }
1938     
1939 FramePrivate::FramePrivate(Page* page, Frame* parent, Frame* thisFrame, HTMLFrameOwnerElement* ownerElement,
1940                            FrameLoaderClient* frameLoaderClient)
1941     : m_page(page)
1942     , m_treeNode(thisFrame, parent)
1943     , m_ownerElement(ownerElement)
1944     , m_jscript(0)
1945     , m_zoomFactor(parent ? parent->d->m_zoomFactor : 100)
1946     , m_selectionController(thisFrame)
1947     , m_caretBlinkTimer(thisFrame, &Frame::caretBlinkTimerFired)
1948     , m_editor(thisFrame)
1949     , m_eventHandler(thisFrame)
1950     , m_caretVisible(false)
1951     , m_caretPaint(true)
1952     , m_isActive(false)
1953     , m_isPainting(false)
1954     , m_lifeSupportTimer(thisFrame, &Frame::lifeSupportTimerFired)
1955     , m_loader(new FrameLoader(thisFrame, frameLoaderClient))
1956     , m_userStyleSheetLoader(0)
1957     , m_paintRestriction(PaintRestrictionNone)
1958     , m_highlightTextMatches(false)
1959     , m_windowHasFocus(false)
1960     , m_inViewSourceMode(false)
1961     , frameCount(0)
1962     , m_prohibitsScrolling(false)
1963     , m_windowScriptNPObject(0)
1964 #if PLATFORM(MAC)
1965     , m_windowScriptObject(nil)
1966     , m_bridge(nil)
1967 #endif
1968 {
1969 }
1970
1971 FramePrivate::~FramePrivate()
1972 {
1973     delete m_jscript;
1974     delete m_loader;
1975 }
1976
1977 } // namespace WebCore