OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2008, 2009, 2010 Apple Inc. All rights reserved. | 2 * Copyright (C) 2004, 2008, 2009, 2010 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 return adoptPtr(new DragCaretController); | 56 return adoptPtr(new DragCaretController); |
57 } | 57 } |
58 | 58 |
59 bool DragCaretController::isContentRichlyEditable() const | 59 bool DragCaretController::isContentRichlyEditable() const |
60 { | 60 { |
61 return isRichlyEditablePosition(m_position.deepEquivalent()); | 61 return isRichlyEditablePosition(m_position.deepEquivalent()); |
62 } | 62 } |
63 | 63 |
64 void DragCaretController::setCaretPosition(const VisiblePosition& position) | 64 void DragCaretController::setCaretPosition(const VisiblePosition& position) |
65 { | 65 { |
66 if (Node* node = m_position.deepEquivalent().deprecatedNode()) | 66 if (m_position.isNotNull()) |
67 invalidateCaretRect(node); | 67 invalidateCaretRect(m_position.deepEquivalent()); |
68 m_position = position; | 68 m_position = position; |
69 setCaretRectNeedsUpdate(); | 69 setCaretRectNeedsUpdate(); |
70 Document* document = 0; | 70 if (m_position.isNotNull()) |
71 if (Node* node = m_position.deepEquivalent().deprecatedNode()) { | 71 invalidateCaretRect(m_position.deepEquivalent()); |
72 invalidateCaretRect(node); | |
73 document = node->document(); | |
74 } | |
75 if (m_position.isNull() || m_position.isOrphan()) | 72 if (m_position.isNull() || m_position.isOrphan()) |
76 clearCaretRect(); | 73 clearCaretRect(); |
77 else | 74 else |
78 updateCaretRect(document, m_position); | 75 updateCaretRect(m_position.deepEquivalent().document(), m_position); |
79 } | 76 } |
80 | 77 |
81 static bool removingNodeRemovesPosition(Node* node, const Position& position) | 78 static bool removingNodeRemovesPosition(Node* node, const Position& position) |
82 { | 79 { |
83 if (!position.anchorNode()) | 80 if (!position.anchorNode()) |
84 return false; | 81 return false; |
85 | 82 |
86 if (position.anchorNode() == node) | 83 if (position.anchorNode() == node) |
87 return true; | 84 return true; |
88 | 85 |
(...skipping 27 matching lines...) Expand all Loading... |
116 void CaretBase::clearCaretRect() | 113 void CaretBase::clearCaretRect() |
117 { | 114 { |
118 m_caretLocalRect = LayoutRect(); | 115 m_caretLocalRect = LayoutRect(); |
119 } | 116 } |
120 | 117 |
121 static inline bool caretRendersInsideNode(Node* node) | 118 static inline bool caretRendersInsideNode(Node* node) |
122 { | 119 { |
123 return node && !isTableElement(node) && !editingIgnoresContent(node); | 120 return node && !isTableElement(node) && !editingIgnoresContent(node); |
124 } | 121 } |
125 | 122 |
126 RenderObject* CaretBase::caretRenderer(Node* node) | 123 RenderObject* CaretBase::caretRenderer(RenderObject* renderer) |
127 { | 124 { |
128 if (!node) | |
129 return 0; | |
130 | |
131 RenderObject* renderer = node->renderer(); | |
132 if (!renderer) | 125 if (!renderer) |
133 return 0; | 126 return 0; |
134 | 127 |
135 // if caretNode is a block and caret is inside it then caret should be paint
ed by that block | 128 // if caretNode is a block and caret is inside it then caret should be paint
ed by that block |
136 bool paintedByBlock = renderer->isBlockFlow() && caretRendersInsideNode(node
); | 129 bool paintedByBlock = renderer->isBlockFlow() && caretRendersInsideNode(rend
erer->node()); |
137 return paintedByBlock ? renderer : renderer->containingBlock(); | 130 return paintedByBlock ? renderer : renderer->containingBlock(); |
138 } | 131 } |
139 | 132 |
| 133 RenderObject* CaretBase::caretRenderer(const Position& position) |
| 134 { |
| 135 return caretRenderer(position.renderer()); |
| 136 } |
| 137 |
140 bool CaretBase::updateCaretRect(Document* document, const VisiblePosition& caret
Position) | 138 bool CaretBase::updateCaretRect(Document* document, const VisiblePosition& caret
Position) |
141 { | 139 { |
142 document->updateStyleIfNeeded(); | 140 document->updateStyleIfNeeded(); |
143 m_caretLocalRect = LayoutRect(); | 141 m_caretLocalRect = LayoutRect(); |
144 | 142 |
145 m_caretRectNeedsUpdate = false; | 143 m_caretRectNeedsUpdate = false; |
146 | 144 |
147 if (caretPosition.isNull()) | 145 if (caretPosition.isNull()) |
148 return false; | 146 return false; |
149 | 147 |
150 ASSERT(caretPosition.deepEquivalent().deprecatedNode()->renderer()); | 148 ASSERT(caretPosition.deepEquivalent().deprecatedNode()->renderer()); |
151 | 149 |
152 // First compute a rect local to the renderer at the selection start. | 150 // First compute a rect local to the renderer at the selection start. |
153 RenderObject* renderer; | 151 RenderObject* renderer; |
154 LayoutRect localRect = caretPosition.localCaretRect(renderer); | 152 LayoutRect localRect = caretPosition.localCaretRect(renderer); |
155 | 153 |
156 // Get the renderer that will be responsible for painting the caret | 154 // Get the renderer that will be responsible for painting the caret |
157 // (which is either the renderer we just found, or one of its containers). | 155 // (which is either the renderer we just found, or one of its containers). |
158 RenderObject* caretPainter = caretRenderer(caretPosition.deepEquivalent().de
precatedNode()); | 156 RenderObject* caretPainter = caretRenderer(caretPosition.deepEquivalent()); |
159 | 157 |
160 // Compute an offset between the renderer and the caretPainter. | 158 // Compute an offset between the renderer and the caretPainter. |
161 bool unrooted = false; | 159 bool unrooted = false; |
162 while (renderer != caretPainter) { | 160 while (renderer != caretPainter) { |
163 RenderObject* containerObject = renderer->container(); | 161 RenderObject* containerObject = renderer->container(); |
164 if (!containerObject) { | 162 if (!containerObject) { |
165 unrooted = true; | 163 unrooted = true; |
166 break; | 164 break; |
167 } | 165 } |
168 localRect.move(renderer->offsetFromContainer(containerObject, localRect.
location())); | 166 localRect.move(renderer->offsetFromContainer(containerObject, localRect.
location())); |
169 renderer = containerObject; | 167 renderer = containerObject; |
170 } | 168 } |
171 | 169 |
172 if (!unrooted) | 170 if (!unrooted) |
173 m_caretLocalRect = localRect; | 171 m_caretLocalRect = localRect; |
174 | 172 |
175 return true; | 173 return true; |
176 } | 174 } |
177 | 175 |
178 RenderObject* DragCaretController::caretRenderer() const | 176 RenderObject* DragCaretController::caretRenderer() const |
179 { | 177 { |
180 return CaretBase::caretRenderer(m_position.deepEquivalent().deprecatedNode()
); | 178 return CaretBase::caretRenderer(m_position.deepEquivalent()); |
181 } | 179 } |
182 | 180 |
183 IntRect CaretBase::absoluteBoundsForLocalRect(Node* node, const LayoutRect& rect
) const | 181 IntRect CaretBase::absoluteBoundsForLocalRect(const Position& position, const La
youtRect& rect) const |
184 { | 182 { |
185 RenderObject* caretPainter = caretRenderer(node); | 183 RenderObject* caretPainter = caretRenderer(position); |
186 if (!caretPainter) | 184 if (!caretPainter) |
187 return IntRect(); | 185 return IntRect(); |
188 | 186 |
189 LayoutRect localRect(rect); | 187 LayoutRect localRect(rect); |
190 if (caretPainter->isBox()) | 188 if (caretPainter->isBox()) |
191 toRenderBox(caretPainter)->flipForWritingMode(localRect); | 189 toRenderBox(caretPainter)->flipForWritingMode(localRect); |
192 return caretPainter->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoun
dingBox(); | 190 return caretPainter->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoun
dingBox(); |
193 } | 191 } |
194 | 192 |
195 void CaretBase::repaintCaretForLocalRect(Node* node, const LayoutRect& rect) | 193 void CaretBase::repaintCaretForLocalRect(const Position& position, const LayoutR
ect& rect) |
196 { | 194 { |
197 RenderObject* caretPainter = caretRenderer(node); | 195 RenderObject* caretPainter = caretRenderer(position); |
198 if (!caretPainter) | 196 if (!caretPainter) |
199 return; | 197 return; |
200 | 198 |
201 // FIXME: Need to over-paint 1 pixel to workaround some rounding problems. | 199 // FIXME: Need to over-paint 1 pixel to workaround some rounding problems. |
202 // https://bugs.webkit.org/show_bug.cgi?id=108283 | 200 // https://bugs.webkit.org/show_bug.cgi?id=108283 |
203 LayoutRect inflatedRect = rect; | 201 LayoutRect inflatedRect = rect; |
204 inflatedRect.inflate(1); | 202 inflatedRect.inflate(1); |
205 | 203 |
206 caretPainter->repaintRectangle(inflatedRect); | 204 caretPainter->repaintRectangle(inflatedRect); |
207 } | 205 } |
208 | 206 |
209 bool CaretBase::shouldRepaintCaret(const RenderView* view, bool isContentEditabl
e) const | 207 bool CaretBase::shouldRepaintCaret(const RenderView* view, bool isContentEditabl
e) const |
210 { | 208 { |
211 ASSERT(view); | 209 ASSERT(view); |
212 Frame* frame = view->frameView() ? view->frameView()->frame() : 0; // The fr
ame where the selection started. | 210 Frame* frame = view->frameView() ? view->frameView()->frame() : 0; // The fr
ame where the selection started. |
213 bool caretBrowsing = frame && frame->settings() && frame->settings()->caretB
rowsingEnabled(); | 211 bool caretBrowsing = frame && frame->settings() && frame->settings()->caretB
rowsingEnabled(); |
214 return (caretBrowsing || isContentEditable); | 212 return (caretBrowsing || isContentEditable); |
215 } | 213 } |
216 | 214 |
217 void CaretBase::invalidateCaretRect(Node* node, bool caretRectChanged) | 215 void CaretBase::invalidateCaretRect(const Position& position, bool caretRectChan
ged) |
218 { | 216 { |
219 // EDIT FIXME: This is an unfortunate hack. | 217 // EDIT FIXME: This is an unfortunate hack. |
220 // Basically, we can't trust this layout position since we | 218 // Basically, we can't trust this layout position since we |
221 // can't guarantee that the check to see if we are in unrendered | 219 // can't guarantee that the check to see if we are in unrendered |
222 // content will work at this point. We may have to wait for | 220 // content will work at this point. We may have to wait for |
223 // a layout and re-render of the document to happen. So, resetting this | 221 // a layout and re-render of the document to happen. So, resetting this |
224 // flag will cause another caret layout to happen the first time | 222 // flag will cause another caret layout to happen the first time |
225 // that we try to paint the caret after this call. That one will work since | 223 // that we try to paint the caret after this call. That one will work since |
226 // it happens after the document has accounted for any editing | 224 // it happens after the document has accounted for any editing |
227 // changes which may have been done. | 225 // changes which may have been done. |
228 // And, we need to leave this layout here so the caret moves right | 226 // And, we need to leave this layout here so the caret moves right |
229 // away after clicking. | 227 // away after clicking. |
230 m_caretRectNeedsUpdate = true; | 228 m_caretRectNeedsUpdate = true; |
231 | 229 |
232 if (caretRectChanged) | 230 if (caretRectChanged) |
233 return; | 231 return; |
234 | 232 |
235 if (RenderView* view = node->document()->renderView()) { | 233 if (RenderView* view = position.document()->renderView()) { |
236 if (shouldRepaintCaret(view, node->isContentEditable(Node::UserSelectAll
IsAlwaysNonEditable))) | 234 if (shouldRepaintCaret(view, position.anchorNode()->isContentEditable(No
de::UserSelectAllIsAlwaysNonEditable))) |
237 repaintCaretForLocalRect(node, localCaretRectWithoutUpdate()); | 235 repaintCaretForLocalRect(position, localCaretRectWithoutUpdate()); |
238 } | 236 } |
239 } | 237 } |
240 | 238 |
241 void CaretBase::paintCaret(Node* node, GraphicsContext* context, const LayoutPoi
nt& paintOffset, const LayoutRect& clipRect) const | 239 void CaretBase::paintCaret(const Position& position, GraphicsContext* context, c
onst LayoutPoint& paintOffset, const LayoutRect& clipRect) const |
242 { | 240 { |
243 if (m_caretVisibility == Hidden) | 241 if (m_caretVisibility == Hidden) |
244 return; | 242 return; |
245 | 243 |
246 LayoutRect drawingRect = localCaretRectWithoutUpdate(); | 244 LayoutRect drawingRect = localCaretRectWithoutUpdate(); |
247 RenderObject* renderer = caretRenderer(node); | 245 RenderObject* renderer = caretRenderer(position); |
248 if (renderer && renderer->isBox()) | 246 if (renderer && renderer->isBox()) |
249 toRenderBox(renderer)->flipForWritingMode(drawingRect); | 247 toRenderBox(renderer)->flipForWritingMode(drawingRect); |
250 drawingRect.moveBy(roundedIntPoint(paintOffset)); | 248 drawingRect.moveBy(roundedIntPoint(paintOffset)); |
251 LayoutRect caret = intersection(drawingRect, clipRect); | 249 LayoutRect caret = intersection(drawingRect, clipRect); |
252 if (caret.isEmpty()) | 250 if (caret.isEmpty()) |
253 return; | 251 return; |
254 | 252 |
255 Color caretColor = Color::black; | 253 Color caretColor = Color::black; |
256 | 254 |
257 Element* element; | 255 Element* element = position.element(); |
258 if (node->isElementNode()) | |
259 element = toElement(node); | |
260 else | |
261 element = node->parentElement(); | |
262 | |
263 if (element && element->renderer()) | 256 if (element && element->renderer()) |
264 caretColor = element->renderer()->resolveColor(CSSPropertyColor); | 257 caretColor = element->renderer()->resolveColor(CSSPropertyColor); |
265 | 258 |
266 context->fillRect(caret, caretColor); | 259 context->fillRect(caret, caretColor); |
267 } | 260 } |
268 | 261 |
269 void DragCaretController::paintDragCaret(Frame* frame, GraphicsContext* p, const
LayoutPoint& paintOffset, const LayoutRect& clipRect) const | 262 void DragCaretController::paintDragCaret(Frame* frame, GraphicsContext* p, const
LayoutPoint& paintOffset, const LayoutRect& clipRect) const |
270 { | 263 { |
271 if (m_position.deepEquivalent().deprecatedNode()->document()->frame() == fra
me) | 264 if (m_position.deepEquivalent().deprecatedNode()->document()->frame() == fra
me) |
272 paintCaret(m_position.deepEquivalent().deprecatedNode(), p, paintOffset,
clipRect); | 265 paintCaret(m_position.deepEquivalent(), p, paintOffset, clipRect); |
273 } | 266 } |
274 | 267 |
275 } | 268 } |
OLD | NEW |