| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. | 2 * Copyright (C) 2005 Apple Computer, 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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 } | 86 } |
| 87 | 87 |
| 88 // This is a scenario that should never happen, but we want to | 88 // This is a scenario that should never happen, but we want to |
| 89 // make sure we don't dereference a null pointer below. | 89 // make sure we don't dereference a null pointer below. |
| 90 | 90 |
| 91 DCHECK(!endingSelection().isNone()); | 91 DCHECK(!endingSelection().isNone()); |
| 92 | 92 |
| 93 if (endingSelection().isNone()) | 93 if (endingSelection().isNone()) |
| 94 return; | 94 return; |
| 95 | 95 |
| 96 VisiblePosition visiblePos = endingSelection().visibleStartDeprecated(); | 96 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 97 |
| 98 VisiblePosition visiblePos = endingSelection().visibleStart(); |
| 97 | 99 |
| 98 // pos is a position equivalent to the caret. We use downstream() so that pos | 100 // pos is a position equivalent to the caret. We use downstream() so that pos |
| 99 // will be in the first node that we need to move (there are a few exceptions | 101 // will be in the first node that we need to move (there are a few exceptions |
| 100 // to this, see below). | 102 // to this, see below). |
| 101 Position pos = mostForwardCaretPosition(endingSelection().start()); | 103 Position pos = mostForwardCaretPosition(endingSelection().start()); |
| 102 | 104 |
| 103 // Find the top-most blockquote from the start. | 105 // Find the top-most blockquote from the start. |
| 104 HTMLQuoteElement* topBlockquote = toHTMLQuoteElement( | 106 HTMLQuoteElement* topBlockquote = toHTMLQuoteElement( |
| 105 highestEnclosingNodeOfType(pos, isMailHTMLBlockquoteElement)); | 107 highestEnclosingNodeOfType(pos, isMailHTMLBlockquoteElement)); |
| 106 if (!topBlockquote || !topBlockquote->parentNode()) | 108 if (!topBlockquote || !topBlockquote->parentNode()) |
| 107 return; | 109 return; |
| 108 | 110 |
| 109 HTMLBRElement* breakElement = HTMLBRElement::create(document()); | 111 HTMLBRElement* breakElement = HTMLBRElement::create(document()); |
| 110 | 112 |
| 111 bool isLastVisPosInNode = | 113 bool isLastVisPosInNode = |
| 112 isLastVisiblePositionInNode(visiblePos, topBlockquote); | 114 isLastVisiblePositionInNode(visiblePos, topBlockquote); |
| 113 | 115 |
| 114 // If the position is at the beginning of the top quoted content, we don't | 116 // If the position is at the beginning of the top quoted content, we don't |
| 115 // need to break the quote. Instead, insert the break before the blockquote, | 117 // need to break the quote. Instead, insert the break before the blockquote, |
| 116 // unless the position is as the end of the the quoted content. | 118 // unless the position is as the end of the the quoted content. |
| 117 if (isFirstVisiblePositionInNode(visiblePos, topBlockquote) && | 119 if (isFirstVisiblePositionInNode(visiblePos, topBlockquote) && |
| 118 !isLastVisPosInNode) { | 120 !isLastVisPosInNode) { |
| 119 insertNodeBefore(breakElement, topBlockquote, editingState); | 121 insertNodeBefore(breakElement, topBlockquote, editingState); |
| 120 if (editingState->isAborted()) | 122 if (editingState->isAborted()) |
| 121 return; | 123 return; |
| 122 setEndingSelection(createVisibleSelectionDeprecated( | 124 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 125 setEndingSelection(createVisibleSelection( |
| 123 Position::beforeNode(breakElement), TextAffinity::Downstream, | 126 Position::beforeNode(breakElement), TextAffinity::Downstream, |
| 124 endingSelection().isDirectional())); | 127 endingSelection().isDirectional())); |
| 125 rebalanceWhitespace(); | 128 rebalanceWhitespace(); |
| 126 return; | 129 return; |
| 127 } | 130 } |
| 128 | 131 |
| 129 // Insert a break after the top blockquote. | 132 // Insert a break after the top blockquote. |
| 130 insertNodeAfter(breakElement, topBlockquote, editingState); | 133 insertNodeAfter(breakElement, topBlockquote, editingState); |
| 131 if (editingState->isAborted()) | 134 if (editingState->isAborted()) |
| 132 return; | 135 return; |
| 133 | 136 |
| 137 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 138 |
| 134 // If we're inserting the break at the end of the quoted content, we don't | 139 // If we're inserting the break at the end of the quoted content, we don't |
| 135 // need to break the quote. | 140 // need to break the quote. |
| 136 if (isLastVisPosInNode) { | 141 if (isLastVisPosInNode) { |
| 137 setEndingSelection(createVisibleSelectionDeprecated( | 142 setEndingSelection(createVisibleSelection( |
| 138 Position::beforeNode(breakElement), TextAffinity::Downstream, | 143 Position::beforeNode(breakElement), TextAffinity::Downstream, |
| 139 endingSelection().isDirectional())); | 144 endingSelection().isDirectional())); |
| 140 rebalanceWhitespace(); | 145 rebalanceWhitespace(); |
| 141 return; | 146 return; |
| 142 } | 147 } |
| 143 | 148 |
| 144 // Don't move a line break just after the caret. Doing so would create an | 149 // Don't move a line break just after the caret. Doing so would create an |
| 145 // extra, empty paragraph in the new blockquote. | 150 // extra, empty paragraph in the new blockquote. |
| 146 if (lineBreakExistsAtVisiblePosition(visiblePos)) { | 151 if (lineBreakExistsAtVisiblePosition(visiblePos)) { |
| 147 pos = nextPositionOf(pos, PositionMoveType::GraphemeCluster); | 152 pos = nextPositionOf(pos, PositionMoveType::GraphemeCluster); |
| 148 } | 153 } |
| 149 | 154 |
| 150 // Adjust the position so we don't split at the beginning of a quote. | 155 // Adjust the position so we don't split at the beginning of a quote. |
| 151 while (isFirstVisiblePositionInNode(createVisiblePositionDeprecated(pos), | 156 while (isFirstVisiblePositionInNode(createVisiblePosition(pos), |
| 152 toHTMLQuoteElement(enclosingNodeOfType( | 157 toHTMLQuoteElement(enclosingNodeOfType( |
| 153 pos, isMailHTMLBlockquoteElement)))) { | 158 pos, isMailHTMLBlockquoteElement)))) { |
| 154 pos = previousPositionOf(pos, PositionMoveType::GraphemeCluster); | 159 pos = previousPositionOf(pos, PositionMoveType::GraphemeCluster); |
| 155 } | 160 } |
| 156 | 161 |
| 157 // startNode is the first node that we need to move to the new blockquote. | 162 // startNode is the first node that we need to move to the new blockquote. |
| 158 Node* startNode = pos.anchorNode(); | 163 Node* startNode = pos.anchorNode(); |
| 159 DCHECK(startNode); | 164 DCHECK(startNode); |
| 160 | 165 |
| 161 // Split at pos if in the middle of a text node. | 166 // Split at pos if in the middle of a text node. |
| 162 if (startNode->isTextNode()) { | 167 if (startNode->isTextNode()) { |
| 163 Text* textNode = toText(startNode); | 168 Text* textNode = toText(startNode); |
| 164 int textOffset = pos.computeOffsetInContainerNode(); | 169 int textOffset = pos.computeOffsetInContainerNode(); |
| 165 if ((unsigned)textOffset >= textNode->length()) { | 170 if ((unsigned)textOffset >= textNode->length()) { |
| 166 startNode = NodeTraversal::next(*startNode); | 171 startNode = NodeTraversal::next(*startNode); |
| 167 DCHECK(startNode); | 172 DCHECK(startNode); |
| 168 } else if (textOffset > 0) { | 173 } else if (textOffset > 0) { |
| 169 splitTextNode(textNode, textOffset); | 174 splitTextNode(textNode, textOffset); |
| 170 } | 175 } |
| 171 } else if (pos.computeEditingOffset() > 0) { | 176 } else if (pos.computeEditingOffset() > 0) { |
| 172 Node* childAtOffset = | 177 Node* childAtOffset = |
| 173 NodeTraversal::childAt(*startNode, pos.computeEditingOffset()); | 178 NodeTraversal::childAt(*startNode, pos.computeEditingOffset()); |
| 174 startNode = childAtOffset ? childAtOffset : NodeTraversal::next(*startNode); | 179 startNode = childAtOffset ? childAtOffset : NodeTraversal::next(*startNode); |
| 175 DCHECK(startNode); | 180 DCHECK(startNode); |
| 176 } | 181 } |
| 177 | 182 |
| 178 // If there's nothing inside topBlockquote to move, we're finished. | 183 // If there's nothing inside topBlockquote to move, we're finished. |
| 179 if (!startNode->isDescendantOf(topBlockquote)) { | 184 if (!startNode->isDescendantOf(topBlockquote)) { |
| 180 setEndingSelection(createVisibleSelectionDeprecated( | 185 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 181 createVisiblePositionDeprecated(firstPositionInOrBeforeNode(startNode)), | 186 setEndingSelection(createVisibleSelection( |
| 187 createVisiblePosition(firstPositionInOrBeforeNode(startNode)), |
| 182 endingSelection().isDirectional())); | 188 endingSelection().isDirectional())); |
| 183 return; | 189 return; |
| 184 } | 190 } |
| 185 | 191 |
| 186 // Build up list of ancestors in between the start node and the top | 192 // Build up list of ancestors in between the start node and the top |
| 187 // blockquote. | 193 // blockquote. |
| 188 HeapVector<Member<Element>> ancestors; | 194 HeapVector<Member<Element>> ancestors; |
| 189 for (Element* node = startNode->parentElement(); | 195 for (Element* node = startNode->parentElement(); |
| 190 node && node != topBlockquote; node = node->parentElement()) | 196 node && node != topBlockquote; node = node->parentElement()) |
| 191 ancestors.append(node); | 197 ancestors.append(node); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 if (editingState->isAborted()) | 258 if (editingState->isAborted()) |
| 253 return; | 259 return; |
| 254 } | 260 } |
| 255 } | 261 } |
| 256 | 262 |
| 257 // Make sure the cloned block quote renders. | 263 // Make sure the cloned block quote renders. |
| 258 addBlockPlaceholderIfNeeded(clonedBlockquote, editingState); | 264 addBlockPlaceholderIfNeeded(clonedBlockquote, editingState); |
| 259 if (editingState->isAborted()) | 265 if (editingState->isAborted()) |
| 260 return; | 266 return; |
| 261 | 267 |
| 268 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 269 |
| 262 // Put the selection right before the break. | 270 // Put the selection right before the break. |
| 263 setEndingSelection(createVisibleSelectionDeprecated( | 271 setEndingSelection(createVisibleSelection(Position::beforeNode(breakElement), |
| 264 Position::beforeNode(breakElement), TextAffinity::Downstream, | 272 TextAffinity::Downstream, |
| 265 endingSelection().isDirectional())); | 273 endingSelection().isDirectional())); |
| 266 rebalanceWhitespace(); | 274 rebalanceWhitespace(); |
| 267 } | 275 } |
| 268 | 276 |
| 269 } // namespace blink | 277 } // namespace blink |
| OLD | NEW |