OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. | 2 * Copyright (C) 2004, 2005, 2006, 2009 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 11 matching lines...) Expand all Loading... |
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 */ | 24 */ |
25 | 25 |
26 #include "config.h" | 26 #include "config.h" |
27 #include "core/editing/Position.h" | 27 #include "core/editing/Position.h" |
28 | 28 |
29 #include "core/dom/shadow/ElementShadow.h" | 29 #include "core/dom/shadow/ElementShadow.h" |
30 #include "core/editing/EditingUtilities.h" | 30 #include "core/editing/EditingUtilities.h" |
31 #include "core/editing/TextAffinity.h" | 31 #include "core/editing/TextAffinity.h" |
32 #include "core/editing/VisibleUnits.h" | |
33 #include "core/layout/LayoutObject.h" | |
34 #include "wtf/text/CString.h" | 32 #include "wtf/text/CString.h" |
35 #include <stdio.h> | 33 #include <stdio.h> |
36 | 34 |
37 namespace blink { | 35 namespace blink { |
38 | 36 |
39 #if ENABLE(ASSERT) | 37 #if ENABLE(ASSERT) |
40 static bool canBeAnchorNode(Node* node) | 38 static bool canBeAnchorNode(Node* node) |
41 { | 39 { |
42 if (!node || node->isFirstLetterPseudoElement()) | 40 if (!node || node->isFirstLetterPseudoElement()) |
43 return true; | 41 return true; |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 int offsetB = positionB.computeOffsetInContainerNode(); | 290 int offsetB = positionB.computeOffsetInContainerNode(); |
293 return comparePositionsInComposedTree(containerA, offsetA, containerB, offse
tB); | 291 return comparePositionsInComposedTree(containerA, offsetA, containerB, offse
tB); |
294 } | 292 } |
295 | 293 |
296 template <typename Strategy> | 294 template <typename Strategy> |
297 int PositionAlgorithm<Strategy>::compareTo(const PositionAlgorithm<Strategy>& ot
her) const | 295 int PositionAlgorithm<Strategy>::compareTo(const PositionAlgorithm<Strategy>& ot
her) const |
298 { | 296 { |
299 return comparePositions(*this, other); | 297 return comparePositions(*this, other); |
300 } | 298 } |
301 | 299 |
302 // TODO(yosin) We should move |uncheckedPreviousOffsetForBackwardDeletion()| | |
303 // to "EditingUtilities.cpp" with |previousPositionOf()|. | |
304 // TODO(yosin) To avoid forward declaration, we should move implementation of | |
305 // |uncheckedPreviousOffsetForBackwardDeletion()| here. | |
306 static int uncheckedPreviousOffsetForBackwardDeletion(const Node*, int current); | |
307 | |
308 template <typename Strategy> | |
309 PositionAlgorithm<Strategy> previousPositionOfAlgorithm(const PositionAlgorithm<
Strategy>& position, PositionMoveType moveType) | |
310 { | |
311 Node* const node = position.anchorNode(); | |
312 if (!node) | |
313 return position; | |
314 | |
315 const int offset = position.computeEditingOffset(); | |
316 | |
317 if (offset > 0) { | |
318 if (editingIgnoresContent(node)) | |
319 return PositionAlgorithm<Strategy>::beforeNode(node); | |
320 if (Node* child = Strategy::childAt(*node, offset - 1)) | |
321 return PositionAlgorithm<Strategy>::lastPositionInOrAfterNode(child)
; | |
322 | |
323 // There are two reasons child might be 0: | |
324 // 1) The node is node like a text node that is not an element, and | |
325 // therefore has no children. Going backward one character at a | |
326 // time is correct. | |
327 // 2) The old offset was a bogus offset like (<br>, 1), and there is | |
328 // no child. Going from 1 to 0 is correct. | |
329 switch (moveType) { | |
330 case PositionMoveType::CodePoint: | |
331 return PositionAlgorithm<Strategy>(node, offset - 1); | |
332 case PositionMoveType::Character: | |
333 return PositionAlgorithm<Strategy>(node, uncheckedPreviousOffset(nod
e, offset)); | |
334 case PositionMoveType::BackwardDeletion: | |
335 return PositionAlgorithm<Strategy>(node, uncheckedPreviousOffsetForB
ackwardDeletion(node, offset)); | |
336 } | |
337 } | |
338 | |
339 if (ContainerNode* parent = Strategy::parent(*node)) { | |
340 if (editingIgnoresContent(parent)) | |
341 return PositionAlgorithm<Strategy>::beforeNode(parent); | |
342 // TODO(yosin) We should use |Strategy::index(Node&)| instead of | |
343 // |Node::nodeIndex()|. | |
344 return PositionAlgorithm<Strategy>(parent, node->nodeIndex()); | |
345 } | |
346 return position; | |
347 } | |
348 | |
349 Position previousPositionOf(const Position& position, PositionMoveType moveType) | |
350 { | |
351 return previousPositionOfAlgorithm<EditingStrategy>(position, moveType); | |
352 } | |
353 | |
354 PositionInComposedTree previousPositionOf(const PositionInComposedTree& position
, PositionMoveType moveType) | |
355 { | |
356 return previousPositionOfAlgorithm<EditingInComposedTreeStrategy>(position,
moveType); | |
357 } | |
358 | |
359 template <typename Strategy> | |
360 PositionAlgorithm<Strategy> nextPositionOfAlgorithm(const PositionAlgorithm<Stra
tegy>& position, PositionMoveType moveType) | |
361 { | |
362 ASSERT(moveType != PositionMoveType::BackwardDeletion); | |
363 | |
364 Node* node = position.anchorNode(); | |
365 if (!node) | |
366 return position; | |
367 | |
368 const int offset = position.computeEditingOffset(); | |
369 | |
370 if (Node* child = Strategy::childAt(*node, offset)) | |
371 return PositionAlgorithm<Strategy>::firstPositionInOrBeforeNode(child); | |
372 | |
373 // TODO(yosin) We should use |Strategy::lastOffsetForEditing()| instead of | |
374 // DOM tree version. | |
375 if (!Strategy::hasChildren(*node) && offset < EditingStrategy::lastOffsetFor
Editing(node)) { | |
376 // There are two reasons child might be 0: | |
377 // 1) The node is node like a text node that is not an element, and | |
378 // therefore has no children. Going forward one character at a time | |
379 // is correct. | |
380 // 2) The new offset is a bogus offset like (<br>, 1), and there is no | |
381 // child. Going from 0 to 1 is correct. | |
382 return PositionAlgorithm<Strategy>::editingPositionOf(node, (moveType ==
PositionMoveType::Character) ? uncheckedNextOffset(node, offset) : offset + 1); | |
383 } | |
384 | |
385 if (ContainerNode* parent = Strategy::parent(*node)) | |
386 return PositionAlgorithm<Strategy>::editingPositionOf(parent, Strategy::
index(*node) + 1); | |
387 return position; | |
388 } | |
389 | |
390 Position nextPositionOf(const Position& position, PositionMoveType moveType) | |
391 { | |
392 return nextPositionOfAlgorithm<EditingStrategy>(position, moveType); | |
393 } | |
394 | |
395 PositionInComposedTree nextPositionOf(const PositionInComposedTree& position, Po
sitionMoveType moveType) | |
396 { | |
397 return nextPositionOfAlgorithm<EditingInComposedTreeStrategy>(position, move
Type); | |
398 } | |
399 | |
400 int uncheckedPreviousOffset(const Node* n, int current) | |
401 { | |
402 return n->layoutObject() ? n->layoutObject()->previousOffset(current) : curr
ent - 1; | |
403 } | |
404 | |
405 static int uncheckedPreviousOffsetForBackwardDeletion(const Node* n, int current
) | |
406 { | |
407 return n->layoutObject() ? n->layoutObject()->previousOffsetForBackwardDelet
ion(current) : current - 1; | |
408 } | |
409 | |
410 int uncheckedNextOffset(const Node* n, int current) | |
411 { | |
412 return n->layoutObject() ? n->layoutObject()->nextOffset(current) : current
+ 1; | |
413 } | |
414 | |
415 template <typename Strategy> | 300 template <typename Strategy> |
416 bool PositionAlgorithm<Strategy>::atFirstEditingPositionForNode() const | 301 bool PositionAlgorithm<Strategy>::atFirstEditingPositionForNode() const |
417 { | 302 { |
418 if (isNull()) | 303 if (isNull()) |
419 return true; | 304 return true; |
420 // FIXME: Position before anchor shouldn't be considered as at the first edi
ting position for node | 305 // FIXME: Position before anchor shouldn't be considered as at the first edi
ting position for node |
421 // since that position resides outside of the node. | 306 // since that position resides outside of the node. |
422 switch (m_anchorType) { | 307 switch (m_anchorType) { |
423 case PositionAnchorType::OffsetInAnchor: | 308 case PositionAnchorType::OffsetInAnchor: |
424 return m_offset == 0; | 309 return m_offset == 0; |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
642 | 527 |
643 void showTree(const blink::Position* pos) | 528 void showTree(const blink::Position* pos) |
644 { | 529 { |
645 if (pos) | 530 if (pos) |
646 pos->showTreeForThis(); | 531 pos->showTreeForThis(); |
647 else | 532 else |
648 fprintf(stderr, "Cannot showTree for (nil)\n"); | 533 fprintf(stderr, "Cannot showTree for (nil)\n"); |
649 } | 534 } |
650 | 535 |
651 #endif | 536 #endif |
OLD | NEW |