| 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 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 continue; | 74 continue; |
| 75 if (!node->hasEditableStyle()) | 75 if (!node->hasEditableStyle()) |
| 76 continue; | 76 continue; |
| 77 if ((layoutObject->isBox() && toLayoutBox(layoutObject)->inlineBoxWrappe
r()) || (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox())) | 77 if ((layoutObject->isBox() && toLayoutBox(layoutObject)->inlineBoxWrappe
r()) || (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox())) |
| 78 return node; | 78 return node; |
| 79 } | 79 } |
| 80 return 0; | 80 return 0; |
| 81 } | 81 } |
| 82 | 82 |
| 83 template <typename Strategy> | 83 template <typename Strategy> |
| 84 const TreeScope* PositionAlgorithm<Strategy>::commonAncestorTreeScope(const Posi
tionType& a, const PositionType& b) | 84 const TreeScope* PositionAlgorithm<Strategy>::commonAncestorTreeScope(const Posi
tionAlgorithm<Strategy>& a, const PositionAlgorithm<Strategy>& b) |
| 85 { | 85 { |
| 86 if (!a.containerNode() || !b.containerNode()) | 86 if (!a.containerNode() || !b.containerNode()) |
| 87 return nullptr; | 87 return nullptr; |
| 88 return a.containerNode()->treeScope().commonAncestorTreeScope(b.containerNod
e()->treeScope()); | 88 return a.containerNode()->treeScope().commonAncestorTreeScope(b.containerNod
e()->treeScope()); |
| 89 } | 89 } |
| 90 | 90 |
| 91 template <typename Strategy> | 91 template <typename Strategy> |
| 92 PositionAlgorithm<Strategy>::PositionAlgorithm(PassRefPtrWillBeRawPtr<Node> anch
orNode, LegacyEditingOffset offset) | 92 PositionAlgorithm<Strategy>::PositionAlgorithm(PassRefPtrWillBeRawPtr<Node> anch
orNode, LegacyEditingOffset offset) |
| 93 : m_anchorNode(anchorNode) | 93 : m_anchorNode(anchorNode) |
| 94 , m_offset(offset.value()) | 94 , m_offset(offset.value()) |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 212 int PositionAlgorithm<Strategy>::offsetForPositionAfterAnchor() const | 212 int PositionAlgorithm<Strategy>::offsetForPositionAfterAnchor() const |
| 213 { | 213 { |
| 214 ASSERT(m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAf
terChildren); | 214 ASSERT(m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAf
terChildren); |
| 215 ASSERT(!m_isLegacyEditingPosition); | 215 ASSERT(!m_isLegacyEditingPosition); |
| 216 return Strategy::lastOffsetForEditing(m_anchorNode.get()); | 216 return Strategy::lastOffsetForEditing(m_anchorNode.get()); |
| 217 } | 217 } |
| 218 | 218 |
| 219 // Neighbor-anchored positions are invalid DOM positions, so they need to be | 219 // Neighbor-anchored positions are invalid DOM positions, so they need to be |
| 220 // fixed up before handing them off to the Range object. | 220 // fixed up before handing them off to the Range object. |
| 221 template <typename Strategy> | 221 template <typename Strategy> |
| 222 typename Strategy::PositionType PositionAlgorithm<Strategy>::parentAnchoredEquiv
alent() const | 222 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::parentAnchoredEquivalen
t() const |
| 223 { | 223 { |
| 224 if (!m_anchorNode) | 224 if (!m_anchorNode) |
| 225 return PositionType(); | 225 return PositionAlgorithm<Strategy>(); |
| 226 | 226 |
| 227 // FIXME: This should only be necessary for legacy positions, but is also ne
eded for positions before and after Tables | 227 // FIXME: This should only be necessary for legacy positions, but is also ne
eded for positions before and after Tables |
| 228 if (m_offset <= 0 && (m_anchorType != PositionIsAfterAnchor && m_anchorType
!= PositionIsAfterChildren)) { | 228 if (m_offset <= 0 && (m_anchorType != PositionIsAfterAnchor && m_anchorType
!= PositionIsAfterChildren)) { |
| 229 if (Strategy::parent(*m_anchorNode) && (Strategy::editingIgnoresContent(
m_anchorNode.get()) || isRenderedHTMLTableElement(m_anchorNode.get()))) | 229 if (Strategy::parent(*m_anchorNode) && (Strategy::editingIgnoresContent(
m_anchorNode.get()) || isRenderedHTMLTableElement(m_anchorNode.get()))) |
| 230 return inParentBeforeNode(*m_anchorNode); | 230 return inParentBeforeNode(*m_anchorNode); |
| 231 return PositionType(m_anchorNode.get(), 0); | 231 return PositionAlgorithm<Strategy>(m_anchorNode.get(), 0); |
| 232 } | 232 } |
| 233 if (!m_anchorNode->offsetInCharacters() | 233 if (!m_anchorNode->offsetInCharacters() |
| 234 && (m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsA
fterChildren || static_cast<unsigned>(m_offset) == m_anchorNode->countChildren()
) | 234 && (m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsA
fterChildren || static_cast<unsigned>(m_offset) == m_anchorNode->countChildren()
) |
| 235 && (Strategy::editingIgnoresContent(m_anchorNode.get()) || isRenderedHTM
LTableElement(m_anchorNode.get())) | 235 && (Strategy::editingIgnoresContent(m_anchorNode.get()) || isRenderedHTM
LTableElement(m_anchorNode.get())) |
| 236 && containerNode()) { | 236 && containerNode()) { |
| 237 return inParentAfterNode(*m_anchorNode); | 237 return inParentAfterNode(*m_anchorNode); |
| 238 } | 238 } |
| 239 | 239 |
| 240 return PositionType(containerNode(), computeOffsetInContainerNode()); | 240 return PositionAlgorithm<Strategy>(containerNode(), computeOffsetInContainer
Node()); |
| 241 } | 241 } |
| 242 | 242 |
| 243 template <typename Strategy> | 243 template <typename Strategy> |
| 244 typename Strategy::PositionType PositionAlgorithm<Strategy>::toOffsetInAnchor()
const | 244 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::toOffsetInAnchor() cons
t |
| 245 { | 245 { |
| 246 if (isNull()) | 246 if (isNull()) |
| 247 return PositionType(); | 247 return PositionAlgorithm<Strategy>(); |
| 248 | 248 |
| 249 return PositionType(containerNode(), computeOffsetInContainerNode()); | 249 return PositionAlgorithm<Strategy>(containerNode(), computeOffsetInContainer
Node()); |
| 250 } | 250 } |
| 251 | 251 |
| 252 template <typename Strategy> | 252 template <typename Strategy> |
| 253 Node* PositionAlgorithm<Strategy>::computeNodeBeforePosition() const | 253 Node* PositionAlgorithm<Strategy>::computeNodeBeforePosition() const |
| 254 { | 254 { |
| 255 if (!m_anchorNode) | 255 if (!m_anchorNode) |
| 256 return 0; | 256 return 0; |
| 257 switch (anchorType()) { | 257 switch (anchorType()) { |
| 258 case PositionIsBeforeChildren: | 258 case PositionIsBeforeChildren: |
| 259 return 0; | 259 return 0; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 if (m_anchorType != PositionIsOffsetInAnchor) | 328 if (m_anchorType != PositionIsOffsetInAnchor) |
| 329 return toOffsetInAnchor().nodeAsRangePastLastNode(); | 329 return toOffsetInAnchor().nodeAsRangePastLastNode(); |
| 330 if (m_anchorNode->offsetInCharacters()) | 330 if (m_anchorNode->offsetInCharacters()) |
| 331 return Strategy::nextSkippingChildren(*m_anchorNode); | 331 return Strategy::nextSkippingChildren(*m_anchorNode); |
| 332 if (Node* child = Strategy::childAt(*m_anchorNode, m_offset)) | 332 if (Node* child = Strategy::childAt(*m_anchorNode, m_offset)) |
| 333 return child; | 333 return child; |
| 334 return Strategy::nextSkippingChildren(*m_anchorNode); | 334 return Strategy::nextSkippingChildren(*m_anchorNode); |
| 335 } | 335 } |
| 336 | 336 |
| 337 template <typename Strategy> | 337 template <typename Strategy> |
| 338 Node* PositionAlgorithm<Strategy>::commonAncestorContainer(const PositionType& o
ther) const | 338 Node* PositionAlgorithm<Strategy>::commonAncestorContainer(const PositionAlgorit
hm<Strategy>& other) const |
| 339 { | 339 { |
| 340 return Strategy::commonAncestor(*containerNode(), *other.containerNode()); | 340 return Strategy::commonAncestor(*containerNode(), *other.containerNode()); |
| 341 } | 341 } |
| 342 | 342 |
| 343 template <typename Strategy> | 343 template <typename Strategy> |
| 344 typename PositionAlgorithm<Strategy>::AnchorType PositionAlgorithm<Strategy>::an
chorTypeForLegacyEditingPosition(Node* anchorNode, int offset) | 344 typename PositionAlgorithm<Strategy>::AnchorType PositionAlgorithm<Strategy>::an
chorTypeForLegacyEditingPosition(Node* anchorNode, int offset) |
| 345 { | 345 { |
| 346 if (anchorNode && Strategy::editingIgnoresContent(anchorNode)) { | 346 if (anchorNode && Strategy::editingIgnoresContent(anchorNode)) { |
| 347 if (offset == 0) | 347 if (offset == 0) |
| 348 return PositionIsBeforeAnchor; | 348 return PositionIsBeforeAnchor; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 377 ASSERT(positionB.isNotNull()); | 377 ASSERT(positionB.isNotNull()); |
| 378 | 378 |
| 379 Node* containerA = positionA.containerNode(); | 379 Node* containerA = positionA.containerNode(); |
| 380 Node* containerB = positionB.containerNode(); | 380 Node* containerB = positionB.containerNode(); |
| 381 int offsetA = positionA.computeOffsetInContainerNode(); | 381 int offsetA = positionA.computeOffsetInContainerNode(); |
| 382 int offsetB = positionB.computeOffsetInContainerNode(); | 382 int offsetB = positionB.computeOffsetInContainerNode(); |
| 383 return EditingInComposedTreeStrategy::comparePositions(containerA, offsetA,
containerB, offsetB); | 383 return EditingInComposedTreeStrategy::comparePositions(containerA, offsetA,
containerB, offsetB); |
| 384 } | 384 } |
| 385 | 385 |
| 386 template <typename Strategy> | 386 template <typename Strategy> |
| 387 int PositionAlgorithm<Strategy>::compareTo(const PositionType& other) 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 typename Strategy::PositionType PositionAlgorithm<Strategy>::previous(PositionMo
veType moveType) const | 393 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::previous(PositionMoveTy
pe moveType) const |
| 394 { | 394 { |
| 395 Node* node = deprecatedNode(); | 395 Node* node = deprecatedNode(); |
| 396 if (!node) | 396 if (!node) |
| 397 return PositionType(*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); |
| 406 | 406 |
| 407 // There are two reasons child might be 0: | 407 // There are two reasons child might be 0: |
| 408 // 1) The node is node like a text node that is not an element, and th
erefore has no children. | 408 // 1) The node is node like a text node that is not an element, and th
erefore has no children. |
| 409 // Going backward one character at a time is correct. | 409 // Going backward one character at a time is correct. |
| 410 // 2) The old offset was a bogus offset like (<br>, 1), and there is n
o child. | 410 // 2) The old offset was a bogus offset like (<br>, 1), and there is n
o child. |
| 411 // Going from 1 to 0 is correct. | 411 // Going from 1 to 0 is correct. |
| 412 switch (moveType) { | 412 switch (moveType) { |
| 413 case CodePoint: | 413 case CodePoint: |
| 414 return createLegacyEditingPosition(node, offset - 1); | 414 return createLegacyEditingPosition(node, offset - 1); |
| 415 case Character: | 415 case Character: |
| 416 return createLegacyEditingPosition(node, uncheckedPreviousOffset(nod
e, offset)); | 416 return createLegacyEditingPosition(node, uncheckedPreviousOffset(nod
e, offset)); |
| 417 case BackwardDeletion: | 417 case BackwardDeletion: |
| 418 return createLegacyEditingPosition(node, uncheckedPreviousOffsetForB
ackwardDeletion(node, offset)); | 418 return createLegacyEditingPosition(node, uncheckedPreviousOffsetForB
ackwardDeletion(node, offset)); |
| 419 } | 419 } |
| 420 } | 420 } |
| 421 | 421 |
| 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 PositionType(*this); | 424 return PositionAlgorithm<Strategy>(*this); |
| 425 } | 425 } |
| 426 | 426 |
| 427 template <typename Strategy> | 427 template <typename Strategy> |
| 428 typename Strategy::PositionType PositionAlgorithm<Strategy>::next(PositionMoveTy
pe moveType) 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 = deprecatedNode(); |
| 433 if (!node) | 433 if (!node) |
| 434 return PositionType(*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 |
| 443 if (!Strategy::hasChildren(*node) && offset < lastOffsetForEditing(node)) { | 443 if (!Strategy::hasChildren(*node) && offset < lastOffsetForEditing(node)) { |
| 444 // There are two reasons child might be 0: | 444 // There are two reasons child might be 0: |
| 445 // 1) The node is node like a text node that is not an element, and th
erefore has no children. | 445 // 1) The node is node like a text node that is not an element, and th
erefore has no children. |
| 446 // Going forward one character at a time is correct. | 446 // Going forward one character at a time is correct. |
| 447 // 2) The new offset is a bogus offset like (<br>, 1), and there is no
child. | 447 // 2) The new offset is a bogus offset like (<br>, 1), and there is no
child. |
| 448 // Going from 0 to 1 is correct. | 448 // Going from 0 to 1 is correct. |
| 449 return createLegacyEditingPosition(node, (moveType == Character) ? unche
ckedNextOffset(node, offset) : offset + 1); | 449 return createLegacyEditingPosition(node, (moveType == Character) ? unche
ckedNextOffset(node, offset) : offset + 1); |
| 450 } | 450 } |
| 451 | 451 |
| 452 if (ContainerNode* parent = Strategy::parent(*node)) | 452 if (ContainerNode* parent = Strategy::parent(*node)) |
| 453 return createLegacyEditingPosition(parent, node->nodeIndex() + 1); | 453 return createLegacyEditingPosition(parent, node->nodeIndex() + 1); |
| 454 return PositionType(*this); | 454 return PositionAlgorithm<Strategy>(*this); |
| 455 } | 455 } |
| 456 | 456 |
| 457 template <typename Strategy> | 457 template <typename Strategy> |
| 458 int PositionAlgorithm<Strategy>::uncheckedPreviousOffset(const Node* n, int curr
ent) | 458 int PositionAlgorithm<Strategy>::uncheckedPreviousOffset(const Node* n, int curr
ent) |
| 459 { | 459 { |
| 460 return n->layoutObject() ? n->layoutObject()->previousOffset(current) : curr
ent - 1; | 460 return n->layoutObject() ? n->layoutObject()->previousOffset(current) : curr
ent - 1; |
| 461 } | 461 } |
| 462 | 462 |
| 463 template <typename Strategy> | 463 template <typename Strategy> |
| 464 int PositionAlgorithm<Strategy>::uncheckedPreviousOffsetForBackwardDeletion(cons
t Node* n, int current) | 464 int PositionAlgorithm<Strategy>::uncheckedPreviousOffsetForBackwardDeletion(cons
t Node* n, int current) |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 PositionType nextPosition = downstream(CanCrossEditingBoundary); | 516 PositionAlgorithm<Strategy> nextPosition = downstream(CanCrossEditingBoundar
y); |
| 517 if (atFirstEditingPositionForNode() && nextPosition.isNotNull() && !nextPosi
tion.deprecatedNode()->hasEditableStyle()) | 517 if (atFirstEditingPositionForNode() && nextPosition.isNotNull() && !nextPosi
tion.deprecatedNode()->hasEditableStyle()) |
| 518 return true; | 518 return true; |
| 519 | 519 |
| 520 PositionType 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.deprecatedNode()->hasEditableStyle()) |
| 522 return true; | 522 return true; |
| 523 | 523 |
| 524 return nextPosition.isNotNull() && !nextPosition.deprecatedNode()->hasEditab
leStyle() | 524 return nextPosition.isNotNull() && !nextPosition.deprecatedNode()->hasEditab
leStyle() |
| 525 && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->hasEditab
leStyle(); | 525 && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->hasEditab
leStyle(); |
| 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 { |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 639 return pos.atStartOfNode(); | 639 return pos.atStartOfNode(); |
| 640 } | 640 } |
| 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 typename Strategy::PositionType PositionAlgorithm<Strategy>::upstream(EditingBou
ndaryCrossingRule rule) const | 649 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::upstream(EditingBoundar
yCrossingRule rule) const |
| 650 { | 650 { |
| 651 Node* startNode = deprecatedNode(); | 651 Node* startNode = deprecatedNode(); |
| 652 if (!startNode) | 652 if (!startNode) |
| 653 return PositionType(); | 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 typename Strategy::PositionIteratorType lastVisible(m_anchorType == Position
IsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m
_anchorNode.get())) : PositionType(*this)); | 658 typename Strategy::PositionIteratorType lastVisible(m_anchorType == Position
IsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m
_anchorNode.get())) : PositionAlgorithm<Strategy>(*this)); |
| 659 typename Strategy::PositionIteratorType currentPos = lastVisible; | 659 typename Strategy::PositionIteratorType currentPos = lastVisible; |
| 660 bool startEditable = startNode->hasEditableStyle(); | 660 bool startEditable = startNode->hasEditableStyle(); |
| 661 Node* lastNode = startNode; | 661 Node* lastNode = startNode; |
| 662 bool boundaryCrossed = false; | 662 bool boundaryCrossed = false; |
| 663 for (; !currentPos.atStart(); currentPos.decrement()) { | 663 for (; !currentPos.atStart(); currentPos.decrement()) { |
| 664 Node* currentNode = currentPos.node(); | 664 Node* currentNode = currentPos.node(); |
| 665 // Don't check for an editability change if we haven't moved to a differ
ent node, | 665 // Don't check for an editability change if we haven't moved to a differ
ent node, |
| 666 // to avoid the expense of computing hasEditableStyle(). | 666 // to avoid the expense of computing hasEditableStyle(). |
| 667 if (currentNode != lastNode) { | 667 if (currentNode != lastNode) { |
| 668 // Don't change editability. | 668 // Don't change editability. |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 761 } | 761 } |
| 762 | 762 |
| 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 typename Strategy::PositionType PositionAlgorithm<Strategy>::downstream(EditingB
oundaryCrossingRule rule) const | 771 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::downstream(EditingBound
aryCrossingRule rule) const |
| 772 { | 772 { |
| 773 Node* startNode = deprecatedNode(); | 773 Node* startNode = deprecatedNode(); |
| 774 if (!startNode) | 774 if (!startNode) |
| 775 return PositionType(); | 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 typename Strategy::PositionIteratorType lastVisible(m_anchorType == Position
IsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m
_anchorNode.get())) : PositionType(*this)); | 780 typename Strategy::PositionIteratorType lastVisible(m_anchorType == Position
IsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m
_anchorNode.get())) : PositionAlgorithm<Strategy>(*this)); |
| 781 typename Strategy::PositionIteratorType currentPos = lastVisible; | 781 typename Strategy::PositionIteratorType currentPos = lastVisible; |
| 782 bool startEditable = startNode->hasEditableStyle(); | 782 bool startEditable = startNode->hasEditableStyle(); |
| 783 Node* lastNode = startNode; | 783 Node* lastNode = startNode; |
| 784 bool boundaryCrossed = false; | 784 bool boundaryCrossed = false; |
| 785 for (; !currentPos.atEnd(); currentPos.increment()) { | 785 for (; !currentPos.atEnd(); currentPos.increment()) { |
| 786 Node* currentNode = currentPos.node(); | 786 Node* currentNode = currentPos.node(); |
| 787 // Don't check for an editability change if we haven't moved to a differ
ent node, | 787 // Don't check for an editability change if we haven't moved to a differ
ent node, |
| 788 // to avoid the expense of computing hasEditableStyle(). | 788 // to avoid the expense of computing hasEditableStyle(). |
| 789 if (currentNode != lastNode) { | 789 if (currentNode != lastNode) { |
| 790 // Don't change editability. | 790 // Don't change editability. |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1032 return false; | 1032 return false; |
| 1033 } | 1033 } |
| 1034 if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast
<int>(box->start() + box->len())) | 1034 if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast
<int>(box->start() + box->len())) |
| 1035 return true; | 1035 return true; |
| 1036 } | 1036 } |
| 1037 | 1037 |
| 1038 return false; | 1038 return false; |
| 1039 } | 1039 } |
| 1040 | 1040 |
| 1041 template <typename Strategy> | 1041 template <typename Strategy> |
| 1042 bool PositionAlgorithm<Strategy>::rendersInDifferentPosition(const PositionType
&pos) const | 1042 bool PositionAlgorithm<Strategy>::rendersInDifferentPosition(const PositionAlgor
ithm<Strategy> &pos) const |
| 1043 { | 1043 { |
| 1044 if (isNull() || pos.isNull()) | 1044 if (isNull() || pos.isNull()) |
| 1045 return false; | 1045 return false; |
| 1046 | 1046 |
| 1047 LayoutObject* layoutObject = deprecatedNode()->layoutObject(); | 1047 LayoutObject* layoutObject = deprecatedNode()->layoutObject(); |
| 1048 if (!layoutObject) | 1048 if (!layoutObject) |
| 1049 return false; | 1049 return false; |
| 1050 | 1050 |
| 1051 LayoutObject* posLayoutObject = pos.deprecatedNode()->layoutObject(); | 1051 LayoutObject* posLayoutObject = pos.deprecatedNode()->layoutObject(); |
| 1052 if (!posLayoutObject) | 1052 if (!posLayoutObject) |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1160 minOffset = caretMinOffset; | 1160 minOffset = caretMinOffset; |
| 1161 } | 1161 } |
| 1162 } | 1162 } |
| 1163 if (match) | 1163 if (match) |
| 1164 return match; | 1164 return match; |
| 1165 } | 1165 } |
| 1166 } | 1166 } |
| 1167 return 0; | 1167 return 0; |
| 1168 } | 1168 } |
| 1169 | 1169 |
| 1170 template <typename PositionType> | 1170 template <typename Strategy> |
| 1171 PositionType downstreamIgnoringEditingBoundaries(PositionType position) | 1171 PositionAlgorithm<Strategy> downstreamIgnoringEditingBoundaries(PositionAlgorith
m<Strategy> position) |
| 1172 { | 1172 { |
| 1173 PositionType lastPosition; | 1173 PositionAlgorithm<Strategy> lastPosition; |
| 1174 while (position != lastPosition) { | 1174 while (position != lastPosition) { |
| 1175 lastPosition = position; | 1175 lastPosition = position; |
| 1176 position = position.downstream(CanCrossEditingBoundary); | 1176 position = position.downstream(CanCrossEditingBoundary); |
| 1177 } | 1177 } |
| 1178 return position; | 1178 return position; |
| 1179 } | 1179 } |
| 1180 | 1180 |
| 1181 template <typename PositionType> | 1181 template <typename Strategy> |
| 1182 PositionType upstreamIgnoringEditingBoundaries(PositionType position) | 1182 PositionAlgorithm<Strategy> upstreamIgnoringEditingBoundaries(PositionAlgorithm<
Strategy> position) |
| 1183 { | 1183 { |
| 1184 PositionType lastPosition; | 1184 PositionAlgorithm<Strategy> lastPosition; |
| 1185 while (position != lastPosition) { | 1185 while (position != lastPosition) { |
| 1186 lastPosition = position; | 1186 lastPosition = position; |
| 1187 position = position.upstream(CanCrossEditingBoundary); | 1187 position = position.upstream(CanCrossEditingBoundary); |
| 1188 } | 1188 } |
| 1189 return position; | 1189 return position; |
| 1190 } | 1190 } |
| 1191 | 1191 |
| 1192 template <typename Strategy> | 1192 template <typename Strategy> |
| 1193 void PositionAlgorithm<Strategy>::getInlineBoxAndOffset(EAffinity affinity, Text
Direction primaryDirection, InlineBox*& inlineBox, int& caretOffset) const | 1193 void PositionAlgorithm<Strategy>::getInlineBoxAndOffset(EAffinity affinity, Text
Direction primaryDirection, InlineBox*& inlineBox, int& caretOffset) const |
| 1194 { | 1194 { |
| 1195 caretOffset = deprecatedEditingOffset(); | 1195 caretOffset = deprecatedEditingOffset(); |
| 1196 LayoutObject* layoutObject = m_anchorNode->isShadowRoot() ? toShadowRoot(m_a
nchorNode)->host()->layoutObject() : m_anchorNode->layoutObject(); | 1196 LayoutObject* layoutObject = m_anchorNode->isShadowRoot() ? toShadowRoot(m_a
nchorNode)->host()->layoutObject() : m_anchorNode->layoutObject(); |
| 1197 | 1197 |
| 1198 if (!layoutObject->isText()) { | 1198 if (!layoutObject->isText()) { |
| 1199 inlineBox = 0; | 1199 inlineBox = 0; |
| 1200 if (canHaveChildrenForEditing(deprecatedNode()) && layoutObject->isLayou
tBlockFlow() && hasRenderedNonAnonymousDescendantsWithHeight(layoutObject)) { | 1200 if (canHaveChildrenForEditing(deprecatedNode()) && layoutObject->isLayou
tBlockFlow() && hasRenderedNonAnonymousDescendantsWithHeight(layoutObject)) { |
| 1201 // Try a visually equivalent position with possibly opposite editabi
lity. This helps in case |this| is in | 1201 // Try a visually equivalent position with possibly opposite editabi
lity. This helps in case |this| is in |
| 1202 // an editable block but surrounded by non-editable positions. It ac
ts to negate the logic at the beginning | 1202 // an editable block but surrounded by non-editable positions. It ac
ts to negate the logic at the beginning |
| 1203 // of LayoutObject::createVisiblePosition(). | 1203 // of LayoutObject::createVisiblePosition(). |
| 1204 PositionType thisPosition = PositionType(*this); | 1204 PositionAlgorithm<Strategy> thisPosition = PositionAlgorithm<Strateg
y>(*this); |
| 1205 PositionType equivalent = downstreamIgnoringEditingBoundaries<typena
me Strategy::PositionType>(thisPosition); | 1205 PositionAlgorithm<Strategy> equivalent = downstreamIgnoringEditingBo
undaries(thisPosition); |
| 1206 if (equivalent == thisPosition) { | 1206 if (equivalent == thisPosition) { |
| 1207 equivalent = upstreamIgnoringEditingBoundaries(thisPosition); | 1207 equivalent = upstreamIgnoringEditingBoundaries(thisPosition); |
| 1208 if (equivalent == thisPosition || downstreamIgnoringEditingBound
aries<typename Strategy::PositionType>(equivalent) == thisPosition) | 1208 if (equivalent == thisPosition || downstreamIgnoringEditingBound
aries(equivalent) == thisPosition) |
| 1209 return; | 1209 return; |
| 1210 } | 1210 } |
| 1211 | 1211 |
| 1212 equivalent.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineB
ox, caretOffset); | 1212 equivalent.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineB
ox, caretOffset); |
| 1213 return; | 1213 return; |
| 1214 } | 1214 } |
| 1215 if (layoutObject->isBox()) { | 1215 if (layoutObject->isBox()) { |
| 1216 inlineBox = toLayoutBox(layoutObject)->inlineBoxWrapper(); | 1216 inlineBox = toLayoutBox(layoutObject)->inlineBoxWrapper(); |
| 1217 if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && care
tOffset < inlineBox->caretMaxOffset())) | 1217 if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && care
tOffset < inlineBox->caretMaxOffset())) |
| 1218 return; | 1218 return; |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1539 | 1539 |
| 1540 void showTree(const blink::Position* pos) | 1540 void showTree(const blink::Position* pos) |
| 1541 { | 1541 { |
| 1542 if (pos) | 1542 if (pos) |
| 1543 pos->showTreeForThis(); | 1543 pos->showTreeForThis(); |
| 1544 else | 1544 else |
| 1545 fprintf(stderr, "Cannot showTree for (nil)\n"); | 1545 fprintf(stderr, "Cannot showTree for (nil)\n"); |
| 1546 } | 1546 } |
| 1547 | 1547 |
| 1548 #endif | 1548 #endif |
| OLD | NEW |