OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserv
ed. | 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserv
ed. |
3 * Portions Copyright (c) 2011 Motorola Mobility, Inc. All rights reserved. | 3 * Portions Copyright (c) 2011 Motorola Mobility, Inc. All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
7 * are met: | 7 * are met: |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
456 | 456 |
457 // Return empty position if this position is non-editable, but pos is editab
le | 457 // Return empty position if this position is non-editable, but pos is editab
le |
458 // FIXME: Move to the next non-editable region. | 458 // FIXME: Move to the next non-editable region. |
459 if (!highestRoot) | 459 if (!highestRoot) |
460 return VisiblePosition(); | 460 return VisiblePosition(); |
461 | 461 |
462 // Return the next position after pos that is in the same editable region as
this position | 462 // Return the next position after pos that is in the same editable region as
this position |
463 return firstEditableVisiblePositionAfterPositionInRoot(pos.deepEquivalent(),
highestRoot); | 463 return firstEditableVisiblePositionAfterPositionInRoot(pos.deepEquivalent(),
highestRoot); |
464 } | 464 } |
465 | 465 |
466 template <typename PositionType> | |
467 static PositionType canonicalizeCandidate(const PositionType& candidate) | |
468 { | |
469 if (candidate.isNull()) | |
470 return PositionType(); | |
471 ASSERT(isVisuallyEquivalentCandidate(candidate)); | |
472 PositionType upstream = mostBackwardCaretPosition(candidate); | |
473 if (isVisuallyEquivalentCandidate(upstream)) | |
474 return upstream; | |
475 return candidate; | |
476 } | |
477 | |
478 template <typename PositionType> | |
479 static PositionType canonicalPosition(const PositionType& passedPosition) | |
480 { | |
481 // Sometimes updating selection positions can be extremely expensive and occ
ur | |
482 // frequently. Often calling preventDefault on mousedown events can avoid | |
483 // doing unnecessary text selection work. http://crbug.com/472258. | |
484 TRACE_EVENT0("blink", "VisiblePosition::canonicalPosition"); | |
485 | |
486 // The updateLayout call below can do so much that even the position passed | |
487 // in to us might get changed as a side effect. Specifically, there are code | |
488 // paths that pass selection endpoints, and updateLayout can change the sele
ction. | |
489 PositionType position = passedPosition; | |
490 | |
491 // FIXME (9535): Canonicalizing to the leftmost candidate means that if we'
re at a line wrap, we will | |
492 // ask layoutObjects to paint downstream carets for other layoutObjects. | |
493 // To fix this, we need to either a) add code to all paintCarets to pass the
responsibility off to | |
494 // the appropriate layoutObject for VisiblePosition's like these, or b) cano
nicalize to the rightmost candidate | |
495 // unless the affinity is upstream. | |
496 if (position.isNull()) | |
497 return PositionType(); | |
498 | |
499 ASSERT(position.document()); | |
500 position.document()->updateLayoutIgnorePendingStylesheets(); | |
501 | |
502 Node* node = position.computeContainerNode(); | |
503 | |
504 PositionType candidate = mostBackwardCaretPosition(position); | |
505 if (isVisuallyEquivalentCandidate(candidate)) | |
506 return candidate; | |
507 candidate = mostForwardCaretPosition(position); | |
508 if (isVisuallyEquivalentCandidate(candidate)) | |
509 return candidate; | |
510 | |
511 // When neither upstream or downstream gets us to a candidate (upstream/down
stream won't leave | |
512 // blocks or enter new ones), we search forward and backward until we find o
ne. | |
513 PositionType next = canonicalizeCandidate(nextCandidate(position)); | |
514 PositionType prev = canonicalizeCandidate(previousCandidate(position)); | |
515 Node* nextNode = next.anchorNode(); | |
516 Node* prevNode = prev.anchorNode(); | |
517 | |
518 // The new position must be in the same editable element. Enforce that first
. | |
519 // Unless the descent is from a non-editable html element to an editable bod
y. | |
520 if (isHTMLHtmlElement(node) && !node->hasEditableStyle() && node->document()
.body() && node->document().body()->hasEditableStyle()) | |
521 return next.isNotNull() ? next : prev; | |
522 | |
523 Element* editingRoot = editableRootForPosition(position); | |
524 | |
525 // If the html element is editable, descending into its body will look like
a descent | |
526 // from non-editable to editable content since rootEditableElement() always
stops at the body. | |
527 if (isHTMLHtmlElement(editingRoot) || position.anchorNode()->isDocumentNode(
)) | |
528 return next.isNotNull() ? next : prev; | |
529 | |
530 bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev)
== editingRoot; | |
531 bool nextIsInSameEditableElement = nextNode && editableRootForPosition(next)
== editingRoot; | |
532 if (prevIsInSameEditableElement && !nextIsInSameEditableElement) | |
533 return prev; | |
534 | |
535 if (nextIsInSameEditableElement && !prevIsInSameEditableElement) | |
536 return next; | |
537 | |
538 if (!nextIsInSameEditableElement && !prevIsInSameEditableElement) | |
539 return PositionType(); | |
540 | |
541 // The new position should be in the same block flow element. Favor that. | |
542 Element* originalBlock = node ? enclosingBlockFlowElement(*node) : 0; | |
543 bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) &
& nextNode != originalBlock; | |
544 bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) &
& prevNode != originalBlock; | |
545 if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock) | |
546 return prev; | |
547 | |
548 return next; | |
549 } | |
550 | |
551 Position canonicalPositionOf(const Position& position) | |
552 { | |
553 return canonicalPosition(position); | |
554 } | |
555 | |
556 PositionInComposedTree canonicalPositionOf(const PositionInComposedTree& positio
n) | |
557 { | |
558 return canonicalPosition(position); | |
559 } | |
560 | |
561 template<typename Strategy> | 466 template<typename Strategy> |
562 static PositionWithAffinityTemplate<Strategy> visiblePositionOfAlgorithm(const P
ositionAlgorithm<Strategy>& position, TextAffinity affinity) | 467 static PositionWithAffinityTemplate<Strategy> visiblePositionOfAlgorithm(const P
ositionAlgorithm<Strategy>& position, TextAffinity affinity) |
563 { | 468 { |
564 const PositionAlgorithm<Strategy> deepPosition = canonicalPosition(position)
; | 469 const PositionAlgorithm<Strategy> deepPosition = canonicalPositionOf(positio
n); |
565 if (deepPosition.isNull()) | 470 if (deepPosition.isNull()) |
566 return PositionWithAffinityTemplate<Strategy>(); | 471 return PositionWithAffinityTemplate<Strategy>(); |
567 if (affinity == TextAffinity::Downstream) | 472 if (affinity == TextAffinity::Downstream) |
568 return PositionWithAffinityTemplate<Strategy>(deepPosition); | 473 return PositionWithAffinityTemplate<Strategy>(deepPosition); |
569 | 474 |
570 // When not at a line wrap, make sure to end up with | 475 // When not at a line wrap, make sure to end up with |
571 // |TextAffinity::Downstream| affinity. | 476 // |TextAffinity::Downstream| affinity. |
572 if (inSameLine(PositionWithAffinityTemplate<Strategy>(deepPosition), Positio
nWithAffinityTemplate<Strategy>(deepPosition, TextAffinity::Upstream))) | 477 if (inSameLine(PositionWithAffinityTemplate<Strategy>(deepPosition), Positio
nWithAffinityTemplate<Strategy>(deepPosition, TextAffinity::Upstream))) |
573 return PositionWithAffinityTemplate<Strategy>(deepPosition); | 478 return PositionWithAffinityTemplate<Strategy>(deepPosition); |
574 return PositionWithAffinityTemplate<Strategy>(deepPosition, TextAffinity::Up
stream); | 479 return PositionWithAffinityTemplate<Strategy>(deepPosition, TextAffinity::Up
stream); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
662 else | 567 else |
663 fprintf(stderr, "Cannot showTree for (nil) VisiblePosition.\n"); | 568 fprintf(stderr, "Cannot showTree for (nil) VisiblePosition.\n"); |
664 } | 569 } |
665 | 570 |
666 void showTree(const blink::VisiblePosition& vpos) | 571 void showTree(const blink::VisiblePosition& vpos) |
667 { | 572 { |
668 vpos.showTreeForThis(); | 573 vpos.showTreeForThis(); |
669 } | 574 } |
670 | 575 |
671 #endif | 576 #endif |
OLD | NEW |