| 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 |