| 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 374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 385 | 385 |
| 386 template <typename Strategy> | 386 template <typename Strategy> |
| 387 int PositionAlgorithm<Strategy>::compareTo(const PositionAlgorithm<Strategy>& ot
her) const | 387 int PositionAlgorithm<Strategy>::compareTo(const PositionAlgorithm<Strategy>& ot
her) const |
| 388 { | 388 { |
| 389 return comparePositions(*this, other); | 389 return comparePositions(*this, other); |
| 390 } | 390 } |
| 391 | 391 |
| 392 template <typename Strategy> | 392 template <typename Strategy> |
| 393 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::previous(PositionMoveTy
pe moveType) const | 393 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::previous(PositionMoveTy
pe moveType) const |
| 394 { | 394 { |
| 395 Node* node = deprecatedNode(); | 395 Node* node = anchorNode(); |
| 396 if (!node) | 396 if (!node) |
| 397 return PositionAlgorithm<Strategy>(*this); | 397 return PositionAlgorithm<Strategy>(*this); |
| 398 | 398 |
| 399 int offset = deprecatedEditingOffset(); | 399 int offset = deprecatedEditingOffset(); |
| 400 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlie
r. | 400 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlie
r. |
| 401 ASSERT(offset >= 0); | 401 ASSERT(offset >= 0); |
| 402 | 402 |
| 403 if (offset > 0) { | 403 if (offset > 0) { |
| 404 if (Node* child = Strategy::childAt(*node, offset - 1)) | 404 if (Node* child = Strategy::childAt(*node, offset - 1)) |
| 405 return lastPositionInOrAfterNode(child); | 405 return lastPositionInOrAfterNode(child); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 422 if (ContainerNode* parent = Strategy::parent(*node)) | 422 if (ContainerNode* parent = Strategy::parent(*node)) |
| 423 return createLegacyEditingPosition(parent, node->nodeIndex()); | 423 return createLegacyEditingPosition(parent, node->nodeIndex()); |
| 424 return PositionAlgorithm<Strategy>(*this); | 424 return PositionAlgorithm<Strategy>(*this); |
| 425 } | 425 } |
| 426 | 426 |
| 427 template <typename Strategy> | 427 template <typename Strategy> |
| 428 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::next(PositionMoveType m
oveType) const | 428 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::next(PositionMoveType m
oveType) const |
| 429 { | 429 { |
| 430 ASSERT(moveType != BackwardDeletion); | 430 ASSERT(moveType != BackwardDeletion); |
| 431 | 431 |
| 432 Node* node = deprecatedNode(); | 432 Node* node = anchorNode(); |
| 433 if (!node) | 433 if (!node) |
| 434 return PositionAlgorithm<Strategy>(*this); | 434 return PositionAlgorithm<Strategy>(*this); |
| 435 | 435 |
| 436 int offset = deprecatedEditingOffset(); | 436 int offset = deprecatedEditingOffset(); |
| 437 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlie
r. | 437 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlie
r. |
| 438 ASSERT(offset >= 0); | 438 ASSERT(offset >= 0); |
| 439 | 439 |
| 440 if (Node* child = Strategy::childAt(*node, offset)) | 440 if (Node* child = Strategy::childAt(*node, offset)) |
| 441 return firstPositionInOrBeforeNode(child); | 441 return firstPositionInOrBeforeNode(child); |
| 442 | 442 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 480 // FIXME: Position before anchor shouldn't be considered as at the first edi
ting position for node | 480 // FIXME: Position before anchor shouldn't be considered as at the first edi
ting position for node |
| 481 // since that position resides outside of the node. | 481 // since that position resides outside of the node. |
| 482 switch (m_anchorType) { | 482 switch (m_anchorType) { |
| 483 case PositionAnchorType::OffsetInAnchor: | 483 case PositionAnchorType::OffsetInAnchor: |
| 484 return m_offset <= 0; | 484 return m_offset <= 0; |
| 485 case PositionAnchorType::BeforeChildren: | 485 case PositionAnchorType::BeforeChildren: |
| 486 case PositionAnchorType::BeforeAnchor: | 486 case PositionAnchorType::BeforeAnchor: |
| 487 return true; | 487 return true; |
| 488 case PositionAnchorType::AfterChildren: | 488 case PositionAnchorType::AfterChildren: |
| 489 case PositionAnchorType::AfterAnchor: | 489 case PositionAnchorType::AfterAnchor: |
| 490 return !lastOffsetForEditing(deprecatedNode()); | 490 return !lastOffsetForEditing(anchorNode()); |
| 491 } | 491 } |
| 492 ASSERT_NOT_REACHED(); | 492 ASSERT_NOT_REACHED(); |
| 493 return false; | 493 return false; |
| 494 } | 494 } |
| 495 | 495 |
| 496 template <typename Strategy> | 496 template <typename Strategy> |
| 497 bool PositionAlgorithm<Strategy>::atLastEditingPositionForNode() const | 497 bool PositionAlgorithm<Strategy>::atLastEditingPositionForNode() const |
| 498 { | 498 { |
| 499 if (isNull()) | 499 if (isNull()) |
| 500 return true; | 500 return true; |
| 501 // FIXME: Position after anchor shouldn't be considered as at the first edit
ing position for node | 501 // FIXME: Position after anchor shouldn't be considered as at the first edit
ing position for node |
| 502 // since that position resides outside of the node. | 502 // since that position resides outside of the node. |
| 503 return m_anchorType == PositionAnchorType::AfterAnchor || m_anchorType == Po
sitionAnchorType::AfterChildren || m_offset >= lastOffsetForEditing(deprecatedNo
de()); | 503 return m_anchorType == PositionAnchorType::AfterAnchor || m_anchorType == Po
sitionAnchorType::AfterChildren || m_offset >= lastOffsetForEditing(anchorNode()
); |
| 504 } | 504 } |
| 505 | 505 |
| 506 // A position is considered at editing boundary if one of the following is true: | 506 // A position is considered at editing boundary if one of the following is true: |
| 507 // 1. It is the first position in the node and the next visually equivalent posi
tion | 507 // 1. It is the first position in the node and the next visually equivalent posi
tion |
| 508 // is non editable. | 508 // is non editable. |
| 509 // 2. It is the last position in the node and the previous visually equivalent p
osition | 509 // 2. It is the last position in the node and the previous visually equivalent p
osition |
| 510 // is non editable. | 510 // is non editable. |
| 511 // 3. It is an editable position and both the next and previous visually equival
ent | 511 // 3. It is an editable position and both the next and previous visually equival
ent |
| 512 // positions are both non editable. | 512 // positions are both non editable. |
| 513 template <typename Strategy> | 513 template <typename Strategy> |
| 514 bool PositionAlgorithm<Strategy>::atEditingBoundary() const | 514 bool PositionAlgorithm<Strategy>::atEditingBoundary() const |
| 515 { | 515 { |
| 516 PositionAlgorithm<Strategy> nextPosition = downstream(CanCrossEditingBoundar
y); | 516 PositionAlgorithm<Strategy> nextPosition = downstream(CanCrossEditingBoundar
y); |
| 517 if (atFirstEditingPositionForNode() && nextPosition.isNotNull() && !nextPosi
tion.deprecatedNode()->hasEditableStyle()) | 517 if (atFirstEditingPositionForNode() && nextPosition.isNotNull() && !nextPosi
tion.anchorNode()->hasEditableStyle()) |
| 518 return true; | 518 return true; |
| 519 | 519 |
| 520 PositionAlgorithm<Strategy> prevPosition = upstream(CanCrossEditingBoundary)
; | 520 PositionAlgorithm<Strategy> prevPosition = upstream(CanCrossEditingBoundary)
; |
| 521 if (atLastEditingPositionForNode() && prevPosition.isNotNull() && !prevPosit
ion.deprecatedNode()->hasEditableStyle()) | 521 if (atLastEditingPositionForNode() && prevPosition.isNotNull() && !prevPosit
ion.anchorNode()->hasEditableStyle()) |
| 522 return true; | 522 return true; |
| 523 | 523 |
| 524 return nextPosition.isNotNull() && !nextPosition.deprecatedNode()->hasEditab
leStyle() | 524 return nextPosition.isNotNull() && !nextPosition.anchorNode()->hasEditableSt
yle() |
| 525 && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->hasEditab
leStyle(); | 525 && prevPosition.isNotNull() && !prevPosition.anchorNode()->hasEditableSt
yle(); |
| 526 } | 526 } |
| 527 | 527 |
| 528 template <typename Strategy> | 528 template <typename Strategy> |
| 529 static ContainerNode* nonShadowBoundaryParentNode(Node* node) | 529 static ContainerNode* nonShadowBoundaryParentNode(Node* node) |
| 530 { | 530 { |
| 531 ContainerNode* parent = Strategy::parent(*node); | 531 ContainerNode* parent = Strategy::parent(*node); |
| 532 return parent && !parent->isShadowRoot() ? parent : nullptr; | 532 return parent && !parent->isShadowRoot() ? parent : nullptr; |
| 533 } | 533 } |
| 534 | 534 |
| 535 template <typename Strategy> | 535 template <typename Strategy> |
| (...skipping 12 matching lines...) Expand all Loading... |
| 548 | 548 |
| 549 return boundary; | 549 return boundary; |
| 550 } | 550 } |
| 551 | 551 |
| 552 | 552 |
| 553 template <typename Strategy> | 553 template <typename Strategy> |
| 554 bool PositionAlgorithm<Strategy>::atStartOfTree() const | 554 bool PositionAlgorithm<Strategy>::atStartOfTree() const |
| 555 { | 555 { |
| 556 if (isNull()) | 556 if (isNull()) |
| 557 return true; | 557 return true; |
| 558 return !Strategy::parent(*deprecatedNode()) && m_offset <= 0; | 558 return !Strategy::parent(*anchorNode()) && m_offset <= 0; |
| 559 } | 559 } |
| 560 | 560 |
| 561 template <typename Strategy> | 561 template <typename Strategy> |
| 562 bool PositionAlgorithm<Strategy>::atEndOfTree() const | 562 bool PositionAlgorithm<Strategy>::atEndOfTree() const |
| 563 { | 563 { |
| 564 if (isNull()) | 564 if (isNull()) |
| 565 return true; | 565 return true; |
| 566 return !Strategy::parent(*deprecatedNode()) && m_offset >= lastOffsetForEdit
ing(deprecatedNode()); | 566 return !Strategy::parent(*anchorNode()) && m_offset >= lastOffsetForEditing(
anchorNode()); |
| 567 } | 567 } |
| 568 | 568 |
| 569 template <typename Strategy> | 569 template <typename Strategy> |
| 570 int PositionAlgorithm<Strategy>::renderedOffset() const | 570 int PositionAlgorithm<Strategy>::renderedOffset() const |
| 571 { | 571 { |
| 572 if (!deprecatedNode()->isTextNode()) | 572 if (!anchorNode()->isTextNode()) |
| 573 return m_offset; | 573 return m_offset; |
| 574 | 574 |
| 575 if (!deprecatedNode()->layoutObject()) | 575 if (!anchorNode()->layoutObject()) |
| 576 return m_offset; | 576 return m_offset; |
| 577 | 577 |
| 578 int result = 0; | 578 int result = 0; |
| 579 LayoutText* textLayoutObject = toLayoutText(deprecatedNode()->layoutObject()
); | 579 LayoutText* textLayoutObject = toLayoutText(anchorNode()->layoutObject()); |
| 580 for (InlineTextBox *box = textLayoutObject->firstTextBox(); box; box = box->
nextTextBox()) { | 580 for (InlineTextBox *box = textLayoutObject->firstTextBox(); box; box = box->
nextTextBox()) { |
| 581 int start = box->start(); | 581 int start = box->start(); |
| 582 int end = box->start() + box->len(); | 582 int end = box->start() + box->len(); |
| 583 if (m_offset < start) | 583 if (m_offset < start) |
| 584 return result; | 584 return result; |
| 585 if (m_offset <= end) { | 585 if (m_offset <= end) { |
| 586 result += m_offset - start; | 586 result += m_offset - start; |
| 587 return result; | 587 return result; |
| 588 } | 588 } |
| 589 result += box->len(); | 589 result += box->len(); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 641 | 641 |
| 642 // This function and downstream() are used for moving back and forth between vis
ually equivalent candidates. | 642 // This function and downstream() are used for moving back and forth between vis
ually equivalent candidates. |
| 643 // For example, for the text node "foo bar" where whitespace is collapsible,
there are two candidates | 643 // For example, for the text node "foo bar" where whitespace is collapsible,
there are two candidates |
| 644 // that map to the VisiblePosition between 'b' and the space. This function wil
l return the left candidate | 644 // that map to the VisiblePosition between 'b' and the space. This function wil
l return the left candidate |
| 645 // and downstream() will return the right one. | 645 // and downstream() will return the right one. |
| 646 // Also, upstream() will return [boundary, 0] for any of the positions from [bou
ndary, 0] to the first candidate | 646 // Also, upstream() will return [boundary, 0] for any of the positions from [bou
ndary, 0] to the first candidate |
| 647 // in boundary, where endsOfNodeAreVisuallyDistinctPositions(boundary) is true. | 647 // in boundary, where endsOfNodeAreVisuallyDistinctPositions(boundary) is true. |
| 648 template <typename Strategy> | 648 template <typename Strategy> |
| 649 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::upstream(EditingBoundar
yCrossingRule rule) const | 649 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::upstream(EditingBoundar
yCrossingRule rule) const |
| 650 { | 650 { |
| 651 Node* startNode = deprecatedNode(); | 651 Node* startNode = anchorNode(); |
| 652 if (!startNode) | 652 if (!startNode) |
| 653 return PositionAlgorithm<Strategy>(); | 653 return PositionAlgorithm<Strategy>(); |
| 654 | 654 |
| 655 // iterate backward from there, looking for a qualified position | 655 // iterate backward from there, looking for a qualified position |
| 656 Node* boundary = enclosingVisualBoundary<Strategy>(startNode); | 656 Node* boundary = enclosingVisualBoundary<Strategy>(startNode); |
| 657 // FIXME: PositionIterator should respect Before and After positions. | 657 // FIXME: PositionIterator should respect Before and After positions. |
| 658 PositionIteratorAlgorithm<Strategy> lastVisible(m_anchorType == PositionAnch
orType::AfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOf
fset(m_anchorNode.get())) : PositionAlgorithm<Strategy>(*this)); | 658 PositionIteratorAlgorithm<Strategy> lastVisible(m_anchorType == PositionAnch
orType::AfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOf
fset(m_anchorNode.get())) : PositionAlgorithm<Strategy>(*this)); |
| 659 PositionIteratorAlgorithm<Strategy> currentPos = lastVisible; | 659 PositionIteratorAlgorithm<Strategy> currentPos = lastVisible; |
| 660 bool startEditable = startNode->hasEditableStyle(); | 660 bool startEditable = startNode->hasEditableStyle(); |
| 661 Node* lastNode = startNode; | 661 Node* lastNode = startNode; |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 763 // This function and upstream() are used for moving back and forth between visua
lly equivalent candidates. | 763 // This function and upstream() are used for moving back and forth between visua
lly equivalent candidates. |
| 764 // For example, for the text node "foo bar" where whitespace is collapsible,
there are two candidates | 764 // For example, for the text node "foo bar" where whitespace is collapsible,
there are two candidates |
| 765 // that map to the VisiblePosition between 'b' and the space. This function wil
l return the right candidate | 765 // that map to the VisiblePosition between 'b' and the space. This function wil
l return the right candidate |
| 766 // and upstream() will return the left one. | 766 // and upstream() will return the left one. |
| 767 // Also, downstream() will return the last position in the last atomic node in b
oundary for all of the positions | 767 // Also, downstream() will return the last position in the last atomic node in b
oundary for all of the positions |
| 768 // in boundary after the last candidate, where endsOfNodeAreVisuallyDistinctPosi
tions(boundary). | 768 // in boundary after the last candidate, where endsOfNodeAreVisuallyDistinctPosi
tions(boundary). |
| 769 // FIXME: This function should never be called when the line box tree is dirty.
See https://bugs.webkit.org/show_bug.cgi?id=97264 | 769 // FIXME: This function should never be called when the line box tree is dirty.
See https://bugs.webkit.org/show_bug.cgi?id=97264 |
| 770 template <typename Strategy> | 770 template <typename Strategy> |
| 771 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::downstream(EditingBound
aryCrossingRule rule) const | 771 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::downstream(EditingBound
aryCrossingRule rule) const |
| 772 { | 772 { |
| 773 Node* startNode = deprecatedNode(); | 773 Node* startNode = anchorNode(); |
| 774 if (!startNode) | 774 if (!startNode) |
| 775 return PositionAlgorithm<Strategy>(); | 775 return PositionAlgorithm<Strategy>(); |
| 776 | 776 |
| 777 // iterate forward from there, looking for a qualified position | 777 // iterate forward from there, looking for a qualified position |
| 778 Node* boundary = enclosingVisualBoundary<Strategy>(startNode); | 778 Node* boundary = enclosingVisualBoundary<Strategy>(startNode); |
| 779 // FIXME: PositionIterator should respect Before and After positions. | 779 // FIXME: PositionIterator should respect Before and After positions. |
| 780 PositionIteratorAlgorithm<Strategy> lastVisible(m_anchorType == PositionAnch
orType::AfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOf
fset(m_anchorNode.get())) : PositionAlgorithm<Strategy>(*this)); | 780 PositionIteratorAlgorithm<Strategy> lastVisible(m_anchorType == PositionAnch
orType::AfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOf
fset(m_anchorNode.get())) : PositionAlgorithm<Strategy>(*this)); |
| 781 PositionIteratorAlgorithm<Strategy> currentPos = lastVisible; | 781 PositionIteratorAlgorithm<Strategy> currentPos = lastVisible; |
| 782 bool startEditable = startNode->hasEditableStyle(); | 782 bool startEditable = startNode->hasEditableStyle(); |
| 783 Node* lastNode = startNode; | 783 Node* lastNode = startNode; |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 938 } | 938 } |
| 939 return candidateRoot; | 939 return candidateRoot; |
| 940 } | 940 } |
| 941 | 941 |
| 942 template <typename Strategy> | 942 template <typename Strategy> |
| 943 bool PositionAlgorithm<Strategy>::isCandidate() const | 943 bool PositionAlgorithm<Strategy>::isCandidate() const |
| 944 { | 944 { |
| 945 if (isNull()) | 945 if (isNull()) |
| 946 return false; | 946 return false; |
| 947 | 947 |
| 948 LayoutObject* layoutObject = deprecatedNode()->layoutObject(); | 948 LayoutObject* layoutObject = anchorNode()->layoutObject(); |
| 949 if (!layoutObject) | 949 if (!layoutObject) |
| 950 return false; | 950 return false; |
| 951 | 951 |
| 952 if (layoutObject->style()->visibility() != VISIBLE) | 952 if (layoutObject->style()->visibility() != VISIBLE) |
| 953 return false; | 953 return false; |
| 954 | 954 |
| 955 if (layoutObject->isBR()) { | 955 if (layoutObject->isBR()) { |
| 956 // TODO(leviw) The condition should be | 956 // TODO(leviw) The condition should be |
| 957 // m_anchorType == PositionAnchorType::BeforeAnchor, but for now we | 957 // m_anchorType == PositionAnchorType::BeforeAnchor, but for now we |
| 958 // still need to support legacy positions. | 958 // still need to support legacy positions. |
| 959 return !m_offset && m_anchorType != PositionAnchorType::AfterAnchor && !
nodeIsUserSelectNone(Strategy::parent(*deprecatedNode())); | 959 return !m_offset && m_anchorType != PositionAnchorType::AfterAnchor && !
nodeIsUserSelectNone(Strategy::parent(*anchorNode())); |
| 960 } | 960 } |
| 961 | 961 |
| 962 if (layoutObject->isText()) | 962 if (layoutObject->isText()) |
| 963 return !nodeIsUserSelectNone(deprecatedNode()) && inRenderedText(); | 963 return !nodeIsUserSelectNone(anchorNode()) && inRenderedText(); |
| 964 | 964 |
| 965 if (layoutObject->isSVG()) { | 965 if (layoutObject->isSVG()) { |
| 966 // We don't consider SVG elements are contenteditable except for | 966 // We don't consider SVG elements are contenteditable except for |
| 967 // associated layoutObject returns isText() true, e.g. LayoutSVGInlineTe
xt. | 967 // associated layoutObject returns isText() true, e.g. LayoutSVGInlineTe
xt. |
| 968 return false; | 968 return false; |
| 969 } | 969 } |
| 970 | 970 |
| 971 if (isRenderedHTMLTableElement(deprecatedNode()) || Strategy::editingIgnores
Content(deprecatedNode())) | 971 if (isRenderedHTMLTableElement(anchorNode()) || Strategy::editingIgnoresCont
ent(anchorNode())) |
| 972 return (atFirstEditingPositionForNode() || atLastEditingPositionForNode(
)) && !nodeIsUserSelectNone(Strategy::parent(*deprecatedNode())); | 972 return (atFirstEditingPositionForNode() || atLastEditingPositionForNode(
)) && !nodeIsUserSelectNone(Strategy::parent(*anchorNode())); |
| 973 | 973 |
| 974 if (isHTMLHtmlElement(*m_anchorNode)) | 974 if (isHTMLHtmlElement(*m_anchorNode)) |
| 975 return false; | 975 return false; |
| 976 | 976 |
| 977 if (layoutObject->isLayoutBlockFlow() || layoutObject->isFlexibleBox() || la
youtObject->isLayoutGrid()) { | 977 if (layoutObject->isLayoutBlockFlow() || layoutObject->isFlexibleBox() || la
youtObject->isLayoutGrid()) { |
| 978 if (toLayoutBlock(layoutObject)->logicalHeight() || isHTMLBodyElement(*m
_anchorNode)) { | 978 if (toLayoutBlock(layoutObject)->logicalHeight() || isHTMLBodyElement(*m
_anchorNode)) { |
| 979 if (!hasRenderedNonAnonymousDescendantsWithHeight(layoutObject)) | 979 if (!hasRenderedNonAnonymousDescendantsWithHeight(layoutObject)) |
| 980 return atFirstEditingPositionForNode() && !nodeIsUserSelectNone(
deprecatedNode()); | 980 return atFirstEditingPositionForNode() && !nodeIsUserSelectNone(
anchorNode()); |
| 981 return m_anchorNode->hasEditableStyle() && !nodeIsUserSelectNone(dep
recatedNode()) && atEditingBoundary(); | 981 return m_anchorNode->hasEditableStyle() && !nodeIsUserSelectNone(anc
horNode()) && atEditingBoundary(); |
| 982 } | 982 } |
| 983 } else { | 983 } else { |
| 984 LocalFrame* frame = m_anchorNode->document().frame(); | 984 LocalFrame* frame = m_anchorNode->document().frame(); |
| 985 bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsi
ngEnabled(); | 985 bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsi
ngEnabled(); |
| 986 return (caretBrowsing || m_anchorNode->hasEditableStyle()) && !nodeIsUse
rSelectNone(deprecatedNode()) && atEditingBoundary(); | 986 return (caretBrowsing || m_anchorNode->hasEditableStyle()) && !nodeIsUse
rSelectNone(anchorNode()) && atEditingBoundary(); |
| 987 } | 987 } |
| 988 | 988 |
| 989 return false; | 989 return false; |
| 990 } | 990 } |
| 991 | 991 |
| 992 template <typename Strategy> | 992 template <typename Strategy> |
| 993 bool PositionAlgorithm<Strategy>::inRenderedText() const | 993 bool PositionAlgorithm<Strategy>::inRenderedText() const |
| 994 { | 994 { |
| 995 if (isNull() || !deprecatedNode()->isTextNode()) | 995 if (isNull() || !anchorNode()->isTextNode()) |
| 996 return false; | 996 return false; |
| 997 | 997 |
| 998 LayoutObject* layoutObject = deprecatedNode()->layoutObject(); | 998 LayoutObject* layoutObject = anchorNode()->layoutObject(); |
| 999 if (!layoutObject) | 999 if (!layoutObject) |
| 1000 return false; | 1000 return false; |
| 1001 | 1001 |
| 1002 LayoutText* textLayoutObject = toLayoutText(layoutObject); | 1002 LayoutText* textLayoutObject = toLayoutText(layoutObject); |
| 1003 for (InlineTextBox *box = textLayoutObject->firstTextBox(); box; box = box->
nextTextBox()) { | 1003 for (InlineTextBox *box = textLayoutObject->firstTextBox(); box; box = box->
nextTextBox()) { |
| 1004 if (m_offset < static_cast<int>(box->start()) && !textLayoutObject->cont
ainsReversedText()) { | 1004 if (m_offset < static_cast<int>(box->start()) && !textLayoutObject->cont
ainsReversedText()) { |
| 1005 // The offset we're looking for is before this node | 1005 // The offset we're looking for is before this node |
| 1006 // this means the offset must be in content that is | 1006 // this means the offset must be in content that is |
| 1007 // not laid out. Return false. | 1007 // not laid out. Return false. |
| 1008 return false; | 1008 return false; |
| 1009 } | 1009 } |
| 1010 if (box->containsCaretOffset(m_offset)) { | 1010 if (box->containsCaretOffset(m_offset)) { |
| 1011 // Return false for offsets inside composed characters. | 1011 // Return false for offsets inside composed characters. |
| 1012 return m_offset == 0 || m_offset == textLayoutObject->nextOffset(tex
tLayoutObject->previousOffset(m_offset)); | 1012 return m_offset == 0 || m_offset == textLayoutObject->nextOffset(tex
tLayoutObject->previousOffset(m_offset)); |
| 1013 } | 1013 } |
| 1014 } | 1014 } |
| 1015 | 1015 |
| 1016 return false; | 1016 return false; |
| 1017 } | 1017 } |
| 1018 | 1018 |
| 1019 template <typename Strategy> | 1019 template <typename Strategy> |
| 1020 bool PositionAlgorithm<Strategy>::isRenderedCharacter() const | 1020 bool PositionAlgorithm<Strategy>::isRenderedCharacter() const |
| 1021 { | 1021 { |
| 1022 if (isNull() || !deprecatedNode()->isTextNode()) | 1022 if (isNull() || !anchorNode()->isTextNode()) |
| 1023 return false; | 1023 return false; |
| 1024 | 1024 |
| 1025 LayoutObject* layoutObject = deprecatedNode()->layoutObject(); | 1025 LayoutObject* layoutObject = anchorNode()->layoutObject(); |
| 1026 if (!layoutObject) | 1026 if (!layoutObject) |
| 1027 return false; | 1027 return false; |
| 1028 | 1028 |
| 1029 LayoutText* textLayoutObject = toLayoutText(layoutObject); | 1029 LayoutText* textLayoutObject = toLayoutText(layoutObject); |
| 1030 for (InlineTextBox* box = textLayoutObject->firstTextBox(); box; box = box->
nextTextBox()) { | 1030 for (InlineTextBox* box = textLayoutObject->firstTextBox(); box; box = box->
nextTextBox()) { |
| 1031 if (m_offset < static_cast<int>(box->start()) && !textLayoutObject->cont
ainsReversedText()) { | 1031 if (m_offset < static_cast<int>(box->start()) && !textLayoutObject->cont
ainsReversedText()) { |
| 1032 // The offset we're looking for is before this node | 1032 // The offset we're looking for is before this node |
| 1033 // this means the offset must be in content that is | 1033 // this means the offset must be in content that is |
| 1034 // not laid out. Return false. | 1034 // not laid out. Return false. |
| 1035 return false; | 1035 return false; |
| 1036 } | 1036 } |
| 1037 if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast
<int>(box->start() + box->len())) | 1037 if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast
<int>(box->start() + box->len())) |
| 1038 return true; | 1038 return true; |
| 1039 } | 1039 } |
| 1040 | 1040 |
| 1041 return false; | 1041 return false; |
| 1042 } | 1042 } |
| 1043 | 1043 |
| 1044 template <typename Strategy> | 1044 template <typename Strategy> |
| 1045 bool PositionAlgorithm<Strategy>::rendersInDifferentPosition(const PositionAlgor
ithm<Strategy> &pos) const | 1045 bool PositionAlgorithm<Strategy>::rendersInDifferentPosition(const PositionAlgor
ithm<Strategy> &pos) const |
| 1046 { | 1046 { |
| 1047 if (isNull() || pos.isNull()) | 1047 if (isNull() || pos.isNull()) |
| 1048 return false; | 1048 return false; |
| 1049 | 1049 |
| 1050 LayoutObject* layoutObject = deprecatedNode()->layoutObject(); | 1050 LayoutObject* layoutObject = anchorNode()->layoutObject(); |
| 1051 if (!layoutObject) | 1051 if (!layoutObject) |
| 1052 return false; | 1052 return false; |
| 1053 | 1053 |
| 1054 LayoutObject* posLayoutObject = pos.deprecatedNode()->layoutObject(); | 1054 LayoutObject* posLayoutObject = pos.anchorNode()->layoutObject(); |
| 1055 if (!posLayoutObject) | 1055 if (!posLayoutObject) |
| 1056 return false; | 1056 return false; |
| 1057 | 1057 |
| 1058 if (layoutObject->style()->visibility() != VISIBLE | 1058 if (layoutObject->style()->visibility() != VISIBLE |
| 1059 || posLayoutObject->style()->visibility() != VISIBLE) | 1059 || posLayoutObject->style()->visibility() != VISIBLE) |
| 1060 return false; | 1060 return false; |
| 1061 | 1061 |
| 1062 if (deprecatedNode() == pos.deprecatedNode()) { | 1062 if (anchorNode() == pos.anchorNode()) { |
| 1063 if (isHTMLBRElement(*deprecatedNode())) | 1063 if (isHTMLBRElement(*anchorNode())) |
| 1064 return false; | 1064 return false; |
| 1065 | 1065 |
| 1066 if (m_offset == pos.deprecatedEditingOffset()) | 1066 if (m_offset == pos.deprecatedEditingOffset()) |
| 1067 return false; | 1067 return false; |
| 1068 | 1068 |
| 1069 if (!deprecatedNode()->isTextNode() && !pos.deprecatedNode()->isTextNode
()) { | 1069 if (!anchorNode()->isTextNode() && !pos.anchorNode()->isTextNode()) { |
| 1070 if (m_offset != pos.deprecatedEditingOffset()) | 1070 if (m_offset != pos.deprecatedEditingOffset()) |
| 1071 return true; | 1071 return true; |
| 1072 } | 1072 } |
| 1073 } | 1073 } |
| 1074 | 1074 |
| 1075 if (isHTMLBRElement(*deprecatedNode()) && pos.isCandidate()) | 1075 if (isHTMLBRElement(*anchorNode()) && pos.isCandidate()) |
| 1076 return true; | 1076 return true; |
| 1077 | 1077 |
| 1078 if (isHTMLBRElement(*pos.deprecatedNode()) && isCandidate()) | 1078 if (isHTMLBRElement(*pos.anchorNode()) && isCandidate()) |
| 1079 return true; | 1079 return true; |
| 1080 | 1080 |
| 1081 if (!inSameContainingBlockFlowElement(deprecatedNode(), pos.deprecatedNode()
)) | 1081 if (!inSameContainingBlockFlowElement(anchorNode(), pos.anchorNode())) |
| 1082 return true; | 1082 return true; |
| 1083 | 1083 |
| 1084 if (deprecatedNode()->isTextNode() && !inRenderedText()) | 1084 if (anchorNode()->isTextNode() && !inRenderedText()) |
| 1085 return false; | 1085 return false; |
| 1086 | 1086 |
| 1087 if (pos.deprecatedNode()->isTextNode() && !pos.inRenderedText()) | 1087 if (pos.anchorNode()->isTextNode() && !pos.inRenderedText()) |
| 1088 return false; | 1088 return false; |
| 1089 | 1089 |
| 1090 int thisRenderedOffset = renderedOffset(); | 1090 int thisRenderedOffset = renderedOffset(); |
| 1091 int posRenderedOffset = pos.renderedOffset(); | 1091 int posRenderedOffset = pos.renderedOffset(); |
| 1092 | 1092 |
| 1093 if (layoutObject == posLayoutObject && thisRenderedOffset == posRenderedOffs
et) | 1093 if (layoutObject == posLayoutObject && thisRenderedOffset == posRenderedOffs
et) |
| 1094 return false; | 1094 return false; |
| 1095 | 1095 |
| 1096 InlineBoxPosition boxPosition1 = computeInlineBoxPosition(DOWNSTREAM); | 1096 InlineBoxPosition boxPosition1 = computeInlineBoxPosition(DOWNSTREAM); |
| 1097 InlineBoxPosition boxPosition2 = pos.computeInlineBoxPosition(DOWNSTREAM); | 1097 InlineBoxPosition boxPosition2 = pos.computeInlineBoxPosition(DOWNSTREAM); |
| 1098 | 1098 |
| 1099 WTF_LOG(Editing, "layoutObject: %p [%p]\n", layoutObject, boxPosit
ion1.inlineBox); | 1099 WTF_LOG(Editing, "layoutObject: %p [%p]\n", layoutObject, boxPosit
ion1.inlineBox); |
| 1100 WTF_LOG(Editing, "thisRenderedOffset: %d\n", thisRenderedOffset); | 1100 WTF_LOG(Editing, "thisRenderedOffset: %d\n", thisRenderedOffset); |
| 1101 WTF_LOG(Editing, "posLayoutObject: %p [%p]\n", posLayoutObject, boxPo
sition2.inlineBox); | 1101 WTF_LOG(Editing, "posLayoutObject: %p [%p]\n", posLayoutObject, boxPo
sition2.inlineBox); |
| 1102 WTF_LOG(Editing, "posRenderedOffset: %d\n", posRenderedOffset); | 1102 WTF_LOG(Editing, "posRenderedOffset: %d\n", posRenderedOffset); |
| 1103 WTF_LOG(Editing, "node min/max: %d:%d\n", caretMinOffset(deprecate
dNode()), caretMaxOffset(deprecatedNode())); | 1103 WTF_LOG(Editing, "node min/max: %d:%d\n", caretMinOffset(anchorNod
e()), caretMaxOffset(anchorNode())); |
| 1104 WTF_LOG(Editing, "pos node min/max: %d:%d\n", caretMinOffset(pos.depre
catedNode()), caretMaxOffset(pos.deprecatedNode())); | 1104 WTF_LOG(Editing, "pos node min/max: %d:%d\n", caretMinOffset(pos.ancho
rNode()), caretMaxOffset(pos.anchorNode())); |
| 1105 WTF_LOG(Editing, "----------------------------------------------------------
------------\n"); | 1105 WTF_LOG(Editing, "----------------------------------------------------------
------------\n"); |
| 1106 | 1106 |
| 1107 if (!boxPosition1.inlineBox || !boxPosition2.inlineBox) { | 1107 if (!boxPosition1.inlineBox || !boxPosition2.inlineBox) { |
| 1108 return false; | 1108 return false; |
| 1109 } | 1109 } |
| 1110 | 1110 |
| 1111 if (boxPosition1.inlineBox->root() != boxPosition2.inlineBox->root()) { | 1111 if (boxPosition1.inlineBox->root() != boxPosition2.inlineBox->root()) { |
| 1112 return true; | 1112 return true; |
| 1113 } | 1113 } |
| 1114 | 1114 |
| 1115 if (nextRenderedEditable(deprecatedNode()) == pos.deprecatedNode() | 1115 if (nextRenderedEditable(anchorNode()) == pos.anchorNode() |
| 1116 && thisRenderedOffset == caretMaxOffset(deprecatedNode()) && !posRendere
dOffset) { | 1116 && thisRenderedOffset == caretMaxOffset(anchorNode()) && !posRenderedOff
set) { |
| 1117 return false; | 1117 return false; |
| 1118 } | 1118 } |
| 1119 | 1119 |
| 1120 if (previousRenderedEditable(deprecatedNode()) == pos.deprecatedNode() | 1120 if (previousRenderedEditable(anchorNode()) == pos.anchorNode() |
| 1121 && !thisRenderedOffset && posRenderedOffset == caretMaxOffset(pos.deprec
atedNode())) { | 1121 && !thisRenderedOffset && posRenderedOffset == caretMaxOffset(pos.anchor
Node())) { |
| 1122 return false; | 1122 return false; |
| 1123 } | 1123 } |
| 1124 | 1124 |
| 1125 return true; | 1125 return true; |
| 1126 } | 1126 } |
| 1127 | 1127 |
| 1128 template <typename Strategy> | 1128 template <typename Strategy> |
| 1129 InlineBoxPosition PositionAlgorithm<Strategy>::computeInlineBoxPosition(EAffinit
y affinity) const | 1129 InlineBoxPosition PositionAlgorithm<Strategy>::computeInlineBoxPosition(EAffinit
y affinity) const |
| 1130 { | 1130 { |
| 1131 return computeInlineBoxPosition(affinity, primaryDirection()); | 1131 return computeInlineBoxPosition(affinity, primaryDirection()); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1191 | 1191 |
| 1192 template <typename Strategy> | 1192 template <typename Strategy> |
| 1193 InlineBoxPosition PositionAlgorithm<Strategy>::computeInlineBoxPosition(EAffinit
y affinity, TextDirection primaryDirection) const | 1193 InlineBoxPosition PositionAlgorithm<Strategy>::computeInlineBoxPosition(EAffinit
y affinity, TextDirection primaryDirection) const |
| 1194 { | 1194 { |
| 1195 InlineBox* inlineBox = nullptr; | 1195 InlineBox* inlineBox = nullptr; |
| 1196 int caretOffset = deprecatedEditingOffset(); | 1196 int caretOffset = deprecatedEditingOffset(); |
| 1197 LayoutObject* layoutObject = m_anchorNode->isShadowRoot() ? toShadowRoot(m_a
nchorNode)->host()->layoutObject() : m_anchorNode->layoutObject(); | 1197 LayoutObject* layoutObject = m_anchorNode->isShadowRoot() ? toShadowRoot(m_a
nchorNode)->host()->layoutObject() : m_anchorNode->layoutObject(); |
| 1198 | 1198 |
| 1199 if (!layoutObject->isText()) { | 1199 if (!layoutObject->isText()) { |
| 1200 inlineBox = 0; | 1200 inlineBox = 0; |
| 1201 if (canHaveChildrenForEditing(deprecatedNode()) && layoutObject->isLayou
tBlockFlow() && hasRenderedNonAnonymousDescendantsWithHeight(layoutObject)) { | 1201 if (canHaveChildrenForEditing(anchorNode()) && layoutObject->isLayoutBlo
ckFlow() && hasRenderedNonAnonymousDescendantsWithHeight(layoutObject)) { |
| 1202 // Try a visually equivalent position with possibly opposite editabi
lity. This helps in case |this| is in | 1202 // Try a visually equivalent position with possibly opposite editabi
lity. This helps in case |this| is in |
| 1203 // an editable block but surrounded by non-editable positions. It ac
ts to negate the logic at the beginning | 1203 // an editable block but surrounded by non-editable positions. It ac
ts to negate the logic at the beginning |
| 1204 // of LayoutObject::createVisiblePosition(). | 1204 // of LayoutObject::createVisiblePosition(). |
| 1205 PositionAlgorithm<Strategy> thisPosition = PositionAlgorithm<Strateg
y>(*this); | 1205 PositionAlgorithm<Strategy> thisPosition = PositionAlgorithm<Strateg
y>(*this); |
| 1206 PositionAlgorithm<Strategy> equivalent = downstreamIgnoringEditingBo
undaries(thisPosition); | 1206 PositionAlgorithm<Strategy> equivalent = downstreamIgnoringEditingBo
undaries(thisPosition); |
| 1207 if (equivalent == thisPosition) { | 1207 if (equivalent == thisPosition) { |
| 1208 equivalent = upstreamIgnoringEditingBoundaries(thisPosition); | 1208 equivalent = upstreamIgnoringEditingBoundaries(thisPosition); |
| 1209 if (equivalent == thisPosition || downstreamIgnoringEditingBound
aries(equivalent) == thisPosition) | 1209 if (equivalent == thisPosition || downstreamIgnoringEditingBound
aries(equivalent) == thisPosition) |
| 1210 return InlineBoxPosition(inlineBox, caretOffset); | 1210 return InlineBoxPosition(inlineBox, caretOffset); |
| 1211 } | 1211 } |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1372 "Invalid", | 1372 "Invalid", |
| 1373 }; | 1373 }; |
| 1374 | 1374 |
| 1375 if (isNull()) { | 1375 if (isNull()) { |
| 1376 fprintf(stderr, "Position [%s]: null\n", msg); | 1376 fprintf(stderr, "Position [%s]: null\n", msg); |
| 1377 return; | 1377 return; |
| 1378 } | 1378 } |
| 1379 | 1379 |
| 1380 const char* anchorType = anchorTypes[std::min(static_cast<size_t>(m_anchorTy
pe), WTF_ARRAY_LENGTH(anchorTypes) - 1)]; | 1380 const char* anchorType = anchorTypes[std::min(static_cast<size_t>(m_anchorTy
pe), WTF_ARRAY_LENGTH(anchorTypes) - 1)]; |
| 1381 if (m_anchorNode->isTextNode()) { | 1381 if (m_anchorNode->isTextNode()) { |
| 1382 fprintf(stderr, "Position [%s]: %s%s [%p] %s, (%s) at %d\n", msg, m_isLe
gacyEditingPosition ? "LEGACY, " : "", deprecatedNode()->nodeName().utf8().data(
), deprecatedNode(), anchorType, m_anchorNode->nodeValue().utf8().data(), m_offs
et); | 1382 fprintf(stderr, "Position [%s]: %s%s [%p] %s, (%s) at %d\n", msg, m_isLe
gacyEditingPosition ? "LEGACY, " : "", anchorNode()->nodeName().utf8().data(), a
nchorNode(), anchorType, m_anchorNode->nodeValue().utf8().data(), m_offset); |
| 1383 return; | 1383 return; |
| 1384 } | 1384 } |
| 1385 | 1385 |
| 1386 fprintf(stderr, "Position [%s]: %s%s [%p] %s at %d\n", msg, m_isLegacyEditin
gPosition ? "LEGACY, " : "", deprecatedNode()->nodeName().utf8().data(), depreca
tedNode(), anchorType, m_offset); | 1386 fprintf(stderr, "Position [%s]: %s%s [%p] %s at %d\n", msg, m_isLegacyEditin
gPosition ? "LEGACY, " : "", anchorNode()->nodeName().utf8().data(), anchorNode(
), anchorType, m_offset); |
| 1387 } | 1387 } |
| 1388 | 1388 |
| 1389 PositionInComposedTree toPositionInComposedTree(const Position& pos) | 1389 PositionInComposedTree toPositionInComposedTree(const Position& pos) |
| 1390 { | 1390 { |
| 1391 if (pos.isNull()) | 1391 if (pos.isNull()) |
| 1392 return PositionInComposedTree(); | 1392 return PositionInComposedTree(); |
| 1393 | 1393 |
| 1394 PositionInComposedTree position; | 1394 PositionInComposedTree position; |
| 1395 if (pos.anchorType() == PositionAnchorType::OffsetInAnchor) { | 1395 if (pos.anchorType() == PositionAnchorType::OffsetInAnchor) { |
| 1396 Node* anchor = pos.anchorNode(); | 1396 Node* anchor = pos.anchorNode(); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1465 { | 1465 { |
| 1466 StringBuilder result; | 1466 StringBuilder result; |
| 1467 | 1467 |
| 1468 if (isNull()) { | 1468 if (isNull()) { |
| 1469 result.appendLiteral("<null>"); | 1469 result.appendLiteral("<null>"); |
| 1470 } else { | 1470 } else { |
| 1471 char s[1024]; | 1471 char s[1024]; |
| 1472 result.appendLiteral("offset "); | 1472 result.appendLiteral("offset "); |
| 1473 result.appendNumber(m_offset); | 1473 result.appendNumber(m_offset); |
| 1474 result.appendLiteral(" of "); | 1474 result.appendLiteral(" of "); |
| 1475 deprecatedNode()->formatForDebugger(s, sizeof(s)); | 1475 anchorNode()->formatForDebugger(s, sizeof(s)); |
| 1476 result.append(s); | 1476 result.append(s); |
| 1477 } | 1477 } |
| 1478 | 1478 |
| 1479 strncpy(buffer, result.toString().utf8().data(), length - 1); | 1479 strncpy(buffer, result.toString().utf8().data(), length - 1); |
| 1480 } | 1480 } |
| 1481 | 1481 |
| 1482 template <typename Strategy> | 1482 template <typename Strategy> |
| 1483 void PositionAlgorithm<Strategy>::showAnchorTypeAndOffset() const | 1483 void PositionAlgorithm<Strategy>::showAnchorTypeAndOffset() const |
| 1484 { | 1484 { |
| 1485 if (m_isLegacyEditingPosition) | 1485 if (m_isLegacyEditingPosition) |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1538 | 1538 |
| 1539 void showTree(const blink::Position* pos) | 1539 void showTree(const blink::Position* pos) |
| 1540 { | 1540 { |
| 1541 if (pos) | 1541 if (pos) |
| 1542 pos->showTreeForThis(); | 1542 pos->showTreeForThis(); |
| 1543 else | 1543 else |
| 1544 fprintf(stderr, "Cannot showTree for (nil)\n"); | 1544 fprintf(stderr, "Cannot showTree for (nil)\n"); |
| 1545 } | 1545 } |
| 1546 | 1546 |
| 1547 #endif | 1547 #endif |
| OLD | NEW |