| 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 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 Position::Position(const Handle<Node>& anchorNode, AnchorType anchorType) | 91 Position::Position(const Handle<Node>& anchorNode, AnchorType anchorType) |
| 92 : m_anchorNode(anchorNode) | 92 : m_anchorNode(anchorNode) |
| 93 , m_offset(0) | 93 , m_offset(0) |
| 94 , m_anchorType(anchorType) | 94 , m_anchorType(anchorType) |
| 95 , m_isLegacyEditingPosition(false) | 95 , m_isLegacyEditingPosition(false) |
| 96 { | 96 { |
| 97 ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement()); | 97 ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement()); |
| 98 | 98 |
| 99 ASSERT(anchorType != PositionIsOffsetInAnchor); | 99 ASSERT(anchorType != PositionIsOffsetInAnchor); |
| 100 ASSERT(!((anchorType == PositionIsBeforeChildren || anchorType == PositionIs
AfterChildren) | 100 ASSERT(!((anchorType == PositionIsBeforeChildren || anchorType == PositionIs
AfterChildren) |
| 101 && (m_anchorNode->isTextNode() || editingIgnoresContent(m_anchorNod
e.raw())))); | 101 && (m_anchorNode->isTextNode() || editingIgnoresContent(m_anchorNod
e)))); |
| 102 } | 102 } |
| 103 | 103 |
| 104 Position::Position(const Handle<Node>& anchorNode, int offset, AnchorType anchor
Type) | 104 Position::Position(const Handle<Node>& anchorNode, int offset, AnchorType anchor
Type) |
| 105 : m_anchorNode(anchorNode) | 105 : m_anchorNode(anchorNode) |
| 106 , m_offset(offset) | 106 , m_offset(offset) |
| 107 , m_anchorType(anchorType) | 107 , m_anchorType(anchorType) |
| 108 , m_isLegacyEditingPosition(false) | 108 , m_isLegacyEditingPosition(false) |
| 109 { | 109 { |
| 110 ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement()); | 110 ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement()); |
| 111 | 111 |
| 112 ASSERT(anchorType == PositionIsOffsetInAnchor); | 112 ASSERT(anchorType == PositionIsOffsetInAnchor); |
| 113 } | 113 } |
| 114 | 114 |
| 115 Position::Position(const Handle<Text>& textNode, unsigned offset) | 115 Position::Position(const Handle<Text>& textNode, unsigned offset) |
| 116 : m_anchorNode(textNode) | 116 : m_anchorNode(textNode) |
| 117 , m_offset(static_cast<int>(offset)) | 117 , m_offset(static_cast<int>(offset)) |
| 118 , m_anchorType(PositionIsOffsetInAnchor) | 118 , m_anchorType(PositionIsOffsetInAnchor) |
| 119 , m_isLegacyEditingPosition(false) | 119 , m_isLegacyEditingPosition(false) |
| 120 { | 120 { |
| 121 ASSERT(m_anchorNode); | 121 ASSERT(m_anchorNode); |
| 122 } | 122 } |
| 123 | 123 |
| 124 void Position::moveToPosition(const Handle<Node>& node, int offset) | 124 void Position::moveToPosition(const Handle<Node>& node, int offset) |
| 125 { | 125 { |
| 126 ASSERT(!editingIgnoresContent(node.raw())); | 126 ASSERT(!editingIgnoresContent(node)); |
| 127 ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition
); | 127 ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition
); |
| 128 m_anchorNode = node; | 128 m_anchorNode = node; |
| 129 m_offset = offset; | 129 m_offset = offset; |
| 130 if (m_isLegacyEditingPosition) | 130 if (m_isLegacyEditingPosition) |
| 131 m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode, m_offset
); | 131 m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode, m_offset
); |
| 132 } | 132 } |
| 133 void Position::moveToOffset(int offset) | 133 void Position::moveToOffset(int offset) |
| 134 { | 134 { |
| 135 ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition
); | 135 ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition
); |
| 136 m_offset = offset; | 136 m_offset = offset; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 return m_anchorNode->nodeIndex() + 1; | 191 return m_anchorNode->nodeIndex() + 1; |
| 192 } | 192 } |
| 193 ASSERT_NOT_REACHED(); | 193 ASSERT_NOT_REACHED(); |
| 194 return 0; | 194 return 0; |
| 195 } | 195 } |
| 196 | 196 |
| 197 int Position::offsetForPositionAfterAnchor() const | 197 int Position::offsetForPositionAfterAnchor() const |
| 198 { | 198 { |
| 199 ASSERT(m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAf
terChildren); | 199 ASSERT(m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAf
terChildren); |
| 200 ASSERT(!m_isLegacyEditingPosition); | 200 ASSERT(!m_isLegacyEditingPosition); |
| 201 return lastOffsetForEditing(m_anchorNode.raw()); | 201 return lastOffsetForEditing(m_anchorNode); |
| 202 } | 202 } |
| 203 | 203 |
| 204 // Neighbor-anchored positions are invalid DOM positions, so they need to be | 204 // Neighbor-anchored positions are invalid DOM positions, so they need to be |
| 205 // fixed up before handing them off to the Range object. | 205 // fixed up before handing them off to the Range object. |
| 206 Position Position::parentAnchoredEquivalent() const | 206 Position Position::parentAnchoredEquivalent() const |
| 207 { | 207 { |
| 208 if (!m_anchorNode) | 208 if (!m_anchorNode) |
| 209 return Position(); | 209 return Position(); |
| 210 | 210 |
| 211 // FIXME: This should only be necessary for legacy positions, but is also ne
eded for positions before and after Tables | 211 // FIXME: This should only be necessary for legacy positions, but is also ne
eded for positions before and after Tables |
| 212 if (m_offset <= 0 && (m_anchorType != PositionIsAfterAnchor && m_anchorType
!= PositionIsAfterChildren)) { | 212 if (m_offset <= 0 && (m_anchorType != PositionIsAfterAnchor && m_anchorType
!= PositionIsAfterChildren)) { |
| 213 if (findParent(m_anchorNode) && (editingIgnoresContent(m_anchorNode.raw(
)) || isTableElement(m_anchorNode.raw()))) | 213 if (findParent(m_anchorNode) && (editingIgnoresContent(m_anchorNode) ||
isTableElement(m_anchorNode))) |
| 214 return positionInParentBeforeNode(m_anchorNode); | 214 return positionInParentBeforeNode(m_anchorNode); |
| 215 return Position(m_anchorNode, 0, PositionIsOffsetInAnchor); | 215 return Position(m_anchorNode, 0, PositionIsOffsetInAnchor); |
| 216 } | 216 } |
| 217 if (!m_anchorNode->offsetInCharacters() | 217 if (!m_anchorNode->offsetInCharacters() |
| 218 && (m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsA
fterChildren || static_cast<unsigned>(m_offset) == m_anchorNode->childNodeCount(
)) | 218 && (m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsA
fterChildren || static_cast<unsigned>(m_offset) == m_anchorNode->childNodeCount(
)) |
| 219 && (editingIgnoresContent(m_anchorNode.raw()) || isTableElement(m_anchor
Node.raw())) | 219 && (editingIgnoresContent(m_anchorNode) || isTableElement(m_anchorNode)) |
| 220 && containerNode()) { | 220 && containerNode()) { |
| 221 return positionInParentAfterNode(m_anchorNode); | 221 return positionInParentAfterNode(m_anchorNode); |
| 222 } | 222 } |
| 223 | 223 |
| 224 return Position(containerNode(), computeOffsetInContainerNode(), PositionIsO
ffsetInAnchor); | 224 return Position(containerNode(), computeOffsetInContainerNode(), PositionIsO
ffsetInAnchor); |
| 225 } | 225 } |
| 226 | 226 |
| 227 Result<Node> Position::computeNodeBeforePosition() const | 227 Result<Node> Position::computeNodeBeforePosition() const |
| 228 { | 228 { |
| 229 if (!m_anchorNode) | 229 if (!m_anchorNode) |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 return m_anchorNode; | 261 return m_anchorNode; |
| 262 case PositionIsAfterAnchor: | 262 case PositionIsAfterAnchor: |
| 263 return m_anchorNode->nextSibling(); | 263 return m_anchorNode->nextSibling(); |
| 264 } | 264 } |
| 265 ASSERT_NOT_REACHED(); | 265 ASSERT_NOT_REACHED(); |
| 266 return nullptr; | 266 return nullptr; |
| 267 } | 267 } |
| 268 | 268 |
| 269 Position::AnchorType Position::anchorTypeForLegacyEditingPosition(const Handle<N
ode>& anchorNode, int offset) | 269 Position::AnchorType Position::anchorTypeForLegacyEditingPosition(const Handle<N
ode>& anchorNode, int offset) |
| 270 { | 270 { |
| 271 if (anchorNode && editingIgnoresContent(anchorNode.raw())) { | 271 if (anchorNode && editingIgnoresContent(anchorNode)) { |
| 272 if (offset == 0) | 272 if (offset == 0) |
| 273 return Position::PositionIsBeforeAnchor; | 273 return Position::PositionIsBeforeAnchor; |
| 274 return Position::PositionIsAfterAnchor; | 274 return Position::PositionIsAfterAnchor; |
| 275 } | 275 } |
| 276 return Position::PositionIsOffsetInAnchor; | 276 return Position::PositionIsOffsetInAnchor; |
| 277 } | 277 } |
| 278 | 278 |
| 279 // FIXME: This method is confusing (does it return anchorNode() or containerNode
()?) and should be renamed or removed | 279 // FIXME: This method is confusing (does it return anchorNode() or containerNode
()?) and should be renamed or removed |
| 280 Result<Element> Position::element() const | 280 Result<Element> Position::element() const |
| 281 { | 281 { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 301 if (!n) | 301 if (!n) |
| 302 return *this; | 302 return *this; |
| 303 | 303 |
| 304 int o = deprecatedEditingOffset(); | 304 int o = deprecatedEditingOffset(); |
| 305 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlie
r. | 305 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlie
r. |
| 306 ASSERT(o >= 0); | 306 ASSERT(o >= 0); |
| 307 | 307 |
| 308 if (o > 0) { | 308 if (o > 0) { |
| 309 Handle<Node> child = n->childNode(o - 1); | 309 Handle<Node> child = n->childNode(o - 1); |
| 310 if (child) | 310 if (child) |
| 311 return lastPositionInOrAfterNode(child.raw()); | 311 return lastPositionInOrAfterNode(child); |
| 312 | 312 |
| 313 // There are two reasons child might be 0: | 313 // There are two reasons child might be 0: |
| 314 // 1) The node is node like a text node that is not an element, and th
erefore has no children. | 314 // 1) The node is node like a text node that is not an element, and th
erefore has no children. |
| 315 // Going backward one character at a time is correct. | 315 // Going backward one character at a time is correct. |
| 316 // 2) The old offset was a bogus offset like (<br>, 1), and there is n
o child. | 316 // 2) The old offset was a bogus offset like (<br>, 1), and there is n
o child. |
| 317 // Going from 1 to 0 is correct. | 317 // Going from 1 to 0 is correct. |
| 318 switch (moveType) { | 318 switch (moveType) { |
| 319 case CodePoint: | 319 case CodePoint: |
| 320 return createLegacyEditingPosition(n, o - 1); | 320 return createLegacyEditingPosition(n, o - 1); |
| 321 case Character: | 321 case Character: |
| (...skipping 16 matching lines...) Expand all Loading... |
| 338 | 338 |
| 339 Handle<Node> n = deprecatedNode(); | 339 Handle<Node> n = deprecatedNode(); |
| 340 if (!n) | 340 if (!n) |
| 341 return *this; | 341 return *this; |
| 342 | 342 |
| 343 int o = deprecatedEditingOffset(); | 343 int o = deprecatedEditingOffset(); |
| 344 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlie
r. | 344 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlie
r. |
| 345 ASSERT(o >= 0); | 345 ASSERT(o >= 0); |
| 346 | 346 |
| 347 Handle<Node> child = n->childNode(o); | 347 Handle<Node> child = n->childNode(o); |
| 348 if (child || (!n->hasChildNodes() && o < lastOffsetForEditing(n.raw()))) { | 348 if (child || (!n->hasChildNodes() && o < lastOffsetForEditing(n))) { |
| 349 if (child) | 349 if (child) |
| 350 return firstPositionInOrBeforeNode(child.raw()); | 350 return firstPositionInOrBeforeNode(child); |
| 351 | 351 |
| 352 // There are two reasons child might be 0: | 352 // There are two reasons child might be 0: |
| 353 // 1) The node is node like a text node that is not an element, and th
erefore has no children. | 353 // 1) The node is node like a text node that is not an element, and th
erefore has no children. |
| 354 // Going forward one character at a time is correct. | 354 // Going forward one character at a time is correct. |
| 355 // 2) The new offset is a bogus offset like (<br>, 1), and there is no
child. | 355 // 2) The new offset is a bogus offset like (<br>, 1), and there is no
child. |
| 356 // Going from 0 to 1 is correct. | 356 // Going from 0 to 1 is correct. |
| 357 return createLegacyEditingPosition(n, (moveType == Character) ? unchecke
dNextOffset(n, o) : o + 1); | 357 return createLegacyEditingPosition(n, (moveType == Character) ? unchecke
dNextOffset(n, o) : o + 1); |
| 358 } | 358 } |
| 359 | 359 |
| 360 Handle<ContainerNode> parent = findParent(n); | 360 Handle<ContainerNode> parent = findParent(n); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 386 // FIXME: Position before anchor shouldn't be considered as at the first edi
ting position for node | 386 // FIXME: Position before anchor shouldn't be considered as at the first edi
ting position for node |
| 387 // since that position resides outside of the node. | 387 // since that position resides outside of the node. |
| 388 switch (m_anchorType) { | 388 switch (m_anchorType) { |
| 389 case PositionIsOffsetInAnchor: | 389 case PositionIsOffsetInAnchor: |
| 390 return m_offset <= 0; | 390 return m_offset <= 0; |
| 391 case PositionIsBeforeChildren: | 391 case PositionIsBeforeChildren: |
| 392 case PositionIsBeforeAnchor: | 392 case PositionIsBeforeAnchor: |
| 393 return true; | 393 return true; |
| 394 case PositionIsAfterChildren: | 394 case PositionIsAfterChildren: |
| 395 case PositionIsAfterAnchor: | 395 case PositionIsAfterAnchor: |
| 396 return !lastOffsetForEditing(deprecatedNode().handle().raw()); | 396 return !lastOffsetForEditing(deprecatedNode()); |
| 397 } | 397 } |
| 398 ASSERT_NOT_REACHED(); | 398 ASSERT_NOT_REACHED(); |
| 399 return false; | 399 return false; |
| 400 } | 400 } |
| 401 | 401 |
| 402 bool Position::atLastEditingPositionForNode() const | 402 bool Position::atLastEditingPositionForNode() const |
| 403 { | 403 { |
| 404 if (isNull()) | 404 if (isNull()) |
| 405 return true; | 405 return true; |
| 406 // FIXME: Position after anchor shouldn't be considered as at the first edit
ing position for node | 406 // FIXME: Position after anchor shouldn't be considered as at the first edit
ing position for node |
| 407 // since that position resides outside of the node. | 407 // since that position resides outside of the node. |
| 408 return m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAf
terChildren || m_offset >= lastOffsetForEditing(deprecatedNode().handle().raw())
; | 408 return m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAf
terChildren || m_offset >= lastOffsetForEditing(deprecatedNode()); |
| 409 } | 409 } |
| 410 | 410 |
| 411 // A position is considered at editing boundary if one of the following is true: | 411 // A position is considered at editing boundary if one of the following is true: |
| 412 // 1. It is the first position in the node and the next visually equivalent posi
tion | 412 // 1. It is the first position in the node and the next visually equivalent posi
tion |
| 413 // is non editable. | 413 // is non editable. |
| 414 // 2. It is the last position in the node and the previous visually equivalent p
osition | 414 // 2. It is the last position in the node and the previous visually equivalent p
osition |
| 415 // is non editable. | 415 // is non editable. |
| 416 // 3. It is an editable position and both the next and previous visually equival
ent | 416 // 3. It is an editable position and both the next and previous visually equival
ent |
| 417 // positions are both non editable. | 417 // positions are both non editable. |
| 418 bool Position::atEditingBoundary() const | 418 bool Position::atEditingBoundary() const |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 454 if (isNull()) | 454 if (isNull()) |
| 455 return true; | 455 return true; |
| 456 return !findParent(deprecatedNode()) && m_offset <= 0; | 456 return !findParent(deprecatedNode()) && m_offset <= 0; |
| 457 } | 457 } |
| 458 | 458 |
| 459 bool Position::atEndOfTree() const | 459 bool Position::atEndOfTree() const |
| 460 { | 460 { |
| 461 HandleScope scope; | 461 HandleScope scope; |
| 462 if (isNull()) | 462 if (isNull()) |
| 463 return true; | 463 return true; |
| 464 return !findParent(deprecatedNode()) && m_offset >= lastOffsetForEditing(dep
recatedNode().handle().raw()); | 464 return !findParent(deprecatedNode()) && m_offset >= lastOffsetForEditing(dep
recatedNode()); |
| 465 } | 465 } |
| 466 | 466 |
| 467 int Position::renderedOffset() const | 467 int Position::renderedOffset() const |
| 468 { | 468 { |
| 469 if (!deprecatedNode()->isTextNode()) | 469 if (!deprecatedNode()->isTextNode()) |
| 470 return m_offset; | 470 return m_offset; |
| 471 | 471 |
| 472 if (!deprecatedNode()->renderer()) | 472 if (!deprecatedNode()->renderer()) |
| 473 return m_offset; | 473 return m_offset; |
| 474 | 474 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 555 return false; | 555 return false; |
| 556 | 556 |
| 557 if (!node->renderer()->isInline()) | 557 if (!node->renderer()->isInline()) |
| 558 return true; | 558 return true; |
| 559 | 559 |
| 560 // Don't include inline tables. | 560 // Don't include inline tables. |
| 561 if (node->hasTagName(tableTag)) | 561 if (node->hasTagName(tableTag)) |
| 562 return false; | 562 return false; |
| 563 | 563 |
| 564 // There is a VisiblePosition inside an empty inline-block container. | 564 // There is a VisiblePosition inside an empty inline-block container. |
| 565 return node->renderer()->isReplaced() && canHaveChildrenForEditing(node.raw(
)) && toRenderBox(node->renderer())->height() != 0 && !node->firstChild(); | 565 return node->renderer()->isReplaced() && canHaveChildrenForEditing(node) &&
toRenderBox(node->renderer())->height() != 0 && !node->firstChild(); |
| 566 } | 566 } |
| 567 | 567 |
| 568 static Result<Node> enclosingVisualBoundary(const Handle<Node>& node) | 568 static Result<Node> enclosingVisualBoundary(const Handle<Node>& node) |
| 569 { | 569 { |
| 570 Handle<Node> current = node; | 570 Handle<Node> current = node; |
| 571 NoHandleScope scope; | 571 NoHandleScope scope; |
| 572 while (current && !endsOfNodeAreVisuallyDistinctPositions(current)) { | 572 while (current && !endsOfNodeAreVisuallyDistinctPositions(current)) { |
| 573 current = current->parentNode(); | 573 current = current->parentNode(); |
| 574 } | 574 } |
| 575 | 575 |
| 576 return current; | 576 return current; |
| 577 } | 577 } |
| 578 | 578 |
| 579 // upstream() and downstream() want to return positions that are either in a | 579 // upstream() and downstream() want to return positions that are either in a |
| 580 // text node or at just before a non-text node. This method checks for that. | 580 // text node or at just before a non-text node. This method checks for that. |
| 581 static bool isStreamer(const PositionIterator& pos) | 581 static bool isStreamer(const PositionIterator& pos) |
| 582 { | 582 { |
| 583 if (!pos.node()) | 583 if (!pos.node()) |
| 584 return true; | 584 return true; |
| 585 | 585 |
| 586 if (isAtomicNode(pos.node().handle().raw())) | 586 if (isAtomicNode(pos.node())) |
| 587 return true; | 587 return true; |
| 588 | 588 |
| 589 return pos.atStartOfNode(); | 589 return pos.atStartOfNode(); |
| 590 } | 590 } |
| 591 | 591 |
| 592 // This function and downstream() are used for moving back and forth between vis
ually equivalent candidates. | 592 // This function and downstream() are used for moving back and forth between vis
ually equivalent candidates. |
| 593 // For example, for the text node "foo bar" where whitespace is collapsible,
there are two candidates | 593 // For example, for the text node "foo bar" where whitespace is collapsible,
there are two candidates |
| 594 // that map to the VisiblePosition between 'b' and the space. This function wil
l return the left candidate | 594 // that map to the VisiblePosition between 'b' and the space. This function wil
l return the left candidate |
| 595 // and downstream() will return the right one. | 595 // and downstream() will return the right one. |
| 596 // Also, upstream() will return [boundary, 0] for any of the positions from [bou
ndary, 0] to the first candidate | 596 // Also, upstream() will return [boundary, 0] for any of the positions from [bou
ndary, 0] to the first candidate |
| 597 // in boundary, where endsOfNodeAreVisuallyDistinctPositions(boundary) is true. | 597 // in boundary, where endsOfNodeAreVisuallyDistinctPositions(boundary) is true. |
| 598 Position Position::upstream(EditingBoundaryCrossingRule rule) const | 598 Position Position::upstream(EditingBoundaryCrossingRule rule) const |
| 599 { | 599 { |
| 600 HandleScope scope; | 600 HandleScope scope; |
| 601 Handle<Node> startNode = deprecatedNode(); | 601 Handle<Node> startNode = deprecatedNode(); |
| 602 if (!startNode) | 602 if (!startNode) |
| 603 return Position(); | 603 return Position(); |
| 604 | 604 |
| 605 // iterate backward from there, looking for a qualified position | 605 // iterate backward from there, looking for a qualified position |
| 606 Handle<Node> boundary = enclosingVisualBoundary(startNode); | 606 Handle<Node> boundary = enclosingVisualBoundary(startNode); |
| 607 // FIXME: PositionIterator should respect Before and After positions. | 607 // FIXME: PositionIterator should respect Before and After positions. |
| 608 PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? creat
eLegacyEditingPosition(m_anchorNode, caretMaxOffset(m_anchorNode.raw())) : *this
; | 608 PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? creat
eLegacyEditingPosition(m_anchorNode, caretMaxOffset(m_anchorNode)) : *this; |
| 609 PositionIterator currentPos = lastVisible; | 609 PositionIterator currentPos = lastVisible; |
| 610 bool startEditable = startNode->rendererIsEditable(); | 610 bool startEditable = startNode->rendererIsEditable(); |
| 611 Handle<Node> lastNode = startNode; | 611 Handle<Node> lastNode = startNode; |
| 612 bool boundaryCrossed = false; | 612 bool boundaryCrossed = false; |
| 613 Handle<Node> currentNode; | 613 Handle<Node> currentNode; |
| 614 for (; !currentPos.atStart(); currentPos.decrement()) { | 614 for (; !currentPos.atStart(); currentPos.decrement()) { |
| 615 HandleScope scope; | 615 HandleScope scope; |
| 616 currentNode = currentPos.node(); | 616 currentNode = currentPos.node(); |
| 617 | 617 |
| 618 // Don't check for an editability change if we haven't moved to a differ
ent node, | 618 // Don't check for an editability change if we haven't moved to a differ
ent node, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 646 // track last visible streamer position | 646 // track last visible streamer position |
| 647 if (isStreamer(currentPos)) | 647 if (isStreamer(currentPos)) |
| 648 lastVisible = currentPos; | 648 lastVisible = currentPos; |
| 649 | 649 |
| 650 // Don't move past a position that is visually distinct. We could rely
on code above to terminate and | 650 // Don't move past a position that is visually distinct. We could rely
on code above to terminate and |
| 651 // return lastVisible on the next iteration, but we terminate early to a
void doing a nodeIndex() call. | 651 // return lastVisible on the next iteration, but we terminate early to a
void doing a nodeIndex() call. |
| 652 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentPos.at
StartOfNode()) | 652 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentPos.at
StartOfNode()) |
| 653 return lastVisible; | 653 return lastVisible; |
| 654 | 654 |
| 655 // Return position after tables and nodes which have content that can be
ignored. | 655 // Return position after tables and nodes which have content that can be
ignored. |
| 656 if (editingIgnoresContent(currentNode.raw()) || isTableElement(currentNo
de.raw())) { | 656 if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) { |
| 657 if (currentPos.atEndOfNode()) | 657 if (currentPos.atEndOfNode()) |
| 658 return positionAfterNode(currentNode); | 658 return positionAfterNode(currentNode); |
| 659 continue; | 659 continue; |
| 660 } | 660 } |
| 661 | 661 |
| 662 // return current position if it is in rendered text | 662 // return current position if it is in rendered text |
| 663 if (renderer->isText() && toRenderText(renderer)->firstTextBox()) { | 663 if (renderer->isText() && toRenderText(renderer)->firstTextBox()) { |
| 664 if (currentNode != startNode) { | 664 if (currentNode != startNode) { |
| 665 // This assertion fires in layout tests in the case-transform.ht
ml test because | 665 // This assertion fires in layout tests in the case-transform.ht
ml test because |
| 666 // of a mix-up between offsets in the text in the DOM tree with
text in the | 666 // of a mix-up between offsets in the text in the DOM tree with
text in the |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 724 Position Position::downstream(EditingBoundaryCrossingRule rule) const | 724 Position Position::downstream(EditingBoundaryCrossingRule rule) const |
| 725 { | 725 { |
| 726 HandleScope scope; | 726 HandleScope scope; |
| 727 Handle<Node> startNode = deprecatedNode(); | 727 Handle<Node> startNode = deprecatedNode(); |
| 728 if (!startNode) | 728 if (!startNode) |
| 729 return Position(); | 729 return Position(); |
| 730 | 730 |
| 731 // iterate forward from there, looking for a qualified position | 731 // iterate forward from there, looking for a qualified position |
| 732 Handle<Node> boundary = enclosingVisualBoundary(startNode); | 732 Handle<Node> boundary = enclosingVisualBoundary(startNode); |
| 733 // FIXME: PositionIterator should respect Before and After positions. | 733 // FIXME: PositionIterator should respect Before and After positions. |
| 734 PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? creat
eLegacyEditingPosition(m_anchorNode, caretMaxOffset(m_anchorNode.raw())) : *this
; | 734 PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? creat
eLegacyEditingPosition(m_anchorNode, caretMaxOffset(m_anchorNode)) : *this; |
| 735 PositionIterator currentPos = lastVisible; | 735 PositionIterator currentPos = lastVisible; |
| 736 bool startEditable = startNode->rendererIsEditable(); | 736 bool startEditable = startNode->rendererIsEditable(); |
| 737 Handle<Node> lastNode = startNode; | 737 Handle<Node> lastNode = startNode; |
| 738 bool boundaryCrossed = false; | 738 bool boundaryCrossed = false; |
| 739 Handle<Node> currentNode; | 739 Handle<Node> currentNode; |
| 740 for (; !currentPos.atEnd(); currentPos.increment()) { | 740 for (; !currentPos.atEnd(); currentPos.increment()) { |
| 741 HandleScope scope; | 741 HandleScope scope; |
| 742 currentNode = currentPos.node(); | 742 currentNode = currentPos.node(); |
| 743 | 743 |
| 744 // Don't check for an editability change if we haven't moved to a differ
ent node, | 744 // Don't check for an editability change if we haven't moved to a differ
ent node, |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 777 if (rule == CanCrossEditingBoundary && boundaryCrossed) { | 777 if (rule == CanCrossEditingBoundary && boundaryCrossed) { |
| 778 lastVisible = currentPos; | 778 lastVisible = currentPos; |
| 779 break; | 779 break; |
| 780 } | 780 } |
| 781 | 781 |
| 782 // track last visible streamer position | 782 // track last visible streamer position |
| 783 if (isStreamer(currentPos)) | 783 if (isStreamer(currentPos)) |
| 784 lastVisible = currentPos; | 784 lastVisible = currentPos; |
| 785 | 785 |
| 786 // Return position before tables and nodes which have content that can b
e ignored. | 786 // Return position before tables and nodes which have content that can b
e ignored. |
| 787 if (editingIgnoresContent(currentNode.raw()) || isTableElement(currentNo
de.raw())) { | 787 if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) { |
| 788 if (currentPos.offsetInLeafNode() <= renderer->caretMinOffset()) | 788 if (currentPos.offsetInLeafNode() <= renderer->caretMinOffset()) |
| 789 return createLegacyEditingPosition(currentNode, renderer->caretM
inOffset()); | 789 return createLegacyEditingPosition(currentNode, renderer->caretM
inOffset()); |
| 790 continue; | 790 continue; |
| 791 } | 791 } |
| 792 | 792 |
| 793 // return current position if it is in rendered text | 793 // return current position if it is in rendered text |
| 794 if (renderer->isText() && toRenderText(renderer)->firstTextBox()) { | 794 if (renderer->isText() && toRenderText(renderer)->firstTextBox()) { |
| 795 if (currentNode != startNode) { | 795 if (currentNode != startNode) { |
| 796 ASSERT(currentPos.atStartOfNode()); | 796 ASSERT(currentPos.atStartOfNode()); |
| 797 return createLegacyEditingPosition(currentNode, renderer->caretM
inOffset()); | 797 return createLegacyEditingPosition(currentNode, renderer->caretM
inOffset()); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 912 if (renderer->style()->visibility() != VISIBLE) | 912 if (renderer->style()->visibility() != VISIBLE) |
| 913 return false; | 913 return false; |
| 914 | 914 |
| 915 if (renderer->isBR()) | 915 if (renderer->isBR()) |
| 916 // FIXME: The condition should be m_anchorType == PositionIsBeforeAnchor
, but for now we still need to support legacy positions. | 916 // FIXME: The condition should be m_anchorType == PositionIsBeforeAnchor
, but for now we still need to support legacy positions. |
| 917 return !m_offset && m_anchorType != PositionIsAfterAnchor && !nodeIsUser
SelectNone(deprecatedNode()->parentNode()); | 917 return !m_offset && m_anchorType != PositionIsAfterAnchor && !nodeIsUser
SelectNone(deprecatedNode()->parentNode()); |
| 918 | 918 |
| 919 if (renderer->isText()) | 919 if (renderer->isText()) |
| 920 return !nodeIsUserSelectNone(deprecatedNode()) && inRenderedText(); | 920 return !nodeIsUserSelectNone(deprecatedNode()) && inRenderedText(); |
| 921 | 921 |
| 922 if (isTableElement(deprecatedNode().handle().raw()) || editingIgnoresContent
(deprecatedNode().handle().raw())) | 922 if (isTableElement(deprecatedNode()) || editingIgnoresContent(deprecatedNode
())) |
| 923 return (atFirstEditingPositionForNode() || atLastEditingPositionForNode(
)) && !nodeIsUserSelectNone(deprecatedNode()->parentNode()); | 923 return (atFirstEditingPositionForNode() || atLastEditingPositionForNode(
)) && !nodeIsUserSelectNone(deprecatedNode()->parentNode()); |
| 924 | 924 |
| 925 if (m_anchorNode->hasTagName(htmlTag)) | 925 if (m_anchorNode->hasTagName(htmlTag)) |
| 926 return false; | 926 return false; |
| 927 | 927 |
| 928 if (renderer->isBlockFlow()) { | 928 if (renderer->isBlockFlow()) { |
| 929 if (toRenderBlock(renderer)->logicalHeight() || m_anchorNode->hasTagName
(bodyTag)) { | 929 if (toRenderBlock(renderer)->logicalHeight() || m_anchorNode->hasTagName
(bodyTag)) { |
| 930 if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer
)) | 930 if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer
)) |
| 931 return atFirstEditingPositionForNode() && !Position::nodeIsUserS
electNone(deprecatedNode()); | 931 return atFirstEditingPositionForNode() && !Position::nodeIsUserS
electNone(deprecatedNode()); |
| 932 return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSe
lectNone(deprecatedNode()) && atEditingBoundary(); | 932 return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSe
lectNone(deprecatedNode()) && atEditingBoundary(); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1040 int ignoredCaretOffset; | 1040 int ignoredCaretOffset; |
| 1041 InlineBox* b1; | 1041 InlineBox* b1; |
| 1042 getInlineBoxAndOffset(DOWNSTREAM, b1, ignoredCaretOffset); | 1042 getInlineBoxAndOffset(DOWNSTREAM, b1, ignoredCaretOffset); |
| 1043 InlineBox* b2; | 1043 InlineBox* b2; |
| 1044 pos.getInlineBoxAndOffset(DOWNSTREAM, b2, ignoredCaretOffset); | 1044 pos.getInlineBoxAndOffset(DOWNSTREAM, b2, ignoredCaretOffset); |
| 1045 | 1045 |
| 1046 LOG(Editing, "renderer: %p [%p]\n", renderer, b1); | 1046 LOG(Editing, "renderer: %p [%p]\n", renderer, b1); |
| 1047 LOG(Editing, "thisRenderedOffset: %d\n", thisRenderedOffset); | 1047 LOG(Editing, "thisRenderedOffset: %d\n", thisRenderedOffset); |
| 1048 LOG(Editing, "posRenderer: %p [%p]\n", posRenderer, b2); | 1048 LOG(Editing, "posRenderer: %p [%p]\n", posRenderer, b2); |
| 1049 LOG(Editing, "posRenderedOffset: %d\n", posRenderedOffset); | 1049 LOG(Editing, "posRenderedOffset: %d\n", posRenderedOffset); |
| 1050 LOG(Editing, "node min/max: %d:%d\n", caretMinOffset(deprecatedNod
e().handle().raw()), caretMaxOffset(deprecatedNode().handle().raw())); | 1050 LOG(Editing, "node min/max: %d:%d\n", caretMinOffset(deprecatedNod
e()), caretMaxOffset(deprecatedNode())); |
| 1051 LOG(Editing, "pos node min/max: %d:%d\n", caretMinOffset(pos.deprecate
dNode().handle().raw()), caretMaxOffset(pos.deprecatedNode().handle().raw())); | 1051 LOG(Editing, "pos node min/max: %d:%d\n", caretMinOffset(pos.deprecate
dNode()), caretMaxOffset(pos.deprecatedNode())); |
| 1052 LOG(Editing, "--------------------------------------------------------------
--------\n"); | 1052 LOG(Editing, "--------------------------------------------------------------
--------\n"); |
| 1053 | 1053 |
| 1054 if (!b1 || !b2) { | 1054 if (!b1 || !b2) { |
| 1055 return false; | 1055 return false; |
| 1056 } | 1056 } |
| 1057 | 1057 |
| 1058 if (b1->root() != b2->root()) { | 1058 if (b1->root() != b2->root()) { |
| 1059 return true; | 1059 return true; |
| 1060 } | 1060 } |
| 1061 | 1061 |
| 1062 if (nextRenderedEditable(deprecatedNode()) == pos.deprecatedNode() | 1062 if (nextRenderedEditable(deprecatedNode()) == pos.deprecatedNode() |
| 1063 && thisRenderedOffset == caretMaxOffset(deprecatedNode().handle().raw())
&& !posRenderedOffset) { | 1063 && thisRenderedOffset == caretMaxOffset(deprecatedNode()) && !posRendere
dOffset) { |
| 1064 return false; | 1064 return false; |
| 1065 } | 1065 } |
| 1066 | 1066 |
| 1067 if (previousRenderedEditable(deprecatedNode()) == pos.deprecatedNode() | 1067 if (previousRenderedEditable(deprecatedNode()) == pos.deprecatedNode() |
| 1068 && !thisRenderedOffset && posRenderedOffset == caretMaxOffset(pos.deprec
atedNode().handle().raw())) { | 1068 && !thisRenderedOffset && posRenderedOffset == caretMaxOffset(pos.deprec
atedNode())) { |
| 1069 return false; | 1069 return false; |
| 1070 } | 1070 } |
| 1071 | 1071 |
| 1072 return true; | 1072 return true; |
| 1073 } | 1073 } |
| 1074 | 1074 |
| 1075 // This assumes that it starts in editable content. | 1075 // This assumes that it starts in editable content. |
| 1076 Position Position::leadingWhitespacePosition(EAffinity affinity, bool considerNo
nCollapsibleWhitespace) const | 1076 Position Position::leadingWhitespacePosition(EAffinity affinity, bool considerNo
nCollapsibleWhitespace) const |
| 1077 { | 1077 { |
| 1078 ASSERT(isEditablePosition(*this)); | 1078 ASSERT(isEditablePosition(*this)); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1173 return position; | 1173 return position; |
| 1174 } | 1174 } |
| 1175 | 1175 |
| 1176 void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDi
rection, InlineBox*& inlineBox, int& caretOffset) const | 1176 void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDi
rection, InlineBox*& inlineBox, int& caretOffset) const |
| 1177 { | 1177 { |
| 1178 caretOffset = deprecatedEditingOffset(); | 1178 caretOffset = deprecatedEditingOffset(); |
| 1179 RenderObject* renderer = deprecatedNode()->renderer(); | 1179 RenderObject* renderer = deprecatedNode()->renderer(); |
| 1180 | 1180 |
| 1181 if (!renderer->isText()) { | 1181 if (!renderer->isText()) { |
| 1182 inlineBox = 0; | 1182 inlineBox = 0; |
| 1183 if (canHaveChildrenForEditing(deprecatedNode().handle().raw()) && render
er->isBlockFlow() && hasRenderedNonAnonymousDescendantsWithHeight(renderer)) { | 1183 if (canHaveChildrenForEditing(deprecatedNode()) && renderer->isBlockFlow
() && hasRenderedNonAnonymousDescendantsWithHeight(renderer)) { |
| 1184 // Try a visually equivalent position with possibly opposite editabi
lity. This helps in case |this| is in | 1184 // Try a visually equivalent position with possibly opposite editabi
lity. This helps in case |this| is in |
| 1185 // an editable block but surrounded by non-editable positions. It ac
ts to negate the logic at the beginning | 1185 // an editable block but surrounded by non-editable positions. It ac
ts to negate the logic at the beginning |
| 1186 // of RenderObject::createVisiblePosition(). | 1186 // of RenderObject::createVisiblePosition(). |
| 1187 Position equivalent = downstreamIgnoringEditingBoundaries(*this); | 1187 Position equivalent = downstreamIgnoringEditingBoundaries(*this); |
| 1188 if (equivalent == *this) { | 1188 if (equivalent == *this) { |
| 1189 equivalent = upstreamIgnoringEditingBoundaries(*this); | 1189 equivalent = upstreamIgnoringEditingBoundaries(*this); |
| 1190 if (equivalent == *this || downstreamIgnoringEditingBoundaries(e
quivalent) == *this) | 1190 if (equivalent == *this || downstreamIgnoringEditingBoundaries(e
quivalent) == *this) |
| 1191 return; | 1191 return; |
| 1192 } | 1192 } |
| 1193 | 1193 |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1411 pos.showTreeForThis(); | 1411 pos.showTreeForThis(); |
| 1412 } | 1412 } |
| 1413 | 1413 |
| 1414 void showTree(const WebCore::Position* pos) | 1414 void showTree(const WebCore::Position* pos) |
| 1415 { | 1415 { |
| 1416 if (pos) | 1416 if (pos) |
| 1417 pos->showTreeForThis(); | 1417 pos->showTreeForThis(); |
| 1418 } | 1418 } |
| 1419 | 1419 |
| 1420 #endif | 1420 #endif |
| OLD | NEW |