| Differences between
and this patch
- Source/WebCore/ChangeLog +57 lines
Lines 1-3 Source/WebCore/ChangeLog_sec1
1
2011-06-28  Ryosuke Niwa  <rniwa@webkit.org>
2
3
        Reviewed by Darin Adler.
4
5
        Stop instantiating Position with PositionIsOffsetInAnchor in various files
6
        https://bugs.webkit.org/show_bug.cgi?id=63384
7
8
        Refactoring.
9
10
        Removed many if conditions that compared the anchor type to Position::PositionIsOffsetInAnchor
11
        because there were also checking that containerNode is a text node.
12
13
        Also added Position::containerText() to avoid manually casting containerNode().
14
15
        * dom/Position.cpp:
16
        (WebCore::Position::Position): Added an assertion to ensure BeforeChildren/AfterChildren
17
        anchor type won't be used for a node whose contents is ignored by editing.
18
        (WebCore::Position::containerText): Added.
19
        * dom/Position.h:
20
        * editing/ApplyBlockElementCommand.cpp:
21
        (WebCore::isNewLineAtPosition): Removed a redundant comparison of anchor type.
22
        (WebCore::ApplyBlockElementCommand::rangeForParagraphSplittingTextNodesIfNeeded): Since containerNode
23
        is always a text node when renderStyleOfEnclosingTextNode returns a render style, use new Position
24
        constructor that takes Text* and offset.
25
        (WebCore::ApplyBlockElementCommand::endOfNextParagrahSplittingTextNodesIfNeeded): Removed redundant
26
        comparison of anchor type and use new Position constructor that takes Text* and offset.
27
        * editing/ApplyStyleCommand.cpp:
28
        (WebCore::ApplyStyleCommand::splitTextAtStart): Replaced an assertion that compared anchor type by
29
        an assertion that the container node is a text node; use new constructor.
30
        (WebCore::ApplyStyleCommand::splitTextAtEnd): Ditto; also added early exits in the case script
31
        modified DOM.
32
        (WebCore::ApplyStyleCommand::splitTextElementAtStart): Ditto.
33
        (WebCore::ApplyStyleCommand::splitTextElementAtEnd): Ditto.
34
        (WebCore::ApplyStyleCommand::joinChildTextNodes): Use new constructor.
35
        * editing/CompositeEditCommand.cpp:
36
        (WebCore::Editor::replaceSelectedTextInNode): Calls containerText instead of manually casting containerNode.
37
        * editing/Editor.cpp:
38
        (WebCore::Editor::canDeleteRange): Call Range::startPosition instead of manually instantiating Position
39
        by calling startContainer and startOffset.
40
        * editing/FrameSelection.cpp:
41
        (WebCore::FrameSelection::setSelectedRange): Ditto.
42
        * editing/InsertTextCommand.cpp:
43
        (WebCore::InsertTextCommand::input): Calls containerText instead of manually casting containerNode.
44
        * editing/ReplaceSelectionCommand.cpp:
45
        (WebCore::ReplaceSelectionCommand::doApply): Calls containerText instead of manually casting containerNode.
46
        * editing/VisiblePosition.cpp:
47
        (WebCore::VisiblePosition::characterAfter): Removed a redundant anchor type comparison.
48
        (WebCore::startVisiblePosition): Call Range::startPosition instead of startContainer and startOffset.
49
        (WebCore::endVisiblePosition): Call Range::endPosition instead of endContainer and endOffset.
50
        * editing/htmlediting.cpp:
51
        (WebCore::firstInSpecialElement): Call containerNode() to address <rdar://problem/5027702>.
52
        (WebCore::lastInSpecialElement): Ditto; use new constructor.
53
        * editing/visible_units.cpp:
54
        (WebCore::endPositionForLine): Use new constructor.
55
        (WebCore::startOfParagraph): Ditto.
56
        (WebCore::endOfParagraph): Ditto.
57
1
2011-06-28  Joone Hur  <joone.hur@collabora.co.uk>
58
2011-06-28  Joone Hur  <joone.hur@collabora.co.uk>
2
59
3
        Reviewed by Martin Robinson.
60
        Reviewed by Martin Robinson.
