Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(102)

Side by Side Diff: webkit/pending/Frame.cpp

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

Powered by Google App Engine
This is Rietveld 408576698