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