- Source/WebCore/dom/Position.cpp -1 / +19 lines
Lines 91-97 Position::Position(PassRefPtr<Node> anch Source/WebCore/dom/Position.cpp_sec1
91
{
91
{
92
    ASSERT(!m_anchorNode || !m_anchorNode->isShadowRoot());
92
    ASSERT(!m_anchorNode || !m_anchorNode->isShadowRoot());
93
    ASSERT(anchorType != PositionIsOffsetInAnchor);
93
    ASSERT(anchorType != PositionIsOffsetInAnchor);
94
    ASSERT(!((anchorType == PositionIsBeforeChildren || anchorType == PositionIsAfterChildren) && m_anchorNode->isTextNode()));
94
    ASSERT(!((anchorType == PositionIsBeforeChildren || anchorType == PositionIsAfterChildren)
95
        && (m_anchorNode->isTextNode() || editingIgnoresContent(m_anchorNode.get()))));
95
}
96
}
96
97
97
Position::Position(PassRefPtr<Node> anchorNode, int offset, AnchorType anchorType)
98
Position::Position(PassRefPtr<Node> anchorNode, int offset, AnchorType anchorType)
Lines 148-153 Node* Position::containerNode() const Source/WebCore/dom/Position.cpp_sec2
148
    return 0;
149
    return 0;
149
}
150
}
150
151
152
Text* Position::containerText() const
153
{
154
    switch (anchorType()) {
155
    case PositionIsOffsetInAnchor:
156
            return m_anchorNode && m_anchorNode->isTextNode() ? static_cast<Text*>(m_anchorNode.get()) : 0;
157
    case PositionIsBeforeAnchor:
158
    case PositionIsAfterAnchor:
159
        return 0;
160
    case PositionIsBeforeChildren:
161
    case PositionIsAfterChildren:
162
        ASSERT(!m_anchorNode || !m_anchorNode->isTextNode());
163
        return 0;
164
    }
165
    ASSERT_NOT_REACHED();
166
    return 0;
167
}
168
151
int Position::computeOffsetInContainerNode() const
169
int Position::computeOffsetInContainerNode() const
152
{
170
{
153
    if (!m_anchorNode)
171
    if (!m_anchorNode)
- Source/WebCore/dom/Position.h +2 lines
Lines 96-101 public: Source/WebCore/dom/Position.h_sec1
96
    // These are always DOM compliant values.  Editing positions like [img, 0] (aka [img, before])
96
    // These are always DOM compliant values.  Editing positions like [img, 0] (aka [img, before])
97
    // will return img->parentNode() and img->nodeIndex() from these functions.
97
    // will return img->parentNode() and img->nodeIndex() from these functions.
98
    Node* containerNode() const; // NULL for a before/after position anchored to a node with no parent
98
    Node* containerNode() const; // NULL for a before/after position anchored to a node with no parent
99
    Text* containerText() const;
100
99
    int computeOffsetInContainerNode() const;  // O(n) for before/after-anchored positions, O(1) for parent-anchored positions
101
    int computeOffsetInContainerNode() const;  // O(n) for before/after-anchored positions, O(1) for parent-anchored positions
100
    Position parentAnchoredEquivalent() const; // Convenience method for DOM positions that also fixes up some positions for editing
102
    Position parentAnchoredEquivalent() const; // Convenience method for DOM positions that also fixes up some positions for editing
101
103
- Source/WebCore/editing/ApplyBlockElementCommand.cpp -39 / +34 lines
Lines 150-158 void ApplyBlockElementCommand::formatSel Source/WebCore/editing/ApplyBlockElementCommand.cpp_sec1
150
150
151
static bool isNewLineAtPosition(const Position& position)
151
static bool isNewLineAtPosition(const Position& position)
152
{
152
{
153
    if (position.anchorType() != Position::PositionIsOffsetInAnchor)
154
        return false;
155
156
    Node* textNode = position.containerNode();
153
    Node* textNode = position.containerNode();
157
    int offset = position.offsetInContainerNode();
154
    int offset = position.offsetInContainerNode();
158
    if (!textNode || !textNode->isTextNode() || offset < 0 || offset >= textNode->maxCharacterOffset())
155
    if (!textNode || !textNode->isTextNode() || offset < 0 || offset >= textNode->maxCharacterOffset())
Lines 181-191 void ApplyBlockElementCommand::rangeForP Source/WebCore/editing/ApplyBlockElementCommand.cpp_sec2
181
    start = startOfParagraph(endOfCurrentParagraph).deepEquivalent();
178
    start = startOfParagraph(endOfCurrentParagraph).deepEquivalent();
182
    end = endOfCurrentParagraph.deepEquivalent();
179
    end = endOfCurrentParagraph.deepEquivalent();
183
180
184
    RenderStyle* startStyle = renderStyleOfEnclosingTextNode(start);
185
    bool isStartAndEndOnSameNode = false;
181
    bool isStartAndEndOnSameNode = false;
186
    if (startStyle) {
182
    if (RenderStyle* startStyle = renderStyleOfEnclosingTextNode(start)) {
187
        isStartAndEndOnSameNode = renderStyleOfEnclosingTextNode(end) && start.deprecatedNode() == end.deprecatedNode();
183
        isStartAndEndOnSameNode = renderStyleOfEnclosingTextNode(end) && start.containerNode() == end.containerNode();
188
        bool isStartAndEndOfLastParagraphOnSameNode = renderStyleOfEnclosingTextNode(m_endOfLastParagraph) && start.deprecatedNode() == m_endOfLastParagraph.deprecatedNode();
184
        bool isStartAndEndOfLastParagraphOnSameNode = renderStyleOfEnclosingTextNode(m_endOfLastParagraph) && start.containerNode() == m_endOfLastParagraph.containerNode();
189
185
190
        // Avoid obtanining the start of next paragraph for start
186
        // Avoid obtanining the start of next paragraph for start
191
        if (startStyle->preserveNewline() && isNewLineAtPosition(start) && !isNewLineAtPosition(start.previous()) && start.offsetInContainerNode() > 0)
187
        if (startStyle->preserveNewline() && isNewLineAtPosition(start) && !isNewLineAtPosition(start.previous()) && start.offsetInContainerNode() > 0)
Lines 194-240 void ApplyBlockElementCommand::rangeForP Source/WebCore/editing/ApplyBlockElementCommand.cpp_sec3
194
        // If start is in the middle of a text node, split.
190
        // If start is in the middle of a text node, split.
195
        if (!startStyle->collapseWhiteSpace() && start.offsetInContainerNode() > 0) {
191
        if (!startStyle->collapseWhiteSpace() && start.offsetInContainerNode() > 0) {
196
            int startOffset = start.offsetInContainerNode();
192
            int startOffset = start.offsetInContainerNode();
197
            splitTextNode(static_cast<Text*>(start.deprecatedNode()), startOffset);
193
            Text* startText = start.containerText();
198
            start = firstPositionInOrBeforeNode(start.deprecatedNode());
194
            splitTextNode(startText, startOffset);
195
            start = firstPositionInNode(startText);
199
            if (isStartAndEndOnSameNode) {
196
            if (isStartAndEndOnSameNode) {
200
                ASSERT(end.offsetInContainerNode() >= startOffset);
197
                ASSERT(end.offsetInContainerNode() >= startOffset);
201
                end = Position(end.deprecatedNode(), end.offsetInContainerNode() - startOffset, Position::PositionIsOffsetInAnchor);
198
                end = Position(startText, end.offsetInContainerNode() - startOffset);
202
            }
199
            }
203
            if (isStartAndEndOfLastParagraphOnSameNode) {
200
            if (isStartAndEndOfLastParagraphOnSameNode) {
204
                ASSERT(m_endOfLastParagraph.offsetInContainerNode() >= startOffset);
201
                ASSERT(m_endOfLastParagraph.offsetInContainerNode() >= startOffset);
205
                m_endOfLastParagraph = Position(m_endOfLastParagraph.deprecatedNode(), m_endOfLastParagraph.offsetInContainerNode() - startOffset,
202
                m_endOfLastParagraph = Position(startText, m_endOfLastParagraph.offsetInContainerNode() - startOffset);
206
                    Position::PositionIsOffsetInAnchor);
207
            }
203
            }
208
        }
204
        }
209
    }
205
    }
210
206
211
    RenderStyle* endStyle = renderStyleOfEnclosingTextNode(end);
207
    if (RenderStyle* endStyle = renderStyleOfEnclosingTextNode(end)) {
212
    if (endStyle) {
213
        bool isEndAndEndOfLastParagraphOnSameNode = renderStyleOfEnclosingTextNode(m_endOfLastParagraph) && end.deprecatedNode() == m_endOfLastParagraph.deprecatedNode();
208
        bool isEndAndEndOfLastParagraphOnSameNode = renderStyleOfEnclosingTextNode(m_endOfLastParagraph) && end.deprecatedNode() == m_endOfLastParagraph.deprecatedNode();
214
        // Include \n at the end of line if we're at an empty paragraph
209
        // Include \n at the end of line if we're at an empty paragraph
215
        if (endStyle->preserveNewline() && start == end
210
        if (endStyle->preserveNewline() && start == end && end.offsetInContainerNode() < end.containerNode()->maxCharacterOffset()) {
216
            && end.offsetInContainerNode() < end.containerNode()->maxCharacterOffset()) {
217
            int endOffset = end.offsetInContainerNode();
211
            int endOffset = end.offsetInContainerNode();
218
            if (!isNewLineAtPosition(end.previous()) && isNewLineAtPosition(end))
212
            if (!isNewLineAtPosition(end.previous()) && isNewLineAtPosition(end))
219
                end = Position(end.deprecatedNode(), endOffset + 1, Position::PositionIsOffsetInAnchor);
213
                end = Position(end.containerText(), endOffset + 1);
220
            if (isEndAndEndOfLastParagraphOnSameNode && end.offsetInContainerNode() >= m_endOfLastParagraph.offsetInContainerNode())
214
            if (isEndAndEndOfLastParagraphOnSameNode && end.offsetInContainerNode() >= m_endOfLastParagraph.offsetInContainerNode())
221
                m_endOfLastParagraph = end;
215
                m_endOfLastParagraph = end;
222
        }
216
        }
223
217
224
        // If end is in the middle of a text node, split.
218
        // If end is in the middle of a text node, split.
225
        if (!endStyle->collapseWhiteSpace() && end.offsetInContainerNode()
219
        if (!endStyle->collapseWhiteSpace() && end.offsetInContainerNode() && end.offsetInContainerNode() < end.containerNode()->maxCharacterOffset()) {
226
            && end.offsetInContainerNode() < end.containerNode()->maxCharacterOffset()) {
220
            RefPtr<Text> endContainer = end.containerText();
227
            splitTextNode(static_cast<Text*>(end.deprecatedNode()), end.offsetInContainerNode());
221
            splitTextNode(endContainer, end.offsetInContainerNode());
228
            if (isStartAndEndOnSameNode)
222
            if (isStartAndEndOnSameNode)
229
                start = firstPositionInOrBeforeNode(end.deprecatedNode()->previousSibling());
223
                start = firstPositionInOrBeforeNode(endContainer->previousSibling());
230
            if (isEndAndEndOfLastParagraphOnSameNode) {
224
            if (isEndAndEndOfLastParagraphOnSameNode) {
231
                if (m_endOfLastParagraph.offsetInContainerNode() == end.offsetInContainerNode())
225
                if (m_endOfLastParagraph.offsetInContainerNode() == end.offsetInContainerNode())
232
                    m_endOfLastParagraph = lastPositionInNode(end.deprecatedNode()->previousSibling());
226
                    m_endOfLastParagraph = lastPositionInOrAfterNode(endContainer->previousSibling());
233
                else
227
                else
234
                    m_endOfLastParagraph = Position(end.deprecatedNode(), m_endOfLastParagraph.offsetInContainerNode() - end.offsetInContainerNode(),
228
                    m_endOfLastParagraph = Position(endContainer, m_endOfLastParagraph.offsetInContainerNode() - end.offsetInContainerNode());
235
                                                    Position::PositionIsOffsetInAnchor);
236
            }
229
            }
237
            end = lastPositionInNode(end.deprecatedNode()->previousSibling());
230
            end = lastPositionInNode(endContainer->previousSibling());
238
        }
231
        }
239
    }
232
    }
240
}
233
}
Lines 247-278 VisiblePosition ApplyBlockElementCommand Source/WebCore/editing/ApplyBlockElementCommand.cpp_sec4
247
    if (!style)
240
    if (!style)
248
        return endOfNextParagraph;
241
        return endOfNextParagraph;
249
242
250
    RefPtr<Node> containerNode = position.containerNode();
243
    RefPtr<Text> text = position.containerText();
251
    if (!style->preserveNewline() || !position.offsetInContainerNode()
244
    if (!style->preserveNewline() || !position.offsetInContainerNode() || !isNewLineAtPosition(firstPositionInNode(text.get())))
252
        || !isNewLineAtPosition(Position(containerNode.get(), 0, Position::PositionIsOffsetInAnchor)))
253
        return endOfNextParagraph;
245
        return endOfNextParagraph;
254
246
255
    // \n at the beginning of the text node immediately following the current paragraph is trimmed by moveParagraphWithClones.
247
    // \n at the beginning of the text node immediately following the current paragraph is trimmed by moveParagraphWithClones.
256
    // If endOfNextParagraph was pointing at this same text node, endOfNextParagraph will be shifted by one paragraph.
248
    // If endOfNextParagraph was pointing at this same text node, endOfNextParagraph will be shifted by one paragraph.
257
    // Avoid this by splitting "\n"
249
    // Avoid this by splitting "\n"
258
    splitTextNode(static_cast<Text*>(containerNode.get()), 1);
250
    splitTextNode(text, 1);
259
251
260
    if (start.anchorType() == Position::PositionIsOffsetInAnchor && containerNode.get() == start.containerNode()) {
252
    if (text == start.containerNode() && text->previousSibling() && text->previousSibling()->isTextNode()) {
261
        ASSERT(start.offsetInContainerNode() < position.offsetInContainerNode());
253
        ASSERT(start.offsetInContainerNode() < position.offsetInContainerNode());
262
        start = Position(containerNode->previousSibling(), start.offsetInContainerNode(), Position::PositionIsOffsetInAnchor);
254
        start = Position(static_cast<Text*>(text->previousSibling()), start.offsetInContainerNode());
263
    }
255
    }
264
    if (end.anchorType() == Position::PositionIsOffsetInAnchor && containerNode.get() == end.containerNode()) {
256
    if (text == end.containerNode() && text->previousSibling() && text->previousSibling()->isTextNode()) {
265
        ASSERT(end.offsetInContainerNode() < position.offsetInContainerNode());
257
        ASSERT(end.offsetInContainerNode() < position.offsetInContainerNode());
266
        end = Position(containerNode->previousSibling(), end.offsetInContainerNode(), Position::PositionIsOffsetInAnchor);
258
        end = Position(static_cast<Text*>(text->previousSibling()), end.offsetInContainerNode());
267
    }
259
    }
268
    if (m_endOfLastParagraph.anchorType() == Position::PositionIsOffsetInAnchor && containerNode.get() == m_endOfLastParagraph.containerNode()) {
260
    if (text == m_endOfLastParagraph.containerNode()) {
269
        if (m_endOfLastParagraph.offsetInContainerNode() < position.offsetInContainerNode())
261
        if (m_endOfLastParagraph.offsetInContainerNode() < position.offsetInContainerNode()) {
270
            m_endOfLastParagraph = Position(containerNode->previousSibling(), m_endOfLastParagraph.offsetInContainerNode(), Position::PositionIsOffsetInAnchor);
262
            // We can only fix endOfLastParagraph if the previous node was still text and hasn't been modified by script.
271
        else
263
            if (text->previousSibling()->isTextNode()
272
            m_endOfLastParagraph = Position(containerNode, m_endOfLastParagraph.offsetInContainerNode() - 1, Position::PositionIsOffsetInAnchor);
264
                && static_cast<unsigned>(m_endOfLastParagraph.offsetInContainerNode()) <= static_cast<Text*>(text->previousSibling())->length())
265
                m_endOfLastParagraph = Position(static_cast<Text*>(text->previousSibling()), m_endOfLastParagraph.offsetInContainerNode());
266
        } else
267
            m_endOfLastParagraph = Position(text.get(), m_endOfLastParagraph.offsetInContainerNode() - 1);
273
    }
268
    }
274
269
275
    return Position(containerNode.get(), position.offsetInContainerNode() - 1, Position::PositionIsOffsetInAnchor);
270
    return Position(text.get(), position.offsetInContainerNode() - 1);
276
}
271
}
277
272
278
PassRefPtr<Element> ApplyBlockElementCommand::createBlockElement() const
273
PassRefPtr<Element> ApplyBlockElementCommand::createBlockElement() const
- Source/WebCore/editing/ApplyStyleCommand.cpp -23 / +28 lines
Lines 1117-1176 bool ApplyStyleCommand::nodeFullyUnselec Source/WebCore/editing/ApplyStyleCommand.cpp_sec1
1117
1117
1118
void ApplyStyleCommand::splitTextAtStart(const Position& start, const Position& end)
1118
void ApplyStyleCommand::splitTextAtStart(const Position& start, const Position& end)
1119
{
1119
{
1120
    ASSERT(start.anchorType() == Position::PositionIsOffsetInAnchor);
1120
    ASSERT(start.containerNode()->isTextNode());
1121
1121
1122
    Position newEnd;
1122
    Position newEnd;
1123
    if (end.anchorType() == Position::PositionIsOffsetInAnchor && start.containerNode() == end.containerNode())
1123
    if (end.anchorType() == Position::PositionIsOffsetInAnchor && start.containerNode() == end.containerNode())
1124
        newEnd = Position(end.containerNode(), end.offsetInContainerNode() - start.offsetInContainerNode(), Position::PositionIsOffsetInAnchor);
1124
        newEnd = Position(end.containerText(), end.offsetInContainerNode() - start.offsetInContainerNode());
1125
    else
1125
    else
1126
        newEnd = end;
1126
        newEnd = end;
1127
1127
1128
    Text* text = static_cast<Text*>(start.deprecatedNode());
1128
    Text* text = start.containerText();
1129
    splitTextNode(text, start.offsetInContainerNode());
1129
    splitTextNode(text, start.offsetInContainerNode());
1130
    updateStartEnd(firstPositionInNode(start.deprecatedNode()), newEnd);
1130
    updateStartEnd(firstPositionInNode(start.containerNode()), newEnd);
1131
}
1131
}
1132
1132
1133
void ApplyStyleCommand::splitTextAtEnd(const Position& start, const Position& end)
1133
void ApplyStyleCommand::splitTextAtEnd(const Position& start, const Position& end)
1134
{
1134
{
1135
    ASSERT(end.anchorType() == Position::PositionIsOffsetInAnchor);
1135
    ASSERT(end.containerNode()->isTextNode());
1136
1136
1137
    bool shouldUpdateStart = start.anchorType() == Position::PositionIsOffsetInAnchor && start.containerNode() == end.containerNode();
1137
    bool shouldUpdateStart = start.anchorType() == Position::PositionIsOffsetInAnchor && start.containerNode() == end.containerNode();
1138
    Text* text = static_cast<Text *>(end.deprecatedNode());
1138
    Text* text = static_cast<Text *>(end.deprecatedNode());
1139
    splitTextNode(text, end.offsetInContainerNode());
1139
    splitTextNode(text, end.offsetInContainerNode());
1140
1140
1141
    Node* prevNode = text->previousSibling();
1141
    Node* prevNode = text->previousSibling();
1142
    ASSERT(prevNode);
1142
    if (!prevNode || !prevNode->isTextNode())
1143
    Position newStart = shouldUpdateStart ? Position(prevNode, start.offsetInContainerNode(), Position::PositionIsOffsetInAnchor) : start;
1143
        return;
1144
1145
    Position newStart = shouldUpdateStart ? Position(static_cast<Text*>(prevNode), start.offsetInContainerNode()) : start;
1144
    updateStartEnd(newStart, lastPositionInNode(prevNode));
1146
    updateStartEnd(newStart, lastPositionInNode(prevNode));
1145
}
1147
}
1146
1148
1147
void ApplyStyleCommand::splitTextElementAtStart(const Position& start, const Position& end)
1149
void ApplyStyleCommand::splitTextElementAtStart(const Position& start, const Position& end)
1148
{
1150
{
1149
    ASSERT(start.anchorType() == Position::PositionIsOffsetInAnchor);
1151
    ASSERT(start.containerNode()->isTextNode());
1150
1152
1151
    Position newEnd;
1153
    Position newEnd;
1152
    if (end.anchorType() == Position::PositionIsOffsetInAnchor && start.containerNode() == end.containerNode())
1154
    if (start.containerNode() == end.containerNode())
1153
        newEnd = Position(end.containerNode(), end.offsetInContainerNode() - start.offsetInContainerNode(), Position::PositionIsOffsetInAnchor);
1155
        newEnd = Position(end.containerText(), end.offsetInContainerNode() - start.offsetInContainerNode());
1154
    else
1156
    else
1155
        newEnd = end;
1157
        newEnd = end;
1156
1158
1157
    Text* text = static_cast<Text*>(start.deprecatedNode());
1159
    splitTextNodeContainingElement(start.containerText(), start.offsetInContainerNode());
1158
    splitTextNodeContainingElement(text, start.deprecatedEditingOffset());
1160
    updateStartEnd(positionBeforeNode(start.containerNode()), newEnd);
1159
    updateStartEnd(Position(start.deprecatedNode()->parentNode(), start.deprecatedNode()->nodeIndex(), Position::PositionIsOffsetInAnchor), newEnd);
1160
}
1161
}
1161
1162
1162
void ApplyStyleCommand::splitTextElementAtEnd(const Position& start, const Position& end)
1163
void ApplyStyleCommand::splitTextElementAtEnd(const Position& start, const Position& end)
1163
{
1164
{
1164
    ASSERT(end.anchorType() == Position::PositionIsOffsetInAnchor);
1165
    ASSERT(end.containerNode()->isTextNode());
1165
1166
1166
    bool shouldUpdateStart = start.anchorType() == Position::PositionIsOffsetInAnchor && start.containerNode() == end.containerNode();
1167
    bool shouldUpdateStart = start.containerNode() == end.containerNode();
1167
    Text* text = static_cast<Text*>(end.deprecatedNode());
1168
    splitTextNodeContainingElement(end.containerText(), end.offsetInContainerNode());
1168
    splitTextNodeContainingElement(text, end.deprecatedEditingOffset());
1169
1170
    Node* parentElement = end.containerNode()->parentNode();
1171
    if (!parentElement || !parentElement->previousSibling())
1172
        return;
1173
    Node* firstTextNode = parentElement->previousSibling()->lastChild();
1174
    if (!firstTextNode || !firstTextNode->isTextNode())
1175
        return;
1169
1176
1170
    Node* prevNode = text->parentNode()->previousSibling()->lastChild();
1177
    Position newStart = shouldUpdateStart ? Position(static_cast<Text*>(firstTextNode), start.offsetInContainerNode()) : start;
1171
    ASSERT(prevNode);
1178
    updateStartEnd(newStart, positionAfterNode(firstTextNode));
1172
    Position newStart = shouldUpdateStart ? Position(prevNode, start.offsetInContainerNode(), Position::PositionIsOffsetInAnchor) : start;
1173
    updateStartEnd(newStart, Position(prevNode->parentNode(), prevNode->nodeIndex() + 1, Position::PositionIsOffsetInAnchor));
1174
}
1179
}
1175
1180
1176
bool ApplyStyleCommand::shouldSplitTextElement(Element* element, EditingStyle* style)
1181
bool ApplyStyleCommand::shouldSplitTextElement(Element* element, EditingStyle* style)
Lines 1480-1488 void ApplyStyleCommand::joinChildTextNod Source/WebCore/editing/ApplyStyleCommand.cpp_sec2
1480
            Text* childText = static_cast<Text *>(child);
