WebCore/editing/FormatBlockCommand.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  * 1. Redistributions of source code must retain the above copyright
       
     8  *    notice, this list of conditions and the following disclaimer.
       
     9  * 2. Redistributions in binary form must reproduce the above copyright
       
    10  *    notice, this list of conditions and the following disclaimer in the
       
    11  *    documentation and/or other materials provided with the distribution.
       
    12  *
       
    13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
       
    14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
       
    17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
       
    21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
       
    24  */
       
    25 
       
    26 #include "config.h"
       
    27 #include "Element.h"
       
    28 #include "FormatBlockCommand.h"
       
    29 #include "Document.h"
       
    30 #include "htmlediting.h"
       
    31 #include "HTMLElement.h"
       
    32 #include "HTMLNames.h"
       
    33 #include "visible_units.h"
       
    34 
       
    35 namespace WebCore {
       
    36 
       
    37 using namespace HTMLNames;
       
    38 
       
    39 FormatBlockCommand::FormatBlockCommand(Document* document, const AtomicString& tagName) 
       
    40     : CompositeEditCommand(document), m_tagName(tagName)
       
    41 {
       
    42 }
       
    43 
       
    44 bool FormatBlockCommand::modifyRange()
       
    45 {
       
    46     ASSERT(endingSelection().isRange());
       
    47     VisiblePosition visibleStart = endingSelection().visibleStart();
       
    48     VisiblePosition visibleEnd = endingSelection().visibleEnd();
       
    49     VisiblePosition startOfLastParagraph = startOfParagraph(visibleEnd);
       
    50     
       
    51     if (startOfParagraph(visibleStart) == startOfLastParagraph)
       
    52         return false;
       
    53 
       
    54     setEndingSelection(visibleStart);
       
    55     doApply();
       
    56     visibleStart = endingSelection().visibleStart();
       
    57     VisiblePosition nextParagraph = endOfParagraph(visibleStart).next();
       
    58     while (nextParagraph.isNotNull() && nextParagraph != startOfLastParagraph) {
       
    59         setEndingSelection(nextParagraph);
       
    60         doApply();
       
    61         nextParagraph = endOfParagraph(endingSelection().visibleStart()).next();
       
    62     }
       
    63     setEndingSelection(visibleEnd);
       
    64     doApply();
       
    65     visibleEnd = endingSelection().visibleEnd();
       
    66     setEndingSelection(VisibleSelection(visibleStart.deepEquivalent(), visibleEnd.deepEquivalent(), DOWNSTREAM));
       
    67 
       
    68     return true;
       
    69 }
       
    70 
       
    71 void FormatBlockCommand::doApply()
       
    72 {
       
    73     if (endingSelection().isNone())
       
    74         return;
       
    75     
       
    76     if (!endingSelection().rootEditableElement())
       
    77         return;
       
    78 
       
    79     VisiblePosition visibleEnd = endingSelection().visibleEnd();
       
    80     VisiblePosition visibleStart = endingSelection().visibleStart();
       
    81     // When a selection ends at the start of a paragraph, we rarely paint 
       
    82     // the selection gap before that paragraph, because there often is no gap.  
       
    83     // In a case like this, it's not obvious to the user that the selection 
       
    84     // ends "inside" that paragraph, so it would be confusing if FormatBlock
       
    85     // operated on that paragraph.
       
    86     // FIXME: We paint the gap before some paragraphs that are indented with left 
       
    87     // margin/padding, but not others.  We should make the gap painting more consistent and 
       
    88     // then use a left margin/padding rule here.
       
    89     if (visibleEnd != visibleStart && isStartOfParagraph(visibleEnd))
       
    90         setEndingSelection(VisibleSelection(visibleStart, visibleEnd.previous(true)));
       
    91 
       
    92     if (endingSelection().isRange() && modifyRange())
       
    93         return;
       
    94 
       
    95     ExceptionCode ec;
       
    96     String localName, prefix;
       
    97     if (!Document::parseQualifiedName(m_tagName, prefix, localName, ec))
       
    98         return;
       
    99     QualifiedName qTypeOfBlock(prefix, localName, xhtmlNamespaceURI);
       
   100 
       
   101     Node* refNode = enclosingBlockFlowElement(endingSelection().visibleStart());
       
   102     if (refNode->hasTagName(qTypeOfBlock))
       
   103         // We're already in a block with the format we want, so we don't have to do anything
       
   104         return;
       
   105     
       
   106     VisiblePosition paragraphStart = startOfParagraph(endingSelection().visibleStart());
       
   107     VisiblePosition paragraphEnd = endOfParagraph(endingSelection().visibleStart());
       
   108     VisiblePosition blockStart = startOfBlock(endingSelection().visibleStart());
       
   109     VisiblePosition blockEnd = endOfBlock(endingSelection().visibleStart());
       
   110     RefPtr<Element> blockNode = createHTMLElement(document(), m_tagName);
       
   111     RefPtr<Element> placeholder = createBreakElement(document());
       
   112     
       
   113     Node* root = endingSelection().start().node()->rootEditableElement();
       
   114     if (validBlockTag(refNode->nodeName().lower()) && 
       
   115         paragraphStart == blockStart && paragraphEnd == blockEnd && 
       
   116         refNode != root && !root->isDescendantOf(refNode))
       
   117         // Already in a valid block tag that only contains the current paragraph, so we can swap with the new tag
       
   118         insertNodeBefore(blockNode, refNode);
       
   119     else {
       
   120         // Avoid inserting inside inline elements that surround paragraphStart with upstream().
       
   121         // This is only to avoid creating bloated markup.
       
   122         insertNodeAt(blockNode, paragraphStart.deepEquivalent().upstream());
       
   123     }
       
   124     appendNode(placeholder, blockNode);
       
   125     
       
   126     VisiblePosition destination(Position(placeholder.get(), 0));
       
   127     if (paragraphStart == paragraphEnd && !lineBreakExistsAtVisiblePosition(paragraphStart)) {
       
   128         setEndingSelection(destination);
       
   129         return;
       
   130     }
       
   131     moveParagraph(paragraphStart, paragraphEnd, destination, true, false);
       
   132 }
       
   133 
       
   134 }