OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. | 2 * Copyright (C) 2004, 2005, 2006, 2007 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 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 bool isEditablePosition(const Position& p, EditableType editableType, EUpdateSty
le updateStyle) | 154 bool isEditablePosition(const Position& p, EditableType editableType, EUpdateSty
le updateStyle) |
155 { | 155 { |
156 Node* node = p.parentAnchoredEquivalent().anchorNode(); | 156 Node* node = p.parentAnchoredEquivalent().anchorNode(); |
157 if (!node) | 157 if (!node) |
158 return false; | 158 return false; |
159 if (updateStyle == UpdateStyle) | 159 if (updateStyle == UpdateStyle) |
160 node->document().updateLayoutIgnorePendingStylesheets(); | 160 node->document().updateLayoutIgnorePendingStylesheets(); |
161 else | 161 else |
162 ASSERT(updateStyle == DoNotUpdateStyle); | 162 ASSERT(updateStyle == DoNotUpdateStyle); |
163 | 163 |
164 if (isRenderedTableElement(node)) | 164 if (isRenderedHTMLTableElement(node)) |
165 node = node->parentNode(); | 165 node = node->parentNode(); |
166 | 166 |
167 return node->hasEditableStyle(editableType); | 167 return node->hasEditableStyle(editableType); |
168 } | 168 } |
169 | 169 |
170 bool isAtUnsplittableElement(const Position& pos) | 170 bool isAtUnsplittableElement(const Position& pos) |
171 { | 171 { |
172 Node* node = pos.deprecatedNode(); | 172 Node* node = pos.deprecatedNode(); |
173 return (node == editableRootForPosition(pos) || node == enclosingNodeOfType(
pos, &isTableCell)); | 173 return (node == editableRootForPosition(pos) || node == enclosingNodeOfType(
pos, &isTableCell)); |
174 } | 174 } |
175 | 175 |
176 | 176 |
177 bool isRichlyEditablePosition(const Position& p, EditableType editableType) | 177 bool isRichlyEditablePosition(const Position& p, EditableType editableType) |
178 { | 178 { |
179 Node* node = p.deprecatedNode(); | 179 Node* node = p.deprecatedNode(); |
180 if (!node) | 180 if (!node) |
181 return false; | 181 return false; |
182 | 182 |
183 if (isRenderedTableElement(node)) | 183 if (isRenderedHTMLTableElement(node)) |
184 node = node->parentNode(); | 184 node = node->parentNode(); |
185 | 185 |
186 return node->rendererIsRichlyEditable(editableType); | 186 return node->rendererIsRichlyEditable(editableType); |
187 } | 187 } |
188 | 188 |
189 Element* editableRootForPosition(const Position& p, EditableType editableType) | 189 Element* editableRootForPosition(const Position& p, EditableType editableType) |
190 { | 190 { |
191 Node* node = p.containerNode(); | 191 Node* node = p.containerNode(); |
192 if (!node) | 192 if (!node) |
193 return 0; | 193 return 0; |
194 | 194 |
195 if (isRenderedTableElement(node)) | 195 if (isRenderedHTMLTableElement(node)) |
196 node = node->parentNode(); | 196 node = node->parentNode(); |
197 | 197 |
198 return node->rootEditableElement(editableType); | 198 return node->rootEditableElement(editableType); |
199 } | 199 } |
200 | 200 |
201 // Finds the enclosing element until which the tree can be split. | 201 // Finds the enclosing element until which the tree can be split. |
202 // When a user hits ENTER, he/she won't expect this element to be split into two
. | 202 // When a user hits ENTER, he/she won't expect this element to be split into two
. |
203 // You may pass it as the second argument of splitTreeToNode. | 203 // You may pass it as the second argument of splitTreeToNode. |
204 Element* unsplittableElementForPosition(const Position& p) | 204 Element* unsplittableElementForPosition(const Position& p) |
205 { | 205 { |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 } | 450 } |
451 | 451 |
452 static HTMLElement* firstInSpecialElement(const Position& pos) | 452 static HTMLElement* firstInSpecialElement(const Position& pos) |
453 { | 453 { |
454 Element* rootEditableElement = pos.containerNode()->rootEditableElement(); | 454 Element* rootEditableElement = pos.containerNode()->rootEditableElement(); |
455 for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEd
itableElement; n = n->parentNode()) { | 455 for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEd
itableElement; n = n->parentNode()) { |
456 if (isSpecialHTMLElement(n)) { | 456 if (isSpecialHTMLElement(n)) { |
457 HTMLElement* specialElement = toHTMLElement(n); | 457 HTMLElement* specialElement = toHTMLElement(n); |
458 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM); | 458 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM); |
459 VisiblePosition firstInElement = VisiblePosition(firstPositionInOrBe
foreNode(specialElement), DOWNSTREAM); | 459 VisiblePosition firstInElement = VisiblePosition(firstPositionInOrBe
foreNode(specialElement), DOWNSTREAM); |
460 if (isRenderedTable(specialElement) && vPos == firstInElement.next()
) | 460 if (isRenderedTableElement(specialElement) && vPos == firstInElement
.next()) |
461 return specialElement; | 461 return specialElement; |
462 if (vPos == firstInElement) | 462 if (vPos == firstInElement) |
463 return specialElement; | 463 return specialElement; |
464 } | 464 } |
465 } | 465 } |
466 return 0; | 466 return 0; |
467 } | 467 } |
468 | 468 |
469 static HTMLElement* lastInSpecialElement(const Position& pos) | 469 static HTMLElement* lastInSpecialElement(const Position& pos) |
470 { | 470 { |
471 Element* rootEditableElement = pos.containerNode()->rootEditableElement(); | 471 Element* rootEditableElement = pos.containerNode()->rootEditableElement(); |
472 for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEd
itableElement; n = n->parentNode()) { | 472 for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEd
itableElement; n = n->parentNode()) { |
473 if (isSpecialHTMLElement(n)) { | 473 if (isSpecialHTMLElement(n)) { |
474 HTMLElement* specialElement = toHTMLElement(n); | 474 HTMLElement* specialElement = toHTMLElement(n); |
475 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM); | 475 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM); |
476 VisiblePosition lastInElement = VisiblePosition(lastPositionInOrAfte
rNode(specialElement), DOWNSTREAM); | 476 VisiblePosition lastInElement = VisiblePosition(lastPositionInOrAfte
rNode(specialElement), DOWNSTREAM); |
477 if (isRenderedTable(specialElement) && vPos == lastInElement.previou
s()) | 477 if (isRenderedTableElement(specialElement) && vPos == lastInElement.
previous()) |
478 return specialElement; | 478 return specialElement; |
479 if (vPos == lastInElement) | 479 if (vPos == lastInElement) |
480 return specialElement; | 480 return specialElement; |
481 } | 481 } |
482 } | 482 } |
483 return 0; | 483 return 0; |
484 } | 484 } |
485 | 485 |
486 Position positionBeforeContainingSpecialElement(const Position& pos, HTMLElement
** containingSpecialElement) | 486 Position positionBeforeContainingSpecialElement(const Position& pos, HTMLElement
** containingSpecialElement) |
487 { | 487 { |
(...skipping 14 matching lines...) Expand all Loading... |
502 if (!n) | 502 if (!n) |
503 return pos; | 503 return pos; |
504 Position result = positionInParentAfterNode(*n); | 504 Position result = positionInParentAfterNode(*n); |
505 if (result.isNull() || result.deprecatedNode()->rootEditableElement() != pos
.deprecatedNode()->rootEditableElement()) | 505 if (result.isNull() || result.deprecatedNode()->rootEditableElement() != pos
.deprecatedNode()->rootEditableElement()) |
506 return pos; | 506 return pos; |
507 if (containingSpecialElement) | 507 if (containingSpecialElement) |
508 *containingSpecialElement = n; | 508 *containingSpecialElement = n; |
509 return result; | 509 return result; |
510 } | 510 } |
511 | 511 |
512 Node* isFirstPositionAfterTable(const VisiblePosition& visiblePosition) | 512 Element* isFirstPositionAfterTable(const VisiblePosition& visiblePosition) |
513 { | 513 { |
514 Position upstream(visiblePosition.deepEquivalent().upstream()); | 514 Position upstream(visiblePosition.deepEquivalent().upstream()); |
515 if (isRenderedTable(upstream.deprecatedNode()) && upstream.atLastEditingPosi
tionForNode()) | 515 if (isRenderedTableElement(upstream.deprecatedNode()) && upstream.atLastEdit
ingPositionForNode()) |
516 return upstream.deprecatedNode(); | 516 return toElement(upstream.deprecatedNode()); |
517 | 517 |
518 return 0; | 518 return 0; |
519 } | 519 } |
520 | 520 |
521 Node* isLastPositionBeforeTable(const VisiblePosition& visiblePosition) | 521 Element* isLastPositionBeforeTable(const VisiblePosition& visiblePosition) |
522 { | 522 { |
523 Position downstream(visiblePosition.deepEquivalent().downstream()); | 523 Position downstream(visiblePosition.deepEquivalent().downstream()); |
524 if (isRenderedTable(downstream.deprecatedNode()) && downstream.atFirstEditin
gPositionForNode()) | 524 if (isRenderedTableElement(downstream.deprecatedNode()) && downstream.atFirs
tEditingPositionForNode()) |
525 return downstream.deprecatedNode(); | 525 return toElement(downstream.deprecatedNode()); |
526 | 526 |
527 return 0; | 527 return 0; |
528 } | 528 } |
529 | 529 |
530 // Returns the visible position at the beginning of a node | 530 // Returns the visible position at the beginning of a node |
531 VisiblePosition visiblePositionBeforeNode(Node& node) | 531 VisiblePosition visiblePositionBeforeNode(Node& node) |
532 { | 532 { |
533 if (node.hasChildren()) | 533 if (node.hasChildren()) |
534 return VisiblePosition(firstPositionInOrBeforeNode(&node), DOWNSTREAM); | 534 return VisiblePosition(firstPositionInOrBeforeNode(&node), DOWNSTREAM); |
535 ASSERT(node.parentNode()); | 535 ASSERT(node.parentNode()); |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
743 if (!firstList || !secondList || !firstList->isHTMLElement() || !secondList-
>isHTMLElement()) | 743 if (!firstList || !secondList || !firstList->isHTMLElement() || !secondList-
>isHTMLElement()) |
744 return false; | 744 return false; |
745 | 745 |
746 return firstList->hasTagName(secondList->tagQName()) // make sure the list t
ypes match (ol vs. ul) | 746 return firstList->hasTagName(secondList->tagQName()) // make sure the list t
ypes match (ol vs. ul) |
747 && firstList->hasEditableStyle() && secondList->hasEditableStyle() // both l
ists are editable | 747 && firstList->hasEditableStyle() && secondList->hasEditableStyle() // both l
ists are editable |
748 && firstList->rootEditableElement() == secondList->rootEditableElement() //
don't cross editing boundaries | 748 && firstList->rootEditableElement() == secondList->rootEditableElement() //
don't cross editing boundaries |
749 && isVisiblyAdjacent(positionInParentAfterNode(*firstList), positionInParent
BeforeNode(*secondList)); | 749 && isVisiblyAdjacent(positionInParentAfterNode(*firstList), positionInParent
BeforeNode(*secondList)); |
750 // Make sure there is no visible content between this li and the previous li
st | 750 // Make sure there is no visible content between this li and the previous li
st |
751 } | 751 } |
752 | 752 |
| 753 bool isRenderedHTMLTableElement(const Node* node) |
| 754 { |
| 755 return isHTMLTableElement(*node) && node->renderer(); |
| 756 } |
| 757 |
753 bool isRenderedTableElement(const Node* node) | 758 bool isRenderedTableElement(const Node* node) |
754 { | 759 { |
755 return isHTMLTableElement(*node) && node->renderer(); | |
756 } | |
757 | |
758 bool isRenderedTable(const Node* node) | |
759 { | |
760 if (!node || !node->isElementNode()) | 760 if (!node || !node->isElementNode()) |
761 return false; | 761 return false; |
762 | 762 |
763 RenderObject* renderer = node->renderer(); | 763 RenderObject* renderer = node->renderer(); |
764 return (renderer && renderer->isTable()); | 764 return (renderer && renderer->isTable()); |
765 } | 765 } |
766 | 766 |
767 bool isTableCell(const Node* node) | 767 bool isTableCell(const Node* node) |
768 { | 768 { |
769 ASSERT(node); | 769 ASSERT(node); |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1074 VisibleSelection selectionForParagraphIteration(const VisibleSelection& original
) | 1074 VisibleSelection selectionForParagraphIteration(const VisibleSelection& original
) |
1075 { | 1075 { |
1076 VisibleSelection newSelection(original); | 1076 VisibleSelection newSelection(original); |
1077 VisiblePosition startOfSelection(newSelection.visibleStart()); | 1077 VisiblePosition startOfSelection(newSelection.visibleStart()); |
1078 VisiblePosition endOfSelection(newSelection.visibleEnd()); | 1078 VisiblePosition endOfSelection(newSelection.visibleEnd()); |
1079 | 1079 |
1080 // If the end of the selection to modify is just after a table, and | 1080 // If the end of the selection to modify is just after a table, and |
1081 // if the start of the selection is inside that table, then the last paragra
ph | 1081 // if the start of the selection is inside that table, then the last paragra
ph |
1082 // that we'll want modify is the last one inside the table, not the table it
self | 1082 // that we'll want modify is the last one inside the table, not the table it
self |
1083 // (a table is itself a paragraph). | 1083 // (a table is itself a paragraph). |
1084 if (Node* table = isFirstPositionAfterTable(endOfSelection)) | 1084 if (Element* table = isFirstPositionAfterTable(endOfSelection)) |
1085 if (startOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(t
able)) | 1085 if (startOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(t
able)) |
1086 newSelection = VisibleSelection(startOfSelection, endOfSelection.pre
vious(CannotCrossEditingBoundary)); | 1086 newSelection = VisibleSelection(startOfSelection, endOfSelection.pre
vious(CannotCrossEditingBoundary)); |
1087 | 1087 |
1088 // If the start of the selection to modify is just before a table, | 1088 // If the start of the selection to modify is just before a table, |
1089 // and if the end of the selection is inside that table, then the first para
graph | 1089 // and if the end of the selection is inside that table, then the first para
graph |
1090 // we'll want to modify is the first one inside the table, not the paragraph | 1090 // we'll want to modify is the first one inside the table, not the paragraph |
1091 // containing the table itself. | 1091 // containing the table itself. |
1092 if (Node* table = isLastPositionBeforeTable(startOfSelection)) | 1092 if (Element* table = isLastPositionBeforeTable(startOfSelection)) |
1093 if (endOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(tab
le)) | 1093 if (endOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(tab
le)) |
1094 newSelection = VisibleSelection(startOfSelection.next(CannotCrossEdi
tingBoundary), endOfSelection); | 1094 newSelection = VisibleSelection(startOfSelection.next(CannotCrossEdi
tingBoundary), endOfSelection); |
1095 | 1095 |
1096 return newSelection; | 1096 return newSelection; |
1097 } | 1097 } |
1098 | 1098 |
1099 // FIXME: indexForVisiblePosition and visiblePositionForIndex use TextIterators
to convert between | 1099 // FIXME: indexForVisiblePosition and visiblePositionForIndex use TextIterators
to convert between |
1100 // VisiblePositions and indices. But TextIterator iteration using TextIteratorEm
itsCharactersBetweenAllVisiblePositions | 1100 // VisiblePositions and indices. But TextIterator iteration using TextIteratorEm
itsCharactersBetweenAllVisiblePositions |
1101 // does not exactly match VisiblePosition iteration, so using them to preserve a
selection during an editing | 1101 // does not exactly match VisiblePosition iteration, so using them to preserve a
selection during an editing |
1102 // opertion is unreliable. TextIterator's TextIteratorEmitsCharactersBetweenAllV
isiblePositions mode needs to be fixed, | 1102 // opertion is unreliable. TextIterator's TextIteratorEmitsCharactersBetweenAllV
isiblePositions mode needs to be fixed, |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1224 // if the selection starts just before a paragraph break, skip over it | 1224 // if the selection starts just before a paragraph break, skip over it |
1225 if (isEndOfParagraph(visiblePosition)) | 1225 if (isEndOfParagraph(visiblePosition)) |
1226 return visiblePosition.next().deepEquivalent().downstream(); | 1226 return visiblePosition.next().deepEquivalent().downstream(); |
1227 | 1227 |
1228 // otherwise, make sure to be at the start of the first selected node, | 1228 // otherwise, make sure to be at the start of the first selected node, |
1229 // instead of possibly at the end of the last node before the selection | 1229 // instead of possibly at the end of the last node before the selection |
1230 return visiblePosition.deepEquivalent().downstream(); | 1230 return visiblePosition.deepEquivalent().downstream(); |
1231 } | 1231 } |
1232 | 1232 |
1233 } // namespace blink | 1233 } // namespace blink |
OLD | NEW |