1485
            Text* childText = static_cast<Text *>(child);
1481
            Text* nextText = static_cast<Text *>(next);
1486
            Text* nextText = static_cast<Text *>(next);
1482
            if (start.anchorType() == Position::PositionIsOffsetInAnchor && next == start.containerNode())
1487
            if (start.anchorType() == Position::PositionIsOffsetInAnchor && next == start.containerNode())
1483
                newStart = Position(childText, childText->length() + start.offsetInContainerNode(), Position::PositionIsOffsetInAnchor);
1488
                newStart = Position(childText, childText->length() + start.offsetInContainerNode());
1484
            if (end.anchorType() == Position::PositionIsOffsetInAnchor && next == end.containerNode())
1489
            if (end.anchorType() == Position::PositionIsOffsetInAnchor && next == end.containerNode())
1485
                newEnd = Position(childText, childText->length() + end.offsetInContainerNode(), Position::PositionIsOffsetInAnchor);
1490
                newEnd = Position(childText, childText->length() + end.offsetInContainerNode());
1486
            String textToMove = nextText->data();
1491
            String textToMove = nextText->data();
1487
            insertTextIntoNode(childText, childText->length(), textToMove);
1492
            insertTextIntoNode(childText, childText->length(), textToMove);
1488
            removeNode(next);
