2 * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #include "visible_position.h"
28 #include "misc/htmltags.h"
29 #include "rendering/render_line.h"
30 #include "rendering/render_object.h"
31 #include "rendering/render_text.h"
32 #include "xml/dom2_rangeimpl.h"
33 #include "xml/dom_nodeimpl.h"
34 #include "xml/dom_textimpl.h"
37 #include "KWQAssertions.h"
38 #include "KWQLogging.h"
40 #define ASSERT(assertion) assert(assertion)
41 #define LOG(channel, formatAndArgs...) ((void)0)
44 using DOM::CharacterDataImpl;
46 using DOM::offsetInCharacters;
47 using DOM::UsingComposedCharacters;
51 using DOM::StayInBlock;
56 VisiblePosition::VisiblePosition(const Position &pos, EAffinity affinity, EInitHint initHint)
58 init(pos, initHint, affinity);
61 VisiblePosition::VisiblePosition(NodeImpl *node, long offset, EAffinity affinity, EInitHint initHint)
63 init(Position(node, offset), initHint, affinity);
66 VisiblePosition::VisiblePosition(const VisiblePosition &other)
68 m_deepPosition = other.m_deepPosition;
69 m_affinity = other.m_affinity;
72 void VisiblePosition::init(const Position &pos, EInitHint initHint, EAffinity affinity)
74 m_affinity = affinity;
76 // A first step toward eliminating the initHint parameter.
77 // For <br> 0, it's important not to move past the <br>.
78 if (pos.node() && pos.node()->id() == ID_BR && pos.offset() == 0)
94 void VisiblePosition::initUpstream(const Position &pos)
96 Position deepPos = deepEquivalent(pos);
98 if (isCandidate(deepPos)) {
99 m_deepPosition = deepPos;
100 Position next = nextVisiblePosition(deepPos);
101 if (next.isNotNull()) {
102 Position previous = previousVisiblePosition(next);
103 if (previous.isNotNull())
104 m_deepPosition = previous;
108 Position previous = previousVisiblePosition(deepPos);
109 if (previous.isNotNull()) {
110 m_deepPosition = previous;
112 Position next = nextVisiblePosition(deepPos);
113 if (next.isNotNull())
114 m_deepPosition = next;
119 static bool isRenderedBR(NodeImpl *node)
124 RenderObject *renderer = node->renderer();
128 if (renderer->style()->visibility() != VISIBLE)
131 if (renderer->isBR())
137 void VisiblePosition::initDownstream(const Position &pos)
139 Position deepPos = deepEquivalent(pos);
141 if (isCandidate(deepPos)) {
142 m_deepPosition = deepPos;
143 Position previous = previousVisiblePosition(deepPos);
144 if (previous.isNotNull()) {
145 Position next = nextVisiblePosition(previous);
146 if (next.isNotNull())
147 m_deepPosition = next;
150 Position next = nextVisiblePosition(deepPos);
151 if (next.isNotNull()) {
152 m_deepPosition = next;
153 } else if (isRenderedBR(deepPos.node()) && deepPos.offset() == 1) {
154 m_deepPosition = deepPos;
156 Position previous = previousVisiblePosition(deepPos);
157 if (previous.isNotNull())
158 m_deepPosition = previous;
163 VisiblePosition VisiblePosition::next() const
165 VisiblePosition result = VisiblePosition(nextVisiblePosition(m_deepPosition), m_affinity);
166 setAffinityUsingLinePosition(result);
170 VisiblePosition VisiblePosition::previous() const
172 VisiblePosition result = VisiblePosition(previousVisiblePosition(m_deepPosition), DOWNSTREAM);
175 // we should always be able to make the affinity DOWNSTREAM, because going previous from an
176 // UPSTREAM position can never yield another UPSTREAM position (unless line wrap length is 0!).
177 if (result.isNotNull() && m_affinity == UPSTREAM) {
178 VisiblePosition temp = result;
179 temp.setAffinity(UPSTREAM);
180 ASSERT(!visiblePositionsOnDifferentLines(temp, result));
186 Position VisiblePosition::previousVisiblePosition(const Position &pos)
188 if (pos.isNull() || pos.atStart())
191 Position test = deepEquivalent(pos);
192 Position downstreamTest = test.downstream(StayInBlock);
193 bool acceptAnyVisiblePosition = !isCandidate(test);
195 Position current = test;
196 while (!current.atStart()) {
197 current = current.previous(UsingComposedCharacters);
198 if (isCandidate(current) && (acceptAnyVisiblePosition || (downstreamTest != current.downstream(StayInBlock)))) {
206 Position VisiblePosition::nextVisiblePosition(const Position &pos)
208 if (pos.isNull() || pos.atEnd())
211 Position test = deepEquivalent(pos);
212 bool acceptAnyVisiblePosition = !isCandidate(test);
214 Position current = test;
215 Position downstreamTest = test.downstream(StayInBlock);
216 while (!current.atEnd()) {
217 current = current.next(UsingComposedCharacters);
218 if (isCandidate(current) && (acceptAnyVisiblePosition || (downstreamTest != current.downstream(StayInBlock)))) {
226 bool VisiblePosition::isCandidate(const Position &pos)
231 RenderObject *renderer = pos.node()->renderer();
235 if (renderer->style()->visibility() != VISIBLE)
238 if (renderer->isReplaced())
239 // return true for replaced elements
240 return pos.offset() == 0 || pos.offset() == 1;
242 if (renderer->isBR()) {
243 if (pos.offset() == 0) {
244 InlineBox* box = static_cast<RenderText*>(renderer)->firstTextBox();
246 // return true for offset 0 into BR element on a line by itself
247 RootInlineBox* root = box->root();
249 return root->firstLeafChild() == box && root->lastLeafChild() == box;
255 if (renderer->isText()) {
256 RenderText *textRenderer = static_cast<RenderText *>(renderer);
257 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
258 if (pos.offset() >= box->m_start && pos.offset() <= box->m_start + box->m_len) {
259 // return true if in a text node
265 if (renderer->isBlockFlow() && (!renderer->firstChild() || !pos.node()->firstChild()) &&
266 (renderer->height() || pos.node()->id() == ID_BODY)) {
267 // return true for offset 0 into rendered blocks that are empty of rendered kids, but have a height
268 return pos.offset() == 0;
274 Position VisiblePosition::deepEquivalent(const Position &pos)
276 NodeImpl *node = pos.node();
277 long offset = pos.offset();
282 if (isAtomicNode(node))
285 if (offset >= (long)node->childNodeCount()) {
287 NodeImpl *child = node->lastChild();
291 } while (!isAtomicNode(node));
292 return Position(node, node->caretMaxOffset());
295 node = node->childNode(offset);
297 while (!isAtomicNode(node)) {
298 NodeImpl *child = node->firstChild();
303 return Position(node, 0);
306 Position VisiblePosition::downstreamDeepEquivalent() const
308 Position pos = m_deepPosition;
310 if (pos.isNull() || pos.atEnd())
313 Position downstreamTest = pos.downstream(StayInBlock);
315 Position current = pos;
316 while (!current.atEnd()) {
317 current = current.next(UsingComposedCharacters);
318 if (isCandidate(current)) {
319 if (downstreamTest != current.downstream(StayInBlock))
328 Position VisiblePosition::rangeCompliantEquivalent(const Position &pos)
330 NodeImpl *node = pos.node();
334 // FIXME: This clamps out-of-range values.
335 // Instead we should probably assert, and not use such values.
337 long offset = pos.offset();
338 if (!offsetInCharacters(node->nodeType()) && isAtomicNode(node) && offset > 0)
339 return Position(node->parentNode(), node->nodeIndex() + 1);
341 return Position(node, kMax(0L, kMin(offset, maxOffset(node))));
344 long VisiblePosition::maxOffset(const NodeImpl *node)
346 return offsetInCharacters(node->nodeType()) ? (long)static_cast<const CharacterDataImpl *>(node)->length() : (long)node->childNodeCount();
349 bool VisiblePosition::isAtomicNode(const NodeImpl *node)
351 return node && (!node->hasChildNodes() || (node->id() == ID_OBJECT && node->renderer() && node->renderer()->isReplaced()));
354 QChar VisiblePosition::character() const
356 Position pos = position();
357 NodeImpl *node = pos.node();
358 if (!node || !node->isTextNode()) {
361 TextImpl *textNode = static_cast<TextImpl *>(pos.node());
362 long offset = pos.offset();
363 if ((unsigned)offset >= textNode->length()) {
366 return textNode->data()[offset];
369 bool isEqualIgnoringAffinity(const VisiblePosition &a, const VisiblePosition &b)
371 bool result = a.m_deepPosition == b.m_deepPosition;
373 // We want to catch cases where positions are equal, but affinities are not, since
374 // this is very likely a bug, given the places where this call is used. The difference
375 // is very likely due to code that set the affinity on a VisiblePosition "by hand" and
376 // did so incorrectly.
377 ASSERT(a.m_affinity == b.m_affinity);
382 bool isNotEqualIgnoringAffinity(const VisiblePosition &a, const VisiblePosition &b)
384 return !isEqualIgnoringAffinity(a, b);
387 void VisiblePosition::debugPosition(const char *msg) const
390 fprintf(stderr, "Position [%s]: null\n", msg);
392 fprintf(stderr, "Position [%s]: %s [%p] at %ld\n", msg, m_deepPosition.node()->nodeName().string().latin1(), m_deepPosition.node(), m_deepPosition.offset());
396 void VisiblePosition::formatForDebugger(char *buffer, unsigned length) const
398 m_deepPosition.formatForDebugger(buffer, length);
402 Range makeRange(const VisiblePosition &start, const VisiblePosition &end)
404 Position s = start.position();
405 Position e = end.position();
406 return Range(s.node(), s.offset(), e.node(), e.offset());
409 VisiblePosition startVisiblePosition(const Range &r, EAffinity affinity)
411 return VisiblePosition(r.startContainer().handle(), r.startOffset(), affinity);
414 VisiblePosition endVisiblePosition(const Range &r, EAffinity affinity)
416 return VisiblePosition(r.endContainer().handle(), r.endOffset(), affinity);
419 bool setStart(Range &r, const VisiblePosition &c)
421 RangeImpl *ri = r.handle();
424 Position p = c.position();
426 ri->setStart(p.node(), p.offset(), code);
430 bool setEnd(Range &r, const VisiblePosition &c)
432 RangeImpl *ri = r.handle();
435 Position p = c.position();
437 ri->setEnd(p.node(), p.offset(), code);
441 void setAffinityUsingLinePosition(VisiblePosition &pos)
443 // When not moving across line wrap, make sure to end up with DOWNSTREAM affinity.
444 if (pos.isNotNull() && pos.affinity() == UPSTREAM) {
445 VisiblePosition temp(pos);
446 temp.setAffinity(DOWNSTREAM);
447 if (!visiblePositionsOnDifferentLines(temp, pos))
448 pos.setAffinity(DOWNSTREAM);
452 DOM::NodeImpl *enclosingBlockFlowElement(const VisiblePosition &vp)
457 return vp.position().node()->enclosingBlockFlowElement();
460 bool visiblePositionsOnDifferentLines(const VisiblePosition &pos1, const VisiblePosition &pos2)
462 if (pos1.isNull() || pos2.isNull())
467 Position p1 = pos1.deepEquivalent();
468 Position p2 = pos2.deepEquivalent();
469 RenderObject *r1 = p1.node()->renderer();
470 RenderObject *r2 = p2.node()->renderer();
471 if (r1->isBlockFlow() || r2->isBlockFlow())
472 return r1 == r2 ? false : true;
473 InlineBox *b1 = r1 ? r1->inlineBox(p1.offset(), pos1.affinity()) : 0;
474 InlineBox *b2 = r2 ? r2->inlineBox(p2.offset(), pos2.affinity()) : 0;
475 return (b1 && b2 && b1->root() != b2->root());
478 enum EBlockRelationship {
480 SameBlockRelationship,
481 PeerBlockRelationship,
482 AncestorBlockRelationship,
483 DescendantBlockRelationship,
484 OtherBlockRelationship
487 static EBlockRelationship blockRelationship(const VisiblePosition &pos1, const VisiblePosition &pos2)
489 if (pos1.isNull() || pos2.isNull())
490 return NoBlockRelationship;
492 return SameBlockRelationship;
494 Position p1 = pos1.deepEquivalent();
495 Position p2 = pos2.deepEquivalent();
496 NodeImpl *b1 = p1.node()->enclosingBlockFlowElement();
497 NodeImpl *b2 = p2.node()->enclosingBlockFlowElement();
499 return NoBlockRelationship;
501 return SameBlockRelationship;
502 if (b1->parentNode() == b2->parentNode())
503 return PeerBlockRelationship;
504 if (b2->isAncestor(b1))
505 return AncestorBlockRelationship;
506 if (b1->isAncestor(b2))
507 return DescendantBlockRelationship;
508 return OtherBlockRelationship;
511 bool visiblePositionsInDifferentBlocks(const VisiblePosition &pos1, const VisiblePosition &pos2)
513 switch (blockRelationship(pos1, pos2)) {
514 case NoBlockRelationship:
515 case SameBlockRelationship:
517 case PeerBlockRelationship:
518 case AncestorBlockRelationship:
519 case DescendantBlockRelationship:
520 case OtherBlockRelationship:
523 ASSERT_NOT_REACHED();
527 bool isFirstVisiblePositionOnLine(const VisiblePosition &pos)
532 VisiblePosition previous = pos.previous();
533 return previous.isNull() || visiblePositionsOnDifferentLines(pos, previous);
536 bool isFirstVisiblePositionInParagraph(const VisiblePosition &pos)
541 return pos.deepEquivalent().upstream(StayInBlock).node()->id() == ID_BR || isFirstVisiblePositionInBlock(pos);
544 bool isFirstVisiblePositionInBlock(const VisiblePosition &pos)
549 Position upstream = pos.deepEquivalent().upstream(StayInBlock);
550 return upstream.node()->isBlockFlow() && upstream.offset() == 0;
553 bool isFirstVisiblePositionInNode(const VisiblePosition &pos, const NodeImpl *node)
558 VisiblePosition previous = pos.previous();
559 return previous.isNull() || !previous.deepEquivalent().node()->isAncestor(node);
562 bool isLastVisiblePositionOnLine(const VisiblePosition &pos)
567 VisiblePosition next = pos.next();
568 return next.isNull() || visiblePositionsOnDifferentLines(pos, next);
571 bool isLastVisiblePositionInParagraph(const VisiblePosition &pos)
576 return pos.deepEquivalent().downstream(StayInBlock).node()->id() == ID_BR || isLastVisiblePositionInBlock(pos);
579 bool isLastVisiblePositionInBlock(const VisiblePosition &pos)
584 VisiblePosition next = pos.next();
588 switch (blockRelationship(pos, next)) {
589 case NoBlockRelationship:
590 case SameBlockRelationship:
591 case AncestorBlockRelationship:
593 case OtherBlockRelationship:
594 case PeerBlockRelationship:
595 case DescendantBlockRelationship:
598 ASSERT_NOT_REACHED();
602 bool isLastVisiblePositionInNode(const VisiblePosition &pos, const NodeImpl *node)
607 VisiblePosition next = pos.next();
608 return next.isNull() || !next.deepEquivalent().node()->isAncestor(node);