Changeset 14071 in webkit


Ignore:
Timestamp:
Apr 25, 2006 9:33:43 PM (18 years ago)
Author:
justing
Message:

LayoutTests:

Reviewed by harrison


<http://bugzilla.opendarwin.org/show_bug.cgi?id=8583>
Moving paste code around and some small fixes

Disabling until the bug it illustrates is fixed (8459):

  • editing/deleting/merge-whitespace-pre.html: Removed.
  • editing/deleting/merge-whitespace-pre.html-disabled: Added.


This illustrates the need to do mergeEnd in the opposite direction:

  • editing/pasteboard/merge-end-borders-expected.checksum: Added.
  • editing/pasteboard/merge-end-borders-expected.png: Added.
  • editing/pasteboard/merge-end-borders-expected.txt: Added.
  • editing/pasteboard/merge-end-borders.html: Added.


These illustrate the need to do the special case checks for list content and Mail
blockquote content at the top of shouldMergeStart:

  • editing/pasteboard/merge-start-blockquote-expected.checksum: Added.
  • editing/pasteboard/merge-start-blockquote-expected.png: Added.
  • editing/pasteboard/merge-start-blockquote-expected.txt: Added.
  • editing/pasteboard/merge-start-blockquote.html: Added.
  • editing/pasteboard/merge-start-list-expected.checksum: Added.
  • editing/pasteboard/merge-start-list-expected.png: Added.
  • editing/pasteboard/merge-start-list-expected.txt: Added.
  • editing/pasteboard/merge-start-list.html: Added.


In these tests, the caret was blown away because it was in content that
participated in the end merge. Now the end merge happens in the opposite
direction (incoming content is what is moved when merging paragraphs), so
the caret is no longer blown away:

  • editing/pasteboard/paste-line-endings-007-expected.txt:
  • editing/pasteboard/paste-line-endings-008-expected.txt:
  • editing/pasteboard/paste-line-endings-009-expected.txt:
  • editing/pasteboard/paste-text-002-expected.txt:


Acceptable change to a complicated paste-a-selection-over-itself:

  • editing/pasteboard/paste-text-003-expected.checksum:
  • editing/pasteboard/paste-text-003-expected.png:
  • editing/pasteboard/paste-text-003-expected.txt:

WebCore:

Reviewed by harrison

<http://bugzilla.opendarwin.org/show_bug.cgi?id=8583>
Moving paste code around and some small fixes


Moved code to make it easier to do the start merge after the fact,
with moveParagraph, instead of in the middle of the paste operation.

  • editing/CompositeEditCommand.cpp: (WebCore::CompositeEditCommand::moveParagraph):
  • editing/ReplaceSelectionCommand.cpp: (WebCore::ReplaceSelectionCommand::ReplaceSelectionCommand): (WebCore::ReplaceSelectionCommand::shouldMergeStart): Moved code to make this decision to its own function. Moved special case checks to the top. Added m_forceMergeStart to override the special cases because moveParagraph uses ReplaceSelectionCommand and expects a merge.


(WebCore::ReplaceSelectionCommand::shouldMergeEnd):
No functional changes, just moved code here.
(WebCore::ReplaceSelectionCommand::doApply):
Do the end merge in the opposite direction. Merging two paragraphs destroys
the moved one's block level styles, and we prefer to use the styles of the
one that was in the document, not the one that's being pasted.


  • editing/ReplaceSelectionCommand.h:
  • editing/Selection.h: (WebCore::Selection::visibleStart): Added. (WebCore::Selection::visibleEnd): Added.
  • editing/htmlediting.cpp: (WebCore::enclosingList): Added. (WebCore::isMailBlockquote): Don't require a renderer so that this can be used on nodes in fragments.


  • editing/htmlediting.h:
