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