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