Reviewed by Darin.
[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 double Frame::s_currentPaintTimeStamp = 0.0;
94
95 class UserStyleSheetLoader : public CachedResourceClient {
96 public:
97     UserStyleSheetLoader(PassRefPtr<Document> document, const String& url)
98         : m_document(document)
99         , m_cachedSheet(m_document->docLoader()->requestUserCSSStyleSheet(url, ""))
100     {
101         if (m_cachedSheet) {
102             m_document->addPendingSheet();
103             m_cachedSheet->ref(this);
104         }
105     }
106     ~UserStyleSheetLoader()
107     {
108         if (m_cachedSheet) {
109             if (!m_cachedSheet->isLoaded())
110                 m_document->removePendingSheet();        
111             m_cachedSheet->deref(this);
112         }
113     }
114 private:
115     virtual void setCSSStyleSheet(const String& /*URL*/, const String& /*charset*/, const String& sheet)
116     {
117         m_document->removePendingSheet();
118         if (Frame* frame = m_document->frame())
119             frame->setUserStyleSheet(sheet);
120     }
121     RefPtr<Document> m_document;
122     CachedCSSStyleSheet* m_cachedSheet;
123 };
124
125 #ifndef NDEBUG
126 WTFLogChannel LogWebCoreFrameLeaks =  { 0x00000000, "", WTFLogChannelOn };
127
128 struct FrameCounter { 
129     static int count; 
130     ~FrameCounter() 
131     { 
132         if (count)
133             LOG(WebCoreFrameLeaks, "LEAK: %d Frame\n", count);
134     }
135 };
136 int FrameCounter::count = 0;
137 static FrameCounter frameCounter;
138 #endif
139
140 static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
141 {
142     if (!ownerElement)
143         return 0;
144     return ownerElement->document()->frame();
145 }
146
147 Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient) 
148     : d(new FramePrivate(page, parentFromOwnerElement(ownerElement), this, ownerElement, frameLoaderClient))
149 {
150     AtomicString::init();
151     EventNames::init();
152     HTMLNames::init();
153     QualifiedName::init();
154     MediaFeatureNames::init();
155
156 #if ENABLE(SVG)
157     SVGNames::init();
158     XLinkNames::init();
159 #endif
160
161     XMLNames::init();
162
163     if (!ownerElement)
164         page->setMainFrame(this);
165     else {
166         // FIXME: Frames were originally created with a refcount of 1.
167         // Leave this ref call here until we can straighten that out.
168         ref();
169         page->incrementFrameCount();
170         ownerElement->m_contentFrame = this;
171     }
172
173 #ifndef NDEBUG
174     ++FrameCounter::count;
175 #endif
176 }
177
178 Frame::~Frame()
179 {
180     setView(0);
181     loader()->clearRecordedFormValues();
182
183 #if PLATFORM(MAC)
184     setBridge(0);
185 #endif
186     
187     loader()->cancelAndClear();
188     
189     // FIXME: We should not be doing all this work inside the destructor
190
191     ASSERT(!d->m_lifeSupportTimer.isActive());
192
193 #ifndef NDEBUG
194     --FrameCounter::count;
195 #endif
196
197     if (d->m_jscript && d->m_jscript->haveGlobalObject())
198         static_cast<KJS::Window*>(d->m_jscript->globalObject())->disconnectFrame();
199
200     disconnectOwnerElement();
201     
202     if (d->m_domWindow)
203         d->m_domWindow->disconnectFrame();
204             
205     if (d->m_view) {
206         d->m_view->hide();
207         d->m_view->clearFrame();
208     }
209   
210     ASSERT(!d->m_lifeSupportTimer.isActive());
211
212     delete d->m_userStyleSheetLoader;
213     delete d;
214     d = 0;
215 }
216
217 void Frame::init()
218 {
219     d->m_loader->init();
220 }
221
222 FrameLoader* Frame::loader() const
223 {
224     return d->m_loader;
225 }
226
227 FrameView* Frame::view() const
228 {
229     return d->m_view.get();
230 }
231
232 void Frame::setView(FrameView* view)
233 {
234     // Detach the document now, so any onUnload handlers get run - if
235     // we wait until the view is destroyed, then things won't be
236     // hooked up enough for some JavaScript calls to work.
237     if (!view && d->m_doc && d->m_doc->attached() && !d->m_doc->inPageCache()) {
238         // FIXME: We don't call willRemove here. Why is that OK?
239         d->m_doc->detach();
240         if (d->m_view)
241             d->m_view->unscheduleRelayout();
242     }
243     eventHandler()->clear();
244
245     d->m_view = view;
246
247     // Only one form submission is allowed per view of a part.
248     // Since this part may be getting reused as a result of being
249     // pulled from the back/forward cache, reset this flag.
250     loader()->resetMultipleFormSubmissionProtection();
251 }
252
253 KJSProxy *Frame::scriptProxy()
254 {
255     if (!d->m_jscript) {
256         Settings* settings = this->settings();
257         if (settings && settings->isJavaScriptEnabled())
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.string());
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 AnimationController* Frame::animationController() const
368 {
369     return &d->m_animationController;
370 }
371
372 // Either get cached regexp or build one that matches any of the labels.
373 // The regexp we build is of the form:  (STR1|STR2|STRN)
374 static RegularExpression *regExpForLabels(const Vector<String>& labels)
375 {
376     // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being
377     // the same across calls.  We can't do that.
378
379     static RegularExpression wordRegExp = RegularExpression("\\w");
380     DeprecatedString pattern("(");
381     unsigned int numLabels = labels.size();
382     unsigned int i;
383     for (i = 0; i < numLabels; i++) {
384         DeprecatedString label = labels[i].deprecatedString();
385
386         bool startsWithWordChar = false;
387         bool endsWithWordChar = false;
388         if (label.length() != 0) {
389             startsWithWordChar = wordRegExp.search(label.at(0)) >= 0;
390             endsWithWordChar = wordRegExp.search(label.at(label.length() - 1)) >= 0;
391         }
392         
393         if (i != 0)
394             pattern.append("|");
395         // Search for word boundaries only if label starts/ends with "word characters".
396         // If we always searched for word boundaries, this wouldn't work for languages
397         // such as Japanese.
398         if (startsWithWordChar) {
399             pattern.append("\\b");
400         }
401         pattern.append(label);
402         if (endsWithWordChar) {
403             pattern.append("\\b");
404         }
405     }
406     pattern.append(")");
407     return new RegularExpression(pattern, false);
408 }
409
410 String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell)
411 {
412     RenderTableCell* cellRenderer = static_cast<RenderTableCell*>(cell->renderer());
413
414     if (cellRenderer && cellRenderer->isTableCell()) {
415         RenderTableCell* cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer);
416
417         if (cellAboveRenderer) {
418             HTMLTableCellElement* aboveCell =
419                 static_cast<HTMLTableCellElement*>(cellAboveRenderer->element());
420
421             if (aboveCell) {
422                 // search within the above cell we found for a match
423                 for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
424                     if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
425                         // For each text chunk, run the regexp
426                         DeprecatedString nodeString = n->nodeValue().deprecatedString();
427                         int pos = regExp->searchRev(nodeString);
428                         if (pos >= 0)
429                             return nodeString.mid(pos, regExp->matchedLength());
430                     }
431                 }
432             }
433         }
434     }
435     // Any reason in practice to search all cells in that are above cell?
436     return String();
437 }
438
439 String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element)
440 {
441     RegularExpression* regExp = regExpForLabels(labels);
442     // We stop searching after we've seen this many chars
443     const unsigned int charsSearchedThreshold = 500;
444     // This is the absolute max we search.  We allow a little more slop than
445     // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
446     const unsigned int maxCharsSearched = 600;
447     // If the starting element is within a table, the cell that contains it
448     HTMLTableCellElement* startingTableCell = 0;
449     bool searchedCellAbove = false;
450
451     // walk backwards in the node tree, until another element, or form, or end of tree
452     int unsigned lengthSearched = 0;
453     Node* n;
454     for (n = element->traversePreviousNode();
455          n && lengthSearched < charsSearchedThreshold;
456          n = n->traversePreviousNode())
457     {
458         if (n->hasTagName(formTag)
459             || (n->isHTMLElement()
460                 && static_cast<HTMLElement*>(n)->isGenericFormElement()))
461         {
462             // We hit another form element or the start of the form - bail out
463             break;
464         } else if (n->hasTagName(tdTag) && !startingTableCell) {
465             startingTableCell = static_cast<HTMLTableCellElement*>(n);
466         } else if (n->hasTagName(trTag) && startingTableCell) {
467             String result = searchForLabelsAboveCell(regExp, startingTableCell);
468             if (!result.isEmpty())
469                 return result;
470             searchedCellAbove = true;
471         } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
472             // For each text chunk, run the regexp
473             DeprecatedString nodeString = n->nodeValue().deprecatedString();
474             // add 100 for slop, to make it more likely that we'll search whole nodes
475             if (lengthSearched + nodeString.length() > maxCharsSearched)
476                 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
477             int pos = regExp->searchRev(nodeString);
478             if (pos >= 0)
479                 return nodeString.mid(pos, regExp->matchedLength());
480             else
481                 lengthSearched += nodeString.length();
482         }
483     }
484
485     // If we started in a cell, but bailed because we found the start of the form or the
486     // previous element, we still might need to search the row above us for a label.
487     if (startingTableCell && !searchedCellAbove) {
488          return searchForLabelsAboveCell(regExp, startingTableCell);
489     }
490     return String();
491 }
492
493 String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element)
494 {
495     DeprecatedString name = element->getAttribute(nameAttr).deprecatedString();
496     // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
497     name.replace(RegularExpression("\\d"), " ");
498     name.replace('_', ' ');
499     
500     RegularExpression* regExp = regExpForLabels(labels);
501     // Use the largest match we can find in the whole name string
502     int pos;
503     int length;
504     int bestPos = -1;
505     int bestLength = -1;
506     int start = 0;
507     do {
508         pos = regExp->search(name, start);
509         if (pos != -1) {
510             length = regExp->matchedLength();
511             if (length >= bestLength) {
512                 bestPos = pos;
513                 bestLength = length;
514             }
515             start = pos+1;
516         }
517     } while (pos != -1);
518
519     if (bestPos != -1)
520         return name.mid(bestPos, bestLength);
521     return String();
522 }
523
524 const Selection& Frame::mark() const
525 {
526     return d->m_mark;
527 }
528
529 void Frame::setMark(const Selection& s)
530 {
531     ASSERT(!s.base().node() || s.base().node()->document() == document());
532     ASSERT(!s.extent().node() || s.extent().node()->document() == document());
533     ASSERT(!s.start().node() || s.start().node()->document() == document());
534     ASSERT(!s.end().node() || s.end().node()->document() == document());
535
536     d->m_mark = s;
537 }
538
539 void Frame::notifyRendererOfSelectionChange(bool userTriggered)
540 {
541     RenderObject* renderer = 0;
542     if (selectionController()->rootEditableElement())
543         renderer = selectionController()->rootEditableElement()->shadowAncestorNode()->renderer();
544
545     // If the current selection is in a textfield or textarea, notify the renderer that the selection has changed
546     if (renderer && (renderer->isTextArea() || renderer->isTextField()))
547         static_cast<RenderTextControl*>(renderer)->selectionChanged(userTriggered);
548 }
549
550 void Frame::invalidateSelection()
551 {
552     selectionController()->setNeedsLayout();
553     selectionLayoutChanged();
554 }
555
556 void Frame::setCaretVisible(bool flag)
557 {
558     if (d->m_caretVisible == flag)
559         return;
560     clearCaretRectIfNeeded();
561     d->m_caretVisible = flag;
562     selectionLayoutChanged();
563 }
564
565 void Frame::clearCaretRectIfNeeded()
566 {
567     if (d->m_caretPaint) {
568         d->m_caretPaint = false;
569         selectionController()->invalidateCaretRect();
570     }
571 }
572
573 // Helper function that tells whether a particular node is an element that has an entire
574 // Frame and FrameView, a <frame>, <iframe>, or <object>.
575 static bool isFrameElement(const Node *n)
576 {
577     if (!n)
578         return false;
579     RenderObject *renderer = n->renderer();
580     if (!renderer || !renderer->isWidget())
581         return false;
582     Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
583     return widget && widget->isFrameView();
584 }
585
586 void Frame::setFocusedNodeIfNeeded()
587 {
588     if (!document() || selectionController()->isNone() || !d->m_isActive)
589         return;
590
591     Node* target = selectionController()->rootEditableElement();
592     if (target) {
593         RenderObject* renderer = target->renderer();
594
595         // Walk up the render tree to search for a node to focus.
596         // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
597         while (renderer) {
598             // We don't want to set focus on a subframe when selecting in a parent frame,
599             // so add the !isFrameElement check here. There's probably a better way to make this
600             // work in the long term, but this is the safest fix at this time.
601             if (target && target->isMouseFocusable() && !isFrameElement(target)) {
602                 page()->focusController()->setFocusedNode(target, this);
603                 return;
604             }
605             renderer = renderer->parent();
606             if (renderer)
607                 target = renderer->element();
608         }
609         document()->setFocusedNode(0);
610     }
611 }
612
613 void Frame::selectionLayoutChanged()
614 {
615     bool caretRectChanged = selectionController()->recomputeCaretRect();
616
617     bool shouldBlink = d->m_caretVisible
618         && selectionController()->isCaret() && selectionController()->isContentEditable();
619
620     // If the caret moved, stop the blink timer so we can restart with a
621     // black caret in the new location.
622     if (caretRectChanged || !shouldBlink)
623         d->m_caretBlinkTimer.stop();
624
625     // Start blinking with a black caret. Be sure not to restart if we're
626     // already blinking in the right location.
627     if (shouldBlink && !d->m_caretBlinkTimer.isActive()) {
628         d->m_caretBlinkTimer.startRepeating(theme()->caretBlinkFrequency());
629         if (!d->m_caretPaint) {
630             d->m_caretPaint = true;
631             selectionController()->invalidateCaretRect();
632         }
633     }
634
635     if (!renderer())
636         return;
637     RenderView* canvas = static_cast<RenderView*>(renderer());
638
639     Selection selection = selectionController()->selection();
640         
641     if (!selection.isRange())
642         canvas->clearSelection();
643     else {
644         // Use the rightmost candidate for the start of the selection, and the leftmost candidate for the end of the selection.
645         // Example: foo <a>bar</a>.  Imagine that a line wrap occurs after 'foo', and that 'bar' is selected.   If we pass [foo, 3]
646         // as the start of the selection, the selection painting code will think that content on the line containing 'foo' is selected
647         // and will fill the gap before 'bar'.
648         Position startPos = selection.visibleStart().deepEquivalent();
649         if (startPos.downstream().isCandidate())
650             startPos = startPos.downstream();
651         Position endPos = selection.visibleEnd().deepEquivalent();
652         if (endPos.upstream().isCandidate())
653             endPos = endPos.upstream();
654         
655         // We can get into a state where the selection endpoints map to the same VisiblePosition when a selection is deleted
656         // because we don't yet notify the SelectionController of text removal.
657         if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) {
658             RenderObject *startRenderer = startPos.node()->renderer();
659             RenderObject *endRenderer = endPos.node()->renderer();
660             canvas->setSelection(startRenderer, startPos.offset(), endRenderer, endPos.offset());
661         }
662     }
663 }
664
665 void Frame::caretBlinkTimerFired(Timer<Frame>*)
666 {
667     ASSERT(d->m_caretVisible);
668     ASSERT(selectionController()->isCaret());
669     bool caretPaint = d->m_caretPaint;
670     if (selectionController()->isCaretBlinkingSuspended() && caretPaint)
671         return;
672     d->m_caretPaint = !caretPaint;
673     selectionController()->invalidateCaretRect();
674 }
675
676 void Frame::paintCaret(GraphicsContext* p, const IntRect& rect) const
677 {
678     if (d->m_caretPaint && d->m_caretVisible)
679         selectionController()->paintCaret(p, rect);
680 }
681
682 void Frame::paintDragCaret(GraphicsContext* p, const IntRect& rect) const
683 {
684     SelectionController* dragCaretController = d->m_page->dragCaretController();
685     ASSERT(dragCaretController->selection().isCaret());
686     if (dragCaretController->selection().start().node()->document()->frame() == this)
687         dragCaretController->paintCaret(p, rect);
688 }
689
690 int Frame::zoomFactor() const
691 {
692   return d->m_zoomFactor;
693 }
694
695 void Frame::setZoomFactor(int percent)
696 {  
697   if (d->m_zoomFactor == percent)
698       return;
699
700 #if ENABLE(SVG)
701     if (d->m_doc && d->m_doc->isSVGDocument()) {
702         if (!static_cast<SVGDocument*>(d->m_doc.get())->zoomAndPanEnabled())
703             return;
704         d->m_zoomFactor = percent;
705         if (d->m_doc->renderer())
706             d->m_doc->renderer()->repaint();
707         return;
708     }
709 #endif
710   d->m_zoomFactor = percent;
711   if (d->m_doc)
712       d->m_doc->recalcStyle(Node::Force);
713
714   for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
715       child->setZoomFactor(d->m_zoomFactor);
716
717   if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout())
718       view()->layout();
719 }
720
721 void Frame::setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize)
722 {
723     if (!d->m_doc)
724         return;
725
726     d->m_doc->setPrinting(printing);
727     view()->setMediaType(printing ? "print" : "screen");
728     d->m_doc->updateStyleSelector();
729     forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth, adjustViewSize);
730
731     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
732         child->setPrinting(printing, minPageWidth, maxPageWidth, adjustViewSize);
733 }
734
735 void Frame::setJSStatusBarText(const String& text)
736 {
737     d->m_kjsStatusBarText = text;
738     if (d->m_page)
739         d->m_page->chrome()->setStatusbarText(this, d->m_kjsStatusBarText);
740 }
741
742 void Frame::setJSDefaultStatusBarText(const String& text)
743 {
744     d->m_kjsDefaultStatusBarText = text;
745     if (d->m_page)
746         d->m_page->chrome()->setStatusbarText(this, d->m_kjsDefaultStatusBarText);
747 }
748
749 String Frame::jsStatusBarText() const
750 {
751     return d->m_kjsStatusBarText;
752 }
753
754 String Frame::jsDefaultStatusBarText() const
755 {
756    return d->m_kjsDefaultStatusBarText;
757 }
758
759 void Frame::setNeedsReapplyStyles()
760 {
761     if (d->m_needsReapplyStyles)
762         return;
763
764     d->m_needsReapplyStyles = true;
765
766     // Invalidate the FrameView so that FrameView::layout will get called,
767     // which calls reapplyStyles.
768     view()->invalidate();
769 }
770
771 bool Frame::needsReapplyStyles() const
772 {
773     return d->m_needsReapplyStyles;
774 }
775
776 void Frame::reapplyStyles()
777 {
778     d->m_needsReapplyStyles = false;
779
780     // FIXME: This call doesn't really make sense in a method called
781     // "reapplyStyles". We should probably eventually move it into its own
782     // method.
783     if (d->m_doc)
784         d->m_doc->docLoader()->setAutoLoadImages(d->m_page && d->m_page->settings()->loadsImagesAutomatically());
785         
786     const KURL userStyleSheetLocation = d->m_page ? d->m_page->settings()->userStyleSheetLocation() : KURL();
787     if (!userStyleSheetLocation.isEmpty())
788         setUserStyleSheetLocation(userStyleSheetLocation);
789     else
790         setUserStyleSheet(String());
791
792     // FIXME: It's not entirely clear why the following is needed.
793     // The document automatically does this as required when you set the style sheet.
794     // But we had problems when this code was removed. Details are in
795     // <http://bugs.webkit.org/show_bug.cgi?id=8079>.
796     if (d->m_doc)
797         d->m_doc->updateStyleSelector();
798 }
799
800 bool Frame::shouldChangeSelection(const Selection& newSelection) const
801 {
802     return shouldChangeSelection(selectionController()->selection(), newSelection, newSelection.affinity(), false);
803 }
804
805 bool Frame::shouldChangeSelection(const Selection& oldSelection, const Selection& newSelection, EAffinity affinity, bool stillSelecting) const
806 {
807     return editor()->client()->shouldChangeSelectedRange(oldSelection.toRange().get(), newSelection.toRange().get(),
808                                                          affinity, stillSelecting);
809 }
810
811 bool Frame::shouldDeleteSelection(const Selection& selection) const
812 {
813     return editor()->client()->shouldDeleteRange(selection.toRange().get());
814 }
815
816 bool Frame::isContentEditable() const 
817 {
818     if (d->m_editor.clientIsEditable())
819         return true;
820     if (!d->m_doc)
821         return false;
822     return d->m_doc->inDesignMode();
823 }
824
825 #if !PLATFORM(MAC)
826
827 void Frame::setUseSecureKeyboardEntry(bool)
828 {
829 }
830
831 #endif
832
833 void Frame::updateSecureKeyboardEntryIfActive()
834 {
835     if (d->m_isActive)
836         setUseSecureKeyboardEntry(d->m_doc->useSecureKeyboardEntryWhenActive());
837 }
838
839 CSSMutableStyleDeclaration *Frame::typingStyle() const
840 {
841     return d->m_typingStyle.get();
842 }
843
844 void Frame::setTypingStyle(CSSMutableStyleDeclaration *style)
845 {
846     d->m_typingStyle = style;
847 }
848
849 void Frame::clearTypingStyle()
850 {
851     d->m_typingStyle = 0;
852 }
853
854 void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction editingAction)
855 {
856     if (!style || style->length() == 0) {
857         clearTypingStyle();
858         return;
859     }
860
861     // Calculate the current typing style.
862     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
863     if (typingStyle()) {
864         typingStyle()->merge(mutableStyle.get());
865         mutableStyle = typingStyle();
866     }
867
868     Node *node = selectionController()->selection().visibleStart().deepEquivalent().node();
869     CSSComputedStyleDeclaration computedStyle(node);
870     computedStyle.diff(mutableStyle.get());
871     
872     // Handle block styles, substracting these from the typing style.
873     RefPtr<CSSMutableStyleDeclaration> blockStyle = mutableStyle->copyBlockProperties();
874     blockStyle->diff(mutableStyle.get());
875     if (document() && blockStyle->length() > 0)
876         applyCommand(new ApplyStyleCommand(document(), blockStyle.get(), editingAction));
877     
878     // Set the remaining style as the typing style.
879     d->m_typingStyle = mutableStyle.release();
880 }
881
882 String Frame::selectionStartStylePropertyValue(int stylePropertyID) const
883 {
884     Node *nodeToRemove;
885     RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
886     if (!selectionStyle)
887         return String();
888
889     String value = selectionStyle->getPropertyValue(stylePropertyID);
890
891     if (nodeToRemove) {
892         ExceptionCode ec = 0;
893         nodeToRemove->remove(ec);
894         ASSERT(ec == 0);
895     }
896
897     return value;
898 }
899
900 CSSComputedStyleDeclaration *Frame::selectionComputedStyle(Node *&nodeToRemove) const
901 {
902     nodeToRemove = 0;
903
904     if (!document())
905         return 0;
906
907     if (selectionController()->isNone())
908         return 0;
909
910     RefPtr<Range> range(selectionController()->toRange());
911     Position pos = range->editingStartPosition();
912
913     Element *elem = pos.element();
914     if (!elem)
915         return 0;
916     
917     RefPtr<Element> styleElement = elem;
918     ExceptionCode ec = 0;
919
920     if (d->m_typingStyle) {
921         styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
922         ASSERT(ec == 0);
923
924         styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
925         ASSERT(ec == 0);
926         
927         styleElement->appendChild(document()->createEditingTextNode(""), ec);
928         ASSERT(ec == 0);
929
930         if (elem->renderer() && elem->renderer()->canHaveChildren()) {
931             elem->appendChild(styleElement, ec);
932         } else {
933             Node *parent = elem->parent();
934             Node *next = elem->nextSibling();
935
936             if (next) {
937                 parent->insertBefore(styleElement, next, ec);
938             } else {
939                 parent->appendChild(styleElement, ec);
940             }
941         }
942         ASSERT(ec == 0);
943
944         nodeToRemove = styleElement.get();
945     }
946
947     return new CSSComputedStyleDeclaration(styleElement);
948 }
949
950 void Frame::textFieldDidBeginEditing(Element* e)
951 {
952     if (editor()->client())
953         editor()->client()->textFieldDidBeginEditing(e);
954 }
955
956 void Frame::textFieldDidEndEditing(Element* e)
957 {
958     if (editor()->client())
959         editor()->client()->textFieldDidEndEditing(e);
960 }
961
962 void Frame::textDidChangeInTextField(Element* e)
963 {
964     if (editor()->client())
965         editor()->client()->textDidChangeInTextField(e);
966 }
967
968 bool Frame::doTextFieldCommandFromEvent(Element* e, KeyboardEvent* ke)
969 {
970     if (editor()->client())
971         return editor()->client()->doTextFieldCommandFromEvent(e, ke);
972
973     return false;
974 }
975
976 void Frame::textWillBeDeletedInTextField(Element* input)
977 {
978     if (editor()->client())
979         editor()->client()->textWillBeDeletedInTextField(input);
980 }
981
982 void Frame::textDidChangeInTextArea(Element* e)
983 {
984     if (editor()->client())
985         editor()->client()->textDidChangeInTextArea(e);
986 }
987
988 void Frame::applyEditingStyleToBodyElement() const
989 {
990     if (!d->m_doc)
991         return;
992         
993     RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
994     unsigned len = list->length();
995     for (unsigned i = 0; i < len; i++) {
996         applyEditingStyleToElement(static_cast<Element*>(list->item(i)));    
997     }
998 }
999
1000 void Frame::removeEditingStyleFromBodyElement() const
1001 {
1002     if (!d->m_doc)
1003         return;
1004         
1005     RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
1006     unsigned len = list->length();
1007     for (unsigned i = 0; i < len; i++) {
1008         removeEditingStyleFromElement(static_cast<Element*>(list->item(i)));    
1009     }
1010 }
1011
1012 void Frame::applyEditingStyleToElement(Element* element) const
1013 {
1014     if (!element)
1015         return;
1016
1017     CSSStyleDeclaration* style = element->style();
1018     ASSERT(style);
1019
1020     ExceptionCode ec = 0;
1021     style->setProperty(CSS_PROP_WORD_WRAP, "break-word", false, ec);
1022     ASSERT(ec == 0);
1023     style->setProperty(CSS_PROP__WEBKIT_NBSP_MODE, "space", false, ec);
1024     ASSERT(ec == 0);
1025     style->setProperty(CSS_PROP__WEBKIT_LINE_BREAK, "after-white-space", false, ec);
1026     ASSERT(ec == 0);
1027 }
1028
1029 void Frame::removeEditingStyleFromElement(Element*) const
1030 {
1031 }
1032
1033 #ifndef NDEBUG
1034 static HashSet<Frame*>& keepAliveSet()
1035 {
1036     static HashSet<Frame*> staticKeepAliveSet;
1037     return staticKeepAliveSet;
1038 }
1039 #endif
1040
1041 void Frame::keepAlive()
1042 {
1043     if (d->m_lifeSupportTimer.isActive())
1044         return;
1045 #ifndef NDEBUG
1046     keepAliveSet().add(this);
1047 #endif
1048     ref();
1049     d->m_lifeSupportTimer.startOneShot(0);
1050 }
1051
1052 #ifndef NDEBUG
1053 void Frame::cancelAllKeepAlive()
1054 {
1055     HashSet<Frame*>::iterator end = keepAliveSet().end();
1056     for (HashSet<Frame*>::iterator it = keepAliveSet().begin(); it != end; ++it) {
1057         Frame* frame = *it;
1058         frame->d->m_lifeSupportTimer.stop();
1059         frame->deref();
1060     }
1061     keepAliveSet().clear();
1062 }
1063 #endif
1064
1065 void Frame::lifeSupportTimerFired(Timer<Frame>*)
1066 {
1067 #ifndef NDEBUG
1068     keepAliveSet().remove(this);
1069 #endif
1070     deref();
1071 }
1072
1073 KJS::Bindings::RootObject* Frame::bindingRootObject()
1074 {
1075     Settings* settings = this->settings();
1076     if (!settings || !settings->isJavaScriptEnabled())
1077         return 0;
1078
1079     if (!d->m_bindingRootObject) {
1080         JSLock lock;
1081         d->m_bindingRootObject = KJS::Bindings::RootObject::create(0, scriptProxy()->globalObject());
1082     }
1083     return d->m_bindingRootObject.get();
1084 }
1085
1086 PassRefPtr<KJS::Bindings::RootObject> Frame::createRootObject(void* nativeHandle, KJS::JSGlobalObject* globalObject)
1087 {
1088     RootObjectMap::iterator it = d->m_rootObjects.find(nativeHandle);
1089     if (it != d->m_rootObjects.end())
1090         return it->second;
1091     
1092     RefPtr<KJS::Bindings::RootObject> rootObject = KJS::Bindings::RootObject::create(nativeHandle, globalObject);
1093     
1094     d->m_rootObjects.set(nativeHandle, rootObject);
1095     return rootObject.release();
1096 }
1097
1098 #if USE(NPOBJECT)
1099 NPObject* Frame::windowScriptNPObject()
1100 {
1101     if (!d->m_windowScriptNPObject) {
1102         Settings* settings = this->settings();
1103         if (settings && settings->isJavaScriptEnabled()) {
1104             // JavaScript is enabled, so there is a JavaScript window object.  Return an NPObject bound to the window
1105             // object.
1106             KJS::JSLock lock;
1107             KJS::JSObject* win = KJS::Window::retrieveWindow(this);
1108             ASSERT(win);
1109             KJS::Bindings::RootObject* root = bindingRootObject();
1110             d->m_windowScriptNPObject = _NPN_CreateScriptObject(0, win, root);
1111         } else {
1112             // JavaScript is not enabled, so we cannot bind the NPObject to the JavaScript window object.
1113             // Instead, we create an NPObject of a different class, one which is not bound to a JavaScript object.
1114             d->m_windowScriptNPObject = _NPN_CreateNoScriptObject();
1115         }
1116     }
1117
1118     return d->m_windowScriptNPObject;
1119 }
1120 #endif
1121     
1122 void Frame::clearScriptProxy()
1123 {
1124     if (d->m_jscript)
1125         d->m_jscript->clear();
1126 }
1127
1128 void Frame::clearDOMWindow()
1129 {
1130     if (d->m_domWindow)
1131         d->m_domWindow->clear();
1132 }
1133
1134 void Frame::cleanupScriptObjectsForPlugin(void* nativeHandle)
1135 {
1136     RootObjectMap::iterator it = d->m_rootObjects.find(nativeHandle);
1137     
1138     if (it == d->m_rootObjects.end())
1139         return;
1140     
1141     it->second->invalidate();
1142     d->m_rootObjects.remove(it);
1143 }
1144     
1145 void Frame::clearScriptObjects()
1146 {
1147     JSLock lock;
1148
1149     RootObjectMap::const_iterator end = d->m_rootObjects.end();
1150     for (RootObjectMap::const_iterator it = d->m_rootObjects.begin(); it != end; ++it)
1151         it->second->invalidate();
1152
1153     d->m_rootObjects.clear();
1154
1155     if (d->m_bindingRootObject) {
1156         d->m_bindingRootObject->invalidate();
1157         d->m_bindingRootObject = 0;
1158     }
1159
1160 #if USE(NPOBJECT)
1161     if (d->m_windowScriptNPObject) {
1162         // Call _NPN_DeallocateObject() instead of _NPN_ReleaseObject() so that we don't leak if a plugin fails to release the window
1163         // script object properly.
1164         // This shouldn't cause any problems for plugins since they should have already been stopped and destroyed at this point.
1165         _NPN_DeallocateObject(d->m_windowScriptNPObject);
1166         d->m_windowScriptNPObject = 0;
1167     }
1168 #endif
1169
1170     clearPlatformScriptObjects();
1171 }
1172
1173 RenderObject *Frame::renderer() const
1174 {
1175     Document *doc = document();
1176     return doc ? doc->renderer() : 0;
1177 }
1178
1179 HTMLFrameOwnerElement* Frame::ownerElement() const
1180 {
1181     return d->m_ownerElement;
1182 }
1183
1184 RenderPart* Frame::ownerRenderer()
1185 {
1186     HTMLFrameOwnerElement* ownerElement = d->m_ownerElement;
1187     if (!ownerElement)
1188         return 0;
1189     return static_cast<RenderPart*>(ownerElement->renderer());
1190 }
1191
1192 // returns FloatRect because going through IntRect would truncate any floats
1193 FloatRect Frame::selectionRect(bool clipToVisibleContent) const
1194 {
1195     RenderView *root = static_cast<RenderView*>(renderer());
1196     if (!root)
1197         return IntRect();
1198     
1199     IntRect selectionRect = root->selectionRect(clipToVisibleContent);
1200     return clipToVisibleContent ? intersection(selectionRect, d->m_view->visibleContentRect()) : selectionRect;
1201 }
1202
1203 void Frame::selectionTextRects(Vector<FloatRect>& rects, bool clipToVisibleContent) const
1204 {
1205     RenderView *root = static_cast<RenderView*>(renderer());
1206     if (!root)
1207         return;
1208
1209     RefPtr<Range> selectedRange = selectionController()->toRange();
1210
1211     Vector<IntRect> intRects;
1212     selectedRange->addLineBoxRects(intRects, true);
1213
1214     unsigned size = intRects.size();
1215     FloatRect visibleContentRect = d->m_view->visibleContentRect();
1216     for (unsigned i = 0; i < size; ++i)
1217         if (clipToVisibleContent)
1218             rects.append(intersection(intRects[i], visibleContentRect));
1219         else
1220             rects.append(intRects[i]);
1221 }
1222
1223
1224 bool Frame::isFrameSet() const
1225 {
1226     Document* document = d->m_doc.get();
1227     if (!document || !document->isHTMLDocument())
1228         return false;
1229     Node *body = static_cast<HTMLDocument*>(document)->body();
1230     return body && body->renderer() && body->hasTagName(framesetTag);
1231 }
1232
1233 // Scans logically forward from "start", including any child frames
1234 static HTMLFormElement *scanForForm(Node *start)
1235 {
1236     Node *n;
1237     for (n = start; n; n = n->traverseNextNode()) {
1238         if (n->hasTagName(formTag))
1239             return static_cast<HTMLFormElement*>(n);
1240         else if (n->isHTMLElement() && static_cast<HTMLElement*>(n)->isGenericFormElement())
1241             return static_cast<HTMLGenericFormElement*>(n)->form();
1242         else if (n->hasTagName(frameTag) || n->hasTagName(iframeTag)) {
1243             Node *childDoc = static_cast<HTMLFrameElementBase*>(n)->contentDocument();
1244             if (HTMLFormElement *frameResult = scanForForm(childDoc))
1245                 return frameResult;
1246         }
1247     }
1248     return 0;
1249 }
1250
1251 // We look for either the form containing the current focus, or for one immediately after it
1252 HTMLFormElement *Frame::currentForm() const
1253 {
1254     // start looking either at the active (first responder) node, or where the selection is
1255     Node *start = d->m_doc ? d->m_doc->focusedNode() : 0;
1256     if (!start)
1257         start = selectionController()->start().node();
1258     
1259     // try walking up the node tree to find a form element
1260     Node *n;
1261     for (n = start; n; n = n->parentNode()) {
1262         if (n->hasTagName(formTag))
1263             return static_cast<HTMLFormElement*>(n);
1264         else if (n->isHTMLElement()
1265                    && static_cast<HTMLElement*>(n)->isGenericFormElement())
1266             return static_cast<HTMLGenericFormElement*>(n)->form();
1267     }
1268     
1269     // try walking forward in the node tree to find a form element
1270     return start ? scanForForm(start) : 0;
1271 }
1272
1273 // FIXME: should this go in SelectionController?
1274 void Frame::revealSelection(const RenderLayer::ScrollAlignment& alignment) const
1275 {
1276     IntRect rect;
1277     
1278     switch (selectionController()->state()) {
1279         case Selection::NONE:
1280             return;
1281             
1282         case Selection::CARET:
1283             rect = selectionController()->caretRect();
1284             break;
1285             
1286         case Selection::RANGE:
1287             rect = enclosingIntRect(selectionRect(false));
1288             break;
1289     }
1290
1291     Position start = selectionController()->start();
1292
1293     ASSERT(start.node());
1294     if (start.node() && start.node()->renderer()) {
1295         // FIXME: This code only handles scrolling the startContainer's layer, but
1296         // the selection rect could intersect more than just that. 
1297         // See <rdar://problem/4799899>.
1298         if (RenderLayer *layer = start.node()->renderer()->enclosingLayer())
1299             layer->scrollRectToVisible(rect, alignment, alignment);
1300     }
1301 }
1302
1303 void Frame::revealCaret(const RenderLayer::ScrollAlignment& alignment) const
1304 {
1305     if (selectionController()->isNone())
1306         return;
1307
1308     Position extent = selectionController()->extent();
1309     if (extent.node() && extent.node()->renderer()) {
1310         IntRect extentRect = VisiblePosition(extent).caretRect();
1311         RenderLayer* layer = extent.node()->renderer()->enclosingLayer();
1312         if (layer)
1313             layer->scrollRectToVisible(extentRect, alignment, alignment);
1314     }
1315 }
1316
1317 // FIXME: why is this here instead of on the FrameView?
1318 void Frame::paint(GraphicsContext* p, const IntRect& rect)
1319 {
1320 #ifndef NDEBUG
1321     bool fillWithRed;
1322     if (!document() || document()->printing())
1323         fillWithRed = false; // Printing, don't fill with red (can't remember why).
1324     else if (document()->ownerElement())
1325         fillWithRed = false; // Subframe, don't fill with red.
1326     else if (view() && view()->isTransparent())
1327         fillWithRed = false; // Transparent, don't fill with red.
1328     else if (d->m_paintRestriction == PaintRestrictionSelectionOnly || d->m_paintRestriction == PaintRestrictionSelectionOnlyBlackText)
1329         fillWithRed = false; // Selections are transparent, don't fill with red.
1330     else if (d->m_elementToDraw)
1331         fillWithRed = false; // Element images are transparent, don't fill with red.
1332     else
1333         fillWithRed = true;
1334     
1335     if (fillWithRed)
1336         p->fillRect(rect, Color(0xFF, 0, 0));
1337 #endif
1338
1339     bool isTopLevelPainter = !s_currentPaintTimeStamp;
1340     if (isTopLevelPainter)
1341         s_currentPaintTimeStamp = currentTime();
1342     
1343     if (renderer()) {
1344         ASSERT(d->m_view && !d->m_view->needsLayout());
1345         ASSERT(!d->m_isPainting);
1346         
1347         d->m_isPainting = true;
1348         
1349         // d->m_elementToDraw is used to draw only one element
1350         RenderObject *eltRenderer = d->m_elementToDraw ? d->m_elementToDraw->renderer() : 0;
1351         if (d->m_paintRestriction == PaintRestrictionNone)
1352             renderer()->document()->invalidateRenderedRectsForMarkersInRect(rect);
1353         renderer()->layer()->paint(p, rect, d->m_paintRestriction, eltRenderer);
1354         
1355         d->m_isPainting = false;
1356
1357         // Regions may have changed as a result of the visibility/z-index of element changing.
1358         if (renderer()->document()->dashboardRegionsDirty())
1359             renderer()->view()->frameView()->updateDashboardRegions();
1360     } else
1361         LOG_ERROR("called Frame::paint with nil renderer");
1362         
1363     if (isTopLevelPainter)
1364         s_currentPaintTimeStamp = 0;
1365 }
1366
1367 void Frame::setPaintRestriction(PaintRestriction pr)
1368 {
1369     d->m_paintRestriction = pr;
1370 }
1371     
1372 bool Frame::isPainting() const
1373 {
1374     return d->m_isPainting;
1375 }
1376
1377 void Frame::adjustPageHeight(float *newBottom, float oldTop, float oldBottom, float bottomLimit)
1378 {
1379     RenderView *root = static_cast<RenderView*>(document()->renderer());
1380     if (root) {
1381         // Use a context with painting disabled.
1382         GraphicsContext context((PlatformGraphicsContext*)0);
1383         root->setTruncatedAt((int)floorf(oldBottom));
1384         IntRect dirtyRect(0, (int)floorf(oldTop), root->docWidth(), (int)ceilf(oldBottom - oldTop));
1385         root->layer()->paint(&context, dirtyRect);
1386         *newBottom = root->bestTruncatedAt();
1387         if (*newBottom == 0)
1388             *newBottom = oldBottom;
1389     } else
1390         *newBottom = oldBottom;
1391 }
1392
1393 Frame* Frame::frameForWidget(const Widget* widget)
1394 {
1395     ASSERT_ARG(widget, widget);
1396
1397     if (RenderWidget* renderer = RenderWidget::find(widget))
1398         if (Node* node = renderer->node())
1399             return node->document()->frame();
1400
1401     // Assume all widgets are either a FrameView or owned by a RenderWidget.
1402     // FIXME: That assumption is not right for scroll bars!
1403     ASSERT(widget->isFrameView());
1404     return static_cast<const FrameView*>(widget)->frame();
1405 }
1406
1407 void Frame::forceLayout(bool allowSubtree)
1408 {
1409     FrameView *v = d->m_view.get();
1410     if (v) {
1411         v->layout(allowSubtree);
1412         // We cannot unschedule a pending relayout, since the force can be called with
1413         // a tiny rectangle from a drawRect update.  By unscheduling we in effect
1414         // "validate" and stop the necessary full repaint from occurring.  Basically any basic
1415         // append/remove DHTML is broken by this call.  For now, I have removed the optimization
1416         // until we have a better invalidation stategy. -dwh
1417         //v->unscheduleRelayout();
1418     }
1419 }
1420
1421 void Frame::forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth, bool adjustViewSize)
1422 {
1423     // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
1424     // the state of things before and after the layout
1425     RenderView *root = static_cast<RenderView*>(document()->renderer());
1426     if (root) {
1427         // This magic is basically copied from khtmlview::print
1428         int pageW = (int)ceilf(minPageWidth);
1429         root->setWidth(pageW);
1430         root->setNeedsLayoutAndPrefWidthsRecalc();
1431         forceLayout();
1432         
1433         // If we don't fit in the minimum page width, we'll lay out again. If we don't fit in the
1434         // maximum page width, we will lay out to the maximum page width and clip extra content.
1435         // FIXME: We are assuming a shrink-to-fit printing implementation.  A cropping
1436         // implementation should not do this!
1437         int rightmostPos = root->rightmostPosition();
1438         if (rightmostPos > minPageWidth) {
1439             pageW = min(rightmostPos, (int)ceilf(maxPageWidth));
1440             root->setWidth(pageW);
1441             root->setNeedsLayoutAndPrefWidthsRecalc();
1442             forceLayout();
1443         }
1444     }
1445
1446     if (adjustViewSize && view())
1447         view()->adjustViewSize();
1448 }
1449
1450 void Frame::sendResizeEvent()
1451 {
1452     if (Document* doc = document())
1453         doc->dispatchWindowEvent(EventNames::resizeEvent, false, false);
1454 }
1455
1456 void Frame::sendScrollEvent()
1457 {
1458     FrameView* v = d->m_view.get();
1459     if (!v)
1460         return;
1461     v->setWasScrolledByUser(true);
1462     Document* doc = document();
1463     if (!doc)
1464         return;
1465     doc->dispatchHTMLEvent(scrollEvent, true, false);
1466 }
1467
1468 void Frame::clearTimers(FrameView *view)
1469 {
1470     if (view) {
1471         view->unscheduleRelayout();
1472         if (view->frame()) {
1473             Document* document = view->frame()->document();
1474             if (document && document->renderer() && document->renderer()->hasLayer())
1475                 document->renderer()->layer()->suspendMarquees();
1476             view->frame()->animationController()->suspendAnimations();
1477         }
1478     }
1479 }
1480
1481 void Frame::clearTimers()
1482 {
1483     clearTimers(d->m_view.get());
1484 }
1485
1486 RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const
1487 {
1488     nodeToRemove = 0;
1489     
1490     if (!document())
1491         return 0;
1492     if (selectionController()->isNone())
1493         return 0;
1494     
1495     Position pos = selectionController()->selection().visibleStart().deepEquivalent();
1496     if (!pos.isCandidate())
1497         return 0;
1498     Node *node = pos.node();
1499     if (!node)
1500         return 0;
1501     
1502     if (!d->m_typingStyle)
1503         return node->renderer()->style();
1504     
1505     ExceptionCode ec = 0;
1506     RefPtr<Element> styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
1507     ASSERT(ec == 0);
1508     
1509     String styleText = d->m_typingStyle->cssText() + " display: inline";
1510     styleElement->setAttribute(styleAttr, styleText.impl(), ec);
1511     ASSERT(ec == 0);
1512     
1513     styleElement->appendChild(document()->createEditingTextNode(""), ec);
1514     ASSERT(ec == 0);
1515     
1516     node->parentNode()->appendChild(styleElement, ec);
1517     ASSERT(ec == 0);
1518     
1519     nodeToRemove = styleElement.get();    
1520     return styleElement->renderer() ? styleElement->renderer()->style() : 0;
1521 }
1522
1523 void Frame::setSelectionFromNone()
1524 {
1525     // Put a caret inside the body if the entire frame is editable (either the 
1526     // entire WebView is editable or designMode is on for this document).
1527     Document *doc = document();
1528     if (!doc || !selectionController()->isNone() || !isContentEditable())
1529         return;
1530         
1531     Node* node = doc->documentElement();
1532     while (node && !node->hasTagName(bodyTag))
1533         node = node->traverseNextNode();
1534     if (node)
1535         selectionController()->setSelection(Selection(Position(node, 0), DOWNSTREAM));
1536 }
1537
1538 bool Frame::isActive() const
1539 {
1540     return d->m_isActive;
1541 }
1542
1543 void Frame::setIsActive(bool flag)
1544 {
1545     if (d->m_isActive == flag)
1546         return;
1547     d->m_isActive = flag;
1548
1549     // Because RenderObject::selectionBackgroundColor() and
1550     // RenderObject::selectionForegroundColor() check if the frame is active,
1551     // we have to update places those colors were painted.
1552     if (d->m_view)
1553         d->m_view->updateContents(enclosingIntRect(selectionRect()));
1554
1555     // Caret appears in the active frame.
1556     if (flag)
1557         setSelectionFromNone();
1558     setCaretVisible(flag);
1559
1560     // Update for caps lock state
1561     eventHandler()->capsLockStateMayHaveChanged();
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->haveGlobalObject())
1767         if (KJS::Window* w = KJS::Window::retrieveWindow(this))
1768             w->disconnectFrame();
1769
1770     clearScriptObjects();
1771     
1772     d->m_page = 0;
1773 }
1774
1775 void Frame::disconnectOwnerElement()
1776 {
1777     if (d->m_ownerElement) {
1778         d->m_ownerElement->m_contentFrame = 0;
1779         if (d->m_page)
1780             d->m_page->decrementFrameCount();
1781     }
1782     d->m_ownerElement = 0;
1783 }
1784
1785 String Frame::documentTypeString() const
1786 {
1787     if (Document *doc = document())
1788         if (DocumentType *doctype = doc->realDocType())
1789             return doctype->toString();
1790
1791     return String();
1792 }
1793
1794 bool Frame::prohibitsScrolling() const
1795 {
1796     return d->m_prohibitsScrolling;
1797 }
1798
1799 void Frame::setProhibitsScrolling(bool prohibit)
1800 {
1801     d->m_prohibitsScrolling = prohibit;
1802 }
1803
1804 void Frame::focusWindow()
1805 {
1806     if (!page())
1807         return;
1808
1809     // If we're a top level window, bring the window to the front.
1810     if (!tree()->parent())
1811         page()->chrome()->focus();
1812
1813     eventHandler()->focusDocumentView();
1814 }
1815
1816 void Frame::unfocusWindow()
1817 {
1818     if (!page())
1819         return;
1820     
1821     // If we're a top level window, deactivate the window.
1822     if (!tree()->parent())
1823         page()->chrome()->unfocus();
1824 }
1825
1826 bool Frame::shouldClose()
1827 {
1828     Chrome* chrome = page() ? page()->chrome() : 0;
1829     if (!chrome || !chrome->canRunBeforeUnloadConfirmPanel())
1830         return true;
1831
1832     RefPtr<Document> doc = document();
1833     if (!doc)
1834         return true;
1835     HTMLElement* body = doc->body();
1836     if (!body)
1837         return true;
1838
1839     RefPtr<BeforeUnloadEvent> beforeUnloadEvent = new BeforeUnloadEvent;
1840     beforeUnloadEvent->setTarget(doc);
1841     doc->handleWindowEvent(beforeUnloadEvent.get(), false);
1842
1843     if (!beforeUnloadEvent->defaultPrevented() && doc)
1844         doc->defaultEventHandler(beforeUnloadEvent.get());
1845     if (beforeUnloadEvent->result().isNull())
1846         return true;
1847
1848     String text = beforeUnloadEvent->result();
1849     text.replace('\\', backslashAsCurrencySymbol());
1850
1851     return chrome->runBeforeUnloadConfirmPanel(text, this);
1852 }
1853
1854 void Frame::scheduleClose()
1855 {
1856     if (!shouldClose())
1857         return;
1858
1859     Chrome* chrome = page() ? page()->chrome() : 0;
1860     if (chrome)
1861         chrome->closeWindowSoon();
1862 }
1863
1864 void Frame::respondToChangedSelection(const Selection& oldSelection, bool closeTyping)
1865 {
1866     if (document()) {
1867         bool isContinuousSpellCheckingEnabled = editor()->isContinuousSpellCheckingEnabled();
1868         bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled && editor()->isGrammarCheckingEnabled();
1869         if (isContinuousSpellCheckingEnabled) {
1870             Selection newAdjacentWords;
1871             Selection newSelectedSentence;
1872             if (selectionController()->selection().isContentEditable()) {
1873                 VisiblePosition newStart(selectionController()->selection().visibleStart());
1874                 newAdjacentWords = Selection(startOfWord(newStart, LeftWordIfOnBoundary), endOfWord(newStart, RightWordIfOnBoundary));
1875                 if (isContinuousGrammarCheckingEnabled)
1876                     newSelectedSentence = Selection(startOfSentence(newStart), endOfSentence(newStart));
1877             }
1878
1879             // When typing we check spelling elsewhere, so don't redo it here.
1880             // If this is a change in selection resulting from a delete operation,
1881             // oldSelection may no longer be in the document.
1882             if (closeTyping && oldSelection.isContentEditable() && oldSelection.start().node() && oldSelection.start().node()->inDocument()) {
1883                 VisiblePosition oldStart(oldSelection.visibleStart());
1884                 Selection oldAdjacentWords = Selection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));   
1885                 if (oldAdjacentWords != newAdjacentWords) {
1886                     editor()->markMisspellings(oldAdjacentWords);
1887                     if (isContinuousGrammarCheckingEnabled) {
1888                         Selection oldSelectedSentence = Selection(startOfSentence(oldStart), endOfSentence(oldStart));   
1889                         if (oldSelectedSentence != newSelectedSentence)
1890                             editor()->markBadGrammar(oldSelectedSentence);
1891                     }
1892                 }
1893             }
1894
1895             // This only erases markers that are in the first unit (word or sentence) of the selection.
1896             // Perhaps peculiar, but it matches AppKit.
1897             if (RefPtr<Range> wordRange = newAdjacentWords.toRange())
1898                 document()->removeMarkers(wordRange.get(), DocumentMarker::Spelling);
1899             if (RefPtr<Range> sentenceRange = newSelectedSentence.toRange())
1900                 document()->removeMarkers(sentenceRange.get(), DocumentMarker::Grammar);
1901         }
1902
1903         // When continuous spell checking is off, existing markers disappear after the selection changes.
1904         if (!isContinuousSpellCheckingEnabled)
1905             document()->removeMarkers(DocumentMarker::Spelling);
1906         if (!isContinuousGrammarCheckingEnabled)
1907             document()->removeMarkers(DocumentMarker::Grammar);
1908     }
1909
1910     editor()->respondToChangedSelection(oldSelection);
1911 }
1912
1913 VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint)
1914 {
1915     HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, true);
1916     Node* node = result.innerNode();
1917     if (!node)
1918         return VisiblePosition();
1919     RenderObject* renderer = node->renderer();
1920     if (!renderer)
1921         return VisiblePosition();
1922     VisiblePosition visiblePos = renderer->positionForCoordinates(result.localPoint().x(), result.localPoint().y());
1923     if (visiblePos.isNull())
1924         visiblePos = VisiblePosition(Position(node, 0));
1925     return visiblePos;
1926 }
1927     
1928 Document* Frame::documentAtPoint(const IntPoint& point)
1929 {  
1930     if (!view()) 
1931         return 0;
1932     
1933     IntPoint pt = view()->windowToContents(point);
1934     HitTestResult result = HitTestResult(pt);
1935     
1936     if (renderer())
1937         result = eventHandler()->hitTestResultAtPoint(pt, false);
1938     return result.innerNode() ? result.innerNode()->document() : 0;
1939 }
1940     
1941 FramePrivate::FramePrivate(Page* page, Frame* parent, Frame* thisFrame, HTMLFrameOwnerElement* ownerElement,
1942                            FrameLoaderClient* frameLoaderClient)
1943     : m_page(page)
1944     , m_treeNode(thisFrame, parent)
1945     , m_ownerElement(ownerElement)
1946     , m_jscript(0)
1947     , m_zoomFactor(parent ? parent->d->m_zoomFactor : 100)
1948     , m_selectionController(thisFrame)
1949     , m_caretBlinkTimer(thisFrame, &Frame::caretBlinkTimerFired)
1950     , m_editor(thisFrame)
1951     , m_eventHandler(thisFrame)
1952     , m_animationController(thisFrame)
1953     , m_caretVisible(false)
1954     , m_caretPaint(true)
1955     , m_isActive(false)
1956     , m_isPainting(false)
1957     , m_lifeSupportTimer(thisFrame, &Frame::lifeSupportTimerFired)
1958     , m_loader(new FrameLoader(thisFrame, frameLoaderClient))
1959     , m_userStyleSheetLoader(0)
1960     , m_paintRestriction(PaintRestrictionNone)
1961     , m_highlightTextMatches(false)
1962     , m_windowHasFocus(false)
1963     , m_inViewSourceMode(false)
1964     , frameCount(0)
1965     , m_prohibitsScrolling(false)
1966     , m_needsReapplyStyles(false)
1967     , m_windowScriptNPObject(0)
1968 #if PLATFORM(MAC)
1969     , m_windowScriptObject(nil)
1970     , m_bridge(nil)
1971 #endif
1972 {
1973 }
1974
1975 FramePrivate::~FramePrivate()
1976 {
1977     delete m_jscript;
1978     delete m_loader;
1979 }
1980
1981 } // namespace WebCore