1493
            removeNode(next);
- Source/WebCore/editing/CompositeEditCommand.cpp -1 / +1 lines
Lines 320-326 Position CompositeEditCommand::replaceSe Source/WebCore/editing/CompositeEditCommand.cpp_sec1
320
    if (start.containerNode() != end.containerNode() || !start.containerNode()->isTextNode() || isTabSpanTextNode(start.containerNode()))
320
    if (start.containerNode() != end.containerNode() || !start.containerNode()->isTextNode() || isTabSpanTextNode(start.containerNode()))
321
        return Position();
321
        return Position();
322
322
323
    RefPtr<Text> textNode = static_cast<Text*>(start.containerNode());
323
    RefPtr<Text> textNode = start.containerText();
324
    replaceTextInNode(textNode, start.offsetInContainerNode(), end.offsetInContainerNode() - start.offsetInContainerNode(), text);
324
    replaceTextInNode(textNode, start.offsetInContainerNode(), end.offsetInContainerNode() - start.offsetInContainerNode(), text);
325
325
326
    return Position(textNode.release(), start.offsetInContainerNode() + text.length());
326
    return Position(textNode.release(), start.offsetInContainerNode() + text.length());
- Source/WebCore/editing/Editor.cpp -1 / +1 lines
Lines 266-272 bool Editor::canDeleteRange(Range* range Source/WebCore/editing/Editor.cpp_sec1
266
        return false;
266
        return false;
267
    
267
    
268
    if (range->collapsed(ec)) {
268
    if (range->collapsed(ec)) {
269
        VisiblePosition start(Position(startContainer, range->startOffset(ec), Position::PositionIsOffsetInAnchor), DOWNSTREAM);
269
        VisiblePosition start(range->startPosition(), DOWNSTREAM);
270
        VisiblePosition previous = start.previous();
270
        VisiblePosition previous = start.previous();
271
        // FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item.
271
        // FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item.
272
        if (previous.isNull() || previous.deepEquivalent().deprecatedNode()->rootEditableElement() != startContainer->rootEditableElement())
272
        if (previous.isNull() || previous.deepEquivalent().deprecatedNode()->rootEditableElement() != startContainer->rootEditableElement())
- Source/WebCore/editing/FrameSelection.cpp -28 / +6 lines
Lines 1462-1506 void FrameSelection::selectAll() Source/WebCore/editing/FrameSelection.cpp_sec1
1462
1462
1463
bool FrameSelection::setSelectedRange(Range* range, EAffinity affinity, bool closeTyping)
1463
bool FrameSelection::setSelectedRange(Range* range, EAffinity affinity, bool closeTyping)
1464
{
1464
{
1465
    if (!range)
1465
    if (!range || !range->startContainer() || !range->endContainer())
1466
        return false;
1466
        return false;
1467
    ASSERT(range->startContainer()->document() == range->endContainer()->document());
1467
1468
1468
    ExceptionCode ec = 0;
1469
    Node* startContainer = range->startContainer(ec);
1470
    if (ec)
1471
        return false;
1472
1473
    Node* endContainer = range->endContainer(ec);
1474
    if (ec)
1475
        return false;
1476
    
1477
    ASSERT(startContainer);
1478
    ASSERT(endContainer);
1479
    ASSERT(startContainer->document() == endContainer->document());
1480
    
1481
    m_frame->document()->updateLayoutIgnorePendingStylesheets();
1469
    m_frame->document()->updateLayoutIgnorePendingStylesheets();
1482
1470
1483
    // Non-collapsed ranges are not allowed to start at the end of a line that is wrapped,
1471
    // Non-collapsed ranges are not allowed to start at the end of a line that is wrapped,
1484
    // they start at the beginning of the next line instead
1472
    // they start at the beginning of the next line instead
1473
    ExceptionCode ec = 0;
1485
    bool collapsed = range->collapsed(ec);
1474
    bool collapsed = range->collapsed(ec);
1486
    if (ec)
1475
    if (ec)
1487
        return false;
1476
        return false;
1488
    
1489
    int startOffset = range->startOffset(ec);
1490
    if (ec)
1491
        return false;
1492
1477
1493
    int endOffset = range->endOffset(ec);
1494
    if (ec)
1495
        return false;
1496
    
1497
    // FIXME: Can we provide extentAffinity?
1478
    // FIXME: Can we provide extentAffinity?
1498
    VisiblePosition visibleStart(Position(startContainer, startOffset, Position::PositionIsOffsetInAnchor), collapsed ? affinity : DOWNSTREAM);
1479
    VisiblePosition visibleStart(range->startPosition(), collapsed ? affinity : DOWNSTREAM);
1499
    VisiblePosition visibleEnd(Position(endContainer, endOffset, Position::PositionIsOffsetInAnchor), SEL_DEFAULT_AFFINITY);
1480
    VisiblePosition visibleEnd(range->endPosition(), SEL_DEFAULT_AFFINITY);
1500
    SetSelectionOptions options = ClearTypingStyle;
1481
    setSelection(VisibleSelection(visibleStart, visibleEnd), ClearTypingStyle | (closeTyping ? CloseTyping : 0));
1501
    if (closeTyping)
1502
        options |= CloseTyping;
1503
    setSelection(VisibleSelection(visibleStart, visibleEnd), options);
1504
    return true;
1482
    return true;
1505
}
1483
}
1506
1484
- Source/WebCore/editing/InsertTextCommand.cpp -1 / +1 lines
Lines 157-163 void InsertTextCommand::input(const Stri Source/WebCore/editing/InsertTextCommand.cpp_sec1
157
        ASSERT(startPosition.containerNode()->isTextNode());
157
        ASSERT(startPosition.containerNode()->isTextNode());
158
        if (placeholder.isNotNull())
158
        if (placeholder.isNotNull())
159
            removePlaceholderAt(placeholder);
159
            removePlaceholderAt(placeholder);
160
        RefPtr<Text> textNode = static_cast<Text*>(startPosition.containerNode());
160
        RefPtr<Text> textNode = startPosition.containerText();
161
        const unsigned offset = startPosition.offsetInContainerNode();
161
        const unsigned offset = startPosition.offsetInContainerNode();
162
162
163
        insertTextIntoNode(textNode, offset, text);
163
        insertTextIntoNode(textNode, offset, text);
- Source/WebCore/editing/ReplaceSelectionCommand.cpp -1 / +1 lines
Lines 939-945 void ReplaceSelectionCommand::doApply() Source/WebCore/editing/ReplaceSelectionCommand.cpp_sec1
939
    // since insertAsListItems already does the right thing.
939
    // since insertAsListItems already does the right thing.
940
    if (!m_matchStyle && !enclosingList(insertionPos.containerNode()) && isStyleSpan(fragment.firstChild())) {
940
    if (!m_matchStyle && !enclosingList(insertionPos.containerNode()) && isStyleSpan(fragment.firstChild())) {
941
        if (insertionPos.containerNode()->isTextNode() && insertionPos.offsetInContainerNode() && !insertionPos.atLastEditingPositionForNode()) {
941
        if (insertionPos.containerNode()->isTextNode() && insertionPos.offsetInContainerNode() && !insertionPos.atLastEditingPositionForNode()) {
942
            splitTextNodeContainingElement(static_cast<Text*>(insertionPos.containerNode()), insertionPos.offsetInContainerNode());
942
            splitTextNodeContainingElement(insertionPos.containerText(), insertionPos.offsetInContainerNode());
943
            insertionPos = firstPositionInNode(insertionPos.containerNode());
943
            insertionPos = firstPositionInNode(insertionPos.containerNode());
944
        }
944
        }
945
945
- Source/WebCore/editing/VisiblePosition.cpp -9 / +6 lines
Lines 552-566 UChar32 VisiblePosition::characterAfter( Source/WebCore/editing/VisiblePosition.cpp_sec1
552
    case Position::PositionIsOffsetInAnchor:
552
    case Position::PositionIsOffsetInAnchor:
553
        break;
553
        break;
554
    }
554
    }
555
    Text* textNode = static_cast<Text*>(pos.containerNode());
555
    unsigned offset = static_cast<unsigned>(pos.offsetInContainerNode());
556
    unsigned offset = pos.anchorType() == Position::PositionIsOffsetInAnchor ? pos.offsetInContainerNode() : 0;
556
    Text* textNode = pos.containerText();
557
    unsigned length = textNode->length();
557
    if (offset >= textNode->length())
558
    if (offset >= length)
559
        return 0;
558
        return 0;
560
559
561
    UChar32 ch;
560
    UChar32 ch;
562
    const UChar* characters = textNode->data().characters();
561
    const UChar* characters = textNode->data().characters();
563
    U16_NEXT(characters, offset, length, ch);
562
    U16_NEXT(characters, offset, textNode->length(), ch);
564
    return ch;
563
    return ch;
565
}
564
}
566
565
Lines 649-662 PassRefPtr<Range> makeRange(const Visibl Source/WebCore/editing/VisiblePosition.cpp_sec2
649
648
650
VisiblePosition startVisiblePosition(const Range *r, EAffinity affinity)
649
VisiblePosition startVisiblePosition(const Range *r, EAffinity affinity)
651
{
650
{
652
    int exception = 0;
651
    return VisiblePosition(r->startPosition(), affinity);
653
    return VisiblePosition(Position(r->startContainer(exception), r->startOffset(exception), Position::PositionIsOffsetInAnchor), affinity);
654
}
652
}
655
653
656
VisiblePosition endVisiblePosition(const Range *r, EAffinity affinity)
654
VisiblePosition endVisiblePosition(const Range *r, EAffinity affinity)
657
{
655
{
658
    int exception = 0;
656
    return VisiblePosition(r->endPosition(), affinity);
659
    return VisiblePosition(Position(r->endContainer(exception), r->endOffset(exception), Position::PositionIsOffsetInAnchor), affinity);
660
}
657
}
661
658
662
bool setStart(Range *r, const VisiblePosition &visiblePosition)
659
bool setStart(Range *r, const VisiblePosition &visiblePosition)
- Source/WebCore/editing/htmlediting.cpp -5 / +3 lines
Lines 402-409 bool isSpecialElement(const Node *n) Source/WebCore/editing/htmlediting.cpp_sec1
402
402
403
static Node* firstInSpecialElement(const Position& pos)
403
static Node* firstInSpecialElement(const Position& pos)
404
{
404
{
405
    // FIXME: This begins at pos.deprecatedNode(), which doesn't necessarily contain pos (suppose pos was [img, 0]).  See <rdar://problem/5027702>.
405
    Node* rootEditableElement = pos.containerNode()->rootEditableElement();
406
    Node* rootEditableElement = pos.deprecatedNode()->rootEditableElement();
407
    for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
406
    for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
408
        if (isSpecialElement(n)) {
407
        if (isSpecialElement(n)) {
409
            VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
408
            VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
Lines 418-429 static Node* firstInSpecialElement(const Source/WebCore/editing/htmlediting.cpp_sec2
418
417
419
static Node* lastInSpecialElement(const Position& pos)
418
static Node* lastInSpecialElement(const Position& pos)
420
{
419
{
421
    // FIXME: This begins at pos.deprecatedNode(), which doesn't necessarily contain pos (suppose pos was [img, 0]).  See <rdar://problem/5027702>.
420
    Node* rootEditableElement = pos.containerNode()->rootEditableElement();
422
    Node* rootEditableElement = pos.deprecatedNode()->rootEditableElement();
423
    for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
421
    for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
424
        if (isSpecialElement(n)) {
422
        if (isSpecialElement(n)) {
425
            VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
423
            VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
426
            VisiblePosition lastInElement = VisiblePosition(Position(n, n->childNodeCount(), Position::PositionIsOffsetInAnchor), DOWNSTREAM);
424
            VisiblePosition lastInElement = VisiblePosition(lastPositionInOrAfterNode(n), DOWNSTREAM);
427
            if (isTableElement(n) && vPos == lastInElement.previous())
425
            if (isTableElement(n) && vPos == lastInElement.previous())
428
                return n;
426
                return n;
429
            if (vPos == lastInElement)
427
            if (vPos == lastInElement)
- Source/WebCore/editing/visible_units.cpp -9 / +15 lines
Lines 437-448 static VisiblePosition endPositionForLin Source/WebCore/editing/visible_units.cpp_sec1
437
    Position pos;
437
    Position pos;
438
    if (endNode->hasTagName(brTag)) {
438
    if (endNode->hasTagName(brTag)) {
439
        pos = positionBeforeNode(endNode);
439
        pos = positionBeforeNode(endNode);
440
    } else if (endBox->isInlineTextBox()) {
440
    } else if (endBox->isInlineTextBox() && endNode->isTextNode()) {
441
        InlineTextBox *endTextBox = static_cast<InlineTextBox *>(endBox);
441
        InlineTextBox* endTextBox = static_cast<InlineTextBox *>(endBox);
442
        int endOffset = endTextBox->start();
442
        int endOffset = endTextBox->start();
443
        if (!endTextBox->isLineBreak())
443
        if (!endTextBox->isLineBreak())
444
            endOffset += endTextBox->len();
444
            endOffset += endTextBox->len();
445
        pos = Position(endNode, endOffset, Position::PositionIsOffsetInAnchor);
445
        pos = Position(static_cast<Text*>(endNode), endOffset);
446
    } else
446
    } else
447
        pos = positionAfterNode(endNode);
447
        pos = positionAfterNode(endNode);
448
    
448
    
Lines 793-798 VisiblePosition startOfParagraph(const V Source/WebCore/editing/visible_units.cpp_sec2
793
            break;
793
            break;
794
794
795
        if (r->isText() && r->caretMaxRenderedOffset() > 0) {
795
        if (r->isText() && r->caretMaxRenderedOffset() > 0) {
796
            ASSERT(n->isTextNode());
796
            type = Position::PositionIsOffsetInAnchor;
797
            type = Position::PositionIsOffsetInAnchor;
797
            if (style->preserveNewline()) {
798
            if (style->preserveNewline()) {
798
                const UChar* chars = toRenderText(r)->characters();
799
                const UChar* chars = toRenderText(r)->characters();
Lines 800-808 VisiblePosition startOfParagraph(const V Source/WebCore/editing/visible_units.cpp_sec3
800
                int o = offset;
801
                int o = offset;
801
                if (n == startNode && o < i)
802
                if (n == startNode && o < i)
802
                    i = max(0, o);
803
                    i = max(0, o);
803
                while (--i >= 0)
804
                while (--i >= 0) {
804
                    if (chars[i] == '\n')
805
                    if (chars[i] == '\n')
805
                        return VisiblePosition(Position(n, i + 1, Position::PositionIsOffsetInAnchor), DOWNSTREAM);
806
                        return VisiblePosition(Position(static_cast<Text*>(n), i + 1), DOWNSTREAM);
807
                }
806
            }
808
            }
807
            node = n;
809
            node = n;
808
            offset = 0;
810
            offset = 0;
Lines 815-823 VisiblePosition startOfParagraph(const V Source/WebCore/editing/visible_units.cpp_sec4
815
            n = n->traversePreviousNodePostOrder(startBlock);
817
            n = n->traversePreviousNodePostOrder(startBlock);
816
    }
818
    }
817
819
818
    if (type == Position::PositionIsOffsetInAnchor)
820
    if (type == Position::PositionIsOffsetInAnchor) {
821
        ASSERT(type != Position::PositionIsOffsetInAnchor || !offset);
819
        return VisiblePosition(Position(node, offset, type), DOWNSTREAM);
822
        return VisiblePosition(Position(node, offset, type), DOWNSTREAM);
820
    
823
    }
824
821
    return VisiblePosition(Position(node, type), DOWNSTREAM);
825
    return VisiblePosition(Position(node, type), DOWNSTREAM);
822
}
826
}
823
827
Lines 867-880 VisiblePosition endOfParagraph(const Vis Source/WebCore/editing/visible_units.cpp_sec5
867
871
868
        // FIXME: We avoid returning a position where the renderer can't accept the caret.
872
        // FIXME: We avoid returning a position where the renderer can't accept the caret.
869
        if (r->isText() && r->caretMaxRenderedOffset() > 0) {
873
        if (r->isText() && r->caretMaxRenderedOffset() > 0) {
874
            ASSERT(n->isTextNode());
870
            int length = toRenderText(r)->textLength();
875
            int length = toRenderText(r)->textLength();
871
            type = Position::PositionIsOffsetInAnchor;
876
            type = Position::PositionIsOffsetInAnchor;
872
            if (style->preserveNewline()) {
877
            if (style->preserveNewline()) {
873
                const UChar* chars = toRenderText(r)->characters();
878
                const UChar* chars = toRenderText(r)->characters();
874
                int o = n == startNode ? offset : 0;
879
                int o = n == startNode ? offset : 0;
875
                for (int i = o; i < length; ++i)
880
                for (int i = o; i < length; ++i) {
876
                    if (chars[i] == '\n')
881
                    if (chars[i] == '\n')
877
                        return VisiblePosition(Position(n, i, Position::PositionIsOffsetInAnchor), DOWNSTREAM);
882
                        return VisiblePosition(Position(static_cast<Text*>(n), i), DOWNSTREAM);
883
                }
878
            }
884
            }
879
            node = n;
885
            node = n;
880
            offset = r->caretMaxOffset();
886
            offset = r->caretMaxOffset();

Return to Bug 63384