| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2008 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 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 | 84 |
| 85 // We should calculate visible range in list item because inserting new | 85 // We should calculate visible range in list item because inserting new |
| 86 // list element will change visibility of list item, e.g. :first-child | 86 // list element will change visibility of list item, e.g. :first-child |
| 87 // CSS selector. | 87 // CSS selector. |
| 88 HTMLElement* newList = toHTMLElement( | 88 HTMLElement* newList = toHTMLElement( |
| 89 document().createElement(listElement->tagQName(), CreatedByCloneNode)); | 89 document().createElement(listElement->tagQName(), CreatedByCloneNode)); |
| 90 insertNodeBefore(newList, selectedListItem, editingState); | 90 insertNodeBefore(newList, selectedListItem, editingState); |
| 91 if (editingState->isAborted()) | 91 if (editingState->isAborted()) |
| 92 return false; | 92 return false; |
| 93 | 93 |
| 94 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 95 |
| 94 // We should clone all the children of the list item for indenting purposes. H
owever, in case the current | 96 // We should clone all the children of the list item for indenting purposes. H
owever, in case the current |
| 95 // selection does not encompass all its children, we need to explicitally hand
le the same. The original | 97 // selection does not encompass all its children, we need to explicitally hand
le the same. The original |
| 96 // list item too would require proper deletion in that case. | 98 // list item too would require proper deletion in that case. |
| 97 if (end.anchorNode() == selectedListItem || | 99 if (end.anchorNode() == selectedListItem || |
| 98 end.anchorNode()->isDescendantOf(selectedListItem->lastChild())) { | 100 end.anchorNode()->isDescendantOf(selectedListItem->lastChild())) { |
| 99 moveParagraphWithClones(createVisiblePositionDeprecated(start), | 101 moveParagraphWithClones(createVisiblePosition(start), |
| 100 createVisiblePositionDeprecated(end), newList, | 102 createVisiblePosition(end), newList, |
| 101 selectedListItem, editingState); | 103 selectedListItem, editingState); |
| 102 } else { | 104 } else { |
| 103 moveParagraphWithClones( | 105 moveParagraphWithClones( |
| 104 createVisiblePositionDeprecated(start), | 106 createVisiblePosition(start), |
| 105 VisiblePosition::afterNode(selectedListItem->lastChild()), newList, | 107 VisiblePosition::afterNode(selectedListItem->lastChild()), newList, |
| 106 selectedListItem, editingState); | 108 selectedListItem, editingState); |
| 107 if (editingState->isAborted()) | 109 if (editingState->isAborted()) |
| 108 return false; | 110 return false; |
| 109 removeNode(selectedListItem, editingState); | 111 removeNode(selectedListItem, editingState); |
| 110 } | 112 } |
| 111 if (editingState->isAborted()) | 113 if (editingState->isAborted()) |
| 112 return false; | 114 return false; |
| 113 | 115 |
| 114 if (canMergeLists(previousList, newList)) { | 116 if (canMergeLists(previousList, newList)) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 139 elementToSplitTo = rootEditableElementOf(start); | 141 elementToSplitTo = rootEditableElementOf(start); |
| 140 | 142 |
| 141 if (!elementToSplitTo) | 143 if (!elementToSplitTo) |
| 142 return; | 144 return; |
| 143 | 145 |
| 144 Node* outerBlock = | 146 Node* outerBlock = |
| 145 (start.computeContainerNode() == elementToSplitTo) | 147 (start.computeContainerNode() == elementToSplitTo) |
| 146 ? start.computeContainerNode() | 148 ? start.computeContainerNode() |
| 147 : splitTreeToNode(start.computeContainerNode(), elementToSplitTo); | 149 : splitTreeToNode(start.computeContainerNode(), elementToSplitTo); |
| 148 | 150 |
| 149 VisiblePosition startOfContents = createVisiblePositionDeprecated(start); | 151 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 152 VisiblePosition startOfContents = createVisiblePosition(start); |
| 150 if (!targetBlockquote) { | 153 if (!targetBlockquote) { |
| 151 // Create a new blockquote and insert it as a child of the root editable ele
ment. We accomplish | 154 // Create a new blockquote and insert it as a child of the root editable ele
ment. We accomplish |
| 152 // this by splitting all parents of the current paragraph up to that point. | 155 // this by splitting all parents of the current paragraph up to that point. |
| 153 targetBlockquote = createBlockElement(); | 156 targetBlockquote = createBlockElement(); |
| 154 if (outerBlock == start.computeContainerNode()) { | 157 if (outerBlock == start.computeContainerNode()) { |
| 155 // When we apply indent to an empty <blockquote>, we should call insertNod
eAfter(). | 158 // When we apply indent to an empty <blockquote>, we should call insertNod
eAfter(). |
| 156 // See http://crbug.com/625802 for more details. | 159 // See http://crbug.com/625802 for more details. |
| 157 if (outerBlock->hasTagName(blockquoteTag)) | 160 if (outerBlock->hasTagName(blockquoteTag)) |
| 158 insertNodeAfter(targetBlockquote, outerBlock, editingState); | 161 insertNodeAfter(targetBlockquote, outerBlock, editingState); |
| 159 else | 162 else |
| 160 insertNodeAt(targetBlockquote, start, editingState); | 163 insertNodeAt(targetBlockquote, start, editingState); |
| 161 } else | 164 } else |
| 162 insertNodeBefore(targetBlockquote, outerBlock, editingState); | 165 insertNodeBefore(targetBlockquote, outerBlock, editingState); |
| 163 if (editingState->isAborted()) | 166 if (editingState->isAborted()) |
| 164 return; | 167 return; |
| 168 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 165 startOfContents = VisiblePosition::inParentAfterNode(*targetBlockquote); | 169 startOfContents = VisiblePosition::inParentAfterNode(*targetBlockquote); |
| 166 } | 170 } |
| 167 | 171 |
| 168 VisiblePosition endOfContents = createVisiblePositionDeprecated(end); | 172 VisiblePosition endOfContents = createVisiblePosition(end); |
| 169 if (startOfContents.isNull() || endOfContents.isNull()) | 173 if (startOfContents.isNull() || endOfContents.isNull()) |
| 170 return; | 174 return; |
| 171 moveParagraphWithClones(startOfContents, endOfContents, targetBlockquote, | 175 moveParagraphWithClones(startOfContents, endOfContents, targetBlockquote, |
| 172 outerBlock, editingState); | 176 outerBlock, editingState); |
| 173 } | 177 } |
| 174 | 178 |
| 175 void IndentOutdentCommand::outdentParagraph(EditingState* editingState) { | 179 void IndentOutdentCommand::outdentParagraph(EditingState* editingState) { |
| 176 VisiblePosition visibleStartOfParagraph = | 180 VisiblePosition visibleStartOfParagraph = |
| 177 startOfParagraphDeprecated(endingSelection().visibleStartDeprecated()); | 181 startOfParagraph(endingSelection().visibleStart()); |
| 178 VisiblePosition visibleEndOfParagraph = | 182 VisiblePosition visibleEndOfParagraph = |
| 179 endOfParagraphDeprecated(visibleStartOfParagraph); | 183 endOfParagraph(visibleStartOfParagraph); |
| 180 | 184 |
| 181 HTMLElement* enclosingElement = toHTMLElement( | 185 HTMLElement* enclosingElement = toHTMLElement( |
| 182 enclosingNodeOfType(visibleStartOfParagraph.deepEquivalent(), | 186 enclosingNodeOfType(visibleStartOfParagraph.deepEquivalent(), |
| 183 &isHTMLListOrBlockquoteElement)); | 187 &isHTMLListOrBlockquoteElement)); |
| 184 if (!enclosingElement || | 188 if (!enclosingElement || |
| 185 !hasEditableStyle( | 189 !hasEditableStyle( |
| 186 *enclosingElement | 190 *enclosingElement |
| 187 ->parentNode())) // We can't outdent if there is no place to go! | 191 ->parentNode())) // We can't outdent if there is no place to go! |
| 188 return; | 192 return; |
| 189 | 193 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 if (splitPointParent->hasTagName(blockquoteTag) && | 235 if (splitPointParent->hasTagName(blockquoteTag) && |
| 232 !splitPoint->hasTagName(blockquoteTag) && | 236 !splitPoint->hasTagName(blockquoteTag) && |
| 233 hasEditableStyle( | 237 hasEditableStyle( |
| 234 *splitPointParent | 238 *splitPointParent |
| 235 ->parentNode())) // We can't outdent if there is no place
to go! | 239 ->parentNode())) // We can't outdent if there is no place
to go! |
| 236 splitElement(splitPointParent, splitPoint); | 240 splitElement(splitPointParent, splitPoint); |
| 237 } | 241 } |
| 238 } | 242 } |
| 239 | 243 |
| 240 document().updateStyleAndLayoutIgnorePendingStylesheets(); | 244 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 241 visibleStartOfParagraph = createVisiblePositionDeprecated( | 245 visibleStartOfParagraph = |
| 242 visibleStartOfParagraph.deepEquivalent()); | 246 createVisiblePosition(visibleStartOfParagraph.deepEquivalent()); |
| 243 visibleEndOfParagraph = | |
| 244 createVisiblePositionDeprecated(visibleEndOfParagraph.deepEquivalent()); | |
| 245 if (visibleStartOfParagraph.isNotNull() && | 247 if (visibleStartOfParagraph.isNotNull() && |
| 246 !isStartOfParagraphDeprecated(visibleStartOfParagraph)) { | 248 !isStartOfParagraph(visibleStartOfParagraph)) { |
| 247 insertNodeAt(HTMLBRElement::create(document()), | 249 insertNodeAt(HTMLBRElement::create(document()), |
| 248 visibleStartOfParagraph.deepEquivalent(), editingState); | 250 visibleStartOfParagraph.deepEquivalent(), editingState); |
| 249 if (editingState->isAborted()) | 251 if (editingState->isAborted()) |
| 250 return; | 252 return; |
| 251 } | 253 } |
| 254 |
| 255 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 256 visibleEndOfParagraph = |
| 257 createVisiblePosition(visibleEndOfParagraph.deepEquivalent()); |
| 252 if (visibleEndOfParagraph.isNotNull() && | 258 if (visibleEndOfParagraph.isNotNull() && |
| 253 !isEndOfParagraphDeprecated(visibleEndOfParagraph)) | 259 !isEndOfParagraph(visibleEndOfParagraph)) |
| 254 insertNodeAt(HTMLBRElement::create(document()), | 260 insertNodeAt(HTMLBRElement::create(document()), |
| 255 visibleEndOfParagraph.deepEquivalent(), editingState); | 261 visibleEndOfParagraph.deepEquivalent(), editingState); |
| 256 return; | 262 return; |
| 257 } | 263 } |
| 264 |
| 258 Node* splitBlockquoteNode = enclosingElement; | 265 Node* splitBlockquoteNode = enclosingElement; |
| 259 if (Element* enclosingBlockFlow = enclosingBlock( | 266 if (Element* enclosingBlockFlow = enclosingBlock( |
| 260 visibleStartOfParagraph.deepEquivalent().anchorNode())) { | 267 visibleStartOfParagraph.deepEquivalent().anchorNode())) { |
| 261 if (enclosingBlockFlow != enclosingElement) { | 268 if (enclosingBlockFlow != enclosingElement) { |
| 262 splitBlockquoteNode = | 269 splitBlockquoteNode = |
| 263 splitTreeToNode(enclosingBlockFlow, enclosingElement, true); | 270 splitTreeToNode(enclosingBlockFlow, enclosingElement, true); |
| 264 } else { | 271 } else { |
| 265 // We split the blockquote at where we start outdenting. | 272 // We split the blockquote at where we start outdenting. |
| 266 Node* highestInlineNode = highestEnclosingNodeOfType( | 273 Node* highestInlineNode = highestEnclosingNodeOfType( |
| 267 visibleStartOfParagraph.deepEquivalent(), isInline, | 274 visibleStartOfParagraph.deepEquivalent(), isInline, |
| 268 CannotCrossEditingBoundary, enclosingBlockFlow); | 275 CannotCrossEditingBoundary, enclosingBlockFlow); |
| 269 splitElement(enclosingElement, | 276 splitElement(enclosingElement, |
| 270 highestInlineNode | 277 highestInlineNode |
| 271 ? highestInlineNode | 278 ? highestInlineNode |
| 272 : visibleStartOfParagraph.deepEquivalent().anchorNode()); | 279 : visibleStartOfParagraph.deepEquivalent().anchorNode()); |
| 273 } | 280 } |
| 281 |
| 282 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 283 |
| 284 // Re-canonicalize visible{Start,End}OfParagraph, make them valid again |
| 285 // after DOM change. |
| 286 // TODO(xiaochengh): We should not store a VisiblePosition and later inspect |
| 287 // its properties when it is already invalidated. |
| 288 visibleStartOfParagraph = |
| 289 createVisiblePosition(visibleStartOfParagraph.toPositionWithAffinity()); |
| 290 visibleEndOfParagraph = |
| 291 createVisiblePosition(visibleEndOfParagraph.toPositionWithAffinity()); |
| 274 } | 292 } |
| 293 |
| 275 VisiblePosition startOfParagraphToMove = | 294 VisiblePosition startOfParagraphToMove = |
| 276 startOfParagraphDeprecated(visibleStartOfParagraph); | 295 startOfParagraph(visibleStartOfParagraph); |
| 277 VisiblePosition endOfParagraphToMove = | 296 VisiblePosition endOfParagraphToMove = endOfParagraph(visibleEndOfParagraph); |
| 278 endOfParagraphDeprecated(visibleEndOfParagraph); | |
| 279 if (startOfParagraphToMove.isNull() || endOfParagraphToMove.isNull()) | 297 if (startOfParagraphToMove.isNull() || endOfParagraphToMove.isNull()) |
| 280 return; | 298 return; |
| 281 HTMLBRElement* placeholder = HTMLBRElement::create(document()); | 299 HTMLBRElement* placeholder = HTMLBRElement::create(document()); |
| 282 insertNodeBefore(placeholder, splitBlockquoteNode, editingState); | 300 insertNodeBefore(placeholder, splitBlockquoteNode, editingState); |
| 283 if (editingState->isAborted()) | 301 if (editingState->isAborted()) |
| 284 return; | 302 return; |
| 303 |
| 304 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 285 moveParagraph(startOfParagraphToMove, endOfParagraphToMove, | 305 moveParagraph(startOfParagraphToMove, endOfParagraphToMove, |
| 286 VisiblePosition::beforeNode(placeholder), editingState, | 306 VisiblePosition::beforeNode(placeholder), editingState, |
| 287 PreserveSelection); | 307 PreserveSelection); |
| 288 } | 308 } |
| 289 | 309 |
| 290 // FIXME: We should merge this function with ApplyBlockElementCommand::formatSel
ection | 310 // FIXME: We should merge this function with ApplyBlockElementCommand::formatSel
ection |
| 291 void IndentOutdentCommand::outdentRegion( | 311 void IndentOutdentCommand::outdentRegion( |
| 292 const VisiblePosition& startOfSelection, | 312 const VisiblePosition& startOfSelection, |
| 293 const VisiblePosition& endOfSelection, | 313 const VisiblePosition& endOfSelection, |
| 294 EditingState* editingState) { | 314 EditingState* editingState) { |
| 295 VisiblePosition endOfCurrentParagraph = | 315 VisiblePosition endOfCurrentParagraph = endOfParagraph(startOfSelection); |
| 296 endOfParagraphDeprecated(startOfSelection); | 316 VisiblePosition endOfLastParagraph = endOfParagraph(endOfSelection); |
| 297 VisiblePosition endOfLastParagraph = endOfParagraphDeprecated(endOfSelection); | |
| 298 | 317 |
| 299 if (endOfCurrentParagraph.deepEquivalent() == | 318 if (endOfCurrentParagraph.deepEquivalent() == |
| 300 endOfLastParagraph.deepEquivalent()) { | 319 endOfLastParagraph.deepEquivalent()) { |
| 301 outdentParagraph(editingState); | 320 outdentParagraph(editingState); |
| 302 return; | 321 return; |
| 303 } | 322 } |
| 304 | 323 |
| 305 Position originalSelectionEnd = endingSelection().end(); | 324 Position originalSelectionEnd = endingSelection().end(); |
| 306 VisiblePosition endAfterSelection = | 325 Position endAfterSelection = |
| 307 endOfParagraphDeprecated(nextPositionOf(endOfLastParagraph)); | 326 endOfParagraph(nextPositionOf(endOfLastParagraph)).deepEquivalent(); |
| 308 | 327 |
| 309 while (endOfCurrentParagraph.deepEquivalent() != | 328 while (endOfCurrentParagraph.deepEquivalent() != endAfterSelection) { |
| 310 endAfterSelection.deepEquivalent()) { | 329 PositionWithAffinity endOfNextParagraph = |
| 311 VisiblePosition endOfNextParagraph = endOfParagraphDeprecated( | 330 endOfParagraph(nextPositionOf(endOfCurrentParagraph)) |
| 312 nextPositionOfDeprecated(endOfCurrentParagraph)); | 331 .toPositionWithAffinity(); |
| 313 if (endOfCurrentParagraph.deepEquivalent() == | 332 if (endOfCurrentParagraph.deepEquivalent() == |
| 314 endOfLastParagraph.deepEquivalent()) | 333 endOfLastParagraph.deepEquivalent()) { |
| 315 setEndingSelection(createVisibleSelectionDeprecated( | 334 setEndingSelection(createVisibleSelection(originalSelectionEnd, |
| 316 originalSelectionEnd, TextAffinity::Downstream)); | 335 TextAffinity::Downstream)); |
| 317 else | 336 } else { |
| 318 setEndingSelection(endOfCurrentParagraph); | 337 setEndingSelection(endOfCurrentParagraph); |
| 338 } |
| 319 | 339 |
| 320 outdentParagraph(editingState); | 340 outdentParagraph(editingState); |
| 321 if (editingState->isAborted()) | 341 if (editingState->isAborted()) |
| 322 return; | 342 return; |
| 323 | 343 |
| 324 // outdentParagraph could move more than one paragraph if the paragraph | 344 // outdentParagraph could move more than one paragraph if the paragraph |
| 325 // is in a list item. As a result, endAfterSelection and endOfNextParagraph | 345 // is in a list item. As a result, endAfterSelection and endOfNextParagraph |
| 326 // could refer to positions no longer in the document. | 346 // could refer to positions no longer in the document. |
| 327 if (endAfterSelection.isNotNull() && | 347 if (endAfterSelection.isNotNull() && !endAfterSelection.isConnected()) |
| 328 !endAfterSelection.deepEquivalent().isConnected()) | |
| 329 break; | 348 break; |
| 330 | 349 |
| 350 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 331 if (endOfNextParagraph.isNotNull() && | 351 if (endOfNextParagraph.isNotNull() && |
| 332 !endOfNextParagraph.deepEquivalent().isConnected()) { | 352 !endOfNextParagraph.position().isConnected()) { |
| 333 endOfCurrentParagraph = | 353 endOfCurrentParagraph = createVisiblePosition(endingSelection().end()); |
| 334 createVisiblePositionDeprecated(endingSelection().end()); | 354 endOfNextParagraph = endOfParagraph(nextPositionOf(endOfCurrentParagraph)) |
| 335 endOfNextParagraph = | 355 .toPositionWithAffinity(); |
| 336 endOfParagraphDeprecated(nextPositionOf(endOfCurrentParagraph)); | |
| 337 } | 356 } |
| 338 endOfCurrentParagraph = endOfNextParagraph; | 357 endOfCurrentParagraph = createVisiblePosition(endOfNextParagraph); |
| 339 } | 358 } |
| 340 } | 359 } |
| 341 | 360 |
| 342 void IndentOutdentCommand::formatSelection( | 361 void IndentOutdentCommand::formatSelection( |
| 343 const VisiblePosition& startOfSelection, | 362 const VisiblePosition& startOfSelection, |
| 344 const VisiblePosition& endOfSelection, | 363 const VisiblePosition& endOfSelection, |
| 345 EditingState* editingState) { | 364 EditingState* editingState) { |
| 346 if (m_typeOfAction == Indent) | 365 if (m_typeOfAction == Indent) |
| 347 ApplyBlockElementCommand::formatSelection(startOfSelection, endOfSelection, | 366 ApplyBlockElementCommand::formatSelection(startOfSelection, endOfSelection, |
| 348 editingState); | 367 editingState); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 364 else | 383 else |
| 365 indentIntoBlockquote(start, end, blockquoteForNextIndent, editingState); | 384 indentIntoBlockquote(start, end, blockquoteForNextIndent, editingState); |
| 366 } | 385 } |
| 367 | 386 |
| 368 InputEvent::InputType IndentOutdentCommand::inputType() const { | 387 InputEvent::InputType IndentOutdentCommand::inputType() const { |
| 369 return m_typeOfAction == Indent ? InputEvent::InputType::Indent | 388 return m_typeOfAction == Indent ? InputEvent::InputType::Indent |
| 370 : InputEvent::InputType::Outdent; | 389 : InputEvent::InputType::Outdent; |
| 371 } | 390 } |
| 372 | 391 |
| 373 } // namespace blink | 392 } // namespace blink |
| OLD | NEW |