| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. | 2 * Copyright (C) 2005, 2006 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 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 // FIXME: The parentAnchoredEquivalent conversion needs to be moved into enc
losingBlock. | 168 // FIXME: The parentAnchoredEquivalent conversion needs to be moved into enc
losingBlock. |
| 169 RefPtrWillBeRawPtr<Element> startBlock = enclosingBlock(insertionPosition.pa
rentAnchoredEquivalent().containerNode()); | 169 RefPtrWillBeRawPtr<Element> startBlock = enclosingBlock(insertionPosition.pa
rentAnchoredEquivalent().containerNode()); |
| 170 Node* listChildNode = enclosingListChild(insertionPosition.parentAnchoredEqu
ivalent().containerNode()); | 170 Node* listChildNode = enclosingListChild(insertionPosition.parentAnchoredEqu
ivalent().containerNode()); |
| 171 RefPtrWillBeRawPtr<HTMLElement> listChild = listChildNode && listChildNode->
isHTMLElement() ? toHTMLElement(listChildNode) : 0; | 171 RefPtrWillBeRawPtr<HTMLElement> listChild = listChildNode && listChildNode->
isHTMLElement() ? toHTMLElement(listChildNode) : 0; |
| 172 Position canonicalPos = VisiblePosition(insertionPosition).deepEquivalent(); | 172 Position canonicalPos = VisiblePosition(insertionPosition).deepEquivalent(); |
| 173 if (!startBlock | 173 if (!startBlock |
| 174 || !startBlock->nonShadowBoundaryParentNode() | 174 || !startBlock->nonShadowBoundaryParentNode() |
| 175 || isTableCell(startBlock.get()) | 175 || isTableCell(startBlock.get()) |
| 176 || isHTMLFormElement(*startBlock) | 176 || isHTMLFormElement(*startBlock) |
| 177 // FIXME: If the node is hidden, we don't have a canonical position so w
e will do the wrong thing for tables and <hr>. https://bugs.webkit.org/show_bug.
cgi?id=40342 | 177 // FIXME: If the node is hidden, we don't have a canonical position so w
e will do the wrong thing for tables and <hr>. https://bugs.webkit.org/show_bug.
cgi?id=40342 |
| 178 || (!canonicalPos.isNull() && isRenderedTableElement(canonicalPos.deprec
atedNode())) | 178 || (!canonicalPos.isNull() && isRenderedTableElement(canonicalPos.anchor
Node())) |
| 179 || (!canonicalPos.isNull() && isHTMLHRElement(*canonicalPos.deprecatedNo
de()))) { | 179 || (!canonicalPos.isNull() && isHTMLHRElement(*canonicalPos.anchorNode()
))) { |
| 180 applyCommandToComposite(InsertLineBreakCommand::create(document())); | 180 applyCommandToComposite(InsertLineBreakCommand::create(document())); |
| 181 return; | 181 return; |
| 182 } | 182 } |
| 183 | 183 |
| 184 // Use the leftmost candidate. | 184 // Use the leftmost candidate. |
| 185 insertionPosition = insertionPosition.upstream(); | 185 insertionPosition = insertionPosition.upstream(); |
| 186 if (!insertionPosition.isCandidate()) | 186 if (!insertionPosition.isCandidate()) |
| 187 insertionPosition = insertionPosition.downstream(); | 187 insertionPosition = insertionPosition.downstream(); |
| 188 | 188 |
| 189 // Adjust the insertion position after the delete | 189 // Adjust the insertion position after the delete |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 Element* siblingElement = startBlock.get(); | 245 Element* siblingElement = startBlock.get(); |
| 246 if (isHTMLDivElement(*blockToInsert)) | 246 if (isHTMLDivElement(*blockToInsert)) |
| 247 siblingElement = highestVisuallyEquivalentDivBelowRoot(start
Block.get()); | 247 siblingElement = highestVisuallyEquivalentDivBelowRoot(start
Block.get()); |
| 248 insertNodeAfter(blockToInsert, siblingElement); | 248 insertNodeAfter(blockToInsert, siblingElement); |
| 249 } | 249 } |
| 250 } | 250 } |
| 251 | 251 |
| 252 // Recreate the same structure in the new paragraph. | 252 // Recreate the same structure in the new paragraph. |
| 253 | 253 |
| 254 WillBeHeapVector<RefPtrWillBeMember<Element>> ancestors; | 254 WillBeHeapVector<RefPtrWillBeMember<Element>> ancestors; |
| 255 getAncestorsInsideBlock(positionOutsideTabSpan(insertionPosition).deprec
atedNode(), startBlock.get(), ancestors); | 255 getAncestorsInsideBlock(positionOutsideTabSpan(insertionPosition).anchor
Node(), startBlock.get(), ancestors); |
| 256 RefPtrWillBeRawPtr<Element> parent = cloneHierarchyUnderNewBlock(ancesto
rs, blockToInsert); | 256 RefPtrWillBeRawPtr<Element> parent = cloneHierarchyUnderNewBlock(ancesto
rs, blockToInsert); |
| 257 | 257 |
| 258 appendBlockPlaceholder(parent); | 258 appendBlockPlaceholder(parent); |
| 259 | 259 |
| 260 setEndingSelection(VisibleSelection(firstPositionInNode(parent.get()), D
OWNSTREAM, endingSelection().isDirectional())); | 260 setEndingSelection(VisibleSelection(firstPositionInNode(parent.get()), D
OWNSTREAM, endingSelection().isDirectional())); |
| 261 return; | 261 return; |
| 262 } | 262 } |
| 263 | 263 |
| 264 | 264 |
| 265 //--------------------------------------------------------------------- | 265 //--------------------------------------------------------------------- |
| 266 // Handle case when position is in the first visible position in its block,
and | 266 // Handle case when position is in the first visible position in its block,
and |
| 267 // similar case where previous position is in another, presumeably nested, b
lock. | 267 // similar case where previous position is in another, presumeably nested, b
lock. |
| 268 if (isFirstInBlock || !inSameBlock(visiblePos, visiblePos.previous())) { | 268 if (isFirstInBlock || !inSameBlock(visiblePos, visiblePos.previous())) { |
| 269 Node* refNode = nullptr; | 269 Node* refNode = nullptr; |
| 270 insertionPosition = positionOutsideTabSpan(insertionPosition); | 270 insertionPosition = positionOutsideTabSpan(insertionPosition); |
| 271 | 271 |
| 272 if (isFirstInBlock && !nestNewBlock) { | 272 if (isFirstInBlock && !nestNewBlock) { |
| 273 if (listChild && listChild != startBlock) { | 273 if (listChild && listChild != startBlock) { |
| 274 RefPtrWillBeRawPtr<Element> listChildToInsert = listChild->clone
ElementWithoutChildren(); | 274 RefPtrWillBeRawPtr<Element> listChildToInsert = listChild->clone
ElementWithoutChildren(); |
| 275 appendNode(blockToInsert, listChildToInsert.get()); | 275 appendNode(blockToInsert, listChildToInsert.get()); |
| 276 insertNodeBefore(listChildToInsert.get(), listChild); | 276 insertNodeBefore(listChildToInsert.get(), listChild); |
| 277 } else { | 277 } else { |
| 278 refNode = startBlock.get(); | 278 refNode = startBlock.get(); |
| 279 } | 279 } |
| 280 } else if (isFirstInBlock && nestNewBlock) { | 280 } else if (isFirstInBlock && nestNewBlock) { |
| 281 // startBlock should always have children, otherwise isLastInBlock w
ould be true and it's handled above. | 281 // startBlock should always have children, otherwise isLastInBlock w
ould be true and it's handled above. |
| 282 ASSERT(startBlock->hasChildren()); | 282 ASSERT(startBlock->hasChildren()); |
| 283 refNode = startBlock->firstChild(); | 283 refNode = startBlock->firstChild(); |
| 284 } | 284 } else if (insertionPosition.anchorNode() == startBlock && nestNewBlock)
{ |
| 285 else if (insertionPosition.deprecatedNode() == startBlock && nestNewBloc
k) { | |
| 286 refNode = NodeTraversal::childAt(*startBlock, insertionPosition.depr
ecatedEditingOffset()); | 285 refNode = NodeTraversal::childAt(*startBlock, insertionPosition.depr
ecatedEditingOffset()); |
| 287 ASSERT(refNode); // must be true or we'd be in the end of block case | 286 ASSERT(refNode); // must be true or we'd be in the end of block case |
| 288 } else | 287 } else { |
| 289 refNode = insertionPosition.deprecatedNode(); | 288 refNode = insertionPosition.anchorNode(); |
| 289 } |
| 290 | 290 |
| 291 // find ending selection position easily before inserting the paragraph | 291 // find ending selection position easily before inserting the paragraph |
| 292 insertionPosition = insertionPosition.downstream(); | 292 insertionPosition = insertionPosition.downstream(); |
| 293 | 293 |
| 294 if (refNode) | 294 if (refNode) |
| 295 insertNodeBefore(blockToInsert, refNode); | 295 insertNodeBefore(blockToInsert, refNode); |
| 296 | 296 |
| 297 // Recreate the same structure in the new paragraph. | 297 // Recreate the same structure in the new paragraph. |
| 298 | 298 |
| 299 WillBeHeapVector<RefPtrWillBeMember<Element>> ancestors; | 299 WillBeHeapVector<RefPtrWillBeMember<Element>> ancestors; |
| 300 getAncestorsInsideBlock(positionAvoidingSpecialElementBoundary(positionO
utsideTabSpan(insertionPosition)).deprecatedNode(), startBlock.get(), ancestors)
; | 300 getAncestorsInsideBlock(positionAvoidingSpecialElementBoundary(positionO
utsideTabSpan(insertionPosition)).anchorNode(), startBlock.get(), ancestors); |
| 301 | 301 |
| 302 appendBlockPlaceholder(cloneHierarchyUnderNewBlock(ancestors, blockToIns
ert)); | 302 appendBlockPlaceholder(cloneHierarchyUnderNewBlock(ancestors, blockToIns
ert)); |
| 303 | 303 |
| 304 // In this case, we need to set the new ending selection. | 304 // In this case, we need to set the new ending selection. |
| 305 setEndingSelection(VisibleSelection(insertionPosition, DOWNSTREAM, endin
gSelection().isDirectional())); | 305 setEndingSelection(VisibleSelection(insertionPosition, DOWNSTREAM, endin
gSelection().isDirectional())); |
| 306 return; | 306 return; |
| 307 } | 307 } |
| 308 | 308 |
| 309 //--------------------------------------------------------------------- | 309 //--------------------------------------------------------------------- |
| 310 // Handle the (more complicated) general case, | 310 // Handle the (more complicated) general case, |
| (...skipping 18 matching lines...) Expand all Loading... |
| 329 // style of the upstream position. | 329 // style of the upstream position. |
| 330 insertionPosition = insertionPosition.downstream(); | 330 insertionPosition = insertionPosition.downstream(); |
| 331 | 331 |
| 332 // At this point, the insertionPosition's node could be a container, and we
want to make sure we include | 332 // At this point, the insertionPosition's node could be a container, and we
want to make sure we include |
| 333 // all of the correct nodes when building the ancestor list. So this needs
to be the deepest representation of the position | 333 // all of the correct nodes when building the ancestor list. So this needs
to be the deepest representation of the position |
| 334 // before we walk the DOM tree. | 334 // before we walk the DOM tree. |
| 335 insertionPosition = positionOutsideTabSpan(VisiblePosition(insertionPosition
).deepEquivalent()); | 335 insertionPosition = positionOutsideTabSpan(VisiblePosition(insertionPosition
).deepEquivalent()); |
| 336 | 336 |
| 337 // If the returned position lies either at the end or at the start of an ele
ment that is ignored by editing | 337 // If the returned position lies either at the end or at the start of an ele
ment that is ignored by editing |
| 338 // we should move to its upstream or downstream position. | 338 // we should move to its upstream or downstream position. |
| 339 if (editingIgnoresContent(insertionPosition.deprecatedNode())) { | 339 if (editingIgnoresContent(insertionPosition.anchorNode())) { |
| 340 if (insertionPosition.atLastEditingPositionForNode()) | 340 if (insertionPosition.atLastEditingPositionForNode()) |
| 341 insertionPosition = insertionPosition.downstream(); | 341 insertionPosition = insertionPosition.downstream(); |
| 342 else if (insertionPosition.atFirstEditingPositionForNode()) | 342 else if (insertionPosition.atFirstEditingPositionForNode()) |
| 343 insertionPosition = insertionPosition.upstream(); | 343 insertionPosition = insertionPosition.upstream(); |
| 344 } | 344 } |
| 345 | 345 |
| 346 // Make sure we do not cause a rendered space to become unrendered. | 346 // Make sure we do not cause a rendered space to become unrendered. |
| 347 // FIXME: We need the affinity for pos, but pos.downstream() does not give i
t | 347 // FIXME: We need the affinity for pos, but pos.downstream() does not give i
t |
| 348 Position leadingWhitespace = leadingWhitespacePosition(insertionPosition, VP
_DEFAULT_AFFINITY); | 348 Position leadingWhitespace = leadingWhitespacePosition(insertionPosition, VP
_DEFAULT_AFFINITY); |
| 349 // FIXME: leadingWhitespacePosition is returning the position before preserv
ed newlines for positions | 349 // FIXME: leadingWhitespacePosition is returning the position before preserv
ed newlines for positions |
| 350 // after the preserved newline, causing the newline to be turned into a nbsp
. | 350 // after the preserved newline, causing the newline to be turned into a nbsp
. |
| 351 if (leadingWhitespace.isNotNull() && leadingWhitespace.deprecatedNode()->isT
extNode()) { | 351 if (leadingWhitespace.isNotNull() && leadingWhitespace.anchorNode()->isTextN
ode()) { |
| 352 Text* textNode = toText(leadingWhitespace.deprecatedNode()); | 352 Text* textNode = toText(leadingWhitespace.anchorNode()); |
| 353 ASSERT(!textNode->layoutObject() || textNode->layoutObject()->style()->c
ollapseWhiteSpace()); | 353 ASSERT(!textNode->layoutObject() || textNode->layoutObject()->style()->c
ollapseWhiteSpace()); |
| 354 replaceTextInNodePreservingMarkers(textNode, leadingWhitespace.deprecate
dEditingOffset(), 1, nonBreakingSpaceString()); | 354 replaceTextInNodePreservingMarkers(textNode, leadingWhitespace.deprecate
dEditingOffset(), 1, nonBreakingSpaceString()); |
| 355 } | 355 } |
| 356 | 356 |
| 357 // Split at pos if in the middle of a text node. | 357 // Split at pos if in the middle of a text node. |
| 358 Position positionAfterSplit; | 358 Position positionAfterSplit; |
| 359 if (insertionPosition.anchorType() == PositionAnchorType::OffsetInAnchor &&
insertionPosition.containerNode()->isTextNode()) { | 359 if (insertionPosition.anchorType() == PositionAnchorType::OffsetInAnchor &&
insertionPosition.containerNode()->isTextNode()) { |
| 360 RefPtrWillBeRawPtr<Text> textNode = toText(insertionPosition.containerNo
de()); | 360 RefPtrWillBeRawPtr<Text> textNode = toText(insertionPosition.containerNo
de()); |
| 361 bool atEnd = static_cast<unsigned>(insertionPosition.offsetInContainerNo
de()) >= textNode->length(); | 361 bool atEnd = static_cast<unsigned>(insertionPosition.offsetInContainerNo
de()) >= textNode->length(); |
| 362 if (insertionPosition.deprecatedEditingOffset() > 0 && !atEnd) { | 362 if (insertionPosition.deprecatedEditingOffset() > 0 && !atEnd) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 412 moveRemainingSiblingsToNewParent(n, blockToInsert.get(), blockToInsert); | 412 moveRemainingSiblingsToNewParent(n, blockToInsert.get(), blockToInsert); |
| 413 } | 413 } |
| 414 | 414 |
| 415 // Handle whitespace that occurs after the split | 415 // Handle whitespace that occurs after the split |
| 416 if (positionAfterSplit.isNotNull()) { | 416 if (positionAfterSplit.isNotNull()) { |
| 417 document().updateLayoutIgnorePendingStylesheets(); | 417 document().updateLayoutIgnorePendingStylesheets(); |
| 418 if (!positionAfterSplit.isRenderedCharacter()) { | 418 if (!positionAfterSplit.isRenderedCharacter()) { |
| 419 // Clear out all whitespace and insert one non-breaking space | 419 // Clear out all whitespace and insert one non-breaking space |
| 420 ASSERT(!positionAfterSplit.containerNode()->layoutObject() || positi
onAfterSplit.containerNode()->layoutObject()->style()->collapseWhiteSpace()); | 420 ASSERT(!positionAfterSplit.containerNode()->layoutObject() || positi
onAfterSplit.containerNode()->layoutObject()->style()->collapseWhiteSpace()); |
| 421 deleteInsignificantTextDownstream(positionAfterSplit); | 421 deleteInsignificantTextDownstream(positionAfterSplit); |
| 422 if (positionAfterSplit.deprecatedNode()->isTextNode()) | 422 if (positionAfterSplit.anchorNode()->isTextNode()) |
| 423 insertTextIntoNode(toText(positionAfterSplit.containerNode()), 0
, nonBreakingSpaceString()); | 423 insertTextIntoNode(toText(positionAfterSplit.containerNode()), 0
, nonBreakingSpaceString()); |
| 424 } | 424 } |
| 425 } | 425 } |
| 426 | 426 |
| 427 setEndingSelection(VisibleSelection(firstPositionInNode(blockToInsert.get())
, DOWNSTREAM, endingSelection().isDirectional())); | 427 setEndingSelection(VisibleSelection(firstPositionInNode(blockToInsert.get())
, DOWNSTREAM, endingSelection().isDirectional())); |
| 428 applyStyleAfterInsertion(startBlock.get()); | 428 applyStyleAfterInsertion(startBlock.get()); |
| 429 } | 429 } |
| 430 | 430 |
| 431 DEFINE_TRACE(InsertParagraphSeparatorCommand) | 431 DEFINE_TRACE(InsertParagraphSeparatorCommand) |
| 432 { | 432 { |
| 433 visitor->trace(m_style); | 433 visitor->trace(m_style); |
| 434 CompositeEditCommand::trace(visitor); | 434 CompositeEditCommand::trace(visitor); |
| 435 } | 435 } |
| 436 | 436 |
| 437 | 437 |
| 438 } // namespace blink | 438 } // namespace blink |
| OLD | NEW |