Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / editing / Caret.cpp
1 /*
2  * Copyright (C) 2004, 2008, 2009, 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "core/editing/Caret.h"
28
29 #include "core/dom/Document.h"
30 #include "core/editing/htmlediting.h"
31 #include "core/frame/Frame.h"
32 #include "core/frame/Settings.h"
33 #include "core/rendering/RenderBlock.h"
34 #include "core/rendering/RenderView.h"
35
36 namespace WebCore {
37
38 CaretBase::CaretBase(CaretVisibility visibility)
39     : m_caretRectNeedsUpdate(true)
40     , m_caretVisibility(visibility)
41 {
42 }
43
44 DragCaretController::DragCaretController()
45     : CaretBase(Visible)
46 {
47 }
48
49 PassOwnPtr<DragCaretController> DragCaretController::create()
50 {
51     return adoptPtr(new DragCaretController);
52 }
53
54 bool DragCaretController::isContentRichlyEditable() const
55 {
56     return isRichlyEditablePosition(m_position.deepEquivalent());
57 }
58
59 void DragCaretController::setCaretPosition(const VisiblePosition& position)
60 {
61     if (Node* node = m_position.deepEquivalent().deprecatedNode())
62         invalidateCaretRect(node);
63     m_position = position;
64     setCaretRectNeedsUpdate();
65     Document* document = 0;
66     if (Node* node = m_position.deepEquivalent().deprecatedNode()) {
67         invalidateCaretRect(node);
68         document = &node->document();
69     }
70     if (m_position.isNull() || m_position.isOrphan())
71         clearCaretRect();
72     else
73         updateCaretRect(document, m_position);
74 }
75
76 static bool removingNodeRemovesPosition(Node& node, const Position& position)
77 {
78     if (!position.anchorNode())
79         return false;
80
81     if (position.anchorNode() == node)
82         return true;
83
84     if (!node.isElementNode())
85         return false;
86
87     Element& element = toElement(node);
88     return element.containsIncludingShadowDOM(position.anchorNode());
89 }
90
91 void DragCaretController::nodeWillBeRemoved(Node& node)
92 {
93     if (!hasCaret() || !node.inActiveDocument())
94         return;
95
96     if (!removingNodeRemovesPosition(node, m_position.deepEquivalent()))
97         return;
98
99     m_position.deepEquivalent().document()->renderView()->clearSelection();
100     clear();
101 }
102
103 void CaretBase::clearCaretRect()
104 {
105     m_caretLocalRect = LayoutRect();
106 }
107
108 static inline bool caretRendersInsideNode(Node* node)
109 {
110     return node && !isRenderedTable(node) && !editingIgnoresContent(node);
111 }
112
113 RenderObject* CaretBase::caretRenderer(Node* node)
114 {
115     if (!node)
116         return 0;
117
118     RenderObject* renderer = node->renderer();
119     if (!renderer)
120         return 0;
121
122     // if caretNode is a block and caret is inside it then caret should be painted by that block
123     bool paintedByBlock = renderer->isRenderBlock() && caretRendersInsideNode(node);
124     return paintedByBlock ? renderer : renderer->containingBlock();
125 }
126
127 bool CaretBase::updateCaretRect(Document* document, const VisiblePosition& caretPosition)
128 {
129     document->updateStyleIfNeeded();
130     m_caretLocalRect = LayoutRect();
131
132     m_caretRectNeedsUpdate = false;
133
134     if (caretPosition.isNull())
135         return false;
136
137     ASSERT(caretPosition.deepEquivalent().deprecatedNode()->renderer());
138
139     // First compute a rect local to the renderer at the selection start.
140     RenderObject* renderer;
141     LayoutRect localRect = caretPosition.localCaretRect(renderer);
142
143     // Get the renderer that will be responsible for painting the caret
144     // (which is either the renderer we just found, or one of its containers).
145     RenderObject* caretPainter = caretRenderer(caretPosition.deepEquivalent().deprecatedNode());
146
147     // Compute an offset between the renderer and the caretPainter.
148     bool unrooted = false;
149     while (renderer != caretPainter) {
150         RenderObject* containerObject = renderer->container();
151         if (!containerObject) {
152             unrooted = true;
153             break;
154         }
155         localRect.move(renderer->offsetFromContainer(containerObject, localRect.location()));
156         renderer = containerObject;
157     }
158
159     if (!unrooted)
160         m_caretLocalRect = localRect;
161
162     return true;
163 }
164
165 RenderObject* DragCaretController::caretRenderer() const
166 {
167     return CaretBase::caretRenderer(m_position.deepEquivalent().deprecatedNode());
168 }
169
170 IntRect CaretBase::absoluteBoundsForLocalRect(Node* node, const LayoutRect& rect) const
171 {
172     RenderObject* caretPainter = caretRenderer(node);
173     if (!caretPainter)
174         return IntRect();
175
176     LayoutRect localRect(rect);
177     if (caretPainter->isBox())
178         toRenderBox(caretPainter)->flipForWritingMode(localRect);
179     return caretPainter->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
180 }
181
182 void CaretBase::repaintCaretForLocalRect(Node* node, const LayoutRect& rect)
183 {
184     RenderObject* caretPainter = caretRenderer(node);
185     if (!caretPainter)
186         return;
187
188     // FIXME: Need to over-paint 1 pixel to workaround some rounding problems.
189     // https://bugs.webkit.org/show_bug.cgi?id=108283
190     LayoutRect inflatedRect = rect;
191     inflatedRect.inflate(1);
192
193     caretPainter->repaintRectangle(inflatedRect);
194 }
195
196 bool CaretBase::shouldRepaintCaret(const RenderView* view, bool isContentEditable) const
197 {
198     ASSERT(view);
199     bool caretBrowsing = false;
200     if (FrameView* frameView = view->frameView()) {
201         Frame& frame = frameView->frame(); // The frame where the selection started
202         caretBrowsing = frame.settings() && frame.settings()->caretBrowsingEnabled();
203     }
204     return (caretBrowsing || isContentEditable);
205 }
206
207 void CaretBase::invalidateCaretRect(Node* node, bool caretRectChanged)
208 {
209     // EDIT FIXME: This is an unfortunate hack.
210     // Basically, we can't trust this layout position since we
211     // can't guarantee that the check to see if we are in unrendered
212     // content will work at this point. We may have to wait for
213     // a layout and re-render of the document to happen. So, resetting this
214     // flag will cause another caret layout to happen the first time
215     // that we try to paint the caret after this call. That one will work since
216     // it happens after the document has accounted for any editing
217     // changes which may have been done.
218     // And, we need to leave this layout here so the caret moves right
219     // away after clicking.
220     m_caretRectNeedsUpdate = true;
221
222     if (caretRectChanged)
223         return;
224
225     if (RenderView* view = node->document().renderView()) {
226         if (shouldRepaintCaret(view, node->isContentEditable(Node::UserSelectAllIsAlwaysNonEditable)))
227             repaintCaretForLocalRect(node, localCaretRectWithoutUpdate());
228     }
229 }
230
231 void CaretBase::paintCaret(Node* node, GraphicsContext* context, const LayoutPoint& paintOffset, const LayoutRect& clipRect) const
232 {
233     if (m_caretVisibility == Hidden)
234         return;
235
236     LayoutRect drawingRect = localCaretRectWithoutUpdate();
237     RenderObject* renderer = caretRenderer(node);
238     if (renderer && renderer->isBox())
239         toRenderBox(renderer)->flipForWritingMode(drawingRect);
240     drawingRect.moveBy(roundedIntPoint(paintOffset));
241     LayoutRect caret = intersection(drawingRect, clipRect);
242     if (caret.isEmpty())
243         return;
244
245     Color caretColor = Color::black;
246
247     Element* element;
248     if (node->isElementNode())
249         element = toElement(node);
250     else
251         element = node->parentElement();
252
253     if (element && element->renderer())
254         caretColor = element->renderer()->resolveColor(CSSPropertyColor);
255
256     context->fillRect(caret, caretColor);
257 }
258
259 void DragCaretController::paintDragCaret(Frame* frame, GraphicsContext* p, const LayoutPoint& paintOffset, const LayoutRect& clipRect) const
260 {
261     if (m_position.deepEquivalent().deprecatedNode()->document().frame() == frame)
262         paintCaret(m_position.deepEquivalent().deprecatedNode(), p, paintOffset, clipRect);
263 }
264
265 }