1 /* This file is part of the KDE project
3 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
4 * 1999 Lars Knoll <knoll@kde.org>
5 * 1999 Antti Koivisto <koivisto@kde.org>
6 * 2000 Simon Hausmann <hausmann@kde.org>
7 * 2000 Stefan Schimanski <1Stein@gmx.de>
8 * 2001 George Staikos <staikos@kde.org>
9 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
10 * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com>
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB. If not, write to
24 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 * Boston, MA 02111-1307, USA.
30 #include "FramePrivate.h"
32 #include "ApplyStyleCommand.h"
33 #include "CSSComputedStyleDeclaration.h"
34 #include "CSSProperty.h"
35 #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"
44 #include "EventNames.h"
45 #include "FloatRect.h"
47 #include "FrameLoader.h"
48 #include "FrameLoadRequest.h"
49 #include "FrameView.h"
50 #include "GraphicsContext.h"
51 #include "HTMLFormElement.h"
52 #include "HTMLFrameElementBase.h"
53 #include "HTMLGenericFormElement.h"
54 #include "HTMLInputElement.h"
55 #include "HTMLNames.h"
56 #include "HTMLObjectElement.h"
57 #include "HitTestRequest.h"
58 #include "HitTestResult.h"
59 #include "IconDatabase.h"
60 #include "IconLoader.h"
61 #include "ImageDocument.h"
62 #include "IndentOutdentCommand.h"
63 #include "MediaFeatureNames.h"
64 #include "MouseEventWithHitTestResults.h"
67 #include "PlatformScrollBar.h"
68 #include "RenderListBox.h"
69 #include "RenderObject.h"
70 #include "RenderPart.h"
71 #include "RenderTextControl.h"
72 #include "RenderTheme.h"
73 #include "RenderView.h"
74 #include "SegmentedString.h"
75 #include "TextIterator.h"
76 #include "TextResourceDecoder.h"
77 #include "TypingCommand.h"
78 #include "XMLTokenizer.h"
79 #include "cssstyleselector.h"
80 #include "htmlediting.h"
81 #include "kjs_proxy.h"
82 #include "kjs_window.h"
84 #include "visible_units.h"
85 #include "xmlhttprequest.h"
87 #include <sys/types.h>
88 #include <wtf/Platform.h>
100 #include "XLinkNames.h"
101 #include "XMLNames.h"
102 #include "SVGDocument.h"
103 #include "SVGDocumentExtensions.h"
111 using KJS::PausedTimeouts;
112 using KJS::SavedProperties;
113 using KJS::SavedBuiltins;
119 using namespace EventNames;
120 using namespace HTMLNames;
122 const double caretBlinkFrequency = 0.5;
123 const double autoscrollInterval = 0.1;
125 class UserStyleSheetLoader : public CachedResourceClient {
127 UserStyleSheetLoader(Frame* frame, const String& url, DocLoader* docLoader)
129 , m_cachedSheet(docLoader->requestCSSStyleSheet(url, ""))
131 m_cachedSheet->ref(this);
133 ~UserStyleSheetLoader()
135 m_cachedSheet->deref(this);
138 virtual void setCSSStyleSheet(const String& /*URL*/, const String& /*charset*/, const String& sheet)
140 m_frame->setUserStyleSheet(sheet);
143 CachedCSSStyleSheet* m_cachedSheet;
147 struct FrameCounter {
149 ~FrameCounter() { if (count != 0) fprintf(stderr, "LEAK: %d Frame\n", count); }
151 int FrameCounter::count = 0;
152 static FrameCounter frameCounter;
155 static inline Frame* parentFromOwnerElement(Element* ownerElement)
159 return ownerElement->document()->frame();
162 Frame::Frame(Page* page, Element* ownerElement, PassRefPtr<EditorClient> client)
163 : d(new FramePrivate(page, parentFromOwnerElement(ownerElement), this, ownerElement, client))
165 AtomicString::init();
168 QualifiedName::init();
169 MediaFeatureNames::init();
178 page->setMainFrame(this);
180 // FIXME: Frames were originally created with a refcount of 1.
181 // Leave this ref call here until we can straighten that out.
183 page->incrementFrameCount();
187 ++FrameCounter::count;
193 // FIXME: We should not be doing all this work inside the destructor
195 ASSERT(!d->m_lifeSupportTimer.isActive());
198 --FrameCounter::count;
201 if (d->m_jscript && d->m_jscript->haveInterpreter())
202 if (Window* w = Window::retrieveWindow(this)) {
203 w->disconnectFrame();
204 // Must clear the window pointer, otherwise we will not
205 // garbage-collect collect the window (inside the call to
210 disconnectOwnerElement();
213 d->m_domWindow->disconnectFrame();
217 d->m_view->m_frame = 0;
220 ASSERT(!d->m_lifeSupportTimer.isActive());
222 delete d->m_userStyleSheetLoader;
227 FrameLoader* Frame::loader() const
232 FrameView* Frame::view() const
234 return d->m_view.get();
237 void Frame::setView(FrameView* view)
239 // Detach the document now, so any onUnload handlers get run - if
240 // we wait until the view is destroyed, then things won't be
241 // hooked up enough for some JavaScript calls to work.
242 if (d->m_doc && view == 0)
248 bool Frame::javaScriptEnabled() const
250 return d->m_bJScriptEnabled;
253 KJSProxy *Frame::scriptProxy()
255 if (!d->m_bJScriptEnabled)
259 d->m_jscript = new KJSProxy(this);
264 bool Frame::javaEnabled() const
266 return d->m_settings->isJavaEnabled();
269 bool Frame::pluginsEnabled() const
271 return d->m_bPluginsEnabled;
274 Document *Frame::document() const
277 return d->m_doc.get();
281 void Frame::setDocument(Document* newDoc)
292 const Settings *Frame::settings() const
294 return d->m_settings;
297 void Frame::setUserStyleSheetLocation(const KURL& url)
299 delete d->m_userStyleSheetLoader;
300 d->m_userStyleSheetLoader = 0;
301 if (d->m_doc && d->m_doc->docLoader())
302 d->m_userStyleSheetLoader = new UserStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
305 void Frame::setUserStyleSheet(const String& styleSheet)
307 delete d->m_userStyleSheetLoader;
308 d->m_userStyleSheetLoader = 0;
310 d->m_doc->setUserStyleSheet(styleSheet);
313 void Frame::setStandardFont(const String& name)
315 d->m_settings->setStdFontName(AtomicString(name));
318 void Frame::setFixedFont(const String& name)
320 d->m_settings->setFixedFontName(AtomicString(name));
323 String Frame::selectedText() const
325 return plainText(selectionController()->toRange().get());
328 SelectionController* Frame::selectionController() const
330 return &d->m_selectionController;
333 Editor* Frame::editor() const
338 CommandByName* Frame::command() const
340 return &d->m_command;
343 TextGranularity Frame::selectionGranularity() const
345 return d->m_selectionGranularity;
348 void Frame::setSelectionGranularity(TextGranularity granularity) const
350 d->m_selectionGranularity = granularity;
353 SelectionController* Frame::dragCaretController() const
355 return d->m_page->dragCaretController();
358 const Selection& Frame::mark() const
363 void Frame::setMark(const Selection& s)
365 ASSERT(!s.base().node() || s.base().node()->document() == document());
366 ASSERT(!s.extent().node() || s.extent().node()->document() == document());
367 ASSERT(!s.start().node() || s.start().node()->document() == document());
368 ASSERT(!s.end().node() || s.end().node()->document() == document());
373 void Frame::notifyRendererOfSelectionChange(bool userTriggered)
375 RenderObject* renderer = 0;
376 if (selectionController()->rootEditableElement())
377 renderer = selectionController()->rootEditableElement()->shadowAncestorNode()->renderer();
379 // If the current selection is in a textfield or textarea, notify the renderer that the selection has changed
380 if (renderer && (renderer->isTextArea() || renderer->isTextField()))
381 static_cast<RenderTextControl*>(renderer)->selectionChanged(userTriggered);
384 void Frame::invalidateSelection()
386 selectionController()->setNeedsLayout();
387 selectionLayoutChanged();
390 void Frame::setCaretVisible(bool flag)
392 if (d->m_caretVisible == flag)
394 clearCaretRectIfNeeded();
396 setFocusNodeIfNeeded();
397 d->m_caretVisible = flag;
398 selectionLayoutChanged();
402 void Frame::clearCaretRectIfNeeded()
404 if (d->m_caretPaint) {
405 d->m_caretPaint = false;
406 selectionController()->invalidateCaretRect();
410 // Helper function that tells whether a particular node is an element that has an entire
411 // Frame and FrameView, a <frame>, <iframe>, or <object>.
412 static bool isFrameElement(const Node *n)
416 RenderObject *renderer = n->renderer();
417 if (!renderer || !renderer->isWidget())
419 Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
420 return widget && widget->isFrameView();
423 void Frame::setFocusNodeIfNeeded()
425 if (!document() || selectionController()->isNone() || !d->m_isActive)
428 Node* target = selectionController()->rootEditableElement();
430 RenderObject* renderer = target->renderer();
432 // Walk up the render tree to search for a node to focus.
433 // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
435 // We don't want to set focus on a subframe when selecting in a parent frame,
436 // so add the !isFrameElement check here. There's probably a better way to make this
437 // work in the long term, but this is the safest fix at this time.
438 if (target && target->isMouseFocusable() && !isFrameElement(target)) {
439 document()->setFocusNode(target);
442 renderer = renderer->parent();
444 target = renderer->element();
446 document()->setFocusNode(0);
450 void Frame::selectionLayoutChanged()
452 bool caretRectChanged = selectionController()->recomputeCaretRect();
454 bool shouldBlink = d->m_caretVisible
455 && selectionController()->isCaret() && selectionController()->isContentEditable();
457 // If the caret moved, stop the blink timer so we can restart with a
458 // black caret in the new location.
459 if (caretRectChanged || !shouldBlink)
460 d->m_caretBlinkTimer.stop();
462 // Start blinking with a black caret. Be sure not to restart if we're
463 // already blinking in the right location.
464 if (shouldBlink && !d->m_caretBlinkTimer.isActive()) {
465 d->m_caretBlinkTimer.startRepeating(caretBlinkFrequency);
466 d->m_caretPaint = true;
470 d->m_doc->updateSelection();
473 void Frame::setXPosForVerticalArrowNavigation(int x)
475 d->m_xPosForVerticalArrowNavigation = x;
478 int Frame::xPosForVerticalArrowNavigation() const
480 return d->m_xPosForVerticalArrowNavigation;
483 void Frame::caretBlinkTimerFired(Timer<Frame>*)
485 ASSERT(d->m_caretVisible);
486 ASSERT(selectionController()->isCaret());
487 bool caretPaint = d->m_caretPaint;
488 if (d->m_bMousePressed && caretPaint)
490 d->m_caretPaint = !caretPaint;
491 selectionController()->invalidateCaretRect();
494 void Frame::paintCaret(GraphicsContext* p, const IntRect& rect) const
496 if (d->m_caretPaint && d->m_caretVisible)
497 selectionController()->paintCaret(p, rect);
500 void Frame::paintDragCaret(GraphicsContext* p, const IntRect& rect) const
502 SelectionController* dragCaretController = d->m_page->dragCaretController();
503 assert(dragCaretController->selection().isCaret());
504 if (dragCaretController->selection().start().node()->document()->frame() == this)
505 dragCaretController->paintCaret(p, rect);
508 int Frame::zoomFactor() const
510 return d->m_zoomFactor;
513 void Frame::setZoomFactor(int percent)
515 if (d->m_zoomFactor == percent)
518 d->m_zoomFactor = percent;
521 d->m_doc->recalcStyle(Node::Force);
523 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
524 child->setZoomFactor(d->m_zoomFactor);
526 if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout())
530 void Frame::setJSStatusBarText(const String& text)
532 d->m_kjsStatusBarText = text;
533 setStatusBarText(d->m_kjsStatusBarText);
536 void Frame::setJSDefaultStatusBarText(const String& text)
538 d->m_kjsDefaultStatusBarText = text;
539 setStatusBarText(d->m_kjsDefaultStatusBarText);
542 String Frame::jsStatusBarText() const
544 return d->m_kjsStatusBarText;
547 String Frame::jsDefaultStatusBarText() const
549 return d->m_kjsDefaultStatusBarText;
552 void Frame::reparseConfiguration()
555 d->m_doc->docLoader()->setAutoLoadImages(d->m_settings->autoLoadImages());
557 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled();
558 d->m_bJavaEnabled = d->m_settings->isJavaEnabled();
559 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled();
561 const KURL& userStyleSheetLocation = d->m_settings->userStyleSheetLocation();
562 if (!userStyleSheetLocation.isEmpty())
563 setUserStyleSheetLocation(userStyleSheetLocation);
565 setUserStyleSheet(String());
567 // FIXME: It's not entirely clear why the following is needed.
568 // The document automatically does this as required when you set the style sheet.
569 // But we had problems when this code was removed. Details are in
570 // <http://bugs.webkit.org/show_bug.cgi?id=8079>.
572 d->m_doc->updateStyleSelector();
575 bool Frame::shouldDragAutoNode(Node *node, const IntPoint& point) const
580 void Frame::selectClosestWordFromMouseEvent(const PlatformMouseEvent& mouse, Node *innerNode)
582 Selection newSelection;
584 if (innerNode && innerNode->renderer() && mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
585 IntPoint vPoint = view()->windowToContents(mouse.pos());
586 VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
587 if (pos.isNotNull()) {
588 newSelection = Selection(pos);
589 newSelection.expandUsingGranularity(WordGranularity);
593 if (newSelection.isRange()) {
594 d->m_selectionGranularity = WordGranularity;
595 d->m_beganSelectingText = true;
598 if (shouldChangeSelection(newSelection))
599 selectionController()->setSelection(newSelection);
602 void Frame::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
604 if (event.event().button() == LeftButton) {
605 if (selectionController()->isRange())
606 // A double-click when range is already selected
607 // should not change the selection. So, do not call
608 // selectClosestWordFromMouseEvent, but do set
609 // m_beganSelectingText to prevent handleMouseReleaseEvent
610 // from setting caret selection.
611 d->m_beganSelectingText = true;
613 selectClosestWordFromMouseEvent(event.event(), event.targetNode());
617 void Frame::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
619 Node *innerNode = event.targetNode();
621 if (event.event().button() == LeftButton && innerNode && innerNode->renderer() &&
622 mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
623 Selection newSelection;
624 IntPoint vPoint = view()->windowToContents(event.event().pos());
625 VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
626 if (pos.isNotNull()) {
627 newSelection = Selection(pos);
628 newSelection.expandUsingGranularity(ParagraphGranularity);
630 if (newSelection.isRange()) {
631 d->m_selectionGranularity = ParagraphGranularity;
632 d->m_beganSelectingText = true;
635 if (shouldChangeSelection(newSelection))
636 selectionController()->setSelection(newSelection);
640 void Frame::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
642 Node *innerNode = event.targetNode();
644 if (event.event().button() == LeftButton) {
645 if (innerNode && innerNode->renderer() &&
646 mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
648 // Extend the selection if the Shift key is down, unless the click is in a link.
649 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
651 // Don't restart the selection when the mouse is pressed on an
652 // existing selection so we can allow for text dragging.
653 IntPoint vPoint = view()->windowToContents(event.event().pos());
654 if (!extendSelection && selectionController()->contains(vPoint))
657 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(vPoint));
658 if (visiblePos.isNull())
659 visiblePos = VisiblePosition(innerNode, innerNode->caretMinOffset(), DOWNSTREAM);
660 Position pos = visiblePos.deepEquivalent();
662 Selection newSelection = selectionController()->selection();
663 if (extendSelection && newSelection.isCaretOrRange()) {
664 selectionController()->clearModifyBias();
666 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
667 // was created right-to-left
668 Position start = newSelection.start();
669 Position end = newSelection.end();
670 short before = Range::compareBoundaryPoints(pos.node(), pos.offset(), start.node(), start.offset());
672 newSelection = Selection(pos, end);
674 newSelection = Selection(start, pos);
676 if (d->m_selectionGranularity != CharacterGranularity)
677 newSelection.expandUsingGranularity(d->m_selectionGranularity);
678 d->m_beganSelectingText = true;
680 newSelection = Selection(visiblePos);
681 d->m_selectionGranularity = CharacterGranularity;
684 if (shouldChangeSelection(newSelection))
685 selectionController()->setSelection(newSelection);
690 void Frame::handleMousePressEvent(const MouseEventWithHitTestResults& event)
692 Node *innerNode = event.targetNode();
694 d->m_mousePressNode = innerNode;
695 d->m_dragStartPos = event.event().pos();
697 if (event.event().button() == LeftButton || event.event().button() == MiddleButton) {
698 d->m_bMousePressed = true;
699 d->m_beganSelectingText = false;
701 if (event.event().clickCount() == 2) {
702 handleMousePressEventDoubleClick(event);
705 if (event.event().clickCount() >= 3) {
706 handleMousePressEventTripleClick(event);
709 handleMousePressEventSingleClick(event);
712 setMouseDownMayStartAutoscroll(mouseDownMayStartSelect() ||
713 (d->m_mousePressNode && d->m_mousePressNode->renderer() && d->m_mousePressNode->renderer()->shouldAutoscroll()));
716 void Frame::handleMouseMoveEvent(const MouseEventWithHitTestResults& event)
718 // Mouse not pressed. Do nothing.
719 if (!d->m_bMousePressed)
722 Node *innerNode = event.targetNode();
724 if (event.event().button() != 0 || !innerNode || !innerNode->renderer())
727 ASSERT(mouseDownMayStartSelect() || mouseDownMayStartAutoscroll());
729 setMouseDownMayStartDrag(false);
730 view()->invalidateClick();
732 if (mouseDownMayStartAutoscroll()) {
733 // If the selection is contained in a layer that can scroll, that layer should handle the autoscroll
734 // Otherwise, let the bridge handle it so the view can scroll itself.
735 RenderObject* renderer = innerNode->renderer();
736 while (renderer && !renderer->shouldAutoscroll())
737 renderer = renderer->parent();
739 handleAutoscroll(renderer);
742 if (mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
743 // handle making selection
744 IntPoint vPoint = view()->windowToContents(event.event().pos());
745 VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
747 updateSelectionForMouseDragOverPosition(pos);
752 void Frame::updateSelectionForMouseDragOverPosition(const VisiblePosition& pos)
754 // Don't modify the selection if we're not on a node.
758 // Restart the selection if this is the first mouse move. This work is usually
759 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
760 Selection newSelection = selectionController()->selection();
761 selectionController()->clearModifyBias();
763 if (!d->m_beganSelectingText) {
764 d->m_beganSelectingText = true;
765 newSelection = Selection(pos);
768 newSelection.setExtent(pos);
769 if (d->m_selectionGranularity != CharacterGranularity)
770 newSelection.expandUsingGranularity(d->m_selectionGranularity);
772 if (shouldChangeSelection(newSelection))
773 selectionController()->setSelection(newSelection);
776 void Frame::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
778 stopAutoscrollTimer();
780 // Used to prevent mouseMoveEvent from initiating a drag before
781 // the mouse is pressed again.
782 d->m_bMousePressed = false;
784 // Clear the selection if the mouse didn't move after the last mouse press.
785 // We do this so when clicking on the selection, the selection goes away.
786 // However, if we are editing, place the caret.
787 if (mouseDownMayStartSelect() && !d->m_beganSelectingText
788 && d->m_dragStartPos == event.event().pos()
789 && selectionController()->isRange()) {
790 Selection newSelection;
791 Node *node = event.targetNode();
792 if (node && node->isContentEditable() && node->renderer()) {
793 IntPoint vPoint = view()->windowToContents(event.event().pos());
794 VisiblePosition pos = node->renderer()->positionForPoint(vPoint);
795 newSelection = Selection(pos);
797 if (shouldChangeSelection(newSelection))
798 selectionController()->setSelection(newSelection);
801 notifyRendererOfSelectionChange(true);
803 selectionController()->selectFrameElementInParentIfFullySelected();
806 bool Frame::shouldChangeSelection(const Selection& newSelection) const
808 return shouldChangeSelection(selectionController()->selection(), newSelection, newSelection.affinity(), false);
811 bool Frame::shouldDeleteSelection(const Selection& newSelection) const
816 bool Frame::isContentEditable() const
820 return d->m_doc->inDesignMode();
823 void Frame::textFieldDidBeginEditing(Element* input)
827 void Frame::textFieldDidEndEditing(Element* input)
831 void Frame::textDidChangeInTextField(Element* input)
835 bool Frame::doTextFieldCommandFromEvent(Element*, KeyboardEvent*)
840 void Frame::textWillBeDeletedInTextField(Element* input)
844 void Frame::textDidChangeInTextArea(Element* input)
848 static void dispatchEditableContentChangedEvents(const EditCommand& command)
850 Element* startRoot = command.startingRootEditableElement();
851 Element* endRoot = command.endingRootEditableElement();
854 startRoot->dispatchEvent(new Event(khtmlEditableContentChangedEvent, false, false), ec, true);
855 if (endRoot && endRoot != startRoot)
856 endRoot->dispatchEvent(new Event(khtmlEditableContentChangedEvent, false, false), ec, true);
859 void Frame::appliedEditing(PassRefPtr<EditCommand> cmd)
861 dispatchEditableContentChangedEvents(*cmd);
863 Selection newSelection(cmd->endingSelection());
864 if (shouldChangeSelection(newSelection))
865 selectionController()->setSelection(newSelection, false);
867 // Now set the typing style from the command. Clear it when done.
868 // This helps make the case work where you completely delete a piece
869 // of styled text and then type a character immediately after.
870 // That new character needs to take on the style of the just-deleted text.
871 // FIXME: Improve typing style.
872 // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
873 if (cmd->typingStyle()) {
874 setTypingStyle(cmd->typingStyle());
875 cmd->setTypingStyle(0);
878 // Command will be equal to last edit command only in the case of typing
879 if (editor()->lastEditCommand() == cmd)
880 assert(cmd->isTypingCommand());
882 // Only register a new undo command if the command passed in is
883 // different from the last command
884 editor()->setLastEditCommand(cmd.get());
885 registerCommandForUndo(cmd);
887 respondToChangedContents(newSelection);
888 editor()->respondToChangedContents();
891 void Frame::unappliedEditing(PassRefPtr<EditCommand> cmd)
893 dispatchEditableContentChangedEvents(*cmd);
895 Selection newSelection(cmd->startingSelection());
896 if (shouldChangeSelection(newSelection))
897 selectionController()->setSelection(newSelection, true);
899 editor()->setLastEditCommand(0);
900 registerCommandForRedo(cmd);
901 respondToChangedContents(newSelection);
902 editor()->respondToChangedContents();
905 void Frame::reappliedEditing(PassRefPtr<EditCommand> cmd)
907 dispatchEditableContentChangedEvents(*cmd);
909 Selection newSelection(cmd->endingSelection());
910 if (shouldChangeSelection(newSelection))
911 selectionController()->setSelection(newSelection, true);
913 editor()->setLastEditCommand(0);
914 registerCommandForUndo(cmd);
915 respondToChangedContents(newSelection);
916 editor()->respondToChangedContents();
919 CSSMutableStyleDeclaration *Frame::typingStyle() const
921 return d->m_typingStyle.get();
924 void Frame::setTypingStyle(CSSMutableStyleDeclaration *style)
926 d->m_typingStyle = style;
929 void Frame::clearTypingStyle()
931 d->m_typingStyle = 0;
934 bool Frame::tabsToLinks(KeyboardEvent*) const
939 bool Frame::tabsToAllControls(KeyboardEvent*) const
944 void Frame::copyToPasteboard()
949 void Frame::cutToPasteboard()
954 void Frame::pasteFromPasteboard()
959 void Frame::pasteAndMatchStyle()
961 issuePasteAndMatchStyleCommand();
964 void Frame::transpose()
966 issueTransposeCommand();
980 void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction editingAction)
982 if (!style || style->length() == 0) {
987 // Calculate the current typing style.
988 RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
990 typingStyle()->merge(mutableStyle.get());
991 mutableStyle = typingStyle();
994 Node *node = selectionController()->selection().visibleStart().deepEquivalent().node();
995 CSSComputedStyleDeclaration computedStyle(node);
996 computedStyle.diff(mutableStyle.get());
998 // Handle block styles, substracting these from the typing style.
999 RefPtr<CSSMutableStyleDeclaration> blockStyle = mutableStyle->copyBlockProperties();
1000 blockStyle->diff(mutableStyle.get());
1001 if (document() && blockStyle->length() > 0)
1002 applyCommand(new ApplyStyleCommand(document(), blockStyle.get(), editingAction));
1004 // Set the remaining style as the typing style.
1005 d->m_typingStyle = mutableStyle.release();
1008 static void updateState(CSSMutableStyleDeclaration *desiredStyle, CSSComputedStyleDeclaration *computedStyle, bool& atStart, Frame::TriState& state)
1010 DeprecatedValueListConstIterator<CSSProperty> end;
1011 for (DeprecatedValueListConstIterator<CSSProperty> it = desiredStyle->valuesIterator(); it != end; ++it) {
1012 int propertyID = (*it).id();
1013 String desiredProperty = desiredStyle->getPropertyValue(propertyID);
1014 String computedProperty = computedStyle->getPropertyValue(propertyID);
1015 Frame::TriState propertyState = equalIgnoringCase(desiredProperty, computedProperty)
1016 ? Frame::trueTriState : Frame::falseTriState;
1018 state = propertyState;
1020 } else if (state != propertyState) {
1021 state = Frame::mixedTriState;
1027 Frame::TriState Frame::selectionHasStyle(CSSStyleDeclaration *style) const
1029 bool atStart = true;
1030 TriState state = falseTriState;
1032 RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
1034 if (!selectionController()->isRange()) {
1036 RefPtr<CSSComputedStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
1037 if (!selectionStyle)
1038 return falseTriState;
1039 updateState(mutableStyle.get(), selectionStyle.get(), atStart, state);
1041 ExceptionCode ec = 0;
1042 nodeToRemove->remove(ec);
1046 for (Node* node = selectionController()->start().node(); node; node = node->traverseNextNode()) {
1047 RefPtr<CSSComputedStyleDeclaration> computedStyle = new CSSComputedStyleDeclaration(node);
1049 updateState(mutableStyle.get(), computedStyle.get(), atStart, state);
1050 if (state == mixedTriState)
1052 if (node == selectionController()->end().node())
1060 String Frame::selectionStartStylePropertyValue(int stylePropertyID) const
1063 RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
1064 if (!selectionStyle)
1067 String value = selectionStyle->getPropertyValue(stylePropertyID);
1070 ExceptionCode ec = 0;
1071 nodeToRemove->remove(ec);
1078 CSSComputedStyleDeclaration *Frame::selectionComputedStyle(Node *&nodeToRemove) const
1085 if (selectionController()->isNone())
1088 RefPtr<Range> range(selectionController()->toRange());
1089 Position pos = range->editingStartPosition();
1091 Element *elem = pos.element();
1095 RefPtr<Element> styleElement = elem;
1096 ExceptionCode ec = 0;
1098 if (d->m_typingStyle) {
1099 styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
1102 styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
1105 styleElement->appendChild(document()->createEditingTextNode(""), ec);
1108 if (elem->renderer() && elem->renderer()->canHaveChildren()) {
1109 elem->appendChild(styleElement, ec);
1111 Node *parent = elem->parent();
1112 Node *next = elem->nextSibling();
1115 parent->insertBefore(styleElement, next, ec);
1117 parent->appendChild(styleElement, ec);
1122 nodeToRemove = styleElement.get();
1125 return new CSSComputedStyleDeclaration(styleElement);
1128 void Frame::applyEditingStyleToBodyElement() const
1133 RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
1134 unsigned len = list->length();
1135 for (unsigned i = 0; i < len; i++) {
1136 applyEditingStyleToElement(static_cast<Element*>(list->item(i)));
1140 void Frame::removeEditingStyleFromBodyElement() const
1145 RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
1146 unsigned len = list->length();
1147 for (unsigned i = 0; i < len; i++) {
1148 removeEditingStyleFromElement(static_cast<Element*>(list->item(i)));
1152 void Frame::applyEditingStyleToElement(Element* element) const
1157 CSSStyleDeclaration* style = element->style();
1160 ExceptionCode ec = 0;
1161 style->setProperty(CSS_PROP_WORD_WRAP, "break-word", false, ec);
1163 style->setProperty(CSS_PROP__WEBKIT_NBSP_MODE, "space", false, ec);
1165 style->setProperty(CSS_PROP__WEBKIT_LINE_BREAK, "after-white-space", false, ec);
1169 void Frame::removeEditingStyleFromElement(Element*) const
1173 bool Frame::isCharacterSmartReplaceExempt(UChar, bool)
1180 static HashSet<Frame*> lifeSupportSet;
1183 void Frame::endAllLifeSupport()
1186 HashSet<Frame*> lifeSupportCopy = lifeSupportSet;
1187 HashSet<Frame*>::iterator end = lifeSupportCopy.end();
1188 for (HashSet<Frame*>::iterator it = lifeSupportCopy.begin(); it != end; ++it)
1189 (*it)->endLifeSupport();
1193 void Frame::keepAlive()
1195 if (d->m_lifeSupportTimer.isActive())
1199 lifeSupportSet.add(this);
1201 d->m_lifeSupportTimer.startOneShot(0);
1204 void Frame::endLifeSupport()
1206 if (!d->m_lifeSupportTimer.isActive())
1208 d->m_lifeSupportTimer.stop();
1210 lifeSupportSet.remove(this);
1215 void Frame::lifeSupportTimerFired(Timer<Frame>*)
1218 lifeSupportSet.remove(this);
1223 bool Frame::mouseDownMayStartAutoscroll() const
1225 return d->m_mouseDownMayStartAutoscroll;
1228 void Frame::setMouseDownMayStartAutoscroll(bool b)
1230 d->m_mouseDownMayStartAutoscroll = b;
1233 bool Frame::mouseDownMayStartDrag() const
1235 return d->m_mouseDownMayStartDrag;
1238 void Frame::setMouseDownMayStartDrag(bool b)
1240 d->m_mouseDownMayStartDrag = b;
1243 void Frame::setSettings(Settings *settings)
1245 d->m_settings = settings;
1248 RenderObject *Frame::renderer() const
1250 Document *doc = document();
1251 return doc ? doc->renderer() : 0;
1254 Element* Frame::ownerElement()
1256 return d->m_ownerElement;
1259 RenderPart* Frame::ownerRenderer()
1261 Element* ownerElement = d->m_ownerElement;
1264 return static_cast<RenderPart*>(ownerElement->renderer());
1267 IntRect Frame::selectionRect() const
1269 RenderView *root = static_cast<RenderView*>(renderer());
1273 return root->selectionRect();
1276 // returns FloatRect because going through IntRect would truncate any floats
1277 FloatRect Frame::visibleSelectionRect() const
1282 return intersection(selectionRect(), d->m_view->visibleContentRect());
1285 bool Frame::isFrameSet() const
1287 Document* document = d->m_doc.get();
1288 if (!document || !document->isHTMLDocument())
1290 Node *body = static_cast<HTMLDocument*>(document)->body();
1291 return body && body->renderer() && body->hasTagName(framesetTag);
1294 // Scans logically forward from "start", including any child frames
1295 static HTMLFormElement *scanForForm(Node *start)
1298 for (n = start; n; n = n->traverseNextNode()) {
1299 if (n->hasTagName(formTag))
1300 return static_cast<HTMLFormElement*>(n);
1301 else if (n->isHTMLElement() && static_cast<HTMLElement*>(n)->isGenericFormElement())
1302 return static_cast<HTMLGenericFormElement*>(n)->form();
1303 else if (n->hasTagName(frameTag) || n->hasTagName(iframeTag)) {
1304 Node *childDoc = static_cast<HTMLFrameElementBase*>(n)->contentDocument();
1305 if (HTMLFormElement *frameResult = scanForForm(childDoc))
1312 // We look for either the form containing the current focus, or for one immediately after it
1313 HTMLFormElement *Frame::currentForm() const
1315 // start looking either at the active (first responder) node, or where the selection is
1316 Node *start = d->m_doc ? d->m_doc->focusNode() : 0;
1318 start = selectionController()->start().node();
1320 // try walking up the node tree to find a form element
1322 for (n = start; n; n = n->parentNode()) {
1323 if (n->hasTagName(formTag))
1324 return static_cast<HTMLFormElement*>(n);
1325 else if (n->isHTMLElement()
1326 && static_cast<HTMLElement*>(n)->isGenericFormElement())
1327 return static_cast<HTMLGenericFormElement*>(n)->form();
1330 // try walking forward in the node tree to find a form element
1331 return start ? scanForForm(start) : 0;
1334 // FIXME: should this go in SelectionController?
1335 void Frame::revealSelection(const RenderLayer::ScrollAlignment& alignment) const
1339 switch (selectionController()->state()) {
1340 case Selection::NONE:
1343 case Selection::CARET:
1344 rect = selectionController()->caretRect();
1347 case Selection::RANGE:
1348 rect = selectionRect();
1352 Position start = selectionController()->start();
1353 Position end = selectionController()->end();
1355 ASSERT(start.node());
1356 if (start.node() && start.node()->renderer()) {
1357 RenderLayer *layer = start.node()->renderer()->enclosingLayer();
1359 ASSERT(!end.node() || !end.node()->renderer()
1360 || (end.node()->renderer()->enclosingLayer() == layer));
1361 layer->scrollRectToVisible(rect, alignment, alignment);
1366 void Frame::revealCaret(const RenderLayer::ScrollAlignment& alignment) const
1368 if (selectionController()->isNone())
1371 Position extent = selectionController()->extent();
1372 if (extent.node() && extent.node()->renderer()) {
1373 IntRect extentRect = VisiblePosition(extent).caretRect();
1374 RenderLayer* layer = extent.node()->renderer()->enclosingLayer();
1376 layer->scrollRectToVisible(extentRect, alignment, alignment);
1380 // FIXME: should this be here?
1381 bool Frame::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity)
1387 Node *node = document()->focusNode();
1389 node = d->m_mousePressNode.get();
1393 RenderObject *r = node->renderer();
1394 if (r != 0 && !r->isListBox()) {
1395 return r->scroll(direction, granularity);
1402 void Frame::handleAutoscroll(RenderObject* renderer)
1404 if (d->m_autoscrollTimer.isActive())
1406 setAutoscrollRenderer(renderer);
1407 startAutoscrollTimer();
1410 void Frame::autoscrollTimerFired(Timer<Frame>*)
1412 if (!d->m_bMousePressed){
1413 stopAutoscrollTimer();
1416 if (RenderObject* r = autoscrollRenderer())
1420 RenderObject* Frame::autoscrollRenderer() const
1422 return d->m_autoscrollRenderer;
1425 void Frame::setAutoscrollRenderer(RenderObject* renderer)
1427 d->m_autoscrollRenderer = renderer;
1430 HitTestResult Frame::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent)
1432 HitTestResult result(point);
1435 renderer()->layer()->hitTest(HitTestRequest(true, true), result);
1437 IntPoint widgetPoint(point);
1439 Node* n = result.innerNode();
1440 if (!n || !n->renderer() || !n->renderer()->isWidget())
1442 Widget* widget = static_cast<RenderWidget*>(n->renderer())->widget();
1443 if (!widget || !widget->isFrameView())
1445 Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame();
1446 if (!frame || !frame->renderer())
1449 n->renderer()->absolutePosition(absX, absY, true);
1450 FrameView* view = static_cast<FrameView*>(widget);
1451 widgetPoint.move(view->contentsX() - absX, view->contentsY() - absY);
1452 HitTestResult widgetHitTestResult(widgetPoint);
1453 frame->renderer()->layer()->hitTest(HitTestRequest(true, true), widgetHitTestResult);
1454 result = widgetHitTestResult;
1457 if (!allowShadowContent) {
1458 Node* node = result.innerNode();
1460 node = node->shadowAncestorNode();
1461 result.setInnerNode(node);
1462 node = result.innerNonSharedNode();
1464 node = node->shadowAncestorNode();
1465 result.setInnerNonSharedNode(node);
1472 void Frame::startAutoscrollTimer()
1474 d->m_autoscrollTimer.startRepeating(autoscrollInterval);
1477 void Frame::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
1479 if (!rendererIsBeingDestroyed && autoscrollRenderer())
1480 autoscrollRenderer()->stopAutoscroll();
1481 setAutoscrollRenderer(0);
1482 d->m_autoscrollTimer.stop();
1485 // FIXME: why is this here instead of on the FrameView?
1486 void Frame::paint(GraphicsContext* p, const IntRect& rect)
1490 if (!document() || document()->printing())
1491 fillWithRed = false; // Printing, don't fill with red (can't remember why).
1492 else if (document()->ownerElement())
1493 fillWithRed = false; // Subframe, don't fill with red.
1494 else if (view() && view()->isTransparent())
1495 fillWithRed = false; // Transparent, don't fill with red.
1496 else if (d->m_paintRestriction == PaintRestrictionSelectionOnly || d->m_paintRestriction == PaintRestrictionSelectionOnlyWhiteText)
1497 fillWithRed = false; // Selections are transparent, don't fill with red.
1498 else if (d->m_elementToDraw)
1499 fillWithRed = false; // Element images are transparent, don't fill with red.
1504 p->fillRect(rect, Color(0xFF, 0, 0));
1508 // d->m_elementToDraw is used to draw only one element
1509 RenderObject *eltRenderer = d->m_elementToDraw ? d->m_elementToDraw->renderer() : 0;
1510 if (d->m_paintRestriction == PaintRestrictionNone)
1511 renderer()->document()->invalidateRenderedRectsForMarkersInRect(rect);
1512 renderer()->layer()->paint(p, rect, d->m_paintRestriction, eltRenderer);
1515 // Regions may have changed as a result of the visibility/z-index of element changing.
1516 if (renderer()->document()->dashboardRegionsDirty())
1517 renderer()->view()->frameView()->updateDashboardRegions();
1520 LOG_ERROR("called Frame::paint with nil renderer");
1525 void Frame::adjustPageHeight(float *newBottom, float oldTop, float oldBottom, float bottomLimit)
1527 RenderView *root = static_cast<RenderView*>(document()->renderer());
1529 // Use a context with painting disabled.
1530 GraphicsContext context((PlatformGraphicsContext*)0);
1531 root->setTruncatedAt((int)floorf(oldBottom));
1532 IntRect dirtyRect(0, (int)floorf(oldTop), root->docWidth(), (int)ceilf(oldBottom - oldTop));
1533 root->layer()->paint(&context, dirtyRect);
1534 *newBottom = root->bestTruncatedAt();
1535 if (*newBottom == 0)
1536 *newBottom = oldBottom;
1538 *newBottom = oldBottom;
1543 Frame *Frame::frameForWidget(const Widget *widget)
1545 ASSERT_ARG(widget, widget);
1547 Node *node = nodeForWidget(widget);
1549 return frameForNode(node);
1551 // Assume all widgets are either form controls, or FrameViews.
1552 ASSERT(widget->isFrameView());
1553 return static_cast<const FrameView*>(widget)->frame();
1556 Frame *Frame::frameForNode(Node *node)
1558 ASSERT_ARG(node, node);
1559 return node->document()->frame();
1562 Node* Frame::nodeForWidget(const Widget* widget)
1564 ASSERT_ARG(widget, widget);
1565 WidgetClient* client = widget->client();
1568 return client->element(const_cast<Widget*>(widget));
1571 void Frame::clearDocumentFocus(Widget *widget)
1573 Node *node = nodeForWidget(widget);
1575 node->document()->setFocusNode(0);
1578 void Frame::forceLayout()
1580 FrameView *v = d->m_view.get();
1583 // We cannot unschedule a pending relayout, since the force can be called with
1584 // a tiny rectangle from a drawRect update. By unscheduling we in effect
1585 // "validate" and stop the necessary full repaint from occurring. Basically any basic
1586 // append/remove DHTML is broken by this call. For now, I have removed the optimization
1587 // until we have a better invalidation stategy. -dwh
1588 //v->unscheduleRelayout();
1592 void Frame::forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth)
1594 // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
1595 // the state of things before and after the layout
1596 RenderView *root = static_cast<RenderView*>(document()->renderer());
1598 // This magic is basically copied from khtmlview::print
1599 int pageW = (int)ceilf(minPageWidth);
1600 root->setWidth(pageW);
1601 root->setNeedsLayoutAndMinMaxRecalc();
1604 // If we don't fit in the minimum page width, we'll lay out again. If we don't fit in the
1605 // maximum page width, we will lay out to the maximum page width and clip extra content.
1606 // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping
1607 // implementation should not do this!
1608 int rightmostPos = root->rightmostPosition();
1609 if (rightmostPos > minPageWidth) {
1610 pageW = min(rightmostPos, (int)ceilf(maxPageWidth));
1611 root->setWidth(pageW);
1612 root->setNeedsLayoutAndMinMaxRecalc();
1618 void Frame::sendResizeEvent()
1620 if (Document* doc = document())
1621 doc->dispatchWindowEvent(EventNames::resizeEvent, false, false);
1624 void Frame::sendScrollEvent()
1626 FrameView *v = d->m_view.get();
1628 Document *doc = document();
1631 doc->dispatchHTMLEvent(scrollEvent, true, false);
1635 bool Frame::canMouseDownStartSelect(Node* node)
1637 if (!node || !node->renderer())
1640 // Check to see if -webkit-user-select has been set to none
1641 if (!node->renderer()->canSelect())
1644 // Some controls and images can't start a select on a mouse down.
1645 for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) {
1646 if (curr->style()->userSelect() == SELECT_IGNORE)
1653 void Frame::clearTimers(FrameView *view)
1656 view->unscheduleRelayout();
1657 if (view->frame()) {
1658 Document* document = view->frame()->document();
1659 if (document && document->renderer() && document->renderer()->layer())
1660 document->renderer()->layer()->suspendMarquees();
1665 void Frame::clearTimers()
1667 clearTimers(d->m_view.get());
1670 RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const
1676 if (selectionController()->isNone())
1679 Position pos = selectionController()->selection().visibleStart().deepEquivalent();
1680 if (!pos.inRenderedContent())
1682 Node *node = pos.node();
1686 if (!d->m_typingStyle)
1687 return node->renderer()->style();
1689 ExceptionCode ec = 0;
1690 RefPtr<Element> styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
1693 styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
1696 styleElement->appendChild(document()->createEditingTextNode(""), ec);
1699 node->parentNode()->appendChild(styleElement, ec);
1702 nodeToRemove = styleElement.get();
1703 return styleElement->renderer()->style();
1706 void Frame::setSelectionFromNone()
1708 // Put a caret inside the body if the entire frame is editable (either the
1709 // entire WebView is editable or designMode is on for this document).
1710 Document *doc = document();
1711 if (!doc || !selectionController()->isNone() || !isContentEditable())
1714 Node* node = doc->documentElement();
1715 while (node && !node->hasTagName(bodyTag))
1716 node = node->traverseNextNode();
1718 selectionController()->setSelection(Selection(Position(node, 0), DOWNSTREAM));
1721 bool Frame::isActive() const
1723 return d->m_isActive;
1726 void Frame::setIsActive(bool flag)
1728 if (d->m_isActive == flag)
1731 d->m_isActive = flag;
1733 // This method does the job of updating the view based on whether the view is "active".
1734 // This involves three kinds of drawing updates:
1736 // 1. The background color used to draw behind selected content (active | inactive color)
1738 d->m_view->updateContents(enclosingIntRect(visibleSelectionRect()));
1740 // 2. Caret blinking (blinks | does not blink)
1742 setSelectionFromNone();
1743 setCaretVisible(flag);
1745 // 3. The drawing of a focus ring around links in web pages.
1746 Document *doc = document();
1748 Node *node = doc->focusNode();
1751 if (node->renderer() && node->renderer()->style()->hasAppearance())
1752 theme()->stateChanged(node->renderer(), FocusState);
1756 // 4. Changing the tint of controls from clear to aqua/graphite and vice versa. We
1757 // do a "fake" paint. When the theme gets a paint call, it can then do an invalidate. This is only
1758 // done if the theme supports control tinting.
1759 if (doc && d->m_view && theme()->supportsControlTints() && renderer()) {
1760 doc->updateLayout(); // Ensure layout is up to date.
1761 IntRect visibleRect(enclosingIntRect(d->m_view->visibleContentRect()));
1762 GraphicsContext context((PlatformGraphicsContext*)0);
1763 context.setUpdatingControlTints(true);
1764 paint(&context, visibleRect);
1767 // 5. Enable or disable secure keyboard entry
1768 if ((flag && !isSecureKeyboardEntry() && doc && doc->focusNode() && doc->focusNode()->hasTagName(inputTag) &&
1769 static_cast<HTMLInputElement*>(doc->focusNode())->inputType() == HTMLInputElement::PASSWORD) ||
1770 (!flag && isSecureKeyboardEntry()))
1771 setSecureKeyboardEntry(flag);
1774 void Frame::setWindowHasFocus(bool flag)
1776 if (d->m_windowHasFocus == flag)
1778 d->m_windowHasFocus = flag;
1780 if (Document *doc = document())
1781 doc->dispatchWindowEvent(flag ? focusEvent : blurEvent, false, false);
1784 bool Frame::inViewSourceMode() const
1786 return d->m_inViewSourceMode;
1789 void Frame::setInViewSourceMode(bool mode) const
1791 d->m_inViewSourceMode = mode;
1794 UChar Frame::backslashAsCurrencySymbol() const
1796 Document *doc = document();
1799 TextResourceDecoder *decoder = doc->decoder();
1803 return decoder->encoding().backslashAsCurrencySymbol();
1806 bool Frame::markedTextUsesUnderlines() const
1808 return d->m_markedTextUsesUnderlines;
1811 const Vector<MarkedTextUnderline>& Frame::markedTextUnderlines() const
1813 return d->m_markedTextUnderlines;
1816 // Searches from the beginning of the document if nothing is selected.
1817 bool Frame::findString(const String& target, bool forward, bool caseFlag, bool wrapFlag)
1819 if (target.isEmpty())
1822 // Initially search from the start (if forward) or end (if backward) of the selection, and search to edge of document.
1823 RefPtr<Range> searchRange(rangeOfContents(document()));
1824 Selection selection(selectionController()->selection());
1825 if (!selection.isNone()) {
1827 setStart(searchRange.get(), selection.visibleStart());
1829 setEnd(searchRange.get(), selection.visibleEnd());
1831 RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, forward, caseFlag));
1832 // If the found range is already selected, find again.
1833 // Build a selection with the found range to remove collapsed whitespace.
1834 // Compare ranges instead of selection objects to ignore the way that the current selection was made.
1835 if (!selection.isNone() && *Selection(resultRange.get()).toRange() == *selection.toRange()) {
1836 searchRange = rangeOfContents(document());
1838 setStart(searchRange.get(), selection.visibleEnd());
1840 setEnd(searchRange.get(), selection.visibleStart());
1841 resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
1846 // If we didn't find anything and we're wrapping, search again in the entire document (this will
1847 // redundantly re-search the area already searched in some cases).
1848 if (resultRange->collapsed(exception) && wrapFlag) {
1849 searchRange = rangeOfContents(document());
1850 resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
1851 // We used to return false here if we ended up with the same range that we started with
1852 // (e.g., the selection was already the only instance of this text). But we decided that
1853 // this should be a success case instead, so we'll just fall through in that case.
1856 if (resultRange->collapsed(exception))
1859 selectionController()->setSelection(Selection(resultRange.get(), DOWNSTREAM));
1864 unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsigned limit)
1866 if (target.isEmpty())
1869 RefPtr<Range> searchRange(rangeOfContents(document()));
1872 unsigned matchCount = 0;
1874 RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, caseFlag));
1875 if (resultRange->collapsed(exception))
1878 // A non-collapsed result range can in some funky whitespace cases still not
1879 // advance the range's start position (4509328). Break to avoid infinite loop.
1880 VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
1881 if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
1886 document()->addMarker(resultRange.get(), DocumentMarker::TextMatch);
1888 // Stop looking if we hit the specified limit. A limit of 0 means no limit.
1889 if (limit > 0 && matchCount >= limit)
1892 setStart(searchRange.get(), newStart);
1895 // Do a "fake" paint in order to execute the code that computes the rendered rect for
1897 Document* doc = document();
1898 if (doc && d->m_view && renderer()) {
1899 doc->updateLayout(); // Ensure layout is up to date.
1900 IntRect visibleRect(enclosingIntRect(d->m_view->visibleContentRect()));
1901 GraphicsContext context((PlatformGraphicsContext*)0);
1902 context.setPaintingDisabled(true);
1903 paint(&context, visibleRect);
1909 bool Frame::markedTextMatchesAreHighlighted() const
1911 return d->m_highlightTextMatches;
1914 void Frame::setMarkedTextMatchesAreHighlighted(bool flag)
1916 if (flag == d->m_highlightTextMatches)
1919 d->m_highlightTextMatches = flag;
1920 document()->repaintMarkers(DocumentMarker::TextMatch);
1923 Node *Frame::mousePressNode()
1925 return d->m_mousePressNode.get();
1928 FrameTree* Frame::tree() const
1930 return &d->m_treeNode;
1933 DOMWindow* Frame::domWindow() const
1935 if (!d->m_domWindow)
1936 d->m_domWindow = new DOMWindow(const_cast<Frame*>(this));
1938 return d->m_domWindow.get();
1941 Page* Frame::page() const
1946 void Frame::pageDestroyed()
1950 // This will stop any JS timers
1951 if (d->m_jscript && d->m_jscript->haveInterpreter())
1952 if (Window* w = Window::retrieveWindow(this))
1953 w->disconnectFrame();
1956 void Frame::setStatusBarText(const String&)
1960 void Frame::disconnectOwnerElement()
1962 if (d->m_ownerElement && d->m_page)
1963 d->m_page->decrementFrameCount();
1965 d->m_ownerElement = 0;
1968 String Frame::documentTypeString() const
1970 if (Document *doc = document())
1971 if (DocumentType *doctype = doc->realDocType())
1972 return doctype->toString();
1977 bool Frame::prohibitsScrolling() const
1979 return d->m_prohibitsScrolling;
1982 void Frame::setProhibitsScrolling(const bool prohibit)
1984 d->m_prohibitsScrolling = prohibit;
1987 FramePrivate::FramePrivate(Page* page, Frame* parent, Frame* thisFrame, Element* ownerElement, PassRefPtr<EditorClient> client)
1989 , m_treeNode(thisFrame, parent)
1990 , m_ownerElement(ownerElement)
1992 , m_bJScriptEnabled(true)
1993 , m_bJavaEnabled(true)
1994 , m_bPluginsEnabled(true)
1996 , m_zoomFactor(parent ? parent->d->m_zoomFactor : 100)
1997 , m_bMousePressed(false)
1998 , m_beganSelectingText(false)
1999 , m_selectionController(thisFrame)
2000 , m_caretBlinkTimer(thisFrame, &Frame::caretBlinkTimerFired)
2001 , m_editor(thisFrame, client)
2002 , m_command(thisFrame)
2003 , m_caretVisible(false)
2004 , m_caretPaint(true)
2006 , m_lifeSupportTimer(thisFrame, &Frame::lifeSupportTimerFired)
2007 , m_loader(new FrameLoader(thisFrame))
2008 , m_userStyleSheetLoader(0)
2009 , m_autoscrollTimer(thisFrame, &Frame::autoscrollTimerFired)
2010 , m_autoscrollRenderer(0)
2011 , m_mouseDownMayStartAutoscroll(false)
2012 , m_mouseDownMayStartDrag(false)
2013 , m_paintRestriction(PaintRestrictionNone)
2014 , m_markedTextUsesUnderlines(false)
2015 , m_highlightTextMatches(false)
2016 , m_windowHasFocus(false)
2017 , m_inViewSourceMode(false)
2019 , m_prohibitsScrolling(false)
2023 FramePrivate::~FramePrivate()
2029 } // namespace WebCore