Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: Source/core/editing/Position.cpp

Issue 1299323006: [Editing][CodeHealth] Move Position::up/downstream implementation to VisibleUnit.cpp (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/core/editing/Position.h ('k') | Source/core/editing/VisibleUnits.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 497 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 template <typename Strategy> 508 template <typename Strategy>
509 bool PositionAlgorithm<Strategy>::atEndOfTree() const 509 bool PositionAlgorithm<Strategy>::atEndOfTree() const
510 { 510 {
511 if (isNull()) 511 if (isNull())
512 return true; 512 return true;
513 // TODO(yosin) We should use |Strategy::lastOffsetForEditing()| instead of 513 // TODO(yosin) We should use |Strategy::lastOffsetForEditing()| instead of
514 // DOM tree version. 514 // DOM tree version.
515 return !Strategy::parent(*anchorNode()) && m_offset >= EditingStrategy::last OffsetForEditing(anchorNode()); 515 return !Strategy::parent(*anchorNode()) && m_offset >= EditingStrategy::last OffsetForEditing(anchorNode());
516 } 516 }
517 517
518 // Whether or not [node, 0] and [node, lastOffsetForEditing(node)] are their own VisiblePositions. 518 template <typename Strategy>
519 // If true, adjacent candidates are visually distinct. 519 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::upstream(EditingBoundar yCrossingRule rule) const
520 // FIXME: Disregard nodes with layoutObjects that have no height, as we do in is Candidate.
521 // FIXME: Share code with isCandidate, if possible.
522 static bool endsOfNodeAreVisuallyDistinctPositions(Node* node)
523 { 520 {
524 if (!node || !node->layoutObject()) 521 return mostForwardCaretPosition(*this, rule);
525 return false;
526
527 if (!node->layoutObject()->isInline())
528 return true;
529
530 // Don't include inline tables.
531 if (isHTMLTableElement(*node))
532 return false;
533
534 // A Marquee elements are moving so we should assume their ends are always
535 // visibily distinct.
536 if (isHTMLMarqueeElement(*node))
537 return true;
538
539 // There is a VisiblePosition inside an empty inline-block container.
540 return node->layoutObject()->isReplaced() && canHaveChildrenForEditing(node) && toLayoutBox(node->layoutObject())->size().height() != 0 && !node->hasChildre n();
541 } 522 }
542 523
543 template <typename Strategy> 524 template <typename Strategy>
544 static Node* enclosingVisualBoundary(Node* node)
545 {
546 while (node && !endsOfNodeAreVisuallyDistinctPositions(node))
547 node = Strategy::parent(*node);
548
549 return node;
550 }
551
552 // upstream() and downstream() want to return positions that are either in a
553 // text node or at just before a non-text node. This method checks for that.
554 template <typename Strategy>
555 static bool isStreamer(const PositionIteratorAlgorithm<Strategy>& pos)
556 {
557 if (!pos.node())
558 return true;
559
560 if (isAtomicNode(pos.node()))
561 return true;
562
563 return pos.atStartOfNode();
564 }
565
566 // This function and downstream() are used for moving back and forth between vis ually equivalent candidates.
567 // For example, for the text node "foo bar" where whitespace is collapsible, there are two candidates
568 // that map to the VisiblePosition between 'b' and the space. This function wil l return the left candidate
569 // and downstream() will return the right one.
570 // Also, upstream() will return [boundary, 0] for any of the positions from [bou ndary, 0] to the first candidate
571 // in boundary, where endsOfNodeAreVisuallyDistinctPositions(boundary) is true.
572 template <typename Strategy>
573 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::upstream(EditingBoundar yCrossingRule rule) const
574 {
575 TRACE_EVENT0("blink", "Position::upstream");
576
577 Node* startNode = anchorNode();
578 if (!startNode)
579 return PositionAlgorithm<Strategy>();
580
581 // iterate backward from there, looking for a qualified position
582 Node* boundary = enclosingVisualBoundary<Strategy>(startNode);
583 // FIXME: PositionIterator should respect Before and After positions.
584 PositionIteratorAlgorithm<Strategy> lastVisible(isAfterAnchor() ? editingPos itionOf(m_anchorNode.get(), Strategy::caretMaxOffset(*m_anchorNode)) : PositionA lgorithm<Strategy>(*this));
585 PositionIteratorAlgorithm<Strategy> currentPos = lastVisible;
586 bool startEditable = startNode->hasEditableStyle();
587 Node* lastNode = startNode;
588 bool boundaryCrossed = false;
589 for (; !currentPos.atStart(); currentPos.decrement()) {
590 Node* currentNode = currentPos.node();
591 // Don't check for an editability change if we haven't moved to a differ ent node,
592 // to avoid the expense of computing hasEditableStyle().
593 if (currentNode != lastNode) {
594 // Don't change editability.
595 bool currentEditable = currentNode->hasEditableStyle();
596 if (startEditable != currentEditable) {
597 if (rule == CannotCrossEditingBoundary)
598 break;
599 boundaryCrossed = true;
600 }
601 lastNode = currentNode;
602 }
603
604 // If we've moved to a position that is visually distinct, return the la st saved position. There
605 // is code below that terminates early if we're *about* to move to a vis ually distinct position.
606 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode ! = boundary)
607 return lastVisible.deprecatedComputePosition();
608
609 // skip position in non-laid out or invisible node
610 LayoutObject* layoutObject = currentNode->layoutObject();
611 if (!layoutObject || layoutObject->style()->visibility() != VISIBLE)
612 continue;
613
614 if (rule == CanCrossEditingBoundary && boundaryCrossed) {
615 lastVisible = currentPos;
616 break;
617 }
618
619 // track last visible streamer position
620 if (isStreamer<Strategy>(currentPos))
621 lastVisible = currentPos;
622
623 // Don't move past a position that is visually distinct. We could rely on code above to terminate and
624 // return lastVisible on the next iteration, but we terminate early to a void doing a nodeIndex() call.
625 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentPos.at StartOfNode())
626 return lastVisible.deprecatedComputePosition();
627
628 // Return position after tables and nodes which have content that can be ignored.
629 if (Strategy::editingIgnoresContent(currentNode) || isRenderedHTMLTableE lement(currentNode)) {
630 if (currentPos.atEndOfNode())
631 return afterNode(currentNode);
632 continue;
633 }
634
635 // return current position if it is in laid out text
636 if (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox() ) {
637 if (currentNode != startNode) {
638 // This assertion fires in layout tests in the case-transform.ht ml test because
639 // of a mix-up between offsets in the text in the DOM tree with text in the
640 // layout tree which can have a different length due to case tra nsformation.
641 // Until we resolve that, disable this so we can run the layout tests!
642 // ASSERT(currentOffset >= layoutObject->caretMaxOffset());
643 return PositionAlgorithm<Strategy>(currentNode, layoutObject->ca retMaxOffset());
644 }
645
646 unsigned textOffset = currentPos.offsetInLeafNode();
647 LayoutText* textLayoutObject = toLayoutText(layoutObject);
648 InlineTextBox* lastTextBox = textLayoutObject->lastTextBox();
649 for (InlineTextBox* box = textLayoutObject->firstTextBox(); box; box = box->nextTextBox()) {
650 if (textOffset <= box->start() + box->len()) {
651 if (textOffset > box->start())
652 return currentPos.computePosition();
653 continue;
654 }
655
656 if (box == lastTextBox || textOffset != box->start() + box->len( ) + 1)
657 continue;
658
659 // The text continues on the next line only if the last text box is not on this line and
660 // none of the boxes on this line have a larger start offset.
661
662 bool continuesOnNextLine = true;
663 InlineBox* otherBox = box;
664 while (continuesOnNextLine) {
665 otherBox = otherBox->nextLeafChild();
666 if (!otherBox)
667 break;
668 if (otherBox == lastTextBox || (otherBox->layoutObject() == textLayoutObject && toInlineTextBox(otherBox)->start() > textOffset))
669 continuesOnNextLine = false;
670 }
671
672 otherBox = box;
673 while (continuesOnNextLine) {
674 otherBox = otherBox->prevLeafChild();
675 if (!otherBox)
676 break;
677 if (otherBox == lastTextBox || (otherBox->layoutObject() == textLayoutObject && toInlineTextBox(otherBox)->start() > textOffset))
678 continuesOnNextLine = false;
679 }
680
681 if (continuesOnNextLine)
682 return currentPos.computePosition();
683 }
684 }
685 }
686 return lastVisible.deprecatedComputePosition();
687 }
688
689 // This function and upstream() are used for moving back and forth between visua lly equivalent candidates.
690 // For example, for the text node "foo bar" where whitespace is collapsible, there are two candidates
691 // that map to the VisiblePosition between 'b' and the space. This function wil l return the right candidate
692 // and upstream() will return the left one.
693 // Also, downstream() will return the last position in the last atomic node in b oundary for all of the positions
694 // in boundary after the last candidate, where endsOfNodeAreVisuallyDistinctPosi tions(boundary).
695 // FIXME: This function should never be called when the line box tree is dirty. See https://bugs.webkit.org/show_bug.cgi?id=97264
696 template <typename Strategy>
697 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::downstream(EditingBound aryCrossingRule rule) const 525 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::downstream(EditingBound aryCrossingRule rule) const
698 { 526 {
699 TRACE_EVENT0("blink", "Position::downstream"); 527 return mostBackwardCaretPosition(*this, rule);
700
701 Node* startNode = anchorNode();
702 if (!startNode)
703 return PositionAlgorithm<Strategy>();
704
705 // iterate forward from there, looking for a qualified position
706 Node* boundary = enclosingVisualBoundary<Strategy>(startNode);
707 // FIXME: PositionIterator should respect Before and After positions.
708 PositionIteratorAlgorithm<Strategy> lastVisible(isAfterAnchor() ? editingPos itionOf(m_anchorNode.get(), Strategy::caretMaxOffset(*m_anchorNode)) : PositionA lgorithm<Strategy>(*this));
709 PositionIteratorAlgorithm<Strategy> currentPos = lastVisible;
710 bool startEditable = startNode->hasEditableStyle();
711 Node* lastNode = startNode;
712 bool boundaryCrossed = false;
713 for (; !currentPos.atEnd(); currentPos.increment()) {
714 Node* currentNode = currentPos.node();
715 // Don't check for an editability change if we haven't moved to a differ ent node,
716 // to avoid the expense of computing hasEditableStyle().
717 if (currentNode != lastNode) {
718 // Don't change editability.
719 bool currentEditable = currentNode->hasEditableStyle();
720 if (startEditable != currentEditable) {
721 if (rule == CannotCrossEditingBoundary)
722 break;
723 boundaryCrossed = true;
724 }
725
726 lastNode = currentNode;
727 }
728
729 // stop before going above the body, up into the head
730 // return the last visible streamer position
731 if (isHTMLBodyElement(*currentNode) && currentPos.atEndOfNode())
732 break;
733
734 // Do not move to a visually distinct position.
735 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode ! = boundary)
736 return lastVisible.deprecatedComputePosition();
737 // Do not move past a visually disinct position.
738 // Note: The first position after the last in a node whose ends are visu ally distinct
739 // positions will be [boundary->parentNode(), originalBlock->nodeIndex() + 1].
740 if (boundary && Strategy::parent(*boundary) == currentNode)
741 return lastVisible.deprecatedComputePosition();
742
743 // skip position in non-laid out or invisible node
744 LayoutObject* layoutObject = currentNode->layoutObject();
745 if (!layoutObject || layoutObject->style()->visibility() != VISIBLE)
746 continue;
747
748 if (rule == CanCrossEditingBoundary && boundaryCrossed) {
749 lastVisible = currentPos;
750 break;
751 }
752
753 // track last visible streamer position
754 if (isStreamer<Strategy>(currentPos))
755 lastVisible = currentPos;
756
757 // Return position before tables and nodes which have content that can b e ignored.
758 if (Strategy::editingIgnoresContent(currentNode) || isRenderedHTMLTableE lement(currentNode)) {
759 if (currentPos.offsetInLeafNode() <= layoutObject->caretMinOffset())
760 return editingPositionOf(currentNode, layoutObject->caretMinOffs et());
761 continue;
762 }
763
764 // return current position if it is in laid out text
765 if (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox() ) {
766 if (currentNode != startNode) {
767 ASSERT(currentPos.atStartOfNode());
768 return PositionAlgorithm<Strategy>(currentNode, layoutObject->ca retMinOffset());
769 }
770
771 unsigned textOffset = currentPos.offsetInLeafNode();
772 LayoutText* textLayoutObject = toLayoutText(layoutObject);
773 InlineTextBox* lastTextBox = textLayoutObject->lastTextBox();
774 for (InlineTextBox* box = textLayoutObject->firstTextBox(); box; box = box->nextTextBox()) {
775 if (textOffset <= box->end()) {
776 if (textOffset >= box->start())
777 return currentPos.computePosition();
778 continue;
779 }
780
781 if (box == lastTextBox || textOffset != box->start() + box->len( ))
782 continue;
783
784 // The text continues on the next line only if the last text box is not on this line and
785 // none of the boxes on this line have a larger start offset.
786
787 bool continuesOnNextLine = true;
788 InlineBox* otherBox = box;
789 while (continuesOnNextLine) {
790 otherBox = otherBox->nextLeafChild();
791 if (!otherBox)
792 break;
793 if (otherBox == lastTextBox || (otherBox->layoutObject() == textLayoutObject && toInlineTextBox(otherBox)->start() >= textOffset))
794 continuesOnNextLine = false;
795 }
796
797 otherBox = box;
798 while (continuesOnNextLine) {
799 otherBox = otherBox->prevLeafChild();
800 if (!otherBox)
801 break;
802 if (otherBox == lastTextBox || (otherBox->layoutObject() == textLayoutObject && toInlineTextBox(otherBox)->start() >= textOffset))
803 continuesOnNextLine = false;
804 }
805
806 if (continuesOnNextLine)
807 return currentPos.computePosition();
808 }
809 }
810 }
811
812 return lastVisible.deprecatedComputePosition();
813 } 528 }
814 529
815 static int boundingBoxLogicalHeight(LayoutObject *o, const IntRect &rect) 530 static int boundingBoxLogicalHeight(LayoutObject *o, const IntRect &rect)
816 { 531 {
817 return o->style()->isHorizontalWritingMode() ? rect.height() : rect.width(); 532 return o->style()->isHorizontalWritingMode() ? rect.height() : rect.width();
818 } 533 }
819 534
820 // TODO(yosin) We should move |hasRenderedNonAnonymousDescendantsWithHeight| 535 // TODO(yosin) We should move |hasRenderedNonAnonymousDescendantsWithHeight|
821 // to "VisibleUnits.cpp" to reduce |LayoutObject| dependency in "Position.cpp" 536 // to "VisibleUnits.cpp" to reduce |LayoutObject| dependency in "Position.cpp"
822 bool hasRenderedNonAnonymousDescendantsWithHeight(LayoutObject* layoutObject) 537 bool hasRenderedNonAnonymousDescendantsWithHeight(LayoutObject* layoutObject)
(...skipping 537 matching lines...) Expand 10 before | Expand all | Expand 10 after
1360 1075
1361 void showTree(const blink::Position* pos) 1076 void showTree(const blink::Position* pos)
1362 { 1077 {
1363 if (pos) 1078 if (pos)
1364 pos->showTreeForThis(); 1079 pos->showTreeForThis();
1365 else 1080 else
1366 fprintf(stderr, "Cannot showTree for (nil)\n"); 1081 fprintf(stderr, "Cannot showTree for (nil)\n");
1367 } 1082 }
1368 1083
1369 #endif 1084 #endif
OLDNEW
« no previous file with comments | « Source/core/editing/Position.h ('k') | Source/core/editing/VisibleUnits.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698