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