Reviewed by harrison
[WebKit-https.git] / WebCore / khtml / editing / rebalance_whitespace_command.cpp
1 /*
2  * Copyright (C) 2005 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 "rebalance_whitespace_command.h"
27
28 #include "htmlediting.h"
29 #include "visible_text.h"
30 #include "xml/dom_docimpl.h"
31 #include "xml/dom_textimpl.h"
32
33 #if APPLE_CHANGES
34 #include <kxmlcore/Assertions.h>
35 #else
36 #define ASSERT(assertion) assert(assertion)
37 #endif
38
39 using DOM::DOMString;
40 using DOM::DocumentImpl;
41 using DOM::Position;
42 using DOM::TextImpl;
43
44 namespace khtml {
45
46 RebalanceWhitespaceCommand::RebalanceWhitespaceCommand(DocumentImpl *document, const Position &pos)
47     : EditCommand(document), m_position(pos), m_upstreamOffset(InvalidOffset)
48 {
49 }
50
51 RebalanceWhitespaceCommand::~RebalanceWhitespaceCommand()
52 {
53 }
54
55 static inline bool isWhitespace(const QChar &c)
56 {
57     return c.unicode() == 0xa0 || isCollapsibleWhitespace(c);
58 }
59
60 void RebalanceWhitespaceCommand::doApply()
61 {
62     if (m_position.isNull() || !m_position.node()->isTextNode())
63         return;
64         
65     TextImpl *textNode = static_cast<TextImpl *>(m_position.node());
66     DOMString text = textNode->data();
67     if (text.length() == 0)
68         return;
69     
70     int offset = m_position.offset();
71     // If neither text[offset] nor text[offset - 1] are some form of whitespace, do nothing.
72     if (!isWhitespace(text[offset])) {
73         offset--;
74         if (offset < 0 || !isWhitespace(text[offset]))
75             return;
76     }
77     
78     // Set upstream and downstream to define the extent of the whitespace surrounding text[offset].
79     int upstream = offset;
80     while (upstream > 0 && isWhitespace(text[upstream - 1]))
81         upstream--;
82     m_upstreamOffset = upstream; // Save m_upstreamOffset, it will be used during an Undo
83     
84     int downstream = offset;
85     while ((unsigned)downstream + 1 < text.length() && isWhitespace(text[downstream + 1]))
86         downstream++;
87     
88     int length = downstream - upstream + 1;
89     ASSERT(length > 0);
90     
91     m_beforeString = text.substring(upstream, length);
92     rebalanceWhitespaceInTextNode(textNode, upstream, length);
93     m_afterString = text.substring(upstream, length);
94 }
95
96 void RebalanceWhitespaceCommand::doUnapply()
97 {
98     if (m_upstreamOffset == InvalidOffset)
99         return;
100     
101     ASSERT(m_position.node()->isTextNode());
102     TextImpl *textNode = static_cast<TextImpl *>(m_position.node());
103     DOMString text = textNode->data();
104     text.remove(m_upstreamOffset, m_afterString.length());
105     text.insert(m_beforeString, m_upstreamOffset);
106 }
107
108 bool RebalanceWhitespaceCommand::preservesTypingStyle() const
109 {
110     return true;
111 }
112
113 } // namespace khtml
114