1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007 Apple 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 "htmlediting.h"
28
29 #include "CharacterNames.h"
30 #include "Document.h"
31 #include "EditingText.h"
32 #include "HTMLBRElement.h"
33 #include "HTMLDivElement.h"
34 #include "HTMLElementFactory.h"
35 #include "HTMLInterchange.h"
36 #include "HTMLLIElement.h"
37 #include "HTMLNames.h"
38 #include "HTMLOListElement.h"
39 #include "HTMLUListElement.h"
40 #include "PositionIterator.h"
41 #include "RenderObject.h"
42 #include "Range.h"
43 #include "VisibleSelection.h"
44 #include "Text.h"
45 #include "TextIterator.h"
46 #include "VisiblePosition.h"
47 #include "visible_units.h"
48 #include <wtf/StdLibExtras.h>
49
50 #if ENABLE(WML)
51 #include "WMLNames.h"
52 #endif
53
54 using namespace std;
55
56 namespace WebCore {
57
58 using namespace HTMLNames;
59
60 // Atomic means that the node has no children, or has children which are ignored for the
61 // purposes of editing.
isAtomicNode(const Node * node)62 bool isAtomicNode(const Node *node)
63 {
64 return node && (!node->hasChildNodes() || editingIgnoresContent(node));
65 }
66
67 // Returns true for nodes that either have no content, or have content that is ignored (skipped
68 // over) while editing. There are no VisiblePositions inside these nodes.
editingIgnoresContent(const Node * node)69 bool editingIgnoresContent(const Node* node)
70 {
71 return !canHaveChildrenForEditing(node) && !node->isTextNode();
72 }
73
canHaveChildrenForEditing(const Node * node)74 bool canHaveChildrenForEditing(const Node* node)
75 {
76 return !node->hasTagName(hrTag) &&
77 !node->hasTagName(brTag) &&
78 !node->hasTagName(imgTag) &&
79 !node->hasTagName(buttonTag) &&
80 !node->hasTagName(inputTag) &&
81 !node->hasTagName(textareaTag) &&
82 !node->hasTagName(objectTag) &&
83 !node->hasTagName(iframeTag) &&
84 !node->hasTagName(embedTag) &&
85 !node->hasTagName(appletTag) &&
86 !node->hasTagName(selectTag) &&
87 !node->hasTagName(datagridTag) &&
88 #if ENABLE(WML)
89 !node->hasTagName(WMLNames::doTag) &&
90 #endif
91 !node->isTextNode();
92 }
93
94 // Compare two positions, taking into account the possibility that one or both
95 // could be inside a shadow tree. Only works for non-null values.
comparePositions(const Position & a,const Position & b)96 int comparePositions(const Position& a, const Position& b)
97 {
98 Node* nodeA = a.node();
99 ASSERT(nodeA);
100 Node* nodeB = b.node();
101 ASSERT(nodeB);
102 int offsetA = a.deprecatedEditingOffset();
103 int offsetB = b.deprecatedEditingOffset();
104
105 Node* shadowAncestorA = nodeA->shadowAncestorNode();
106 if (shadowAncestorA == nodeA)
107 shadowAncestorA = 0;
108 Node* shadowAncestorB = nodeB->shadowAncestorNode();
109 if (shadowAncestorB == nodeB)
110 shadowAncestorB = 0;
111
112 int bias = 0;
113 if (shadowAncestorA != shadowAncestorB) {
114 if (shadowAncestorA) {
115 nodeA = shadowAncestorA;
116 offsetA = 0;
117 bias = 1;
118 }
119 if (shadowAncestorB) {
120 nodeB = shadowAncestorB;
121 offsetB = 0;
122 bias = -1;
123 }
124 }
125
126 int result = Range::compareBoundaryPoints(nodeA, offsetA, nodeB, offsetB);
127 return result ? result : bias;
128 }
129
comparePositions(const VisiblePosition & a,const VisiblePosition & b)130 int comparePositions(const VisiblePosition& a, const VisiblePosition& b)
131 {
132 return comparePositions(a.deepEquivalent(), b.deepEquivalent());
133 }
134
highestEditableRoot(const Position & position)135 Node* highestEditableRoot(const Position& position)
136 {
137 Node* node = position.node();
138 if (!node)
139 return 0;
140
141 Node* highestRoot = editableRootForPosition(position);
142 if (!highestRoot)
143 return 0;
144
145 node = highestRoot;
146 while (node) {
147 if (node->isContentEditable())
148 highestRoot = node;
149 if (node->hasTagName(bodyTag))
150 break;
151 node = node->parentNode();
152 }
153
154 return highestRoot;
155 }
156
lowestEditableAncestor(Node * node)157 Node* lowestEditableAncestor(Node* node)
158 {
159 if (!node)
160 return 0;
161
162 Node *lowestRoot = 0;
163 while (node) {
164 if (node->isContentEditable())
165 return node->rootEditableElement();
166 if (node->hasTagName(bodyTag))
167 break;
168 node = node->parentNode();
169 }
170
171 return lowestRoot;
172 }
173
isEditablePosition(const Position & p)174 bool isEditablePosition(const Position& p)
175 {
176 Node* node = p.node();
177 if (!node)
178 return false;
179
180 if (node->renderer() && node->renderer()->isTable())
181 node = node->parentNode();
182
183 return node->isContentEditable();
184 }
185
isRichlyEditablePosition(const Position & p)186 bool isRichlyEditablePosition(const Position& p)
187 {
188 Node* node = p.node();
189 if (!node)
190 return false;
191
192 if (node->renderer() && node->renderer()->isTable())
193 node = node->parentNode();
194
195 return node->isContentRichlyEditable();
196 }
197
editableRootForPosition(const Position & p)198 Element* editableRootForPosition(const Position& p)
199 {
200 Node* node = p.node();
201 if (!node)
202 return 0;
203
204 if (node->renderer() && node->renderer()->isTable())
205 node = node->parentNode();
206
207 return node->rootEditableElement();
208 }
209
210 // Finds the enclosing element until which the tree can be split.
211 // When a user hits ENTER, he/she won't expect this element to be split into two.
212 // You may pass it as the second argument of splitTreeToNode.
unsplittableElementForPosition(const Position & p)213 Element* unsplittableElementForPosition(const Position& p)
214 {
215 // Since enclosingNodeOfType won't search beyond the highest root editable node,
216 // this code works even if the closest table cell was outside of the root editable node.
217 Element* enclosingCell = static_cast<Element*>(enclosingNodeOfType(p, &isTableCell, true));
218 if (enclosingCell)
219 return enclosingCell;
220
221 return editableRootForPosition(p);
222 }
223
nextCandidate(const Position & position)224 Position nextCandidate(const Position& position)
225 {
226 PositionIterator p = position;
227 while (!p.atEnd()) {
228 p.increment();
229 if (p.isCandidate())
230 return p;
231 }
232 return Position();
233 }
234
nextVisuallyDistinctCandidate(const Position & position)235 Position nextVisuallyDistinctCandidate(const Position& position)
236 {
237 Position p = position;
238 Position downstreamStart = p.downstream();
239 while (!p.atEndOfTree()) {
240 p = p.next(Character);
241 if (p.isCandidate() && p.downstream() != downstreamStart)
242 return p;
243 }
244 return Position();
245 }
246
previousCandidate(const Position & position)247 Position previousCandidate(const Position& position)
248 {
249 PositionIterator p = position;
250 while (!p.atStart()) {
251 p.decrement();
252 if (p.isCandidate())
253 return p;
254 }
255 return Position();
256 }
257
previousVisuallyDistinctCandidate(const Position & position)258 Position previousVisuallyDistinctCandidate(const Position& position)
259 {
260 Position p = position;
261 Position downstreamStart = p.downstream();
262 while (!p.atStartOfTree()) {
263 p = p.previous(Character);
264 if (p.isCandidate() && p.downstream() != downstreamStart)
265 return p;
266 }
267 return Position();
268 }
269
firstEditablePositionAfterPositionInRoot(const Position & position,Node * highestRoot)270 VisiblePosition firstEditablePositionAfterPositionInRoot(const Position& position, Node* highestRoot)
271 {
272 // position falls before highestRoot.
273 if (comparePositions(position, firstDeepEditingPositionForNode(highestRoot)) == -1 && highestRoot->isContentEditable())
274 return firstDeepEditingPositionForNode(highestRoot);
275
276 Position p = position;
277
278 if (Node* shadowAncestor = p.node()->shadowAncestorNode())
279 if (shadowAncestor != p.node())
280 p = lastDeepEditingPositionForNode(shadowAncestor);
281
282 while (p.node() && !isEditablePosition(p) && p.node()->isDescendantOf(highestRoot))
283 p = isAtomicNode(p.node()) ? positionAfterNode(p.node()) : nextVisuallyDistinctCandidate(p);
284
285 if (p.node() && !p.node()->isDescendantOf(highestRoot))
286 return VisiblePosition();
287
288 return VisiblePosition(p);
289 }
290
lastEditablePositionBeforePositionInRoot(const Position & position,Node * highestRoot)291 VisiblePosition lastEditablePositionBeforePositionInRoot(const Position& position, Node* highestRoot)
292 {
293 // When position falls after highestRoot, the result is easy to compute.
294 if (comparePositions(position, lastDeepEditingPositionForNode(highestRoot)) == 1)
295 return lastDeepEditingPositionForNode(highestRoot);
296
297 Position p = position;
298
299 if (Node* shadowAncestor = p.node()->shadowAncestorNode())
300 if (shadowAncestor != p.node())
301 p = firstDeepEditingPositionForNode(shadowAncestor);
302
303 while (p.node() && !isEditablePosition(p) && p.node()->isDescendantOf(highestRoot))
304 p = isAtomicNode(p.node()) ? positionBeforeNode(p.node()) : previousVisuallyDistinctCandidate(p);
305
306 if (p.node() && !p.node()->isDescendantOf(highestRoot))
307 return VisiblePosition();
308
309 return VisiblePosition(p);
310 }
311
312 // FIXME: The method name, comment, and code say three different things here!
313 // Whether or not content before and after this node will collapse onto the same line as it.
isBlock(const Node * node)314 bool isBlock(const Node* node)
315 {
316 return node && node->renderer() && !node->renderer()->isInline();
317 }
318
319 // FIXME: Deploy this in all of the places where enclosingBlockFlow/enclosingBlockFlowOrTableElement are used.
320 // FIXME: Pass a position to this function. The enclosing block of [table, x] for example, should be the
321 // block that contains the table and not the table, and this function should be the only one responsible for
322 // knowing about these kinds of special cases.
enclosingBlock(Node * node)323 Node* enclosingBlock(Node* node)
324 {
325 return static_cast<Element*>(enclosingNodeOfType(Position(node, 0), isBlock));
326 }
327
328 // Internally editing uses "invalid" positions for historical reasons. For
329 // example, in <div><img /></div>, Editing might use (img, 1) for the position
330 // after <img>, but we have to convert that to (div, 1) before handing the
331 // position to a Range object. Ideally all internal positions should
332 // be "range compliant" for simplicity.
rangeCompliantEquivalent(const Position & pos)333 Position rangeCompliantEquivalent(const Position& pos)
334 {
335 if (pos.isNull())
336 return Position();
337
338 Node* node = pos.node();
339
340 if (pos.deprecatedEditingOffset() <= 0) {
341 if (node->parentNode() && (editingIgnoresContent(node) || isTableElement(node)))
342 return positionBeforeNode(node);
343 return Position(node, 0);
344 }
345
346 if (node->offsetInCharacters())
347 return Position(node, min(node->maxCharacterOffset(), pos.deprecatedEditingOffset()));
348
349 int maxCompliantOffset = node->childNodeCount();
350 if (pos.deprecatedEditingOffset() > maxCompliantOffset) {
351 if (node->parentNode())
352 return positionAfterNode(node);
353
354 // there is no other option at this point than to
355 // use the highest allowed position in the node
356 return Position(node, maxCompliantOffset);
357 }
358
359 // Editing should never generate positions like this.
360 if ((pos.deprecatedEditingOffset() < maxCompliantOffset) && editingIgnoresContent(node)) {
361 ASSERT_NOT_REACHED();
362 return node->parentNode() ? positionBeforeNode(node) : Position(node, 0);
363 }
364
365 if (pos.deprecatedEditingOffset() == maxCompliantOffset && (editingIgnoresContent(node) || isTableElement(node)))
366 return positionAfterNode(node);
367
368 return Position(pos);
369 }
370
rangeCompliantEquivalent(const VisiblePosition & vpos)371 Position rangeCompliantEquivalent(const VisiblePosition& vpos)
372 {
373 return rangeCompliantEquivalent(vpos.deepEquivalent());
374 }
375
376 // This method is used to create positions in the DOM. It returns the maximum valid offset
377 // in a node. It returns 1 for some elements even though they do not have children, which
378 // creates technically invalid DOM Positions. Be sure to call rangeCompliantEquivalent
379 // on a Position before using it to create a DOM Range, or an exception will be thrown.
lastOffsetForEditing(const Node * node)380 int lastOffsetForEditing(const Node* node)
381 {
382 ASSERT(node);
383 if (!node)
384 return 0;
385 if (node->offsetInCharacters())
386 return node->maxCharacterOffset();
387
388 if (node->hasChildNodes())
389 return node->childNodeCount();
390
391 // NOTE: This should preempt the childNodeCount for, e.g., select nodes
392 if (editingIgnoresContent(node))
393 return 1;
394
395 return 0;
396 }
397
stringWithRebalancedWhitespace(const String & string,bool startIsStartOfParagraph,bool endIsEndOfParagraph)398 String stringWithRebalancedWhitespace(const String& string, bool startIsStartOfParagraph, bool endIsEndOfParagraph)
399 {
400 DEFINE_STATIC_LOCAL(String, twoSpaces, (" "));
401 DEFINE_STATIC_LOCAL(String, nbsp, ("\xa0"));
402 DEFINE_STATIC_LOCAL(String, pattern, (" \xa0"));
403
404 String rebalancedString = string;
405
406 rebalancedString.replace(noBreakSpace, ' ');
407 rebalancedString.replace('\n', ' ');
408 rebalancedString.replace('\t', ' ');
409
410 rebalancedString.replace(twoSpaces, pattern);
411
412 if (startIsStartOfParagraph && rebalancedString[0] == ' ')
413 rebalancedString.replace(0, 1, nbsp);
414 int end = rebalancedString.length() - 1;
415 if (endIsEndOfParagraph && rebalancedString[end] == ' ')
416 rebalancedString.replace(end, 1, nbsp);
417
418 return rebalancedString;
419 }
420
isTableStructureNode(const Node * node)421 bool isTableStructureNode(const Node *node)
422 {
423 RenderObject *r = node->renderer();
424 return (r && (r->isTableCell() || r->isTableRow() || r->isTableSection() || r->isTableCol()));
425 }
426
nonBreakingSpaceString()427 const String& nonBreakingSpaceString()
428 {
429 DEFINE_STATIC_LOCAL(String, nonBreakingSpaceString, (&noBreakSpace, 1));
430 return nonBreakingSpaceString;
431 }
432
433 // FIXME: need to dump this
isSpecialElement(const Node * n)434 bool isSpecialElement(const Node *n)
435 {
436 if (!n)
437 return false;
438
439 if (!n->isHTMLElement())
440 return false;
441
442 if (n->isLink())
443 return true;
444
445 RenderObject *renderer = n->renderer();
446 if (!renderer)
447 return false;
448
449 if (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE)
450 return true;
451
452 if (renderer->style()->isFloating())
453 return true;
454
455 if (renderer->style()->position() != StaticPosition)
456 return true;
457
458 return false;
459 }
460
461 // Checks if a string is a valid tag for the FormatBlockCommand function of execCommand. Expects lower case strings.
validBlockTag(const String & blockTag)462 bool validBlockTag(const String& blockTag)
463 {
464 if (blockTag == "address" ||
465 blockTag == "blockquote" ||
466 blockTag == "dd" ||
467 blockTag == "div" ||
468 blockTag == "dl" ||
469 blockTag == "dt" ||
470 blockTag == "h1" ||
471 blockTag == "h2" ||
472 blockTag == "h3" ||
473 blockTag == "h4" ||
474 blockTag == "h5" ||
475 blockTag == "h6" ||
476 blockTag == "p" ||
477 blockTag == "pre")
478 return true;
479 return false;
480 }
481
firstInSpecialElement(const Position & pos)482 static Node* firstInSpecialElement(const Position& pos)
483 {
484 Node* rootEditableElement = pos.node()->rootEditableElement();
485 for (Node* n = pos.node(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
486 if (isSpecialElement(n)) {
487 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
488 VisiblePosition firstInElement = VisiblePosition(n, 0, DOWNSTREAM);
489 if (isTableElement(n) && vPos == firstInElement.next())
490 return n;
491 if (vPos == firstInElement)
492 return n;
493 }
494 return 0;
495 }
496
lastInSpecialElement(const Position & pos)497 static Node* lastInSpecialElement(const Position& pos)
498 {
499 Node* rootEditableElement = pos.node()->rootEditableElement();
500 for (Node* n = pos.node(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
501 if (isSpecialElement(n)) {
502 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
503 VisiblePosition lastInElement = VisiblePosition(n, n->childNodeCount(), DOWNSTREAM);
504 if (isTableElement(n) && vPos == lastInElement.previous())
505 return n;
506 if (vPos == lastInElement)
507 return n;
508 }
509 return 0;
510 }
511
isFirstVisiblePositionInSpecialElement(const Position & pos)512 bool isFirstVisiblePositionInSpecialElement(const Position& pos)
513 {
514 return firstInSpecialElement(pos);
515 }
516
positionBeforeContainingSpecialElement(const Position & pos,Node ** containingSpecialElement)517 Position positionBeforeContainingSpecialElement(const Position& pos, Node** containingSpecialElement)
518 {
519 Node* n = firstInSpecialElement(pos);
520 if (!n)
521 return pos;
522 Position result = positionBeforeNode(n);
523 if (result.isNull() || result.node()->rootEditableElement() != pos.node()->rootEditableElement())
524 return pos;
525 if (containingSpecialElement)
526 *containingSpecialElement = n;
527 return result;
528 }
529
isLastVisiblePositionInSpecialElement(const Position & pos)530 bool isLastVisiblePositionInSpecialElement(const Position& pos)
531 {
532 return lastInSpecialElement(pos);
533 }
534
positionAfterContainingSpecialElement(const Position & pos,Node ** containingSpecialElement)535 Position positionAfterContainingSpecialElement(const Position& pos, Node **containingSpecialElement)
536 {
537 Node* n = lastInSpecialElement(pos);
538 if (!n)
539 return pos;
540 Position result = positionAfterNode(n);
541 if (result.isNull() || result.node()->rootEditableElement() != pos.node()->rootEditableElement())
542 return pos;
543 if (containingSpecialElement)
544 *containingSpecialElement = n;
545 return result;
546 }
547
positionOutsideContainingSpecialElement(const Position & pos,Node ** containingSpecialElement)548 Position positionOutsideContainingSpecialElement(const Position &pos, Node **containingSpecialElement)
549 {
550 if (isFirstVisiblePositionInSpecialElement(pos))
551 return positionBeforeContainingSpecialElement(pos, containingSpecialElement);
552 if (isLastVisiblePositionInSpecialElement(pos))
553 return positionAfterContainingSpecialElement(pos, containingSpecialElement);
554 return pos;
555 }
556
isFirstPositionAfterTable(const VisiblePosition & visiblePosition)557 Node* isFirstPositionAfterTable(const VisiblePosition& visiblePosition)
558 {
559 Position upstream(visiblePosition.deepEquivalent().upstream());
560 if (upstream.node() && upstream.node()->renderer() && upstream.node()->renderer()->isTable() && upstream.atLastEditingPositionForNode())
561 return upstream.node();
562
563 return 0;
564 }
565
isLastPositionBeforeTable(const VisiblePosition & visiblePosition)566 Node* isLastPositionBeforeTable(const VisiblePosition& visiblePosition)
567 {
568 Position downstream(visiblePosition.deepEquivalent().downstream());
569 if (downstream.node() && downstream.node()->renderer() && downstream.node()->renderer()->isTable() && downstream.atFirstEditingPositionForNode())
570 return downstream.node();
571
572 return 0;
573 }
574
positionBeforeNode(const Node * node)575 Position positionBeforeNode(const Node* node)
576 {
577 ASSERT(node);
578 // FIXME: Should ASSERT(node->parentNode()) but doing so results in editing/deleting/delete-ligature-001.html crashing
579 return Position(node->parentNode(), node->nodeIndex());
580 }
581
positionAfterNode(const Node * node)582 Position positionAfterNode(const Node* node)
583 {
584 ASSERT(node);
585 // FIXME: Should ASSERT(node->parentNode()) but doing so results in editing/deleting/delete-ligature-001.html crashing
586 return Position(node->parentNode(), node->nodeIndex() + 1);
587 }
588
589 // Returns the visible position at the beginning of a node
visiblePositionBeforeNode(Node * node)590 VisiblePosition visiblePositionBeforeNode(Node* node)
591 {
592 ASSERT(node);
593 if (node->childNodeCount())
594 return VisiblePosition(node, 0, DOWNSTREAM);
595 ASSERT(node->parentNode());
596 return positionBeforeNode(node);
597 }
598
599 // Returns the visible position at the ending of a node
visiblePositionAfterNode(Node * node)600 VisiblePosition visiblePositionAfterNode(Node* node)
601 {
602 ASSERT(node);
603 if (node->childNodeCount())
604 return VisiblePosition(node, node->childNodeCount(), DOWNSTREAM);
605 ASSERT(node->parentNode());
606 return positionAfterNode(node);
607 }
608
609 // Create a range object with two visible positions, start and end.
610 // create(PassRefPtr<Document>, const Position&, const Position&); will use deprecatedEditingOffset
611 // Use this function instead of create a regular range object (avoiding editing offset).
createRange(PassRefPtr<Document> document,const VisiblePosition & start,const VisiblePosition & end,ExceptionCode & ec)612 PassRefPtr<Range> createRange(PassRefPtr<Document> document, const VisiblePosition& start, const VisiblePosition& end, ExceptionCode& ec)
613 {
614 ec = 0;
615 RefPtr<Range> selectedRange = Range::create(document);
616 selectedRange->setStart(start.deepEquivalent().containerNode(), start.deepEquivalent().computeOffsetInContainerNode(), ec);
617 if (!ec)
618 selectedRange->setEnd(end.deepEquivalent().containerNode(), end.deepEquivalent().computeOffsetInContainerNode(), ec);
619 return selectedRange.release();
620 }
621
622 // Extend rangeToExtend to include nodes that wraps range and visibly starts and ends inside or at the boudnaries of maximumRange
623 // e.g. if the original range spaned "hello" in <div>hello</div>, then this function extends the range to contain div's around it.
624 // Call this function before copying / moving paragraphs to contain all wrapping nodes.
625 // This function stops extending the range immediately below rootNode; i.e. the extended range can contain a child node of rootNode
626 // but it can never contain rootNode itself.
extendRangeToWrappingNodes(PassRefPtr<Range> range,const Range * maximumRange,const Node * rootNode)627 PassRefPtr<Range> extendRangeToWrappingNodes(PassRefPtr<Range> range, const Range* maximumRange, const Node* rootNode)
628 {
629 ASSERT(range);
630 ASSERT(maximumRange);
631
632 ExceptionCode ec = 0;
633 Node* ancestor = range->commonAncestorContainer(ec);// find the cloeset common ancestor
634 Node* highestNode = 0;
635 // traverse through ancestors as long as they are contained within the range, content-editable, and below rootNode (could be =0).
636 while (ancestor && ancestor->isContentEditable() && isNodeVisiblyContainedWithin(ancestor, maximumRange) && ancestor != rootNode) {
637 highestNode = ancestor;
638 ancestor = ancestor->parentNode();
639 }
640
641 if (!highestNode)
642 return range;
643
644 // Create new range with the highest editable node contained within the range
645 RefPtr<Range> extendedRange = Range::create(range->ownerDocument());
646 extendedRange->selectNode(highestNode, ec);
647 return extendedRange.release();
648 }
649
isListElement(Node * n)650 bool isListElement(Node *n)
651 {
652 return (n && (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(dlTag)));
653 }
654
enclosingNodeWithTag(const Position & p,const QualifiedName & tagName)655 Node* enclosingNodeWithTag(const Position& p, const QualifiedName& tagName)
656 {
657 if (p.isNull())
658 return 0;
659
660 Node* root = highestEditableRoot(p);
661 for (Node* n = p.node(); n; n = n->parentNode()) {
662 if (root && !n->isContentEditable())
663 continue;
664 if (n->hasTagName(tagName))
665 return n;
666 if (n == root)
667 return 0;
668 }
669
670 return 0;
671 }
672
enclosingNodeOfType(const Position & p,bool (* nodeIsOfType)(const Node *),bool onlyReturnEditableNodes)673 Node* enclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*), bool onlyReturnEditableNodes)
674 {
675 if (p.isNull())
676 return 0;
677
678 Node* root = highestEditableRoot(p);
679 for (Node* n = p.node(); n; n = n->parentNode()) {
680 // Don't return a non-editable node if the input position was editable, since
681 // the callers from editing will no doubt want to perform editing inside the returned node.
682 if (root && !n->isContentEditable() && onlyReturnEditableNodes)
683 continue;
684 if ((*nodeIsOfType)(n))
685 return n;
686 if (n == root)
687 return 0;
688 }
689
690 return 0;
691 }
692
highestEnclosingNodeOfType(const Position & p,bool (* nodeIsOfType)(const Node *))693 Node* highestEnclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*))
694 {
695 Node* highest = 0;
696 Node* root = highestEditableRoot(p);
697 for (Node* n = p.node(); n; n = n->parentNode()) {
698 if ((*nodeIsOfType)(n))
699 highest = n;
700 if (n == root)
701 break;
702 }
703
704 return highest;
705 }
706
enclosingTableCell(const Position & p)707 Node* enclosingTableCell(const Position& p)
708 {
709 return static_cast<Element*>(enclosingNodeOfType(p, isTableCell));
710 }
711
enclosingAnchorElement(const Position & p)712 Node* enclosingAnchorElement(const Position& p)
713 {
714 if (p.isNull())
715 return 0;
716
717 Node* node = p.node();
718 while (node && !(node->isElementNode() && node->isLink()))
719 node = node->parentNode();
720 return node;
721 }
722
enclosingList(Node * node)723 HTMLElement* enclosingList(Node* node)
724 {
725 if (!node)
726 return 0;
727
728 Node* root = highestEditableRoot(Position(node, 0));
729
730 for (Node* n = node->parentNode(); n; n = n->parentNode()) {
731 if (n->hasTagName(ulTag) || n->hasTagName(olTag))
732 return static_cast<HTMLElement*>(n);
733 if (n == root)
734 return 0;
735 }
736
737 return 0;
738 }
739
enclosingListChild(Node * node)740 HTMLElement* enclosingListChild(Node *node)
741 {
742 if (!node)
743 return 0;
744 // Check for a list item element, or for a node whose parent is a list element. Such a node
745 // will appear visually as a list item (but without a list marker)
746 Node* root = highestEditableRoot(Position(node, 0));
747
748 // FIXME: This function is inappropriately named if it starts with node instead of node->parentNode()
749 for (Node* n = node; n && n->parentNode(); n = n->parentNode()) {
750 if (n->hasTagName(liTag) || isListElement(n->parentNode()))
751 return static_cast<HTMLElement*>(n);
752 if (n == root || isTableCell(n))
753 return 0;
754 }
755
756 return 0;
757 }
758
embeddedSublist(Node * listItem)759 static HTMLElement* embeddedSublist(Node* listItem)
760 {
761 // Check the DOM so that we'll find collapsed sublists without renderers.
762 for (Node* n = listItem->firstChild(); n; n = n->nextSibling()) {
763 if (isListElement(n))
764 return static_cast<HTMLElement*>(n);
765 }
766
767 return 0;
768 }
769
appendedSublist(Node * listItem)770 static Node* appendedSublist(Node* listItem)
771 {
772 // Check the DOM so that we'll find collapsed sublists without renderers.
773 for (Node* n = listItem->nextSibling(); n; n = n->nextSibling()) {
774 if (isListElement(n))
775 return static_cast<HTMLElement*>(n);
776 if (n->renderer() && n->renderer()->isListItem())
777 return 0;
778 }
779
780 return 0;
781 }
782
783 // FIXME: This method should not need to call isStartOfParagraph/isEndOfParagraph
enclosingEmptyListItem(const VisiblePosition & visiblePos)784 Node* enclosingEmptyListItem(const VisiblePosition& visiblePos)
785 {
786 // Check that position is on a line by itself inside a list item
787 Node* listChildNode = enclosingListChild(visiblePos.deepEquivalent().node());
788 if (!listChildNode || !isStartOfParagraph(visiblePos) || !isEndOfParagraph(visiblePos))
789 return 0;
790
791 VisiblePosition firstInListChild(firstDeepEditingPositionForNode(listChildNode));
792 VisiblePosition lastInListChild(lastDeepEditingPositionForNode(listChildNode));
793
794 if (firstInListChild != visiblePos || lastInListChild != visiblePos)
795 return 0;
796
797 if (embeddedSublist(listChildNode) || appendedSublist(listChildNode))
798 return 0;
799
800 return listChildNode;
801 }
802
outermostEnclosingList(Node * node)803 HTMLElement* outermostEnclosingList(Node* node)
804 {
805 HTMLElement* list = enclosingList(node);
806 if (!list)
807 return 0;
808 while (HTMLElement* nextList = enclosingList(list))
809 list = nextList;
810 return list;
811 }
812
canMergeLists(Element * firstList,Element * secondList)813 bool canMergeLists(Element* firstList, Element* secondList)
814 {
815 if (!firstList || !secondList)
816 return false;
817
818 return firstList->hasTagName(secondList->tagQName())// make sure the list types match (ol vs. ul)
819 && firstList->isContentEditable() && secondList->isContentEditable()// both lists are editable
820 && firstList->rootEditableElement() == secondList->rootEditableElement()// don't cross editing boundaries
821 && isVisiblyAdjacent(positionAfterNode(firstList), positionBeforeNode(secondList));
822 // Make sure there is no visible content between this li and the previous list
823 }
824
highestAncestor(Node * node)825 Node* highestAncestor(Node* node)
826 {
827 ASSERT(node);
828 Node* parent = node;
829 while ((node = node->parentNode()))
830 parent = node;
831 return parent;
832 }
833
834 // FIXME: do not require renderer, so that this can be used within fragments, or rename to isRenderedTable()
isTableElement(Node * n)835 bool isTableElement(Node* n)
836 {
837 if (!n || !n->isElementNode())
838 return false;
839
840 RenderObject* renderer = n->renderer();
841 return (renderer && (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE));
842 }
843
isTableCell(const Node * node)844 bool isTableCell(const Node* node)
845 {
846 RenderObject* r = node->renderer();
847 if (!r)
848 return node->hasTagName(tdTag) || node->hasTagName(thTag);
849
850 return r->isTableCell();
851 }
852
createDefaultParagraphElement(Document * document)853 PassRefPtr<HTMLElement> createDefaultParagraphElement(Document* document)
854 {
855 return new HTMLDivElement(divTag, document);
856 }
857
createBreakElement(Document * document)858 PassRefPtr<HTMLElement> createBreakElement(Document* document)
859 {
860 return new HTMLBRElement(brTag, document);
861 }
862
createOrderedListElement(Document * document)863 PassRefPtr<HTMLElement> createOrderedListElement(Document* document)
864 {
865 return new HTMLOListElement(olTag, document);
866 }
867
createUnorderedListElement(Document * document)868 PassRefPtr<HTMLElement> createUnorderedListElement(Document* document)
869 {
870 return new HTMLUListElement(ulTag, document);
871 }
872
createListItemElement(Document * document)873 PassRefPtr<HTMLElement> createListItemElement(Document* document)
874 {
875 return new HTMLLIElement(liTag, document);
876 }
877
createHTMLElement(Document * document,const QualifiedName & name)878 PassRefPtr<HTMLElement> createHTMLElement(Document* document, const QualifiedName& name)
879 {
880 return HTMLElementFactory::createHTMLElement(name, document, 0, false);
881 }
882
createHTMLElement(Document * document,const AtomicString & tagName)883 PassRefPtr<HTMLElement> createHTMLElement(Document* document, const AtomicString& tagName)
884 {
885 return createHTMLElement(document, QualifiedName(nullAtom, tagName, xhtmlNamespaceURI));
886 }
887
isTabSpanNode(const Node * node)888 bool isTabSpanNode(const Node *node)
889 {
890 return node && node->hasTagName(spanTag) && node->isElementNode() && static_cast<const Element *>(node)->getAttribute(classAttr) == AppleTabSpanClass;
891 }
892
isTabSpanTextNode(const Node * node)893 bool isTabSpanTextNode(const Node *node)
894 {
895 return node && node->isTextNode() && node->parentNode() && isTabSpanNode(node->parentNode());
896 }
897
tabSpanNode(const Node * node)898 Node *tabSpanNode(const Node *node)
899 {
900 return isTabSpanTextNode(node) ? node->parentNode() : 0;
901 }
902
positionBeforeTabSpan(const Position & pos)903 Position positionBeforeTabSpan(const Position& pos)
904 {
905 Node *node = pos.node();
906 if (isTabSpanTextNode(node))
907 node = tabSpanNode(node);
908 else if (!isTabSpanNode(node))
909 return pos;
910
911 return positionBeforeNode(node);
912 }
913
createTabSpanElement(Document * document,PassRefPtr<Node> tabTextNode)914 PassRefPtr<Element> createTabSpanElement(Document* document, PassRefPtr<Node> tabTextNode)
915 {
916 // Make the span to hold the tab.
917 RefPtr<Element> spanElement = document->createElement(spanTag, false);
918 spanElement->setAttribute(classAttr, AppleTabSpanClass);
919 spanElement->setAttribute(styleAttr, "white-space:pre");
920
921 // Add tab text to that span.
922 if (!tabTextNode)
923 tabTextNode = document->createEditingTextNode("\t");
924
925 ExceptionCode ec = 0;
926 spanElement->appendChild(tabTextNode, ec);
927 ASSERT(ec == 0);
928
929 return spanElement.release();
930 }
931
createTabSpanElement(Document * document,const String & tabText)932 PassRefPtr<Element> createTabSpanElement(Document* document, const String& tabText)
933 {
934 return createTabSpanElement(document, document->createTextNode(tabText));
935 }
936
createTabSpanElement(Document * document)937 PassRefPtr<Element> createTabSpanElement(Document* document)
938 {
939 return createTabSpanElement(document, PassRefPtr<Node>());
940 }
941
isNodeRendered(const Node * node)942 bool isNodeRendered(const Node *node)
943 {
944 if (!node)
945 return false;
946
947 RenderObject *renderer = node->renderer();
948 if (!renderer)
949 return false;
950
951 return renderer->style()->visibility() == VISIBLE;
952 }
953
nearestMailBlockquote(const Node * node)954 Node *nearestMailBlockquote(const Node *node)
955 {
956 for (Node *n = const_cast<Node *>(node); n; n = n->parentNode()) {
957 if (isMailBlockquote(n))
958 return n;
959 }
960 return 0;
961 }
962
numEnclosingMailBlockquotes(const Position & p)963 unsigned numEnclosingMailBlockquotes(const Position& p)
964 {
965 unsigned num = 0;
966 for (Node* n = p.node(); n; n = n->parentNode())
967 if (isMailBlockquote(n))
968 num++;
969
970 return num;
971 }
972
isMailBlockquote(const Node * node)973 bool isMailBlockquote(const Node *node)
974 {
975 if (!node || (!node->isElementNode() && !node->hasTagName(blockquoteTag)))
976 return false;
977
978 return static_cast<const Element *>(node)->getAttribute("type") == "cite";
979 }
980
caretMinOffset(const Node * n)981 int caretMinOffset(const Node* n)
982 {
983 RenderObject* r = n->renderer();
984 ASSERT(!n->isCharacterDataNode() || !r || r->isText()); // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now.
985 return r ? r->caretMinOffset() : 0;
986 }
987
988 // If a node can contain candidates for VisiblePositions, return the offset of the last candidate, otherwise
989 // return the number of children for container nodes and the length for unrendered text nodes.
caretMaxOffset(const Node * n)990 int caretMaxOffset(const Node* n)
991 {
992 // For rendered text nodes, return the last position that a caret could occupy.
993 if (n->isTextNode() && n->renderer())
994 return n->renderer()->caretMaxOffset();
995 // For containers return the number of children. For others do the same as above.
996 return lastOffsetForEditing(n);
997 }
998
lineBreakExistsAtVisiblePosition(const VisiblePosition & visiblePosition)999 bool lineBreakExistsAtVisiblePosition(const VisiblePosition& visiblePosition)
1000 {
1001 return lineBreakExistsAtPosition(visiblePosition.deepEquivalent().downstream());
1002 }
1003
lineBreakExistsAtPosition(const Position & position)1004 bool lineBreakExistsAtPosition(const Position& position)
1005 {
1006 if (position.isNull())
1007 return false;
1008
1009 if (position.anchorNode()->hasTagName(brTag) && position.atFirstEditingPositionForNode())
1010 return true;
1011
1012 if (!position.anchorNode()->isTextNode() || !position.anchorNode()->renderer()->style()->preserveNewline())
1013 return false;
1014
1015 Text* textNode = static_cast<Text*>(position.anchorNode());
1016 unsigned offset = position.offsetInContainerNode();
1017 return offset < textNode->length() && textNode->data()[offset] == '\n';
1018 }
1019
1020 // Modifies selections that have an end point at the edge of a table
1021 // that contains the other endpoint so that they don't confuse
1022 // code that iterates over selected paragraphs.
selectionForParagraphIteration(const VisibleSelection & original)1023 VisibleSelection selectionForParagraphIteration(const VisibleSelection& original)
1024 {
1025 VisibleSelection newSelection(original);
1026 VisiblePosition startOfSelection(newSelection.visibleStart());
1027 VisiblePosition endOfSelection(newSelection.visibleEnd());
1028
1029 // If the end of the selection to modify is just after a table, and
1030 // if the start of the selection is inside that table, then the last paragraph
1031 // that we'll want modify is the last one inside the table, not the table itself
1032 // (a table is itself a paragraph).
1033 if (Node* table = isFirstPositionAfterTable(endOfSelection))
1034 if (startOfSelection.deepEquivalent().node()->isDescendantOf(table))
1035 newSelection = VisibleSelection(startOfSelection, endOfSelection.previous(true));
1036
1037 // If the start of the selection to modify is just before a table,
1038 // and if the end of the selection is inside that table, then the first paragraph
1039 // we'll want to modify is the first one inside the table, not the paragraph
1040 // containing the table itself.
1041 if (Node* table = isLastPositionBeforeTable(startOfSelection))
1042 if (endOfSelection.deepEquivalent().node()->isDescendantOf(table))
1043 newSelection = VisibleSelection(startOfSelection.next(true), endOfSelection);
1044
1045 return newSelection;
1046 }
1047
1048
indexForVisiblePosition(const VisiblePosition & visiblePosition)1049 int indexForVisiblePosition(const VisiblePosition& visiblePosition)
1050 {
1051 if (visiblePosition.isNull())
1052 return 0;
1053 Position p(visiblePosition.deepEquivalent());
1054 RefPtr<Range> range = Range::create(p.node()->document(), Position(p.node()->document(), 0), rangeCompliantEquivalent(p));
1055 return TextIterator::rangeLength(range.get(), true);
1056 }
1057
1058 // Determines whether two positions are visibly next to each other (first then second)
1059 // while ignoring whitespaces and unrendered nodes
isVisiblyAdjacent(const Position & first,const Position & second)1060 bool isVisiblyAdjacent(const Position& first, const Position& second)
1061 {
1062 return VisiblePosition(first) == VisiblePosition(second.upstream());
1063 }
1064
1065 // Determines whether a node is inside a range or visibly starts and ends at the boundaries of the range.
1066 // Call this function to determine whether a node is visibly fit inside selectedRange
isNodeVisiblyContainedWithin(Node * node,const Range * selectedRange)1067 bool isNodeVisiblyContainedWithin(Node* node, const Range* selectedRange)
1068 {
1069 ASSERT(node);
1070 ASSERT(selectedRange);
1071 // If the node is inside the range, then it surely is contained within
1072 ExceptionCode ec = 0;
1073 if (selectedRange->compareNode(node, ec) == Range::NODE_INSIDE)
1074 return true;
1075
1076 // If the node starts and ends at where selectedRange starts and ends, the node is contained within
1077 return visiblePositionBeforeNode(node) == selectedRange->startPosition()
1078 && visiblePositionAfterNode(node) == selectedRange->endPosition();
1079 }
1080
avoidIntersectionWithNode(const Range * range,Node * node)1081 PassRefPtr<Range> avoidIntersectionWithNode(const Range* range, Node* node)
1082 {
1083 if (!range)
1084 return 0;
1085
1086 Document* document = range->ownerDocument();
1087
1088 Node* startContainer = range->startContainer();
1089 int startOffset = range->startOffset();
1090 Node* endContainer = range->endContainer();
1091 int endOffset = range->endOffset();
1092
1093 if (!startContainer)
1094 return 0;
1095
1096 ASSERT(endContainer);
1097
1098 if (startContainer == node || startContainer->isDescendantOf(node)) {
1099 ASSERT(node->parentNode());
1100 startContainer = node->parentNode();
1101 startOffset = node->nodeIndex();
1102 }
1103 if (endContainer == node || endContainer->isDescendantOf(node)) {
1104 ASSERT(node->parentNode());
1105 endContainer = node->parentNode();
1106 endOffset = node->nodeIndex();
1107 }
1108
1109 return Range::create(document, startContainer, startOffset, endContainer, endOffset);
1110 }
1111
avoidIntersectionWithNode(const VisibleSelection & selection,Node * node)1112 VisibleSelection avoidIntersectionWithNode(const VisibleSelection& selection, Node* node)
1113 {
1114 if (selection.isNone())
1115 return VisibleSelection(selection);
1116
1117 VisibleSelection updatedSelection(selection);
1118 Node* base = selection.base().node();
1119 Node* extent = selection.extent().node();
1120 ASSERT(base);
1121 ASSERT(extent);
1122
1123 if (base == node || base->isDescendantOf(node)) {
1124 ASSERT(node->parentNode());
1125 updatedSelection.setBase(Position(node->parentNode(), node->nodeIndex()));
1126 }
1127
1128 if (extent == node || extent->isDescendantOf(node)) {
1129 ASSERT(node->parentNode());
1130 updatedSelection.setExtent(Position(node->parentNode(), node->nodeIndex()));
1131 }
1132
1133 return updatedSelection;
1134 }
1135
1136 } // namespace WebCore
1137