OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. | 2 * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
11 * documentation and/or other materials provided with the distribution. | 11 * documentation and/or other materials provided with the distribution. |
12 * | 12 * |
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 */ | 24 */ |
25 | 25 |
26 #include "config.h" | 26 #include "config.h" |
27 #include "core/editing/Position.h" | 27 #include "core/editing/Position.h" |
28 | 28 |
29 #include "core/HTMLNames.h" | |
30 #include "core/css/CSSComputedStyleDeclaration.h" | |
31 #include "core/dom/Text.h" | |
32 #include "core/dom/shadow/ElementShadow.h" | 29 #include "core/dom/shadow/ElementShadow.h" |
33 #include "core/editing/EditingUtilities.h" | 30 #include "core/editing/EditingUtilities.h" |
34 #include "core/editing/PositionIterator.h" | 31 #include "core/editing/PositionIterator.h" |
35 #include "core/editing/TextAffinity.h" | 32 #include "core/editing/TextAffinity.h" |
36 #include "core/editing/VisiblePosition.h" | |
37 #include "core/editing/VisibleUnits.h" | 33 #include "core/editing/VisibleUnits.h" |
38 #include "core/editing/iterators/TextIterator.h" | |
39 #include "core/frame/LocalFrame.h" | |
40 #include "core/frame/Settings.h" | |
41 #include "core/html/HTMLTableElement.h" | |
42 #include "core/layout/LayoutBlock.h" | 34 #include "core/layout/LayoutBlock.h" |
43 #include "core/layout/LayoutInline.h" | 35 #include "core/layout/LayoutInline.h" |
44 #include "core/layout/LayoutText.h" | 36 #include "core/layout/LayoutText.h" |
45 #include "core/layout/line/InlineTextBox.h" | 37 #include "core/layout/line/InlineTextBox.h" |
46 #include "wtf/text/CString.h" | 38 #include "wtf/text/CString.h" |
47 #include <stdio.h> | 39 #include <stdio.h> |
48 | 40 |
49 namespace blink { | 41 namespace blink { |
50 | 42 |
51 using namespace HTMLNames; | |
52 | |
53 #if ENABLE(ASSERT) | 43 #if ENABLE(ASSERT) |
54 static bool canBeAnchorNode(Node* node) | 44 static bool canBeAnchorNode(Node* node) |
55 { | 45 { |
56 if (!node || node->isFirstLetterPseudoElement()) | 46 if (!node || node->isFirstLetterPseudoElement()) |
57 return true; | 47 return true; |
58 return !node->isPseudoElement(); | 48 return !node->isPseudoElement(); |
59 } | 49 } |
60 #endif | 50 #endif |
61 | 51 |
62 template <typename Strategy> | 52 template <typename Strategy> |
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
431 if (isNull()) | 421 if (isNull()) |
432 return true; | 422 return true; |
433 // TODO(yosin): Position after anchor shouldn't be considered as at the | 423 // TODO(yosin): Position after anchor shouldn't be considered as at the |
434 // first editing position for node since that position resides outside of | 424 // first editing position for node since that position resides outside of |
435 // the node. | 425 // the node. |
436 // TODO(yosin) We should use |Strategy::lastOffsetForEditing()| instead of | 426 // TODO(yosin) We should use |Strategy::lastOffsetForEditing()| instead of |
437 // DOM tree version. | 427 // DOM tree version. |
438 return isAfterAnchorOrAfterChildren() || m_offset >= EditingStrategy::lastOf
fsetForEditing(anchorNode()); | 428 return isAfterAnchorOrAfterChildren() || m_offset >= EditingStrategy::lastOf
fsetForEditing(anchorNode()); |
439 } | 429 } |
440 | 430 |
441 // Returns true if the visually equivalent positions around have different | |
442 // editability. A position is considered at editing boundary if one of the | |
443 // following is true: | |
444 // 1. It is the first position in the node and the next visually equivalent | |
445 // position is non editable. | |
446 // 2. It is the last position in the node and the previous visually equivalent | |
447 // position is non editable. | |
448 // 3. It is an editable position and both the next and previous visually | |
449 // equivalent positions are both non editable. | |
450 template <typename Strategy> | |
451 static bool atEditingBoundary(const PositionAlgorithm<Strategy> positions) | |
452 { | |
453 PositionAlgorithm<Strategy> nextPosition = positions.downstream(CanCrossEdit
ingBoundary); | |
454 if (positions.atFirstEditingPositionForNode() && nextPosition.isNotNull() &&
!nextPosition.anchorNode()->hasEditableStyle()) | |
455 return true; | |
456 | |
457 PositionAlgorithm<Strategy> prevPosition = positions.upstream(CanCrossEditin
gBoundary); | |
458 if (positions.atLastEditingPositionForNode() && prevPosition.isNotNull() &&
!prevPosition.anchorNode()->hasEditableStyle()) | |
459 return true; | |
460 | |
461 return nextPosition.isNotNull() && !nextPosition.anchorNode()->hasEditableSt
yle() | |
462 && prevPosition.isNotNull() && !prevPosition.anchorNode()->hasEditableSt
yle(); | |
463 } | |
464 | |
465 template <typename Strategy> | 431 template <typename Strategy> |
466 bool PositionAlgorithm<Strategy>::atStartOfTree() const | 432 bool PositionAlgorithm<Strategy>::atStartOfTree() const |
467 { | 433 { |
468 if (isNull()) | 434 if (isNull()) |
469 return true; | 435 return true; |
470 return !Strategy::parent(*anchorNode()) && m_offset == 0; | 436 return !Strategy::parent(*anchorNode()) && m_offset == 0; |
471 } | 437 } |
472 | 438 |
473 template <typename Strategy> | 439 template <typename Strategy> |
474 bool PositionAlgorithm<Strategy>::atEndOfTree() const | 440 bool PositionAlgorithm<Strategy>::atEndOfTree() const |
(...skipping 10 matching lines...) Expand all Loading... |
485 { | 451 { |
486 return mostForwardCaretPosition(*this, rule); | 452 return mostForwardCaretPosition(*this, rule); |
487 } | 453 } |
488 | 454 |
489 template <typename Strategy> | 455 template <typename Strategy> |
490 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::downstream(EditingBound
aryCrossingRule rule) const | 456 PositionAlgorithm<Strategy> PositionAlgorithm<Strategy>::downstream(EditingBound
aryCrossingRule rule) const |
491 { | 457 { |
492 return mostBackwardCaretPosition(*this, rule); | 458 return mostBackwardCaretPosition(*this, rule); |
493 } | 459 } |
494 | 460 |
495 // TODO(yosin) We should move |isVisuallyEquivalentCandidate()| to | |
496 // "VisibleUnits.cpp" to reduce |LayoutObject| dependency in "Position.cpp". | |
497 template <typename Strategy> | |
498 static bool isVisuallyEquivalentCandidateAlgorithm(const PositionAlgorithm<Strat
egy>& position) | |
499 { | |
500 Node* const anchorNode = position.anchorNode(); | |
501 if (!anchorNode) | |
502 return false; | |
503 | |
504 LayoutObject* layoutObject = anchorNode->layoutObject(); | |
505 if (!layoutObject) | |
506 return false; | |
507 | |
508 if (layoutObject->style()->visibility() != VISIBLE) | |
509 return false; | |
510 | |
511 if (layoutObject->isBR()) { | |
512 // TODO(leviw) The condition should be | |
513 // m_anchorType == PositionAnchorType::BeforeAnchor, but for now we | |
514 // still need to support legacy positions. | |
515 if (position.isAfterAnchor()) | |
516 return false; | |
517 return !position.computeEditingOffset() && !nodeIsUserSelectNone(Strateg
y::parent(*anchorNode)); | |
518 } | |
519 | |
520 if (layoutObject->isText()) | |
521 return !nodeIsUserSelectNone(anchorNode) && inRenderedText(position); | |
522 | |
523 if (layoutObject->isSVG()) { | |
524 // We don't consider SVG elements are contenteditable except for | |
525 // associated |layoutObject| returns |isText()| true, | |
526 // e.g. |LayoutSVGInlineText|. | |
527 return false; | |
528 } | |
529 | |
530 if (isRenderedHTMLTableElement(anchorNode) || Strategy::editingIgnoresConten
t(anchorNode)) | |
531 return (position.atFirstEditingPositionForNode() || position.atLastEditi
ngPositionForNode()) && !nodeIsUserSelectNone(Strategy::parent(*anchorNode)); | |
532 | |
533 if (isHTMLHtmlElement(*anchorNode)) | |
534 return false; | |
535 | |
536 if (layoutObject->isLayoutBlockFlow() || layoutObject->isFlexibleBox() || la
youtObject->isLayoutGrid()) { | |
537 if (toLayoutBlock(layoutObject)->logicalHeight() || isHTMLBodyElement(*a
nchorNode)) { | |
538 if (!hasRenderedNonAnonymousDescendantsWithHeight(layoutObject)) | |
539 return position.atFirstEditingPositionForNode() && !nodeIsUserSe
lectNone(anchorNode); | |
540 return anchorNode->hasEditableStyle() && !nodeIsUserSelectNone(ancho
rNode) && atEditingBoundary(position); | |
541 } | |
542 } else { | |
543 LocalFrame* frame = anchorNode->document().frame(); | |
544 bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsi
ngEnabled(); | |
545 return (caretBrowsing || anchorNode->hasEditableStyle()) && !nodeIsUserS
electNone(anchorNode) && atEditingBoundary(position); | |
546 } | |
547 | |
548 return false; | |
549 } | |
550 | |
551 // TODO(yosin) We should move |inRenderedText()| to "VisibleUnits.h" for | |
552 // reduce dependency of |LayoutObject| in |Position| class. | |
553 bool isVisuallyEquivalentCandidate(const Position& position) | |
554 { | |
555 return isVisuallyEquivalentCandidateAlgorithm<EditingStrategy>(position); | |
556 } | |
557 | |
558 bool isVisuallyEquivalentCandidate(const PositionInComposedTree& position) | |
559 { | |
560 return isVisuallyEquivalentCandidateAlgorithm<EditingInComposedTreeStrategy>
(position); | |
561 } | |
562 | |
563 template <typename Strategy> | 461 template <typename Strategy> |
564 static bool inRenderedTextAlgorithm(const PositionAlgorithm<Strategy>& position) | 462 static bool inRenderedTextAlgorithm(const PositionAlgorithm<Strategy>& position) |
565 { | 463 { |
566 Node* const anchorNode = position.anchorNode(); | 464 Node* const anchorNode = position.anchorNode(); |
567 if (!anchorNode || !anchorNode->isTextNode()) | 465 if (!anchorNode || !anchorNode->isTextNode()) |
568 return false; | 466 return false; |
569 | 467 |
570 LayoutObject* layoutObject = anchorNode->layoutObject(); | 468 LayoutObject* layoutObject = anchorNode->layoutObject(); |
571 if (!layoutObject) | 469 if (!layoutObject) |
572 return false; | 470 return false; |
(...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1025 | 923 |
1026 void showTree(const blink::Position* pos) | 924 void showTree(const blink::Position* pos) |
1027 { | 925 { |
1028 if (pos) | 926 if (pos) |
1029 pos->showTreeForThis(); | 927 pos->showTreeForThis(); |
1030 else | 928 else |
1031 fprintf(stderr, "Cannot showTree for (nil)\n"); | 929 fprintf(stderr, "Cannot showTree for (nil)\n"); |
1032 } | 930 } |
1033 | 931 |
1034 #endif | 932 #endif |
OLD | NEW |