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