Location:
trunk
Files:
13 added
1 deleted
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r14069 r14071  
     12006-04-25  Justin Garcia  <justin.garcia@apple.com>
     2
     3        Reviewed by harrison
     4       
     5        <http://bugzilla.opendarwin.org/show_bug.cgi?id=8583>
     6        Moving paste code around and some small fixes
     7
     8        Disabling until the bug it illustrates is fixed (8459):
     9        * editing/deleting/merge-whitespace-pre.html: Removed.
     10        * editing/deleting/merge-whitespace-pre.html-disabled: Added.
     11       
     12        This illustrates the need to do mergeEnd in the opposite direction:
     13        * editing/pasteboard/merge-end-borders-expected.checksum: Added.
     14        * editing/pasteboard/merge-end-borders-expected.png: Added.
     15        * editing/pasteboard/merge-end-borders-expected.txt: Added.
     16        * editing/pasteboard/merge-end-borders.html: Added.
     17       
     18        These illustrate the need to do the special case checks for list content and Mail
     19        blockquote content at the top of shouldMergeStart:
     20        * editing/pasteboard/merge-start-blockquote-expected.checksum: Added.
     21        * editing/pasteboard/merge-start-blockquote-expected.png: Added.
     22        * editing/pasteboard/merge-start-blockquote-expected.txt: Added.
     23        * editing/pasteboard/merge-start-blockquote.html: Added.
     24        * editing/pasteboard/merge-start-list-expected.checksum: Added.
     25        * editing/pasteboard/merge-start-list-expected.png: Added.
     26        * editing/pasteboard/merge-start-list-expected.txt: Added.
     27        * editing/pasteboard/merge-start-list.html: Added.
     28       
     29        In these tests, the caret was blown away because it was in content that
     30        participated in the end merge.  Now the end merge happens in the opposite
     31        direction (incoming content is what is moved when merging paragraphs), so
     32        the caret is no longer blown away:
     33        * editing/pasteboard/paste-line-endings-007-expected.txt:
     34        * editing/pasteboard/paste-line-endings-008-expected.txt:
     35        * editing/pasteboard/paste-line-endings-009-expected.txt:
     36        * editing/pasteboard/paste-text-002-expected.txt:
     37       
     38        Acceptable change to a complicated paste-a-selection-over-itself:
     39        * editing/pasteboard/paste-text-003-expected.checksum:
     40        * editing/pasteboard/paste-text-003-expected.png:
     41        * editing/pasteboard/paste-text-003-expected.txt:
     42
    1432006-04-25  Geoffrey Garen  <ggaren@apple.com>
    244
  • trunk/LayoutTests/editing/pasteboard/paste-line-endings-007-expected.txt

    r13869 r14071  
    1313EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
    1414EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 9 of #text > DIV > DIV > BODY > HTML > #document to 1 of #text > DIV > DIV > DIV > BODY > HTML > #document givenAction:WebViewInsertActionPasted
    15 EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 1 of #text > DIV > DIV > DIV > BODY > HTML > #document to 1 of #text > DIV > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
     15EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 9 of #text > DIV > DIV > BODY > HTML > #document to 1 of #text > DIV > DIV > DIV > BODY > HTML > #document toDOMRange:range from 1 of #text > DIV > DIV > DIV > BODY > HTML > #document to 1 of #text > DIV > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
    1616EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
    1717EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
  • trunk/LayoutTests/editing/pasteboard/paste-line-endings-008-expected.txt

    r13869 r14071  
    1313EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
    1414EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 8 of #text > DIV > DIV > DIV > BODY > HTML > #document to 1 of #text > DIV > DIV > DIV > BODY > HTML > #document givenAction:WebViewInsertActionPasted
    15 EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 1 of #text > DIV > DIV > DIV > BODY > HTML > #document to 1 of #text > DIV > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
     15EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 8 of #text > DIV > DIV > DIV > BODY > HTML > #document to 1 of #text > DIV > DIV > DIV > BODY > HTML > #document toDOMRange:range from 1 of #text > DIV > DIV > DIV > BODY > HTML > #document to 1 of #text > DIV > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
    1616EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
    1717EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
  • trunk/LayoutTests/editing/pasteboard/paste-line-endings-009-expected.txt

    r13869 r14071  
    1313EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
    1414EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 8 of #text > DIV > DIV > DIV > BODY > HTML > #document to 1 of #text > DIV > DIV > DIV > DIV > BODY > HTML > #document givenAction:WebViewInsertActionPasted
    15 EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 1 of #text > DIV > DIV > DIV > DIV > BODY > HTML > #document to 1 of #text > DIV > DIV > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
     15EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 8 of #text > DIV > DIV > DIV > BODY > HTML > #document to 1 of #text > DIV > DIV > DIV > DIV > BODY > HTML > #document toDOMRange:range from 1 of #text > DIV > DIV > DIV > DIV > BODY > HTML > #document to 1 of #text > DIV > DIV > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
    1616EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
    1717EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
  • trunk/LayoutTests/editing/pasteboard/paste-text-002-expected.txt

    r13869 r14071  
    5353EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
    5454EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 6 of #text > DIV > BODY > HTML > #document to 11 of #text > DIV > BODY > HTML > #document givenAction:WebViewInsertActionPasted
    55 EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 11 of #text > DIV > BODY > HTML > #document to 11 of #text > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
     55EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of #text > DIV > BODY > HTML > #document to 11 of #text > DIV > BODY > HTML > #document toDOMRange:range from 11 of #text > DIV > BODY > HTML > #document to 11 of #text > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
    5656EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
    5757EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
  • trunk/LayoutTests/editing/pasteboard/paste-text-003-expected.checksum

    r12710 r14071  
    1 c68c2361f29830226a28d3a29ad15136
     1077b13e8b68aed08b794db609d67025e
  • trunk/LayoutTests/editing/pasteboard/paste-text-003-expected.txt

    r13869 r14071  
    9595EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
    9696EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 6 of #text > DIV > BODY > HTML > #document to 7 of #text > DIV > DIV > DIV > BODY > HTML > #document givenAction:WebViewInsertActionPasted
    97 EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 7 of #text > DIV > DIV > DIV > BODY > HTML > #document to 7 of #text > DIV > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
     97EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of #text > DIV > BODY > HTML > #document to 7 of #text > DIV > DIV > DIV > BODY > HTML > #document toDOMRange:range from 7 of #text > DIV > DIV > DIV > BODY > HTML > #document to 7 of #text > DIV > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
    9898EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
    9999EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
    100100EDITING DELEGATE: shouldInsertNode:#document-fragment replacingDOMRange:range from 7 of #text > DIV > DIV > DIV > BODY > HTML > #document to 7 of #text > DIV > DIV > DIV > BODY > HTML > #document givenAction:WebViewInsertActionPasted
    101 EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 7 of #text > DIV > DIV > DIV > BODY > HTML > #document to 7 of #text > DIV > DIV > DIV > BODY > HTML > #document toDOMRange:range from 7 of #text > DIV > DIV > DIV > DIV > BODY > HTML > #document to 7 of #text > DIV > DIV > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
     101EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 7 of #text > DIV > DIV > DIV > BODY > HTML > #document to 7 of #text > DIV > DIV > DIV > BODY > HTML > #document toDOMRange:range from 7 of #text > DIV > DIV > DIV > BODY > HTML > #document to 7 of #text > DIV > DIV > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
    102102EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
    103103EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
     
    107107  RenderBlock {HTML} at (0,0) size 800x600
    108108    RenderBody {BODY} at (8,8) size 784x584
    109       RenderBlock {DIV} at (0,0) size 784x392 [border: (2px solid #FF0000)]
     109      RenderBlock {DIV} at (0,0) size 784x364 [border: (2px solid #FF0000)]
    110110        RenderBlock (anonymous) at (14,14) size 756x28
    111111          RenderText {#text} at (0,0) size 63x28
     
    113113          RenderText {#text} at (63,0) size 285x28
    114114            text run at (63,0) width 285: "is a tide in the affairs of men,"
    115         RenderBlock {DIV} at (14,42) size 756x224 [border: (2px solid #FF0000)]
    116           RenderBlock (anonymous) at (14,14) size 728x28
    117             RenderText {#text} at (0,0) size 434x28
    118               text run at (0,0) width 434: "Which taken at the flood leads on to fortune."
    119           RenderBlock {DIV} at (14,42) size 728x56 [border: (2px solid #FF0000)]
     115        RenderBlock {DIV} at (14,42) size 756x56 [border: (2px solid #FF0000)]
     116          RenderText {#text} at (14,14) size 434x28
     117            text run at (14,14) width 434: "Which taken at the flood leads on to fortune."
     118        RenderBlock {DIV} at (14,98) size 756x252 [border: (2px solid #FF0000)]
     119          RenderBlock (anonymous) at (14,14) size 728x0
     120          RenderBlock {DIV} at (14,14) size 728x56 [border: (2px solid #FF0000)]
    120121            RenderText {#text} at (14,14) size 80x28
    121122              text run at (14,14) width 80: "Omitted"
    122123            RenderText {#text} at (94,14) size 285x28
    123124              text run at (94,14) width 285: "is a tide in the affairs of men,"
    124           RenderBlock {DIV} at (14,98) size 728x112 [border: (2px solid #FF0000)]
     125          RenderBlock {DIV} at (14,70) size 728x56 [border: (2px solid #FF0000)]
     126            RenderText {#text} at (14,14) size 434x28
     127              text run at (14,14) width 434: "Which taken at the flood leads on to fortune."
     128          RenderBlock {DIV} at (14,126) size 728x112 [border: (2px solid #FF0000)]
    125129            RenderBlock (anonymous) at (14,14) size 700x28
    126               RenderText {#text} at (0,0) size 434x28
    127                 text run at (0,0) width 434: "Which taken at the flood leads on to fortune."
     130              RenderText {#text} at (0,0) size 80x28
     131                text run at (0,0) width 80: "Omitted"
     132              RenderText {#text} at (80,0) size 271x28
     133                text run at (80,0) width 271: ", all the voyage of their life,"
    128134            RenderBlock {DIV} at (14,42) size 700x56 [border: (2px solid #FF0000)]
    129               RenderText {#text} at (14,14) size 80x28
    130                 text run at (14,14) width 80: "Omitted"
    131               RenderText {#text} at (94,14) size 271x28
    132                 text run at (94,14) width 271: ", all the voyage of their life,"
    133         RenderBlock {DIV} at (14,266) size 756x112 [border: (2px solid #FF0000)]
    134           RenderBlock (anonymous) at (14,14) size 728x0
    135           RenderBlock {DIV} at (14,14) size 728x84 [border: (2px solid #FF0000)]
    136             RenderBlock (anonymous) at (14,14) size 700x0
    137             RenderBlock {DIV} at (14,14) size 700x56 [border: (2px solid #FF0000)]
    138135              RenderText {#text} at (14,14) size 357x28
    139136                text run at (14,14) width 357: "Is bound in shallows and in miseries."
    140 caret: position 7 of child 0 {#text} of child 1 {DIV} of child 2 {DIV} of child 2 {DIV} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
     137caret: position 7 of child 0 {#text} of child 2 {DIV} of child 3 {DIV} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
  • trunk/WebCore/ChangeLog

    r14069 r14071  
     12006-04-25  Justin Garcia  <justin.garcia@apple.com>
     2
     3        Reviewed by harrison
     4
     5        <http://bugzilla.opendarwin.org/show_bug.cgi?id=8583>
     6        Moving paste code around and some small fixes
     7       
     8        Moved code to make it easier to do the start merge after the fact,
     9        with moveParagraph, instead of in the middle of the paste operation.
     10
     11        * editing/CompositeEditCommand.cpp:
     12        (WebCore::CompositeEditCommand::moveParagraph):
     13        * editing/ReplaceSelectionCommand.cpp:
     14        (WebCore::ReplaceSelectionCommand::ReplaceSelectionCommand):
     15        (WebCore::ReplaceSelectionCommand::shouldMergeStart):
     16        Moved code to make this decision to its own function.  Moved special case
     17        checks to the top.  Added m_forceMergeStart to override the special cases
     18        because moveParagraph uses ReplaceSelectionCommand and expects a merge.
     19       
     20        (WebCore::ReplaceSelectionCommand::shouldMergeEnd):
     21        No functional changes, just moved code here.
     22        (WebCore::ReplaceSelectionCommand::doApply):
     23        Do the end merge in the opposite direction.  Merging two paragraphs destroys
     24        the moved one's block level styles, and we prefer to use the styles of the
     25        one that was in the document, not the one that's being pasted.
     26       
     27        * editing/ReplaceSelectionCommand.h:
     28        * editing/Selection.h:
     29        (WebCore::Selection::visibleStart): Added.
     30        (WebCore::Selection::visibleEnd): Added.
     31        * editing/htmlediting.cpp:
     32        (WebCore::enclosingList): Added.
     33        (WebCore::isMailBlockquote):
     34        Don't require a renderer so that this can be used on nodes in fragments.
     35       
     36        * editing/htmlediting.h:
     37
    1382006-04-25  Geoffrey Garen  <ggaren@apple.com>
    239
  • trunk/WebCore/editing/CompositeEditCommand.cpp

    r13957 r14071  
    710710   
    711711    setEndingSelection(destination);
    712     EditCommandPtr cmd(new ReplaceSelectionCommand(document(), fragment.get(), false));
     712    EditCommandPtr cmd(new ReplaceSelectionCommand(document(), fragment.get(), false, false, false, true));
    713713    applyCommandToComposite(cmd);
    714714}
  • trunk/WebCore/editing/ReplaceSelectionCommand.cpp

    r13957 r14071  
    386386}
    387387
     388// FIXME: This counts two blocks for <span><div>foo</div></span>.  Get rid of uses of hasMoreThanOneBlock so that we can get rid of this function.
    388389int ReplacementFragment::renderedBlocks(Node *holder)
    389390{
     
    453454}
    454455
    455 ReplaceSelectionCommand::ReplaceSelectionCommand(Document *document, DocumentFragment *fragment, bool selectReplacement, bool smartReplace, bool matchStyle)
     456ReplaceSelectionCommand::ReplaceSelectionCommand(Document *document, DocumentFragment *fragment, bool selectReplacement, bool smartReplace, bool matchStyle, bool forceMergeStart)
    456457    : CompositeEditCommand(document),
    457458      m_selectReplacement(selectReplacement),
    458459      m_smartReplace(smartReplace),
    459460      m_matchStyle(matchStyle),
    460       m_documentFragment(fragment)
     461      m_documentFragment(fragment),
     462      m_forceMergeStart(forceMergeStart)
    461463{
    462464}
     
    464466ReplaceSelectionCommand::~ReplaceSelectionCommand()
    465467{
     468}
     469
     470// FIXME: This will soon operate on the fragment after it's been inserted so that it can check renderers and create visible positions.
     471bool ReplaceSelectionCommand::shouldMergeStart(const ReplacementFragment& incomingFragment, const Selection& destinationSelection)
     472{
     473    if (m_forceMergeStart)
     474        return true;
     475       
     476    VisiblePosition visibleStart = destinationSelection.visibleStart();
     477    Node* startBlock = destinationSelection.start().node()->enclosingBlockFlowElement();
     478
     479    // <rdar://problem/4013642> Copied quoted word does not paste as a quote if pasted at the start of a line   
     480    if (isStartOfParagraph(visibleStart) && isMailBlockquote(incomingFragment.firstChild()))
     481        return false;
     482   
     483    // Don't pull content out of a list item.
     484    // FIXMEs: Do this check in shouldMergeEnd too.  Don't pull content out of a table cell either.
     485    if (enclosingList(incomingFragment.mergeStartNode()))
     486        return false;
     487   
     488    // Merge if this is an empty editable subtree, to prevent an extra level of block nesting.
     489    if (startBlock == startBlock->rootEditableElement() && isStartOfBlock(visibleStart) && isEndOfBlock(visibleStart))
     490        return true;
     491   
     492    if (!incomingFragment.hasInterchangeNewlineAtStart() &&
     493        (!isStartOfParagraph(visibleStart) || !incomingFragment.hasInterchangeNewlineAtEnd() && !incomingFragment.hasMoreThanOneBlock()))
     494       return true;
     495   
     496    return false;
     497}
     498
     499bool ReplaceSelectionCommand::shouldMergeEnd(const ReplacementFragment& incomingFragment, const Selection& destinationSelection)
     500{
     501    return !incomingFragment.hasInterchangeNewlineAtEnd() && !isEndOfParagraph(destinationSelection.visibleEnd());
    466502}
    467503
     
    487523    VisiblePosition visibleEnd(selection.end(), selection.affinity());
    488524    bool startAtStartOfBlock = isStartOfBlock(visibleStart);
    489     bool startAtEndOfBlock = isEndOfBlock(visibleStart);
    490     Node *startBlock = selection.start().node()->enclosingBlockFlowElement();
    491 
    492     // decide whether to later merge content into the startBlock
    493     bool mergeStart = false;
    494     if (startBlock == startBlock->rootEditableElement() && startAtStartOfBlock && startAtEndOfBlock) {
    495         // empty editable subtree, need to mergeStart so that fragment ends up
    496         // merged into the editable subtree rather than adding more levels of block nesting
    497         mergeStart = true;
    498     } else {
    499         // merge if current selection starts inside a paragraph, or there is only one block and no interchange newline to add
    500         mergeStart = !fragment.hasInterchangeNewlineAtStart() &&
    501             (!isStartOfParagraph(visibleStart) || (!fragment.hasInterchangeNewlineAtEnd() && !fragment.hasMoreThanOneBlock()));
    502        
    503         // This is a workaround for this bug:
    504         // <rdar://problem/4013642> Copied quoted word does not paste as a quote if pasted at the start of a line
    505         // We need more powerful logic in this whole mergeStart code for this case to come out right without
    506         // breaking other cases.
    507         if (isStartOfParagraph(visibleStart) && isMailBlockquote(fragment.firstChild()))
    508             mergeStart = false;
    509        
    510         // prevent first list item from getting merged into target, thereby pulled out of list
    511         // NOTE: ideally, we'd check for "first visible position in list" here,
    512         // but we cannot.  Fragments do not have any visible positions.  Instead, we
    513         // assume that the mergeStartNode() contains the first visible content to paste.
    514         // Any better ideas?
    515         if (mergeStart) {
    516             for (Node *n = fragment.mergeStartNode(); n; n = n->parentNode()) {
    517                 if (isListElement(n)) {
    518                     mergeStart = false;
    519                     break;
    520                 }
    521             }
    522         }
    523     }
     525    Node* startBlock = selection.start().node()->enclosingBlockFlowElement();
     526
     527    // Whether the first paragraph of the incoming fragment should be merged with content from visibleStart to startOfParagraph(visibleStart).
     528    bool mergeStart = shouldMergeStart(fragment, selection);
    524529   
    525530    // Whether the last paragraph of the incoming fragment should be merged with content from visibleEnd to endOfParagraph(visibleEnd).
    526     bool mergeEnd = !isEndOfParagraph(visibleEnd) && !fragment.hasInterchangeNewlineAtEnd();
     531    bool mergeEnd = shouldMergeEnd(fragment, selection);
    527532
    528533    Position startPos = selection.start();
     
    533538        deleteSelection(false, mergeBlocksAfterDelete);
    534539        updateLayout();
    535         visibleStart = VisiblePosition(endingSelection().start(), VP_DEFAULT_AFFINITY);
     540        visibleStart = endingSelection().visibleStart();
    536541        if (fragment.hasInterchangeNewlineAtStart()) {
    537542            if (isEndOfParagraph(visibleStart) && !isStartOfParagraph(visibleStart)) {
     
    569574        startPos = endingSelection().start();
    570575    }
    571 
     576   
    572577    if (startAtStartOfBlock && startBlock->inDocument())
    573578        startPos = Position(startBlock, 0);
     
    787792            }
    788793        }
    789        
    790         if (mergeEnd) {
    791             // FIXME: This move should happen in the opposite direction, because we'd rather preserve the styles on the block containing the
    792             // paragraph that was already in the document than preserve block styles from the incoming fragment.
    793             VisiblePosition afterInsertedContent(Position(m_lastNodeInserted->parentNode(), m_lastNodeInserted->nodeIndex() + 1));
    794             if (isEndOfParagraph(afterInsertedContent)) {
    795                 VisiblePosition startOfParagraphToMove = afterInsertedContent.next();
    796                 VisiblePosition endOfParagraphToMove = endOfParagraph(startOfParagraphToMove);
    797                 moveParagraph(startOfParagraphToMove, endOfParagraphToMove, afterInsertedContent);
    798             }
    799         }
    800794    }
    801795   
    802796    if (!m_matchStyle)
    803797        fixupNodeStyles(fragment.nodes(), fragment.renderingInfo());
     798   
     799    if (mergeEnd) {
     800        VisiblePosition afterInsertedContent(positionAfterNode(m_lastNodeInserted.get()));
     801        if (isEndOfParagraph(afterInsertedContent)) {
     802            VisiblePosition startOfParagraphToMove = startOfParagraph(afterInsertedContent);
     803            VisiblePosition destination = afterInsertedContent.next();
     804            moveParagraph(startOfParagraphToMove, afterInsertedContent, destination);
     805        }
     806    }
     807   
    804808    completeHTMLReplacement(lastPositionToSelect);
    805809   
  • trunk/WebCore/editing/ReplaceSelectionCommand.h

    r13821 r14071  
    114114{
    115115public:
    116     ReplaceSelectionCommand(Document *document, DocumentFragment *fragment, bool selectReplacement=true, bool smartReplace=false, bool matchStyle=false);
     116    ReplaceSelectionCommand(Document *document, DocumentFragment *fragment, bool selectReplacement=true, bool smartReplace=false, bool matchStyle=false, bool forceMergeStart=false);
    117117    virtual ~ReplaceSelectionCommand();
    118118   
     
    130130    void fixupNodeStyles(const NodeVector&, const RenderingInfoMap&);
    131131    void removeLinePlaceholderIfNeeded(Node *);
     132   
     133    bool shouldMergeStart(const ReplacementFragment&, const Selection&);
     134    bool shouldMergeEnd(const ReplacementFragment&, const Selection&);
    132135
    133136    RefPtr<Node> m_firstNodeInserted;
     
    139142    bool m_matchStyle;
    140143    RefPtr<DocumentFragment> m_documentFragment;
     144    bool m_forceMergeStart;
    141145};
    142146
  • trunk/WebCore/editing/Selection.h

    r13821 r14071  
    2828
    2929#include "Position.h"
     30#include "VisiblePosition.h"
    3031#include "TextGranularity.h"
    3132
     
    5859    Position start() const { return m_start; }
    5960    Position end() const { return m_end; }
     61   
     62    VisiblePosition visibleStart() const { return VisiblePosition(m_start, isRange() ? DOWNSTREAM : affinity()); }
     63    VisiblePosition visibleEnd() const { return VisiblePosition(m_end, isRange() ? UPSTREAM : affinity()); }
    6064
    6165    bool isNone() const { return state() == NONE; }
  • trunk/WebCore/editing/htmlediting.cpp

    r13874 r14071  
    374374}
    375375
     376Node* enclosingList(Node* node)
     377{
     378    if (!node)
     379        return 0;
     380       
     381    for (Node* n = node->parentNode(); n; n = n->parentNode())
     382        if (n->hasTagName(ulTag) || n->hasTagName(olTag))
     383            return n;
     384    return 0;
     385}
     386
    376387Node *enclosingListChild (Node *node)
    377388{
     
    551562bool isMailBlockquote(const Node *node)
    552563{
    553     if (!node || !node->renderer() || !node->isElementNode() && !node->hasTagName(blockquoteTag))
     564    if (!node || !node->isElementNode() && !node->hasTagName(blockquoteTag))
    554565        return false;
    555566       
  • trunk/WebCore/editing/htmlediting.h

    r13821 r14071  
    8383
    8484bool isListElement(Node* n);
     85Node* enclosingList(Node* node);
    8586Node *enclosingListChild(Node *n);
    8687bool isTableElement(Node* n);
Note: See TracChangeset for help on using the changeset viewer.