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 |