| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2005, 2006, 2008, 2009 Apple Inc. All rights reserved. | 2 * Copyright (C) 2005, 2006, 2008, 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 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 | 252 |
| 253 VisiblePosition visibleStart(start); | 253 VisiblePosition visibleStart(start); |
| 254 VisiblePosition visibleEnd(end); | 254 VisiblePosition visibleEnd(end); |
| 255 | 255 |
| 256 if (visibleStart.isNull() || visibleStart.isOrphan() || visibleEnd.isNull()
|| visibleEnd.isOrphan()) | 256 if (visibleStart.isNull() || visibleStart.isOrphan() || visibleEnd.isNull()
|| visibleEnd.isOrphan()) |
| 257 return; | 257 return; |
| 258 | 258 |
| 259 // Save and restore the selection endpoints using their indices in the docum
ent, since | 259 // Save and restore the selection endpoints using their indices in the docum
ent, since |
| 260 // addBlockStyleIfNeeded may moveParagraphs, which can remove these endpoint
s. | 260 // addBlockStyleIfNeeded may moveParagraphs, which can remove these endpoint
s. |
| 261 // Calculate start and end indices from the start of the tree that they're i
n. | 261 // Calculate start and end indices from the start of the tree that they're i
n. |
| 262 Node& scope = NodeTraversal::highestAncestorOrSelf(*visibleStart.deepEquival
ent().deprecatedNode()); | 262 Node& scope = NodeTraversal::highestAncestorOrSelf(*visibleStart.deepEquival
ent().anchorNode()); |
| 263 RefPtrWillBeRawPtr<Range> startRange = Range::create(document(), firstPositi
onInNode(&scope), visibleStart.deepEquivalent().parentAnchoredEquivalent()); | 263 RefPtrWillBeRawPtr<Range> startRange = Range::create(document(), firstPositi
onInNode(&scope), visibleStart.deepEquivalent().parentAnchoredEquivalent()); |
| 264 RefPtrWillBeRawPtr<Range> endRange = Range::create(document(), firstPosition
InNode(&scope), visibleEnd.deepEquivalent().parentAnchoredEquivalent()); | 264 RefPtrWillBeRawPtr<Range> endRange = Range::create(document(), firstPosition
InNode(&scope), visibleEnd.deepEquivalent().parentAnchoredEquivalent()); |
| 265 int startIndex = TextIterator::rangeLength(startRange->startPosition(), star
tRange->endPosition(), true); | 265 int startIndex = TextIterator::rangeLength(startRange->startPosition(), star
tRange->endPosition(), true); |
| 266 int endIndex = TextIterator::rangeLength(endRange->startPosition(), endRange
->endPosition(), true); | 266 int endIndex = TextIterator::rangeLength(endRange->startPosition(), endRange
->endPosition(), true); |
| 267 | 267 |
| 268 VisiblePosition paragraphStart(startOfParagraph(visibleStart)); | 268 VisiblePosition paragraphStart(startOfParagraph(visibleStart)); |
| 269 VisiblePosition nextParagraphStart(endOfParagraph(paragraphStart).next()); | 269 VisiblePosition nextParagraphStart(endOfParagraph(paragraphStart).next()); |
| 270 VisiblePosition beyondEnd(endOfParagraph(visibleEnd).next()); | 270 VisiblePosition beyondEnd(endOfParagraph(visibleEnd).next()); |
| 271 while (paragraphStart.isNotNull() && paragraphStart != beyondEnd) { | 271 while (paragraphStart.isNotNull() && paragraphStart != beyondEnd) { |
| 272 StyleChange styleChange(style, paragraphStart.deepEquivalent()); | 272 StyleChange styleChange(style, paragraphStart.deepEquivalent()); |
| 273 if (styleChange.cssStyle().length() || m_removeOnly) { | 273 if (styleChange.cssStyle().length() || m_removeOnly) { |
| 274 RefPtrWillBeRawPtr<Element> block = enclosingBlock(paragraphStart.de
epEquivalent().deprecatedNode()); | 274 RefPtrWillBeRawPtr<Element> block = enclosingBlock(paragraphStart.de
epEquivalent().anchorNode()); |
| 275 const Position& paragraphStartToMove = paragraphStart.deepEquivalent
(); | 275 const Position& paragraphStartToMove = paragraphStart.deepEquivalent
(); |
| 276 if (!m_removeOnly && isEditablePosition(paragraphStartToMove)) { | 276 if (!m_removeOnly && isEditablePosition(paragraphStartToMove)) { |
| 277 RefPtrWillBeRawPtr<HTMLElement> newBlock = moveParagraphContents
ToNewBlockIfNecessary(paragraphStartToMove); | 277 RefPtrWillBeRawPtr<HTMLElement> newBlock = moveParagraphContents
ToNewBlockIfNecessary(paragraphStartToMove); |
| 278 if (newBlock) | 278 if (newBlock) |
| 279 block = newBlock; | 279 block = newBlock; |
| 280 } | 280 } |
| 281 if (block && block->isHTMLElement()) { | 281 if (block && block->isHTMLElement()) { |
| 282 removeCSSStyle(style, toHTMLElement(block)); | 282 removeCSSStyle(style, toHTMLElement(block)); |
| 283 if (!m_removeOnly) | 283 if (!m_removeOnly) |
| 284 addBlockStyle(styleChange, toHTMLElement(block)); | 284 addBlockStyle(styleChange, toHTMLElement(block)); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 317 | 317 |
| 318 Position start = startPosition(); | 318 Position start = startPosition(); |
| 319 Position end = endPosition(); | 319 Position end = endPosition(); |
| 320 if (comparePositions(end, start) < 0) { | 320 if (comparePositions(end, start) < 0) { |
| 321 Position swap = start; | 321 Position swap = start; |
| 322 start = end; | 322 start = end; |
| 323 end = swap; | 323 end = swap; |
| 324 } | 324 } |
| 325 | 325 |
| 326 // Join up any adjacent text nodes. | 326 // Join up any adjacent text nodes. |
| 327 if (start.deprecatedNode()->isTextNode()) { | 327 if (start.anchorNode()->isTextNode()) { |
| 328 joinChildTextNodes(start.deprecatedNode()->parentNode(), start, end); | 328 joinChildTextNodes(start.anchorNode()->parentNode(), start, end); |
| 329 start = startPosition(); | 329 start = startPosition(); |
| 330 end = endPosition(); | 330 end = endPosition(); |
| 331 } | 331 } |
| 332 | 332 |
| 333 if (start.isNull() || end.isNull()) | 333 if (start.isNull() || end.isNull()) |
| 334 return; | 334 return; |
| 335 | 335 |
| 336 if (end.deprecatedNode()->isTextNode() && start.deprecatedNode()->parentNode
() != end.deprecatedNode()->parentNode()) { | 336 if (end.anchorNode()->isTextNode() && start.anchorNode()->parentNode() != en
d.anchorNode()->parentNode()) { |
| 337 joinChildTextNodes(end.deprecatedNode()->parentNode(), start, end); | 337 joinChildTextNodes(end.anchorNode()->parentNode(), start, end); |
| 338 start = startPosition(); | 338 start = startPosition(); |
| 339 end = endPosition(); | 339 end = endPosition(); |
| 340 } | 340 } |
| 341 | 341 |
| 342 if (start.isNull() || end.isNull()) | 342 if (start.isNull() || end.isNull()) |
| 343 return; | 343 return; |
| 344 | 344 |
| 345 // Split the start text nodes if needed to apply style. | 345 // Split the start text nodes if needed to apply style. |
| 346 if (isValidCaretPositionInTextNode(start)) { | 346 if (isValidCaretPositionInTextNode(start)) { |
| 347 splitTextAtStart(start, end); | 347 splitTextAtStart(start, end); |
| 348 start = startPosition(); | 348 start = startPosition(); |
| 349 end = endPosition(); | 349 end = endPosition(); |
| 350 } | 350 } |
| 351 | 351 |
| 352 if (isValidCaretPositionInTextNode(end)) { | 352 if (isValidCaretPositionInTextNode(end)) { |
| 353 splitTextAtEnd(start, end); | 353 splitTextAtEnd(start, end); |
| 354 start = startPosition(); | 354 start = startPosition(); |
| 355 end = endPosition(); | 355 end = endPosition(); |
| 356 } | 356 } |
| 357 | 357 |
| 358 // Calculate loop end point. | 358 // Calculate loop end point. |
| 359 // If the end node is before the start node (can only happen if the end node
is | 359 // If the end node is before the start node (can only happen if the end node
is |
| 360 // an ancestor of the start node), we gather nodes up to the next sibling of
the end node | 360 // an ancestor of the start node), we gather nodes up to the next sibling of
the end node |
| 361 Node* beyondEnd; | 361 Node* beyondEnd; |
| 362 ASSERT(start.deprecatedNode()); | 362 ASSERT(start.anchorNode()); |
| 363 ASSERT(end.deprecatedNode()); | 363 ASSERT(end.anchorNode()); |
| 364 if (start.deprecatedNode()->isDescendantOf(end.deprecatedNode())) | 364 if (start.anchorNode()->isDescendantOf(end.anchorNode())) |
| 365 beyondEnd = NodeTraversal::nextSkippingChildren(*end.deprecatedNode()); | 365 beyondEnd = NodeTraversal::nextSkippingChildren(*end.anchorNode()); |
| 366 else | 366 else |
| 367 beyondEnd = NodeTraversal::next(*end.deprecatedNode()); | 367 beyondEnd = NodeTraversal::next(*end.anchorNode()); |
| 368 | 368 |
| 369 start = start.upstream(); // Move upstream to ensure we do not add redundant
spans. | 369 start = start.upstream(); // Move upstream to ensure we do not add redundant
spans. |
| 370 Node* startNode = start.deprecatedNode(); | 370 Node* startNode = start.anchorNode(); |
| 371 ASSERT(startNode); | 371 ASSERT(startNode); |
| 372 | 372 |
| 373 // Make sure we're not already at the end or the next NodeTraversal::next()
will traverse | 373 // Make sure we're not already at the end or the next NodeTraversal::next()
will traverse |
| 374 // past it. | 374 // past it. |
| 375 if (startNode == beyondEnd) | 375 if (startNode == beyondEnd) |
| 376 return; | 376 return; |
| 377 | 377 |
| 378 if (startNode->isTextNode() && start.deprecatedEditingOffset() >= caretMaxOf
fset(startNode)) { | 378 if (startNode->isTextNode() && start.deprecatedEditingOffset() >= caretMaxOf
fset(startNode)) { |
| 379 // Move out of text node if range does not include its characters. | 379 // Move out of text node if range does not include its characters. |
| 380 startNode = NodeTraversal::next(*startNode); | 380 startNode = NodeTraversal::next(*startNode); |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 576 | 576 |
| 577 if (comparePositions(end, start) < 0) { | 577 if (comparePositions(end, start) < 0) { |
| 578 Position swap = start; | 578 Position swap = start; |
| 579 start = end; | 579 start = end; |
| 580 end = swap; | 580 end = swap; |
| 581 } | 581 } |
| 582 | 582 |
| 583 // split the start node and containing element if the selection starts insid
e of it | 583 // split the start node and containing element if the selection starts insid
e of it |
| 584 bool splitStart = isValidCaretPositionInTextNode(start); | 584 bool splitStart = isValidCaretPositionInTextNode(start); |
| 585 if (splitStart) { | 585 if (splitStart) { |
| 586 if (shouldSplitTextElement(start.deprecatedNode()->parentElement(), styl
e)) | 586 if (shouldSplitTextElement(start.anchorNode()->parentElement(), style)) |
| 587 splitTextElementAtStart(start, end); | 587 splitTextElementAtStart(start, end); |
| 588 else | 588 else |
| 589 splitTextAtStart(start, end); | 589 splitTextAtStart(start, end); |
| 590 start = startPosition(); | 590 start = startPosition(); |
| 591 end = endPosition(); | 591 end = endPosition(); |
| 592 if (start.isNull() || end.isNull()) | 592 if (start.isNull() || end.isNull()) |
| 593 return; | 593 return; |
| 594 startDummySpanAncestor = dummySpanAncestorForNode(start.deprecatedNode()
); | 594 startDummySpanAncestor = dummySpanAncestorForNode(start.anchorNode()); |
| 595 } | 595 } |
| 596 | 596 |
| 597 // split the end node and containing element if the selection ends inside of
it | 597 // split the end node and containing element if the selection ends inside of
it |
| 598 bool splitEnd = isValidCaretPositionInTextNode(end); | 598 bool splitEnd = isValidCaretPositionInTextNode(end); |
| 599 if (splitEnd) { | 599 if (splitEnd) { |
| 600 if (shouldSplitTextElement(end.deprecatedNode()->parentElement(), style)
) | 600 if (shouldSplitTextElement(end.anchorNode()->parentElement(), style)) |
| 601 splitTextElementAtEnd(start, end); | 601 splitTextElementAtEnd(start, end); |
| 602 else | 602 else |
| 603 splitTextAtEnd(start, end); | 603 splitTextAtEnd(start, end); |
| 604 start = startPosition(); | 604 start = startPosition(); |
| 605 end = endPosition(); | 605 end = endPosition(); |
| 606 if (start.isNull() || end.isNull()) | 606 if (start.isNull() || end.isNull()) |
| 607 return; | 607 return; |
| 608 endDummySpanAncestor = dummySpanAncestorForNode(end.deprecatedNode()); | 608 endDummySpanAncestor = dummySpanAncestorForNode(end.anchorNode()); |
| 609 } | 609 } |
| 610 | 610 |
| 611 // Remove style from the selection. | 611 // Remove style from the selection. |
| 612 // Use the upstream position of the start for removing style. | 612 // Use the upstream position of the start for removing style. |
| 613 // This will ensure we remove all traces of the relevant styles from the sel
ection | 613 // This will ensure we remove all traces of the relevant styles from the sel
ection |
| 614 // and prevent us from adding redundant ones, as described in: | 614 // and prevent us from adding redundant ones, as described in: |
| 615 // <rdar://problem/3724344> Bolding and unbolding creates extraneous tags | 615 // <rdar://problem/3724344> Bolding and unbolding creates extraneous tags |
| 616 Position removeStart = start.upstream(); | 616 Position removeStart = start.upstream(); |
| 617 WritingDirection textDirection = NaturalWritingDirection; | 617 WritingDirection textDirection = NaturalWritingDirection; |
| 618 bool hasTextDirection = style->textDirection(textDirection); | 618 bool hasTextDirection = style->textDirection(textDirection); |
| 619 RefPtrWillBeRawPtr<EditingStyle> styleWithoutEmbedding = nullptr; | 619 RefPtrWillBeRawPtr<EditingStyle> styleWithoutEmbedding = nullptr; |
| 620 RefPtrWillBeRawPtr<EditingStyle> embeddingStyle = nullptr; | 620 RefPtrWillBeRawPtr<EditingStyle> embeddingStyle = nullptr; |
| 621 if (hasTextDirection) { | 621 if (hasTextDirection) { |
| 622 // Leave alone an ancestor that provides the desired single level embedd
ing, if there is one. | 622 // Leave alone an ancestor that provides the desired single level embedd
ing, if there is one. |
| 623 HTMLElement* startUnsplitAncestor = splitAncestorsWithUnicodeBidi(start.
deprecatedNode(), true, textDirection); | 623 HTMLElement* startUnsplitAncestor = splitAncestorsWithUnicodeBidi(start.
anchorNode(), true, textDirection); |
| 624 HTMLElement* endUnsplitAncestor = splitAncestorsWithUnicodeBidi(end.depr
ecatedNode(), false, textDirection); | 624 HTMLElement* endUnsplitAncestor = splitAncestorsWithUnicodeBidi(end.anch
orNode(), false, textDirection); |
| 625 removeEmbeddingUpToEnclosingBlock(start.deprecatedNode(), startUnsplitAn
cestor); | 625 removeEmbeddingUpToEnclosingBlock(start.anchorNode(), startUnsplitAncest
or); |
| 626 removeEmbeddingUpToEnclosingBlock(end.deprecatedNode(), endUnsplitAncest
or); | 626 removeEmbeddingUpToEnclosingBlock(end.anchorNode(), endUnsplitAncestor); |
| 627 | 627 |
| 628 // Avoid removing the dir attribute and the unicode-bidi and direction p
roperties from the unsplit ancestors. | 628 // Avoid removing the dir attribute and the unicode-bidi and direction p
roperties from the unsplit ancestors. |
| 629 Position embeddingRemoveStart = removeStart; | 629 Position embeddingRemoveStart = removeStart; |
| 630 if (startUnsplitAncestor && elementFullySelected(*startUnsplitAncestor,
removeStart, end)) | 630 if (startUnsplitAncestor && elementFullySelected(*startUnsplitAncestor,
removeStart, end)) |
| 631 embeddingRemoveStart = positionInParentAfterNode(*startUnsplitAncest
or); | 631 embeddingRemoveStart = positionInParentAfterNode(*startUnsplitAncest
or); |
| 632 | 632 |
| 633 Position embeddingRemoveEnd = end; | 633 Position embeddingRemoveEnd = end; |
| 634 if (endUnsplitAncestor && elementFullySelected(*endUnsplitAncestor, remo
veStart, end)) | 634 if (endUnsplitAncestor && elementFullySelected(*endUnsplitAncestor, remo
veStart, end)) |
| 635 embeddingRemoveEnd = positionInParentBeforeNode(*endUnsplitAncestor)
.downstream(); | 635 embeddingRemoveEnd = positionInParentBeforeNode(*endUnsplitAncestor)
.downstream(); |
| 636 | 636 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 661 } | 661 } |
| 662 | 662 |
| 663 // update document layout once before running the rest of the function | 663 // update document layout once before running the rest of the function |
| 664 // so that we avoid the expense of updating before each and every call | 664 // so that we avoid the expense of updating before each and every call |
| 665 // to check a computed style | 665 // to check a computed style |
| 666 document().updateLayoutIgnorePendingStylesheets(); | 666 document().updateLayoutIgnorePendingStylesheets(); |
| 667 | 667 |
| 668 RefPtrWillBeRawPtr<EditingStyle> styleToApply = style; | 668 RefPtrWillBeRawPtr<EditingStyle> styleToApply = style; |
| 669 if (hasTextDirection) { | 669 if (hasTextDirection) { |
| 670 // Avoid applying the unicode-bidi and direction properties beneath ance
stors that already have them. | 670 // Avoid applying the unicode-bidi and direction properties beneath ance
stors that already have them. |
| 671 HTMLElement* embeddingStartElement = highestEmbeddingAncestor(start.depr
ecatedNode(), enclosingBlock(start.deprecatedNode())); | 671 HTMLElement* embeddingStartElement = highestEmbeddingAncestor(start.anch
orNode(), enclosingBlock(start.anchorNode())); |
| 672 HTMLElement* embeddingEndElement = highestEmbeddingAncestor(end.deprecat
edNode(), enclosingBlock(end.deprecatedNode())); | 672 HTMLElement* embeddingEndElement = highestEmbeddingAncestor(end.anchorNo
de(), enclosingBlock(end.anchorNode())); |
| 673 | 673 |
| 674 if (embeddingStartElement || embeddingEndElement) { | 674 if (embeddingStartElement || embeddingEndElement) { |
| 675 Position embeddingApplyStart = embeddingStartElement ? positionInPar
entAfterNode(*embeddingStartElement) : start; | 675 Position embeddingApplyStart = embeddingStartElement ? positionInPar
entAfterNode(*embeddingStartElement) : start; |
| 676 Position embeddingApplyEnd = embeddingEndElement ? positionInParentB
eforeNode(*embeddingEndElement) : end; | 676 Position embeddingApplyEnd = embeddingEndElement ? positionInParentB
eforeNode(*embeddingEndElement) : end; |
| 677 ASSERT(embeddingApplyStart.isNotNull() && embeddingApplyEnd.isNotNul
l()); | 677 ASSERT(embeddingApplyStart.isNotNull() && embeddingApplyEnd.isNotNul
l()); |
| 678 | 678 |
| 679 if (!embeddingStyle) { | 679 if (!embeddingStyle) { |
| 680 styleWithoutEmbedding = style->copy(); | 680 styleWithoutEmbedding = style->copy(); |
| 681 embeddingStyle = styleWithoutEmbedding->extractAndRemoveTextDire
ction(); | 681 embeddingStyle = styleWithoutEmbedding->extractAndRemoveTextDire
ction(); |
| 682 } | 682 } |
| 683 fixRangeAndApplyInlineStyle(embeddingStyle.get(), embeddingApplyStar
t, embeddingApplyEnd); | 683 fixRangeAndApplyInlineStyle(embeddingStyle.get(), embeddingApplyStar
t, embeddingApplyEnd); |
| 684 | 684 |
| 685 styleToApply = styleWithoutEmbedding; | 685 styleToApply = styleWithoutEmbedding; |
| 686 } | 686 } |
| 687 } | 687 } |
| 688 | 688 |
| 689 fixRangeAndApplyInlineStyle(styleToApply.get(), start, end); | 689 fixRangeAndApplyInlineStyle(styleToApply.get(), start, end); |
| 690 | 690 |
| 691 // Remove dummy style spans created by splitting text elements. | 691 // Remove dummy style spans created by splitting text elements. |
| 692 cleanupUnstyledAppleStyleSpans(startDummySpanAncestor.get()); | 692 cleanupUnstyledAppleStyleSpans(startDummySpanAncestor.get()); |
| 693 if (endDummySpanAncestor != startDummySpanAncestor) | 693 if (endDummySpanAncestor != startDummySpanAncestor) |
| 694 cleanupUnstyledAppleStyleSpans(endDummySpanAncestor.get()); | 694 cleanupUnstyledAppleStyleSpans(endDummySpanAncestor.get()); |
| 695 } | 695 } |
| 696 | 696 |
| 697 void ApplyStyleCommand::fixRangeAndApplyInlineStyle(EditingStyle* style, const P
osition& start, const Position& end) | 697 void ApplyStyleCommand::fixRangeAndApplyInlineStyle(EditingStyle* style, const P
osition& start, const Position& end) |
| 698 { | 698 { |
| 699 Node* startNode = start.deprecatedNode(); | 699 Node* startNode = start.anchorNode(); |
| 700 ASSERT(startNode); | 700 ASSERT(startNode); |
| 701 | 701 |
| 702 if (start.deprecatedEditingOffset() >= caretMaxOffset(start.deprecatedNode()
)) { | 702 if (start.deprecatedEditingOffset() >= caretMaxOffset(start.anchorNode())) { |
| 703 startNode = NodeTraversal::next(*startNode); | 703 startNode = NodeTraversal::next(*startNode); |
| 704 if (!startNode || comparePositions(end, firstPositionInOrBeforeNode(star
tNode)) < 0) | 704 if (!startNode || comparePositions(end, firstPositionInOrBeforeNode(star
tNode)) < 0) |
| 705 return; | 705 return; |
| 706 } | 706 } |
| 707 | 707 |
| 708 Node* pastEndNode = end.deprecatedNode(); | 708 Node* pastEndNode = end.anchorNode(); |
| 709 if (end.deprecatedEditingOffset() >= caretMaxOffset(end.deprecatedNode())) | 709 if (end.deprecatedEditingOffset() >= caretMaxOffset(end.anchorNode())) |
| 710 pastEndNode = NodeTraversal::nextSkippingChildren(*end.deprecatedNode())
; | 710 pastEndNode = NodeTraversal::nextSkippingChildren(*end.anchorNode()); |
| 711 | 711 |
| 712 // FIXME: Callers should perform this operation on a Range that includes the
br | 712 // FIXME: Callers should perform this operation on a Range that includes the
br |
| 713 // if they want style applied to the empty line. | 713 // if they want style applied to the empty line. |
| 714 if (start == end && isHTMLBRElement(*start.deprecatedNode())) | 714 if (start == end && isHTMLBRElement(*start.anchorNode())) |
| 715 pastEndNode = NodeTraversal::next(*start.deprecatedNode()); | 715 pastEndNode = NodeTraversal::next(*start.anchorNode()); |
| 716 | 716 |
| 717 // Start from the highest fully selected ancestor so that we can modify the
fully selected node. | 717 // Start from the highest fully selected ancestor so that we can modify the
fully selected node. |
| 718 // e.g. When applying font-size: large on <font color="blue">hello</font>, w
e need to include the font element in our run | 718 // e.g. When applying font-size: large on <font color="blue">hello</font>, w
e need to include the font element in our run |
| 719 // to generate <font color="blue" size="4">hello</font> instead of <font col
or="blue"><font size="4">hello</font></font> | 719 // to generate <font color="blue" size="4">hello</font> instead of <font col
or="blue"><font size="4">hello</font></font> |
| 720 RefPtrWillBeRawPtr<Range> range = Range::create(startNode->document(), start
, end); | 720 RefPtrWillBeRawPtr<Range> range = Range::create(startNode->document(), start
, end); |
| 721 Element* editableRoot = startNode->rootEditableElement(); | 721 Element* editableRoot = startNode->rootEditableElement(); |
| 722 if (startNode != editableRoot) { | 722 if (startNode != editableRoot) { |
| 723 while (editableRoot && startNode->parentNode() != editableRoot && isNode
VisiblyContainedWithin(*startNode->parentNode(), *range)) | 723 while (editableRoot && startNode->parentNode() != editableRoot && isNode
VisiblyContainedWithin(*startNode->parentNode(), *range)) |
| 724 startNode = startNode->parentNode(); | 724 startNode = startNode->parentNode(); |
| 725 } | 725 } |
| (...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1129 if (pushDownStartContainer && pushDownStartContainer->isTextNode() | 1129 if (pushDownStartContainer && pushDownStartContainer->isTextNode() |
| 1130 && pushDownStart.computeOffsetInContainerNode() == pushDownStartContaine
r->maxCharacterOffset()) | 1130 && pushDownStart.computeOffsetInContainerNode() == pushDownStartContaine
r->maxCharacterOffset()) |
| 1131 pushDownStart = nextVisuallyDistinctCandidate(pushDownStart); | 1131 pushDownStart = nextVisuallyDistinctCandidate(pushDownStart); |
| 1132 Position pushDownEnd = end.upstream(); | 1132 Position pushDownEnd = end.upstream(); |
| 1133 // If pushDownEnd is at the start of a text node, then this node is not full
y selected. | 1133 // If pushDownEnd is at the start of a text node, then this node is not full
y selected. |
| 1134 // Move it to the previous deep equivalent position to avoid removing the st
yle from this node. | 1134 // Move it to the previous deep equivalent position to avoid removing the st
yle from this node. |
| 1135 Node* pushDownEndContainer = pushDownEnd.containerNode(); | 1135 Node* pushDownEndContainer = pushDownEnd.containerNode(); |
| 1136 if (pushDownEndContainer && pushDownEndContainer->isTextNode() && !pushDownE
nd.computeOffsetInContainerNode()) | 1136 if (pushDownEndContainer && pushDownEndContainer->isTextNode() && !pushDownE
nd.computeOffsetInContainerNode()) |
| 1137 pushDownEnd = previousVisuallyDistinctCandidate(pushDownEnd); | 1137 pushDownEnd = previousVisuallyDistinctCandidate(pushDownEnd); |
| 1138 | 1138 |
| 1139 pushDownInlineStyleAroundNode(style, pushDownStart.deprecatedNode()); | 1139 pushDownInlineStyleAroundNode(style, pushDownStart.anchorNode()); |
| 1140 pushDownInlineStyleAroundNode(style, pushDownEnd.deprecatedNode()); | 1140 pushDownInlineStyleAroundNode(style, pushDownEnd.anchorNode()); |
| 1141 | 1141 |
| 1142 // The s and e variables store the positions used to set the ending selectio
n after style removal | 1142 // The s and e variables store the positions used to set the ending selectio
n after style removal |
| 1143 // takes place. This will help callers to recognize when either the start no
de or the end node | 1143 // takes place. This will help callers to recognize when either the start no
de or the end node |
| 1144 // are removed from the document during the work of this function. | 1144 // are removed from the document during the work of this function. |
| 1145 // If pushDownInlineStyleAroundNode has pruned start.deprecatedNode() or end
.deprecatedNode(), | 1145 // If pushDownInlineStyleAroundNode has pruned start.anchorNode() or end.anc
horNode(), |
| 1146 // use pushDownStart or pushDownEnd instead, which pushDownInlineStyleAround
Node won't prune. | 1146 // use pushDownStart or pushDownEnd instead, which pushDownInlineStyleAround
Node won't prune. |
| 1147 Position s = start.isNull() || start.isOrphan() ? pushDownStart : start; | 1147 Position s = start.isNull() || start.isOrphan() ? pushDownStart : start; |
| 1148 Position e = end.isNull() || end.isOrphan() ? pushDownEnd : end; | 1148 Position e = end.isNull() || end.isOrphan() ? pushDownEnd : end; |
| 1149 | 1149 |
| 1150 // Current ending selection resetting algorithm assumes |start| and |end| | 1150 // Current ending selection resetting algorithm assumes |start| and |end| |
| 1151 // are in a same DOM tree even if they are not in document. | 1151 // are in a same DOM tree even if they are not in document. |
| 1152 if (!Position::commonAncestorTreeScope(start, end)) | 1152 if (!Position::commonAncestorTreeScope(start, end)) |
| 1153 return; | 1153 return; |
| 1154 | 1154 |
| 1155 RefPtrWillBeRawPtr<Node> node = start.deprecatedNode(); | 1155 RefPtrWillBeRawPtr<Node> node = start.anchorNode(); |
| 1156 while (node) { | 1156 while (node) { |
| 1157 RefPtrWillBeRawPtr<Node> next = nullptr; | 1157 RefPtrWillBeRawPtr<Node> next = nullptr; |
| 1158 if (editingIgnoresContent(node.get())) { | 1158 if (editingIgnoresContent(node.get())) { |
| 1159 ASSERT(node == end.deprecatedNode() || !node->contains(end.deprecate
dNode())); | 1159 ASSERT(node == end.anchorNode() || !node->contains(end.anchorNode())
); |
| 1160 next = NodeTraversal::nextSkippingChildren(*node); | 1160 next = NodeTraversal::nextSkippingChildren(*node); |
| 1161 } else { | 1161 } else { |
| 1162 next = NodeTraversal::next(*node); | 1162 next = NodeTraversal::next(*node); |
| 1163 } | 1163 } |
| 1164 if (node->isHTMLElement() && elementFullySelected(toHTMLElement(*node),
start, end)) { | 1164 if (node->isHTMLElement() && elementFullySelected(toHTMLElement(*node),
start, end)) { |
| 1165 RefPtrWillBeRawPtr<HTMLElement> elem = toHTMLElement(node); | 1165 RefPtrWillBeRawPtr<HTMLElement> elem = toHTMLElement(node); |
| 1166 RefPtrWillBeRawPtr<Node> prev = NodeTraversal::previousPostOrder(*el
em); | 1166 RefPtrWillBeRawPtr<Node> prev = NodeTraversal::previousPostOrder(*el
em); |
| 1167 RefPtrWillBeRawPtr<Node> next = NodeTraversal::next(*elem); | 1167 RefPtrWillBeRawPtr<Node> next = NodeTraversal::next(*elem); |
| 1168 RefPtrWillBeRawPtr<EditingStyle> styleToPushDown = nullptr; | 1168 RefPtrWillBeRawPtr<EditingStyle> styleToPushDown = nullptr; |
| 1169 RefPtrWillBeRawPtr<Node> childNode = nullptr; | 1169 RefPtrWillBeRawPtr<Node> childNode = nullptr; |
| 1170 if (isStyledInlineElementToRemove(elem.get())) { | 1170 if (isStyledInlineElementToRemove(elem.get())) { |
| 1171 styleToPushDown = EditingStyle::create(); | 1171 styleToPushDown = EditingStyle::create(); |
| 1172 childNode = elem->firstChild(); | 1172 childNode = elem->firstChild(); |
| 1173 } | 1173 } |
| 1174 | 1174 |
| 1175 removeInlineStyleFromElement(style, elem.get(), RemoveIfNeeded, styl
eToPushDown.get()); | 1175 removeInlineStyleFromElement(style, elem.get(), RemoveIfNeeded, styl
eToPushDown.get()); |
| 1176 if (!elem->inDocument()) { | 1176 if (!elem->inDocument()) { |
| 1177 if (s.deprecatedNode() == elem) { | 1177 if (s.anchorNode() == elem) { |
| 1178 // Since elem must have been fully selected, and it is at th
e start | 1178 // Since elem must have been fully selected, and it is at th
e start |
| 1179 // of the selection, it is clear we can set the new s offset
to 0. | 1179 // of the selection, it is clear we can set the new s offset
to 0. |
| 1180 ASSERT(s.anchorType() == PositionAnchorType::BeforeAnchor ||
s.anchorType() == PositionAnchorType::BeforeChildren || s.offsetInContainerNode
() <= 0); | 1180 ASSERT(s.anchorType() == PositionAnchorType::BeforeAnchor ||
s.anchorType() == PositionAnchorType::BeforeChildren || s.offsetInContainerNode
() <= 0); |
| 1181 s = firstPositionInOrBeforeNode(next.get()); | 1181 s = firstPositionInOrBeforeNode(next.get()); |
| 1182 } | 1182 } |
| 1183 if (e.deprecatedNode() == elem) { | 1183 if (e.anchorNode() == elem) { |
| 1184 // Since elem must have been fully selected, and it is at th
e end | 1184 // Since elem must have been fully selected, and it is at th
e end |
| 1185 // of the selection, it is clear we can set the new e offset
to | 1185 // of the selection, it is clear we can set the new e offset
to |
| 1186 // the max range offset of prev. | 1186 // the max range offset of prev. |
| 1187 ASSERT(s.anchorType() == PositionAnchorType::AfterAnchor ||
!offsetIsBeforeLastNodeOffset(s.offsetInContainerNode(), s.containerNode())); | 1187 ASSERT(s.anchorType() == PositionAnchorType::AfterAnchor ||
!offsetIsBeforeLastNodeOffset(s.offsetInContainerNode(), s.containerNode())); |
| 1188 e = lastPositionInOrAfterNode(prev.get()); | 1188 e = lastPositionInOrAfterNode(prev.get()); |
| 1189 } | 1189 } |
| 1190 } | 1190 } |
| 1191 | 1191 |
| 1192 if (styleToPushDown) { | 1192 if (styleToPushDown) { |
| 1193 for (; childNode; childNode = childNode->nextSibling()) | 1193 for (; childNode; childNode = childNode->nextSibling()) |
| 1194 applyInlineStyleToPushDown(childNode.get(), styleToPushDown.
get()); | 1194 applyInlineStyleToPushDown(childNode.get(), styleToPushDown.
get()); |
| 1195 } | 1195 } |
| 1196 } | 1196 } |
| 1197 if (node == end.deprecatedNode()) | 1197 if (node == end.anchorNode()) |
| 1198 break; | 1198 break; |
| 1199 node = next; | 1199 node = next; |
| 1200 } | 1200 } |
| 1201 | 1201 |
| 1202 updateStartEnd(s, e); | 1202 updateStartEnd(s, e); |
| 1203 } | 1203 } |
| 1204 | 1204 |
| 1205 bool ApplyStyleCommand::elementFullySelected(HTMLElement& element, const Positio
n& start, const Position& end) const | 1205 bool ApplyStyleCommand::elementFullySelected(HTMLElement& element, const Positio
n& start, const Position& end) const |
| 1206 { | 1206 { |
| 1207 // The tree may have changed and Position::upstream() relies on an up-to-dat
e layout. | 1207 // The tree may have changed and Position::upstream() relies on an up-to-dat
e layout. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1224 RefPtrWillBeRawPtr<Text> text = start.containerText(); | 1224 RefPtrWillBeRawPtr<Text> text = start.containerText(); |
| 1225 splitTextNode(text, start.offsetInContainerNode()); | 1225 splitTextNode(text, start.offsetInContainerNode()); |
| 1226 updateStartEnd(firstPositionInNode(text.get()), newEnd); | 1226 updateStartEnd(firstPositionInNode(text.get()), newEnd); |
| 1227 } | 1227 } |
| 1228 | 1228 |
| 1229 void ApplyStyleCommand::splitTextAtEnd(const Position& start, const Position& en
d) | 1229 void ApplyStyleCommand::splitTextAtEnd(const Position& start, const Position& en
d) |
| 1230 { | 1230 { |
| 1231 ASSERT(end.containerNode()->isTextNode()); | 1231 ASSERT(end.containerNode()->isTextNode()); |
| 1232 | 1232 |
| 1233 bool shouldUpdateStart = start.anchorType() == PositionAnchorType::OffsetInA
nchor && start.containerNode() == end.containerNode(); | 1233 bool shouldUpdateStart = start.anchorType() == PositionAnchorType::OffsetInA
nchor && start.containerNode() == end.containerNode(); |
| 1234 Text* text = toText(end.deprecatedNode()); | 1234 Text* text = toText(end.anchorNode()); |
| 1235 splitTextNode(text, end.offsetInContainerNode()); | 1235 splitTextNode(text, end.offsetInContainerNode()); |
| 1236 | 1236 |
| 1237 Node* prevNode = text->previousSibling(); | 1237 Node* prevNode = text->previousSibling(); |
| 1238 if (!prevNode || !prevNode->isTextNode()) | 1238 if (!prevNode || !prevNode->isTextNode()) |
| 1239 return; | 1239 return; |
| 1240 | 1240 |
| 1241 Position newStart = shouldUpdateStart ? Position(toText(prevNode), start.off
setInContainerNode()) : start; | 1241 Position newStart = shouldUpdateStart ? Position(toText(prevNode), start.off
setInContainerNode()) : start; |
| 1242 updateStartEnd(newStart, lastPositionInNode(prevNode)); | 1242 updateStartEnd(newStart, lastPositionInNode(prevNode)); |
| 1243 } | 1243 } |
| 1244 | 1244 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1315 Node* previousSibling = startNode->previousSibling(); | 1315 Node* previousSibling = startNode->previousSibling(); |
| 1316 | 1316 |
| 1317 if (previousSibling && areIdenticalElements(startNode, previousSibling)) { | 1317 if (previousSibling && areIdenticalElements(startNode, previousSibling)) { |
| 1318 Element* previousElement = toElement(previousSibling); | 1318 Element* previousElement = toElement(previousSibling); |
| 1319 Element* element = toElement(startNode); | 1319 Element* element = toElement(startNode); |
| 1320 Node* startChild = element->firstChild(); | 1320 Node* startChild = element->firstChild(); |
| 1321 ASSERT(startChild); | 1321 ASSERT(startChild); |
| 1322 mergeIdenticalElements(previousElement, element); | 1322 mergeIdenticalElements(previousElement, element); |
| 1323 | 1323 |
| 1324 int startOffsetAdjustment = startChild->nodeIndex(); | 1324 int startOffsetAdjustment = startChild->nodeIndex(); |
| 1325 int endOffsetAdjustment = startNode == end.deprecatedNode() ? startOffse
tAdjustment : 0; | 1325 int endOffsetAdjustment = startNode == end.anchorNode() ? startOffsetAdj
ustment : 0; |
| 1326 updateStartEnd(Position(startNode, startOffsetAdjustment), | 1326 updateStartEnd(Position(startNode, startOffsetAdjustment), |
| 1327 Position(end.deprecatedNode(), end.deprecatedEditingOffset() + endOf
fsetAdjustment)); | 1327 Position(end.anchorNode(), end.deprecatedEditingOffset() + endOffset
Adjustment)); |
| 1328 return true; | 1328 return true; |
| 1329 } | 1329 } |
| 1330 | 1330 |
| 1331 return false; | 1331 return false; |
| 1332 } | 1332 } |
| 1333 | 1333 |
| 1334 bool ApplyStyleCommand::mergeEndWithNextIfIdentical(const Position& start, const
Position& end) | 1334 bool ApplyStyleCommand::mergeEndWithNextIfIdentical(const Position& start, const
Position& end) |
| 1335 { | 1335 { |
| 1336 Node* endNode = end.containerNode(); | 1336 Node* endNode = end.containerNode(); |
| 1337 | 1337 |
| 1338 if (isAtomicNode(endNode)) { | 1338 if (isAtomicNode(endNode)) { |
| 1339 int endOffset = end.computeOffsetInContainerNode(); | 1339 int endOffset = end.computeOffsetInContainerNode(); |
| 1340 if (offsetIsBeforeLastNodeOffset(endOffset, endNode)) | 1340 if (offsetIsBeforeLastNodeOffset(endOffset, endNode)) |
| 1341 return false; | 1341 return false; |
| 1342 | 1342 |
| 1343 if (end.deprecatedNode()->nextSibling()) | 1343 if (end.anchorNode()->nextSibling()) |
| 1344 return false; | 1344 return false; |
| 1345 | 1345 |
| 1346 endNode = end.deprecatedNode()->parentNode(); | 1346 endNode = end.anchorNode()->parentNode(); |
| 1347 } | 1347 } |
| 1348 | 1348 |
| 1349 if (!endNode->isElementNode() || isHTMLBRElement(*endNode)) | 1349 if (!endNode->isElementNode() || isHTMLBRElement(*endNode)) |
| 1350 return false; | 1350 return false; |
| 1351 | 1351 |
| 1352 Node* nextSibling = endNode->nextSibling(); | 1352 Node* nextSibling = endNode->nextSibling(); |
| 1353 if (nextSibling && areIdenticalElements(endNode, nextSibling)) { | 1353 if (nextSibling && areIdenticalElements(endNode, nextSibling)) { |
| 1354 Element* nextElement = toElement(nextSibling); | 1354 Element* nextElement = toElement(nextSibling); |
| 1355 Element* element = toElement(endNode); | 1355 Element* element = toElement(endNode); |
| 1356 Node* nextChild = nextElement->firstChild(); | 1356 Node* nextChild = nextElement->firstChild(); |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1594 DEFINE_TRACE(ApplyStyleCommand) | 1594 DEFINE_TRACE(ApplyStyleCommand) |
| 1595 { | 1595 { |
| 1596 visitor->trace(m_style); | 1596 visitor->trace(m_style); |
| 1597 visitor->trace(m_start); | 1597 visitor->trace(m_start); |
| 1598 visitor->trace(m_end); | 1598 visitor->trace(m_end); |
| 1599 visitor->trace(m_styledInlineElement); | 1599 visitor->trace(m_styledInlineElement); |
| 1600 CompositeEditCommand::trace(visitor); | 1600 CompositeEditCommand::trace(visitor); |
| 1601 } | 1601 } |
| 1602 | 1602 |
| 1603 } | 1603 } |
| OLD | NEW |