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