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