Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Side by Side Diff: third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp

Issue 2397963002: Reflow comments in //third_party/WebKit/Source/core/editing/commands (Closed)
Patch Set: . Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 248 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 end = swap; 259 end = swap;
260 } 260 }
261 261
262 VisiblePosition visibleStart = createVisiblePositionDeprecated(start); 262 VisiblePosition visibleStart = createVisiblePositionDeprecated(start);
263 VisiblePosition visibleEnd = createVisiblePositionDeprecated(end); 263 VisiblePosition visibleEnd = createVisiblePositionDeprecated(end);
264 264
265 if (visibleStart.isNull() || visibleStart.isOrphan() || visibleEnd.isNull() || 265 if (visibleStart.isNull() || visibleStart.isOrphan() || visibleEnd.isNull() ||
266 visibleEnd.isOrphan()) 266 visibleEnd.isOrphan())
267 return; 267 return;
268 268
269 // Save and restore the selection endpoints using their indices in the documen t, since 269 // Save and restore the selection endpoints using their indices in the
270 // addBlockStyleIfNeeded may moveParagraphs, which can remove these endpoints. 270 // document, since addBlockStyleIfNeeded may moveParagraphs, which can remove
271 // Calculate start and end indices from the start of the tree that they're in. 271 // these endpoints. Calculate start and end indices from the start of the tree
272 // that they're in.
272 Node& scope = NodeTraversal::highestAncestorOrSelf( 273 Node& scope = NodeTraversal::highestAncestorOrSelf(
273 *visibleStart.deepEquivalent().anchorNode()); 274 *visibleStart.deepEquivalent().anchorNode());
274 Range* startRange = 275 Range* startRange =
275 Range::create(document(), Position::firstPositionInNode(&scope), 276 Range::create(document(), Position::firstPositionInNode(&scope),
276 visibleStart.deepEquivalent().parentAnchoredEquivalent()); 277 visibleStart.deepEquivalent().parentAnchoredEquivalent());
277 Range* endRange = 278 Range* endRange =
278 Range::create(document(), Position::firstPositionInNode(&scope), 279 Range::create(document(), Position::firstPositionInNode(&scope),
279 visibleEnd.deepEquivalent().parentAnchoredEquivalent()); 280 visibleEnd.deepEquivalent().parentAnchoredEquivalent());
280 int startIndex = TextIterator::rangeLength(startRange->startPosition(), 281 int startIndex = TextIterator::rangeLength(startRange->startPosition(),
281 startRange->endPosition(), true); 282 startRange->endPosition(), true);
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
401 402
402 if (isValidCaretPositionInTextNode(end)) { 403 if (isValidCaretPositionInTextNode(end)) {
403 splitTextAtEnd(start, end); 404 splitTextAtEnd(start, end);
404 start = startPosition(); 405 start = startPosition();
405 end = endPosition(); 406 end = endPosition();
406 } 407 }
407 408
408 DCHECK(start.anchorNode()); 409 DCHECK(start.anchorNode());
409 DCHECK(end.anchorNode()); 410 DCHECK(end.anchorNode());
410 // Calculate loop end point. 411 // Calculate loop end point.
411 // If the end node is before the start node (can only happen if the end node i s 412 // If the end node is before the start node (can only happen if the end node
412 // an ancestor of the start node), we gather nodes up to the next sibling of t he end node 413 // is an ancestor of the start node), we gather nodes up to the next sibling
414 // of the end node
413 const Node* const beyondEnd = end.nodeAsRangePastLastNode(); 415 const Node* const beyondEnd = end.nodeAsRangePastLastNode();
414 start = mostBackwardCaretPosition( 416 // Move upstream to ensure we do not add redundant spans.
415 start); // Move upstream to ensure we do not add redundant spans. 417 start = mostBackwardCaretPosition(start);
416 Node* startNode = start.anchorNode(); 418 Node* startNode = start.anchorNode();
417 DCHECK(startNode); 419 DCHECK(startNode);
418 420
419 // Make sure we're not already at the end or the next NodeTraversal::next() wi ll traverse 421 // Make sure we're not already at the end or the next NodeTraversal::next()
420 // past it. 422 // will traverse past it.
421 if (startNode == beyondEnd) 423 if (startNode == beyondEnd)
422 return; 424 return;
423 425
424 if (startNode->isTextNode() && 426 if (startNode->isTextNode() &&
425 start.computeOffsetInContainerNode() >= caretMaxOffset(startNode)) { 427 start.computeOffsetInContainerNode() >= caretMaxOffset(startNode)) {
426 // Move out of text node if range does not include its characters. 428 // Move out of text node if range does not include its characters.
427 startNode = NodeTraversal::next(*startNode); 429 startNode = NodeTraversal::next(*startNode);
428 if (!startNode) 430 if (!startNode)
429 return; 431 return;
430 } 432 }
431 433
432 // Store away font size before making any changes to the document. 434 // Store away font size before making any changes to the document.
433 // This ensures that changes to one node won't effect another. 435 // This ensures that changes to one node won't effect another.
434 HeapHashMap<Member<Node>, float> startingFontSizes; 436 HeapHashMap<Member<Node>, float> startingFontSizes;
435 for (Node* node = startNode; node != beyondEnd; 437 for (Node* node = startNode; node != beyondEnd;
436 node = NodeTraversal::next(*node)) { 438 node = NodeTraversal::next(*node)) {
437 DCHECK(node); 439 DCHECK(node);
438 startingFontSizes.set(node, computedFontSize(node)); 440 startingFontSizes.set(node, computedFontSize(node));
439 } 441 }
440 442
441 // These spans were added by us. If empty after font size changes, they can be removed. 443 // These spans were added by us. If empty after font size changes, they can be
444 // removed.
442 HeapVector<Member<HTMLElement>> unstyledSpans; 445 HeapVector<Member<HTMLElement>> unstyledSpans;
443 446
444 Node* lastStyledNode = nullptr; 447 Node* lastStyledNode = nullptr;
445 for (Node* node = startNode; node != beyondEnd; 448 for (Node* node = startNode; node != beyondEnd;
446 node = NodeTraversal::next(*node)) { 449 node = NodeTraversal::next(*node)) {
447 DCHECK(node); 450 DCHECK(node);
448 HTMLElement* element = nullptr; 451 HTMLElement* element = nullptr;
449 if (node->isHTMLElement()) { 452 if (node->isHTMLElement()) {
450 // Only work on fully selected nodes. 453 // Only work on fully selected nodes.
451 if (!elementFullySelected(toHTMLElement(*node), start, end)) 454 if (!elementFullySelected(toHTMLElement(*node), start, end))
452 continue; 455 continue;
453 element = toHTMLElement(node); 456 element = toHTMLElement(node);
454 } else if (node->isTextNode() && node->layoutObject() && 457 } else if (node->isTextNode() && node->layoutObject() &&
455 node->parentNode() != lastStyledNode) { 458 node->parentNode() != lastStyledNode) {
456 // Last styled node was not parent node of this text node, but we wish to style this 459 // Last styled node was not parent node of this text node, but we wish to
457 // text node. To make this possible, add a style span to surround this tex t node. 460 // style this text node. To make this possible, add a style span to
461 // surround this text node.
458 HTMLSpanElement* span = HTMLSpanElement::create(document()); 462 HTMLSpanElement* span = HTMLSpanElement::create(document());
459 surroundNodeRangeWithElement(node, node, span, editingState); 463 surroundNodeRangeWithElement(node, node, span, editingState);
460 if (editingState->isAborted()) 464 if (editingState->isAborted())
461 return; 465 return;
462 element = span; 466 element = span;
463 } else { 467 } else {
464 // Only handle HTML elements and text nodes. 468 // Only handle HTML elements and text nodes.
465 continue; 469 continue;
466 } 470 }
467 lastStyledNode = node; 471 lastStyledNode = node;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
525 if (editingState->isAborted()) 529 if (editingState->isAborted())
526 return; 530 return;
527 } 531 }
528 } 532 }
529 } 533 }
530 534
531 HTMLElement* ApplyStyleCommand::splitAncestorsWithUnicodeBidi( 535 HTMLElement* ApplyStyleCommand::splitAncestorsWithUnicodeBidi(
532 Node* node, 536 Node* node,
533 bool before, 537 bool before,
534 WritingDirection allowedDirection) { 538 WritingDirection allowedDirection) {
535 // We are allowed to leave the highest ancestor with unicode-bidi unsplit if i t is unicode-bidi: embed and direction: allowedDirection. 539 // We are allowed to leave the highest ancestor with unicode-bidi unsplit if
536 // In that case, we return the unsplit ancestor. Otherwise, we return 0. 540 // it is unicode-bidi: embed and direction: allowedDirection. In that case, we
541 // return the unsplit ancestor. Otherwise, we return 0.
537 Element* block = enclosingBlock(node); 542 Element* block = enclosingBlock(node);
538 if (!block) 543 if (!block)
539 return 0; 544 return 0;
540 545
541 ContainerNode* highestAncestorWithUnicodeBidi = nullptr; 546 ContainerNode* highestAncestorWithUnicodeBidi = nullptr;
542 ContainerNode* nextHighestAncestorWithUnicodeBidi = nullptr; 547 ContainerNode* nextHighestAncestorWithUnicodeBidi = nullptr;
543 int highestAncestorUnicodeBidi = 0; 548 int highestAncestorUnicodeBidi = 0;
544 for (Node& runner : NodeTraversal::ancestorsOf(*node)) { 549 for (Node& runner : NodeTraversal::ancestorsOf(*node)) {
545 if (runner == block) 550 if (runner == block)
546 break; 551 break;
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
599 break; 604 break;
600 if (!runner.isStyledElement()) 605 if (!runner.isStyledElement())
601 continue; 606 continue;
602 607
603 Element* element = toElement(&runner); 608 Element* element = toElement(&runner);
604 int unicodeBidi = getIdentifierValue( 609 int unicodeBidi = getIdentifierValue(
605 CSSComputedStyleDeclaration::create(element), CSSPropertyUnicodeBidi); 610 CSSComputedStyleDeclaration::create(element), CSSPropertyUnicodeBidi);
606 if (!unicodeBidi || unicodeBidi == CSSValueNormal) 611 if (!unicodeBidi || unicodeBidi == CSSValueNormal)
607 continue; 612 continue;
608 613
609 // FIXME: This code should really consider the mapped attribute 'dir', the i nline style declaration, 614 // FIXME: This code should really consider the mapped attribute 'dir', the
610 // and all matching style rules in order to determine how to best set the un icode-bidi property to 'normal'. 615 // inline style declaration, and all matching style rules in order to
611 // For now, it assumes that if the 'dir' attribute is present, then removing it will suffice, and 616 // determine how to best set the unicode-bidi property to 'normal'. For now,
612 // otherwise it sets the property in the inline style declaration. 617 // it assumes that if the 'dir' attribute is present, then removing it will
618 // suffice, and otherwise it sets the property in the inline style
619 // declaration.
613 if (element->hasAttribute(dirAttr)) { 620 if (element->hasAttribute(dirAttr)) {
614 // FIXME: If this is a BDO element, we should probably just remove it if i t has no 621 // FIXME: If this is a BDO element, we should probably just remove it if
615 // other attributes, like we (should) do with B and I elements. 622 // it has no other attributes, like we (should) do with B and I elements.
616 removeElementAttribute(element, dirAttr); 623 removeElementAttribute(element, dirAttr);
617 } else { 624 } else {
618 MutableStylePropertySet* inlineStyle = 625 MutableStylePropertySet* inlineStyle =
619 copyStyleOrCreateEmpty(element->inlineStyle()); 626 copyStyleOrCreateEmpty(element->inlineStyle());
620 inlineStyle->setProperty(CSSPropertyUnicodeBidi, CSSValueNormal); 627 inlineStyle->setProperty(CSSPropertyUnicodeBidi, CSSValueNormal);
621 inlineStyle->removeProperty(CSSPropertyDirection); 628 inlineStyle->removeProperty(CSSPropertyDirection);
622 setNodeAttribute(element, styleAttr, AtomicString(inlineStyle->asText())); 629 setNodeAttribute(element, styleAttr, AtomicString(inlineStyle->asText()));
623 if (isSpanWithoutAttributesOrUnstyledStyleSpan(element)) { 630 if (isSpanWithoutAttributesOrUnstyledStyleSpan(element)) {
624 removeNodePreservingChildren(element, editingState); 631 removeNodePreservingChildren(element, editingState);
625 if (editingState->isAborted()) 632 if (editingState->isAborted())
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
658 665
659 if (start.isNull() || end.isNull()) 666 if (start.isNull() || end.isNull())
660 return; 667 return;
661 668
662 if (comparePositions(end, start) < 0) { 669 if (comparePositions(end, start) < 0) {
663 Position swap = start; 670 Position swap = start;
664 start = end; 671 start = end;
665 end = swap; 672 end = swap;
666 } 673 }
667 674
668 // split the start node and containing element if the selection starts inside of it 675 // split the start node and containing element if the selection starts inside
676 // of it
669 bool splitStart = isValidCaretPositionInTextNode(start); 677 bool splitStart = isValidCaretPositionInTextNode(start);
670 if (splitStart) { 678 if (splitStart) {
671 if (shouldSplitTextElement(start.anchorNode()->parentElement(), style)) 679 if (shouldSplitTextElement(start.anchorNode()->parentElement(), style))
672 splitTextElementAtStart(start, end); 680 splitTextElementAtStart(start, end);
673 else 681 else
674 splitTextAtStart(start, end); 682 splitTextAtStart(start, end);
675 start = startPosition(); 683 start = startPosition();
676 end = endPosition(); 684 end = endPosition();
677 if (start.isNull() || end.isNull()) 685 if (start.isNull() || end.isNull())
678 return; 686 return;
679 startDummySpanAncestor = dummySpanAncestorForNode(start.anchorNode()); 687 startDummySpanAncestor = dummySpanAncestorForNode(start.anchorNode());
680 } 688 }
681 689
682 // split the end node and containing element if the selection ends inside of i t 690 // split the end node and containing element if the selection ends inside of
691 // it
683 bool splitEnd = isValidCaretPositionInTextNode(end); 692 bool splitEnd = isValidCaretPositionInTextNode(end);
684 if (splitEnd) { 693 if (splitEnd) {
685 if (shouldSplitTextElement(end.anchorNode()->parentElement(), style)) 694 if (shouldSplitTextElement(end.anchorNode()->parentElement(), style))
686 splitTextElementAtEnd(start, end); 695 splitTextElementAtEnd(start, end);
687 else 696 else
688 splitTextAtEnd(start, end); 697 splitTextAtEnd(start, end);
689 start = startPosition(); 698 start = startPosition();
690 end = endPosition(); 699 end = endPosition();
691 if (start.isNull() || end.isNull()) 700 if (start.isNull() || end.isNull())
692 return; 701 return;
693 endDummySpanAncestor = dummySpanAncestorForNode(end.anchorNode()); 702 endDummySpanAncestor = dummySpanAncestorForNode(end.anchorNode());
694 } 703 }
695 704
696 // Remove style from the selection. 705 // Remove style from the selection.
697 // Use the upstream position of the start for removing style. 706 // Use the upstream position of the start for removing style.
698 // This will ensure we remove all traces of the relevant styles from the selec tion 707 // This will ensure we remove all traces of the relevant styles from the
699 // and prevent us from adding redundant ones, as described in: 708 // selection and prevent us from adding redundant ones, as described in:
700 // <rdar://problem/3724344> Bolding and unbolding creates extraneous tags 709 // <rdar://problem/3724344> Bolding and unbolding creates extraneous tags
701 Position removeStart = mostBackwardCaretPosition(start); 710 Position removeStart = mostBackwardCaretPosition(start);
702 WritingDirection textDirection = NaturalWritingDirection; 711 WritingDirection textDirection = NaturalWritingDirection;
703 bool hasTextDirection = style->textDirection(textDirection); 712 bool hasTextDirection = style->textDirection(textDirection);
704 EditingStyle* styleWithoutEmbedding = nullptr; 713 EditingStyle* styleWithoutEmbedding = nullptr;
705 EditingStyle* embeddingStyle = nullptr; 714 EditingStyle* embeddingStyle = nullptr;
706 if (hasTextDirection) { 715 if (hasTextDirection) {
707 // Leave alone an ancestor that provides the desired single level embedding, if there is one. 716 // Leave alone an ancestor that provides the desired single level embedding,
717 // if there is one.
708 HTMLElement* startUnsplitAncestor = 718 HTMLElement* startUnsplitAncestor =
709 splitAncestorsWithUnicodeBidi(start.anchorNode(), true, textDirection); 719 splitAncestorsWithUnicodeBidi(start.anchorNode(), true, textDirection);
710 HTMLElement* endUnsplitAncestor = 720 HTMLElement* endUnsplitAncestor =
711 splitAncestorsWithUnicodeBidi(end.anchorNode(), false, textDirection); 721 splitAncestorsWithUnicodeBidi(end.anchorNode(), false, textDirection);
712 removeEmbeddingUpToEnclosingBlock(start.anchorNode(), startUnsplitAncestor, 722 removeEmbeddingUpToEnclosingBlock(start.anchorNode(), startUnsplitAncestor,
713 editingState); 723 editingState);
714 if (editingState->isAborted()) 724 if (editingState->isAborted())
715 return; 725 return;
716 removeEmbeddingUpToEnclosingBlock(end.anchorNode(), endUnsplitAncestor, 726 removeEmbeddingUpToEnclosingBlock(end.anchorNode(), endUnsplitAncestor,
717 editingState); 727 editingState);
718 if (editingState->isAborted()) 728 if (editingState->isAborted())
719 return; 729 return;
720 730
721 // Avoid removing the dir attribute and the unicode-bidi and direction prope rties from the unsplit ancestors. 731 // Avoid removing the dir attribute and the unicode-bidi and direction
732 // properties from the unsplit ancestors.
722 Position embeddingRemoveStart = removeStart; 733 Position embeddingRemoveStart = removeStart;
723 if (startUnsplitAncestor && 734 if (startUnsplitAncestor &&
724 elementFullySelected(*startUnsplitAncestor, removeStart, end)) 735 elementFullySelected(*startUnsplitAncestor, removeStart, end))
725 embeddingRemoveStart = Position::inParentAfterNode(*startUnsplitAncestor); 736 embeddingRemoveStart = Position::inParentAfterNode(*startUnsplitAncestor);
726 737
727 Position embeddingRemoveEnd = end; 738 Position embeddingRemoveEnd = end;
728 if (endUnsplitAncestor && 739 if (endUnsplitAncestor &&
729 elementFullySelected(*endUnsplitAncestor, removeStart, end)) 740 elementFullySelected(*endUnsplitAncestor, removeStart, end))
730 embeddingRemoveEnd = mostForwardCaretPosition( 741 embeddingRemoveEnd = mostForwardCaretPosition(
731 Position::inParentBeforeNode(*endUnsplitAncestor)); 742 Position::inParentBeforeNode(*endUnsplitAncestor));
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
771 end = endPosition(); 782 end = endPosition();
772 } 783 }
773 784
774 // update document layout once before running the rest of the function 785 // update document layout once before running the rest of the function
775 // so that we avoid the expense of updating before each and every call 786 // so that we avoid the expense of updating before each and every call
776 // to check a computed style 787 // to check a computed style
777 document().updateStyleAndLayoutIgnorePendingStylesheets(); 788 document().updateStyleAndLayoutIgnorePendingStylesheets();
778 789
779 EditingStyle* styleToApply = style; 790 EditingStyle* styleToApply = style;
780 if (hasTextDirection) { 791 if (hasTextDirection) {
781 // Avoid applying the unicode-bidi and direction properties beneath ancestor s that already have them. 792 // Avoid applying the unicode-bidi and direction properties beneath
793 // ancestors that already have them.
782 HTMLElement* embeddingStartElement = highestEmbeddingAncestor( 794 HTMLElement* embeddingStartElement = highestEmbeddingAncestor(
783 start.anchorNode(), enclosingBlock(start.anchorNode())); 795 start.anchorNode(), enclosingBlock(start.anchorNode()));
784 HTMLElement* embeddingEndElement = highestEmbeddingAncestor( 796 HTMLElement* embeddingEndElement = highestEmbeddingAncestor(
785 end.anchorNode(), enclosingBlock(end.anchorNode())); 797 end.anchorNode(), enclosingBlock(end.anchorNode()));
786 798
787 if (embeddingStartElement || embeddingEndElement) { 799 if (embeddingStartElement || embeddingEndElement) {
788 Position embeddingApplyStart = 800 Position embeddingApplyStart =
789 embeddingStartElement 801 embeddingStartElement
790 ? Position::inParentAfterNode(*embeddingStartElement) 802 ? Position::inParentAfterNode(*embeddingStartElement)
791 : start; 803 : start;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
833 startNode = NodeTraversal::next(*startNode); 845 startNode = NodeTraversal::next(*startNode);
834 if (!startNode || 846 if (!startNode ||
835 comparePositions(end, firstPositionInOrBeforeNode(startNode)) < 0) 847 comparePositions(end, firstPositionInOrBeforeNode(startNode)) < 0)
836 return; 848 return;
837 } 849 }
838 850
839 Node* pastEndNode = end.anchorNode(); 851 Node* pastEndNode = end.anchorNode();
840 if (end.computeEditingOffset() >= caretMaxOffset(end.anchorNode())) 852 if (end.computeEditingOffset() >= caretMaxOffset(end.anchorNode()))
841 pastEndNode = NodeTraversal::nextSkippingChildren(*end.anchorNode()); 853 pastEndNode = NodeTraversal::nextSkippingChildren(*end.anchorNode());
842 854
843 // FIXME: Callers should perform this operation on a Range that includes the b r 855 // FIXME: Callers should perform this operation on a Range that includes the
844 // if they want style applied to the empty line. 856 // br if they want style applied to the empty line.
845 if (start == end && isHTMLBRElement(*start.anchorNode())) 857 if (start == end && isHTMLBRElement(*start.anchorNode()))
846 pastEndNode = NodeTraversal::next(*start.anchorNode()); 858 pastEndNode = NodeTraversal::next(*start.anchorNode());
847 859
848 // Start from the highest fully selected ancestor so that we can modify the fu lly selected node. 860 // Start from the highest fully selected ancestor so that we can modify the
849 // e.g. When applying font-size: large on <font color="blue">hello</font>, we need to include the font element in our run 861 // fully selected node. e.g. When applying font-size: large on <font
850 // to generate <font color="blue" size="4">hello</font> instead of <font color ="blue"><font size="4">hello</font></font> 862 // color="blue">hello</font>, we need to include the font element in our run
863 // to generate <font color="blue" size="4">hello</font> instead of <font
864 // color="blue"><font size="4">hello</font></font>
851 Range* range = Range::create(startNode->document(), start, end); 865 Range* range = Range::create(startNode->document(), start, end);
852 Element* editableRoot = rootEditableElement(*startNode); 866 Element* editableRoot = rootEditableElement(*startNode);
853 if (startNode != editableRoot) { 867 if (startNode != editableRoot) {
854 while (editableRoot && startNode->parentNode() != editableRoot && 868 while (editableRoot && startNode->parentNode() != editableRoot &&
855 isNodeVisiblyContainedWithin(*startNode->parentNode(), *range)) 869 isNodeVisiblyContainedWithin(*startNode->parentNode(), *range))
856 startNode = startNode->parentNode(); 870 startNode = startNode->parentNode();
857 } 871 }
858 872
859 applyInlineStyleToNodeRange(style, startNode, pastEndNode, editingState); 873 applyInlineStyleToNodeRange(style, startNode, pastEndNode, editingState);
860 } 874 }
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
923 Node* node = startNode; 937 Node* node = startNode;
924 for (Node* next; node && node != pastEndNode; node = next) { 938 for (Node* next; node && node != pastEndNode; node = next) {
925 next = NodeTraversal::next(*node); 939 next = NodeTraversal::next(*node);
926 940
927 if (!node->layoutObject() || !hasEditableStyle(*node)) 941 if (!node->layoutObject() || !hasEditableStyle(*node))
928 continue; 942 continue;
929 943
930 if (!hasRichlyEditableStyle(*node) && node->isHTMLElement()) { 944 if (!hasRichlyEditableStyle(*node) && node->isHTMLElement()) {
931 HTMLElement* element = toHTMLElement(node); 945 HTMLElement* element = toHTMLElement(node);
932 // This is a plaintext-only region. Only proceed if it's fully selected. 946 // This is a plaintext-only region. Only proceed if it's fully selected.
933 // pastEndNode is the node after the last fully selected node, so if it's inside node then 947 // pastEndNode is the node after the last fully selected node, so if it's
934 // node isn't fully selected. 948 // inside node then node isn't fully selected.
935 if (pastEndNode && pastEndNode->isDescendantOf(element)) 949 if (pastEndNode && pastEndNode->isDescendantOf(element))
936 break; 950 break;
937 // Add to this element's inline style and skip over its contents. 951 // Add to this element's inline style and skip over its contents.
938 next = NodeTraversal::nextSkippingChildren(*node); 952 next = NodeTraversal::nextSkippingChildren(*node);
939 if (!style->style()) 953 if (!style->style())
940 continue; 954 continue;
941 MutableStylePropertySet* inlineStyle = 955 MutableStylePropertySet* inlineStyle =
942 copyStyleOrCreateEmpty(element->inlineStyle()); 956 copyStyleOrCreateEmpty(element->inlineStyle());
943 inlineStyle->mergeAndOverrideOnConflict(style->style()); 957 inlineStyle->mergeAndOverrideOnConflict(style->style());
944 setNodeAttribute(element, styleAttr, AtomicString(inlineStyle->asText())); 958 setNodeAttribute(element, styleAttr, AtomicString(inlineStyle->asText()));
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1023 bool ApplyStyleCommand::shouldApplyInlineStyleToRun(EditingStyle* style, 1037 bool ApplyStyleCommand::shouldApplyInlineStyleToRun(EditingStyle* style,
1024 Node* runStart, 1038 Node* runStart,
1025 Node* pastEndNode) { 1039 Node* pastEndNode) {
1026 DCHECK(style); 1040 DCHECK(style);
1027 DCHECK(runStart); 1041 DCHECK(runStart);
1028 1042
1029 for (Node* node = runStart; node && node != pastEndNode; 1043 for (Node* node = runStart; node && node != pastEndNode;
1030 node = NodeTraversal::next(*node)) { 1044 node = NodeTraversal::next(*node)) {
1031 if (node->hasChildren()) 1045 if (node->hasChildren())
1032 continue; 1046 continue;
1033 // We don't consider m_isInlineElementToRemoveFunction here because we never apply style when m_isInlineElementToRemoveFunction is specified 1047 // We don't consider m_isInlineElementToRemoveFunction here because we never
1048 // apply style when m_isInlineElementToRemoveFunction is specified
1034 if (!style->styleIsPresentInComputedStyleOfNode(node)) 1049 if (!style->styleIsPresentInComputedStyleOfNode(node))
1035 return true; 1050 return true;
1036 if (m_styledInlineElement && 1051 if (m_styledInlineElement &&
1037 !enclosingElementWithTag(Position::beforeNode(node), 1052 !enclosingElementWithTag(Position::beforeNode(node),
1038 m_styledInlineElement->tagQName())) 1053 m_styledInlineElement->tagQName()))
1039 return true; 1054 return true;
1040 } 1055 }
1041 return false; 1056 return false;
1042 } 1057 }
1043 1058
(...skipping 18 matching lines...) Expand all
1062 continue; 1077 continue;
1063 1078
1064 HTMLElement& element = toHTMLElement(*node); 1079 HTMLElement& element = toHTMLElement(*node);
1065 Node* previousSibling = element.previousSibling(); 1080 Node* previousSibling = element.previousSibling();
1066 Node* nextSibling = element.nextSibling(); 1081 Node* nextSibling = element.nextSibling();
1067 ContainerNode* parent = element.parentNode(); 1082 ContainerNode* parent = element.parentNode();
1068 removeInlineStyleFromElement(style, &element, editingState, RemoveAlways); 1083 removeInlineStyleFromElement(style, &element, editingState, RemoveAlways);
1069 if (editingState->isAborted()) 1084 if (editingState->isAborted())
1070 return; 1085 return;
1071 if (!element.isConnected()) { 1086 if (!element.isConnected()) {
1072 // FIXME: We might need to update the start and the end of current selecti on here but need a test. 1087 // FIXME: We might need to update the start and the end of current
1088 // selection here but need a test.
1073 if (runStart == element) 1089 if (runStart == element)
1074 runStart = previousSibling ? previousSibling->nextSibling() 1090 runStart = previousSibling ? previousSibling->nextSibling()
1075 : parent->firstChild(); 1091 : parent->firstChild();
1076 if (runEnd == element) 1092 if (runEnd == element)
1077 runEnd = 1093 runEnd =
1078 nextSibling ? nextSibling->previousSibling() : parent->lastChild(); 1094 nextSibling ? nextSibling->previousSibling() : parent->lastChild();
1079 } 1095 }
1080 } 1096 }
1081 } 1097 }
1082 1098
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
1147 if (style->conflictsWithImplicitStyleOfElement( 1163 if (style->conflictsWithImplicitStyleOfElement(
1148 element, extractedStyle, 1164 element, extractedStyle,
1149 mode == RemoveAlways ? EditingStyle::ExtractMatchingStyle 1165 mode == RemoveAlways ? EditingStyle::ExtractMatchingStyle
1150 : EditingStyle::DoNotExtractMatchingStyle)) { 1166 : EditingStyle::DoNotExtractMatchingStyle)) {
1151 replaceWithSpanOrRemoveIfWithoutAttributes(element, editingState); 1167 replaceWithSpanOrRemoveIfWithoutAttributes(element, editingState);
1152 if (editingState->isAborted()) 1168 if (editingState->isAborted())
1153 return false; 1169 return false;
1154 return true; 1170 return true;
1155 } 1171 }
1156 1172
1157 // unicode-bidi and direction are pushed down separately so don't push down wi th other styles 1173 // unicode-bidi and direction are pushed down separately so don't push down
1174 // with other styles
1158 Vector<QualifiedName> attributes; 1175 Vector<QualifiedName> attributes;
1159 if (!style->extractConflictingImplicitStyleOfAttributes( 1176 if (!style->extractConflictingImplicitStyleOfAttributes(
1160 element, extractedStyle ? EditingStyle::PreserveWritingDirection 1177 element, extractedStyle ? EditingStyle::PreserveWritingDirection
1161 : EditingStyle::DoNotPreserveWritingDirection, 1178 : EditingStyle::DoNotPreserveWritingDirection,
1162 extractedStyle, attributes, 1179 extractedStyle, attributes,
1163 mode == RemoveAlways ? EditingStyle::ExtractMatchingStyle 1180 mode == RemoveAlways ? EditingStyle::ExtractMatchingStyle
1164 : EditingStyle::DoNotExtractMatchingStyle)) 1181 : EditingStyle::DoNotExtractMatchingStyle))
1165 return false; 1182 return false;
1166 1183
1167 for (const auto& attribute : attributes) 1184 for (const auto& attribute : attributes)
(...skipping 18 matching lines...) Expand all
1186 DCHECK(element); 1203 DCHECK(element);
1187 1204
1188 if (mode == RemoveNone) 1205 if (mode == RemoveNone)
1189 return style->conflictsWithInlineStyleOfElement(element); 1206 return style->conflictsWithInlineStyleOfElement(element);
1190 1207
1191 Vector<CSSPropertyID> properties; 1208 Vector<CSSPropertyID> properties;
1192 if (!style->conflictsWithInlineStyleOfElement(element, extractedStyle, 1209 if (!style->conflictsWithInlineStyleOfElement(element, extractedStyle,
1193 properties)) 1210 properties))
1194 return false; 1211 return false;
1195 1212
1196 // FIXME: We should use a mass-removal function here but we don't have an undo able one yet. 1213 // FIXME: We should use a mass-removal function here but we don't have an
1214 // undoable one yet.
1197 for (const auto& property : properties) 1215 for (const auto& property : properties)
1198 removeCSSProperty(element, property); 1216 removeCSSProperty(element, property);
1199 1217
1200 if (isSpanWithoutAttributesOrUnstyledStyleSpan(element)) 1218 if (isSpanWithoutAttributesOrUnstyledStyleSpan(element))
1201 removeNodePreservingChildren(element, editingState); 1219 removeNodePreservingChildren(element, editingState);
1202 1220
1203 return true; 1221 return true;
1204 } 1222 }
1205 1223
1206 // Finds the enclosing element until which the tree can be split. 1224 // Finds the enclosing element until which the tree can be split.
1207 // When a user hits ENTER, they won't expect this element to be split into two. 1225 // When a user hits ENTER, they won't expect this element to be split into two.
1208 // You may pass it as the second argument of splitTreeToNode. 1226 // You may pass it as the second argument of splitTreeToNode.
1209 static Element* unsplittableElementForPosition(const Position& p) { 1227 static Element* unsplittableElementForPosition(const Position& p) {
1210 // Since enclosingNodeOfType won't search beyond the highest root editable nod e, 1228 // Since enclosingNodeOfType won't search beyond the highest root editable
1211 // this code works even if the closest table cell was outside of the root edit able node. 1229 // node, this code works even if the closest table cell was outside of the
1230 // root editable node.
1212 Element* enclosingCell = toElement(enclosingNodeOfType(p, &isTableCell)); 1231 Element* enclosingCell = toElement(enclosingNodeOfType(p, &isTableCell));
1213 if (enclosingCell) 1232 if (enclosingCell)
1214 return enclosingCell; 1233 return enclosingCell;
1215 1234
1216 return rootEditableElementOf(p); 1235 return rootEditableElementOf(p);
1217 } 1236 }
1218 1237
1219 HTMLElement* ApplyStyleCommand::highestAncestorWithConflictingInlineStyle( 1238 HTMLElement* ApplyStyleCommand::highestAncestorWithConflictingInlineStyle(
1220 EditingStyle* style, 1239 EditingStyle* style,
1221 Node* node) { 1240 Node* node) {
(...skipping 28 matching lines...) Expand all
1250 isHTMLIFrameElement(*node)) 1269 isHTMLIFrameElement(*node))
1251 return; 1270 return;
1252 1271
1253 EditingStyle* newInlineStyle = style; 1272 EditingStyle* newInlineStyle = style;
1254 if (node->isHTMLElement() && toHTMLElement(node)->inlineStyle()) { 1273 if (node->isHTMLElement() && toHTMLElement(node)->inlineStyle()) {
1255 newInlineStyle = style->copy(); 1274 newInlineStyle = style->copy();
1256 newInlineStyle->mergeInlineStyleOfElement(toHTMLElement(node), 1275 newInlineStyle->mergeInlineStyleOfElement(toHTMLElement(node),
1257 EditingStyle::OverrideValues); 1276 EditingStyle::OverrideValues);
1258 } 1277 }
1259 1278
1260 // Since addInlineStyleIfNeeded can't add styles to block-flow layout objects, add style attribute instead. 1279 // Since addInlineStyleIfNeeded can't add styles to block-flow layout objects,
1280 // add style attribute instead.
1261 // FIXME: applyInlineStyleToRange should be used here instead. 1281 // FIXME: applyInlineStyleToRange should be used here instead.
1262 if ((node->layoutObject()->isLayoutBlockFlow() || node->hasChildren()) && 1282 if ((node->layoutObject()->isLayoutBlockFlow() || node->hasChildren()) &&
1263 node->isHTMLElement()) { 1283 node->isHTMLElement()) {
1264 setNodeAttribute(toHTMLElement(node), styleAttr, 1284 setNodeAttribute(toHTMLElement(node), styleAttr,
1265 AtomicString(newInlineStyle->style()->asText())); 1285 AtomicString(newInlineStyle->style()->asText()));
1266 return; 1286 return;
1267 } 1287 }
1268 1288
1269 if (node->layoutObject()->isText() && 1289 if (node->layoutObject()->isText() &&
1270 toLayoutText(node->layoutObject())->isAllCollapsibleWhitespace()) 1290 toLayoutText(node->layoutObject())->isAllCollapsibleWhitespace())
1271 return; 1291 return;
1272 1292
1273 // We can't wrap node with the styled element here because new styled element will never be removed if we did. 1293 // We can't wrap node with the styled element here because new styled element
1274 // If we modified the child pointer in pushDownInlineStyleAroundNode to point to new style element 1294 // will never be removed if we did. If we modified the child pointer in
1275 // then we fall into an infinite loop where we keep removing and adding styled element wrapping node. 1295 // pushDownInlineStyleAroundNode to point to new style element then we fall
1296 // into an infinite loop where we keep removing and adding styled element
1297 // wrapping node.
1276 addInlineStyleIfNeeded(newInlineStyle, node, node, editingState); 1298 addInlineStyleIfNeeded(newInlineStyle, node, node, editingState);
1277 } 1299 }
1278 1300
1279 void ApplyStyleCommand::pushDownInlineStyleAroundNode( 1301 void ApplyStyleCommand::pushDownInlineStyleAroundNode(
1280 EditingStyle* style, 1302 EditingStyle* style,
1281 Node* targetNode, 1303 Node* targetNode,
1282 EditingState* editingState) { 1304 EditingState* editingState) {
1283 HTMLElement* highestAncestor = 1305 HTMLElement* highestAncestor =
1284 highestAncestorWithConflictingInlineStyle(style, targetNode); 1306 highestAncestorWithConflictingInlineStyle(style, targetNode);
1285 if (!highestAncestor) 1307 if (!highestAncestor)
1286 return; 1308 return;
1287 1309
1288 // The outer loop is traversing the tree vertically from highestAncestor to ta rgetNode 1310 // The outer loop is traversing the tree vertically from highestAncestor to
1311 // targetNode
1289 Node* current = highestAncestor; 1312 Node* current = highestAncestor;
1290 // Along the way, styled elements that contain targetNode are removed and accu mulated into elementsToPushDown. 1313 // Along the way, styled elements that contain targetNode are removed and
1291 // Each child of the removed element, exclusing ancestors of targetNode, is th en wrapped by clones of elements in elementsToPushDown. 1314 // accumulated into elementsToPushDown. Each child of the removed element,
1315 // exclusing ancestors of targetNode, is then wrapped by clones of elements in
1316 // elementsToPushDown.
1292 HeapVector<Member<Element>> elementsToPushDown; 1317 HeapVector<Member<Element>> elementsToPushDown;
1293 while (current && current != targetNode && current->contains(targetNode)) { 1318 while (current && current != targetNode && current->contains(targetNode)) {
1294 NodeVector currentChildren; 1319 NodeVector currentChildren;
1295 getChildNodes(toContainerNode(*current), currentChildren); 1320 getChildNodes(toContainerNode(*current), currentChildren);
1296 Element* styledElement = nullptr; 1321 Element* styledElement = nullptr;
1297 if (current->isStyledElement() && 1322 if (current->isStyledElement() &&
1298 isStyledInlineElementToRemove(toElement(current))) { 1323 isStyledInlineElementToRemove(toElement(current))) {
1299 styledElement = toElement(current); 1324 styledElement = toElement(current);
1300 elementsToPushDown.append(styledElement); 1325 elementsToPushDown.append(styledElement);
1301 } 1326 }
1302 1327
1303 EditingStyle* styleToPushDown = EditingStyle::create(); 1328 EditingStyle* styleToPushDown = EditingStyle::create();
1304 if (current->isHTMLElement()) { 1329 if (current->isHTMLElement()) {
1305 removeInlineStyleFromElement(style, toHTMLElement(current), editingState, 1330 removeInlineStyleFromElement(style, toHTMLElement(current), editingState,
1306 RemoveIfNeeded, styleToPushDown); 1331 RemoveIfNeeded, styleToPushDown);
1307 if (editingState->isAborted()) 1332 if (editingState->isAborted())
1308 return; 1333 return;
1309 } 1334 }
1310 1335
1311 // The inner loop will go through children on each level 1336 // The inner loop will go through children on each level
1312 // FIXME: we should aggregate inline child elements together so that we don' t wrap each child separately. 1337 // FIXME: we should aggregate inline child elements together so that we
1338 // don't wrap each child separately.
1313 for (const auto& currentChild : currentChildren) { 1339 for (const auto& currentChild : currentChildren) {
1314 Node* child = currentChild; 1340 Node* child = currentChild;
1315 if (!child->parentNode()) 1341 if (!child->parentNode())
1316 continue; 1342 continue;
1317 if (!child->contains(targetNode) && elementsToPushDown.size()) { 1343 if (!child->contains(targetNode) && elementsToPushDown.size()) {
1318 for (const auto& element : elementsToPushDown) { 1344 for (const auto& element : elementsToPushDown) {
1319 Element* wrapper = element->cloneElementWithoutChildren(); 1345 Element* wrapper = element->cloneElementWithoutChildren();
1320 wrapper->removeAttribute(styleAttr); 1346 wrapper->removeAttribute(styleAttr);
1321 // Delete id attribute from the second element because the same id can not be used for more than one element 1347 // Delete id attribute from the second element because the same id
1348 // cannot be used for more than one element
1322 element->removeAttribute(HTMLNames::idAttr); 1349 element->removeAttribute(HTMLNames::idAttr);
1323 if (isHTMLAnchorElement(element)) 1350 if (isHTMLAnchorElement(element))
1324 element->removeAttribute(HTMLNames::nameAttr); 1351 element->removeAttribute(HTMLNames::nameAttr);
1325 surroundNodeRangeWithElement(child, child, wrapper, editingState); 1352 surroundNodeRangeWithElement(child, child, wrapper, editingState);
1326 if (editingState->isAborted()) 1353 if (editingState->isAborted())
1327 return; 1354 return;
1328 } 1355 }
1329 } 1356 }
1330 1357
1331 // Apply style to all nodes containing targetNode and their siblings but N OT to targetNode 1358 // Apply style to all nodes containing targetNode and their siblings but
1332 // But if we've removed styledElement then go ahead and always apply the s tyle. 1359 // NOT to targetNode But if we've removed styledElement then go ahead and
1360 // always apply the style.
1333 if (child != targetNode || styledElement) { 1361 if (child != targetNode || styledElement) {
1334 applyInlineStyleToPushDown(child, styleToPushDown, editingState); 1362 applyInlineStyleToPushDown(child, styleToPushDown, editingState);
1335 if (editingState->isAborted()) 1363 if (editingState->isAborted())
1336 return; 1364 return;
1337 } 1365 }
1338 1366
1339 // We found the next node for the outer loop (contains targetNode) 1367 // We found the next node for the outer loop (contains targetNode)
1340 // When reached targetNode, stop the outer loop upon the completion of the current inner loop 1368 // When reached targetNode, stop the outer loop upon the completion of the
1369 // current inner loop
1341 if (child == targetNode || child->contains(targetNode)) 1370 if (child == targetNode || child->contains(targetNode))
1342 current = child; 1371 current = child;
1343 } 1372 }
1344 } 1373 }
1345 } 1374 }
1346 1375
1347 void ApplyStyleCommand::removeInlineStyle(EditingStyle* style, 1376 void ApplyStyleCommand::removeInlineStyle(EditingStyle* style,
1348 const Position& start, 1377 const Position& start,
1349 const Position& end, 1378 const Position& end,
1350 EditingState* editingState) { 1379 EditingState* editingState) {
1351 DCHECK(start.isNotNull()); 1380 DCHECK(start.isNotNull());
1352 DCHECK(end.isNotNull()); 1381 DCHECK(end.isNotNull());
1353 DCHECK(start.isConnected()) << start; 1382 DCHECK(start.isConnected()) << start;
1354 DCHECK(end.isConnected()) << end; 1383 DCHECK(end.isConnected()) << end;
1355 DCHECK(Position::commonAncestorTreeScope(start, end)) << start << " " << end; 1384 DCHECK(Position::commonAncestorTreeScope(start, end)) << start << " " << end;
1356 DCHECK_LE(start, end); 1385 DCHECK_LE(start, end);
1357 // FIXME: We should assert that start/end are not in the middle of a text node . 1386 // FIXME: We should assert that start/end are not in the middle of a text
1387 // node.
1358 1388
1359 Position pushDownStart = mostForwardCaretPosition(start); 1389 Position pushDownStart = mostForwardCaretPosition(start);
1360 // If the pushDownStart is at the end of a text node, then this node is not fu lly selected. 1390 // If the pushDownStart is at the end of a text node, then this node is not
1361 // Move it to the next deep quivalent position to avoid removing the style fro m this node. 1391 // fully selected. Move it to the next deep quivalent position to avoid
1362 // e.g. if pushDownStart was at Position("hello", 5) in <b>hello<div>world</di v></b>, we want Position("world", 0) instead. 1392 // removing the style from this node. e.g. if pushDownStart was at
1393 // Position("hello", 5) in <b>hello<div>world</div></b>, we want
1394 // Position("world", 0) instead.
1363 Node* pushDownStartContainer = pushDownStart.computeContainerNode(); 1395 Node* pushDownStartContainer = pushDownStart.computeContainerNode();
1364 if (pushDownStartContainer && pushDownStartContainer->isTextNode() && 1396 if (pushDownStartContainer && pushDownStartContainer->isTextNode() &&
1365 pushDownStart.computeOffsetInContainerNode() == 1397 pushDownStart.computeOffsetInContainerNode() ==
1366 pushDownStartContainer->maxCharacterOffset()) 1398 pushDownStartContainer->maxCharacterOffset())
1367 pushDownStart = nextVisuallyDistinctCandidate(pushDownStart); 1399 pushDownStart = nextVisuallyDistinctCandidate(pushDownStart);
1368 Position pushDownEnd = mostBackwardCaretPosition(end); 1400 Position pushDownEnd = mostBackwardCaretPosition(end);
1369 // If pushDownEnd is at the start of a text node, then this node is not fully selected. 1401 // If pushDownEnd is at the start of a text node, then this node is not fully
1370 // Move it to the previous deep equivalent position to avoid removing the styl e from this node. 1402 // selected. Move it to the previous deep equivalent position to avoid
1403 // removing the style from this node.
1371 Node* pushDownEndContainer = pushDownEnd.computeContainerNode(); 1404 Node* pushDownEndContainer = pushDownEnd.computeContainerNode();
1372 if (pushDownEndContainer && pushDownEndContainer->isTextNode() && 1405 if (pushDownEndContainer && pushDownEndContainer->isTextNode() &&
1373 !pushDownEnd.computeOffsetInContainerNode()) 1406 !pushDownEnd.computeOffsetInContainerNode())
1374 pushDownEnd = previousVisuallyDistinctCandidate(pushDownEnd); 1407 pushDownEnd = previousVisuallyDistinctCandidate(pushDownEnd);
1375 1408
1376 pushDownInlineStyleAroundNode(style, pushDownStart.anchorNode(), 1409 pushDownInlineStyleAroundNode(style, pushDownStart.anchorNode(),
1377 editingState); 1410 editingState);
1378 if (editingState->isAborted()) 1411 if (editingState->isAborted())
1379 return; 1412 return;
1380 pushDownInlineStyleAroundNode(style, pushDownEnd.anchorNode(), editingState); 1413 pushDownInlineStyleAroundNode(style, pushDownEnd.anchorNode(), editingState);
1381 if (editingState->isAborted()) 1414 if (editingState->isAborted())
1382 return; 1415 return;
1383 1416
1384 // The s and e variables store the positions used to set the ending selection after style removal 1417 // The s and e variables store the positions used to set the ending selection
1385 // takes place. This will help callers to recognize when either the start node or the end node 1418 // after style removal takes place. This will help callers to recognize when
1386 // are removed from the document during the work of this function. 1419 // either the start node or the end node are removed from the document during
1387 // If pushDownInlineStyleAroundNode has pruned start.anchorNode() or end.ancho rNode(), 1420 // the work of this function.
1388 // use pushDownStart or pushDownEnd instead, which pushDownInlineStyleAroundNo de won't prune. 1421 // If pushDownInlineStyleAroundNode has pruned start.anchorNode() or
1422 // end.anchorNode(), use pushDownStart or pushDownEnd instead, which
1423 // pushDownInlineStyleAroundNode won't prune.
1389 Position s = start.isNull() || start.isOrphan() ? pushDownStart : start; 1424 Position s = start.isNull() || start.isOrphan() ? pushDownStart : start;
1390 Position e = end.isNull() || end.isOrphan() ? pushDownEnd : end; 1425 Position e = end.isNull() || end.isOrphan() ? pushDownEnd : end;
1391 1426
1392 // Current ending selection resetting algorithm assumes |start| and |end| 1427 // Current ending selection resetting algorithm assumes |start| and |end|
1393 // are in a same DOM tree even if they are not in document. 1428 // are in a same DOM tree even if they are not in document.
1394 if (!Position::commonAncestorTreeScope(start, end)) 1429 if (!Position::commonAncestorTreeScope(start, end))
1395 return; 1430 return;
1396 1431
1397 Node* node = start.anchorNode(); 1432 Node* node = start.anchorNode();
1398 while (node) { 1433 while (node) {
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1453 break; 1488 break;
1454 node = next; 1489 node = next;
1455 } 1490 }
1456 1491
1457 updateStartEnd(s, e); 1492 updateStartEnd(s, e);
1458 } 1493 }
1459 1494
1460 bool ApplyStyleCommand::elementFullySelected(HTMLElement& element, 1495 bool ApplyStyleCommand::elementFullySelected(HTMLElement& element,
1461 const Position& start, 1496 const Position& start,
1462 const Position& end) const { 1497 const Position& end) const {
1463 // The tree may have changed and Position::upstream() relies on an up-to-date layout. 1498 // The tree may have changed and Position::upstream() relies on an up-to-date
1499 // layout.
1464 element.document().updateStyleAndLayoutIgnorePendingStylesheets(); 1500 element.document().updateStyleAndLayoutIgnorePendingStylesheets();
1465 1501
1466 return comparePositions(firstPositionInOrBeforeNode(&element), start) >= 0 && 1502 return comparePositions(firstPositionInOrBeforeNode(&element), start) >= 0 &&
1467 comparePositions( 1503 comparePositions(
1468 mostBackwardCaretPosition(lastPositionInOrAfterNode(&element)), 1504 mostBackwardCaretPosition(lastPositionInOrAfterNode(&element)),
1469 end) <= 0; 1505 end) <= 0;
1470 } 1506 }
1471 1507
1472 void ApplyStyleCommand::splitTextAtStart(const Position& start, 1508 void ApplyStyleCommand::splitTextAtStart(const Position& start,
1473 const Position& end) { 1509 const Position& end) {
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
1702 if (mergedElement->isElementNode() && hasEditableStyle(*mergedElement) && 1738 if (mergedElement->isElementNode() && hasEditableStyle(*mergedElement) &&
1703 areIdenticalElements(toElement(*previousSibling), 1739 areIdenticalElements(toElement(*previousSibling),
1704 toElement(*mergedElement))) { 1740 toElement(*mergedElement))) {
1705 mergeIdenticalElements(toElement(previousSibling), 1741 mergeIdenticalElements(toElement(previousSibling),
1706 toElement(mergedElement), editingState); 1742 toElement(mergedElement), editingState);
1707 if (editingState->isAborted()) 1743 if (editingState->isAborted())
1708 return; 1744 return;
1709 } 1745 }
1710 } 1746 }
1711 1747
1712 // FIXME: We should probably call updateStartEnd if the start or end was in th e node 1748 // FIXME: We should probably call updateStartEnd if the start or end was in
1713 // range so that the endingSelection() is canonicalized. See the comments at the end of 1749 // the node range so that the endingSelection() is canonicalized. See the
1714 // VisibleSelection::validate(). 1750 // comments at the end of VisibleSelection::validate().
1715 } 1751 }
1716 1752
1717 void ApplyStyleCommand::addBlockStyle(const StyleChange& styleChange, 1753 void ApplyStyleCommand::addBlockStyle(const StyleChange& styleChange,
1718 HTMLElement* block) { 1754 HTMLElement* block) {
1719 // Do not check for legacy styles here. Those styles, like <B> and <I>, only a pply for 1755 // Do not check for legacy styles here. Those styles, like <B> and <I>, only
1720 // inline content. 1756 // apply for inline content.
1721 if (!block) 1757 if (!block)
1722 return; 1758 return;
1723 1759
1724 String cssStyle = styleChange.cssStyle(); 1760 String cssStyle = styleChange.cssStyle();
1725 StringBuilder cssText; 1761 StringBuilder cssText;
1726 cssText.append(cssStyle); 1762 cssText.append(cssStyle);
1727 if (const StylePropertySet* decl = block->inlineStyle()) { 1763 if (const StylePropertySet* decl = block->inlineStyle()) {
1728 if (!cssStyle.isEmpty()) 1764 if (!cssStyle.isEmpty())
1729 cssText.append(' '); 1765 cssText.append(' ');
1730 cssText.append(decl->asText()); 1766 cssText.append(decl->asText());
(...skipping 23 matching lines...) Expand all
1754 } 1790 }
1755 1791
1756 applyInlineStyleChange(start, passedEnd, styleChange, DoNotAddStyledElement, 1792 applyInlineStyleChange(start, passedEnd, styleChange, DoNotAddStyledElement,
1757 editingState); 1793 editingState);
1758 } 1794 }
1759 1795
1760 Position ApplyStyleCommand::positionToComputeInlineStyleChange( 1796 Position ApplyStyleCommand::positionToComputeInlineStyleChange(
1761 Node* startNode, 1797 Node* startNode,
1762 Member<HTMLSpanElement>& dummyElement, 1798 Member<HTMLSpanElement>& dummyElement,
1763 EditingState* editingState) { 1799 EditingState* editingState) {
1764 // It's okay to obtain the style at the startNode because we've removed all re levant styles from the current run. 1800 // It's okay to obtain the style at the startNode because we've removed all
1801 // relevant styles from the current run.
1765 if (!startNode->isElementNode()) { 1802 if (!startNode->isElementNode()) {
1766 dummyElement = HTMLSpanElement::create(document()); 1803 dummyElement = HTMLSpanElement::create(document());
1767 insertNodeAt(dummyElement, Position::beforeNode(startNode), editingState); 1804 insertNodeAt(dummyElement, Position::beforeNode(startNode), editingState);
1768 if (editingState->isAborted()) 1805 if (editingState->isAborted())
1769 return Position(); 1806 return Position();
1770 return Position::beforeNode(dummyElement); 1807 return Position::beforeNode(dummyElement);
1771 } 1808 }
1772 1809
1773 return firstPositionInOrBeforeNode(startNode); 1810 return firstPositionInOrBeforeNode(startNode);
1774 } 1811 }
(...skipping 22 matching lines...) Expand all
1797 if (isHTMLSpanElement(*containerElement) || 1834 if (isHTMLSpanElement(*containerElement) ||
1798 (styleContainerIsNotSpan && containerElement->hasChildren())) 1835 (styleContainerIsNotSpan && containerElement->hasChildren()))
1799 styleContainer = toHTMLElement(container); 1836 styleContainer = toHTMLElement(container);
1800 } 1837 }
1801 if (!container->hasChildren()) 1838 if (!container->hasChildren())
1802 break; 1839 break;
1803 startNode = container->firstChild(); 1840 startNode = container->firstChild();
1804 endNode = container->lastChild(); 1841 endNode = container->lastChild();
1805 } 1842 }
1806 1843
1807 // Font tags need to go outside of CSS so that CSS font sizes override leagcy font sizes. 1844 // Font tags need to go outside of CSS so that CSS font sizes override leagcy
1845 // font sizes.
1808 if (styleChange.applyFontColor() || styleChange.applyFontFace() || 1846 if (styleChange.applyFontColor() || styleChange.applyFontFace() ||
1809 styleChange.applyFontSize()) { 1847 styleChange.applyFontSize()) {
1810 if (fontContainer) { 1848 if (fontContainer) {
1811 if (styleChange.applyFontColor()) 1849 if (styleChange.applyFontColor())
1812 setNodeAttribute(fontContainer, colorAttr, 1850 setNodeAttribute(fontContainer, colorAttr,
1813 AtomicString(styleChange.fontColor())); 1851 AtomicString(styleChange.fontColor()));
1814 if (styleChange.applyFontFace()) 1852 if (styleChange.applyFontFace())
1815 setNodeAttribute(fontContainer, faceAttr, 1853 setNodeAttribute(fontContainer, faceAttr,
1816 AtomicString(styleChange.fontFace())); 1854 AtomicString(styleChange.fontFace()));
1817 if (styleChange.applyFontSize()) 1855 if (styleChange.applyFontSize())
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
1974 2012
1975 DEFINE_TRACE(ApplyStyleCommand) { 2013 DEFINE_TRACE(ApplyStyleCommand) {
1976 visitor->trace(m_style); 2014 visitor->trace(m_style);
1977 visitor->trace(m_start); 2015 visitor->trace(m_start);
1978 visitor->trace(m_end); 2016 visitor->trace(m_end);
1979 visitor->trace(m_styledInlineElement); 2017 visitor->trace(m_styledInlineElement);
1980 CompositeEditCommand::trace(visitor); 2018 CompositeEditCommand::trace(visitor);
1981 } 2019 }
1982 2020
1983 } // namespace blink 2021 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698