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 |
(...skipping 21 matching lines...) Expand all Loading... |
32 #include "core/dom/Text.h" | 32 #include "core/dom/Text.h" |
33 #include "core/editing/VisiblePosition.h" | 33 #include "core/editing/VisiblePosition.h" |
34 #include "core/editing/VisibleUnits.h" | 34 #include "core/editing/VisibleUnits.h" |
35 #include "core/editing/htmlediting.h" | 35 #include "core/editing/htmlediting.h" |
36 #include "core/editing/iterators/TextIterator.h" | 36 #include "core/editing/iterators/TextIterator.h" |
37 #include "core/frame/LocalFrame.h" | 37 #include "core/frame/LocalFrame.h" |
38 #include "core/frame/Settings.h" | 38 #include "core/frame/Settings.h" |
39 #include "core/html/HTMLTableElement.h" | 39 #include "core/html/HTMLTableElement.h" |
40 #include "core/layout/LayoutBlock.h" | 40 #include "core/layout/LayoutBlock.h" |
41 #include "core/layout/LayoutInline.h" | 41 #include "core/layout/LayoutInline.h" |
| 42 #include "core/layout/LayoutText.h" |
42 #include "core/layout/line/InlineIterator.h" | 43 #include "core/layout/line/InlineIterator.h" |
43 #include "core/layout/line/InlineTextBox.h" | 44 #include "core/layout/line/InlineTextBox.h" |
44 #include "core/rendering/RenderText.h" | |
45 #include "platform/Logging.h" | 45 #include "platform/Logging.h" |
46 #include "wtf/text/CString.h" | 46 #include "wtf/text/CString.h" |
47 #include "wtf/unicode/CharacterNames.h" | 47 #include "wtf/unicode/CharacterNames.h" |
48 #include <stdio.h> | 48 #include <stdio.h> |
49 | 49 |
50 namespace blink { | 50 namespace blink { |
51 | 51 |
52 using namespace HTMLNames; | 52 using namespace HTMLNames; |
53 | 53 |
54 static Node* nextRenderedEditable(Node* node) | 54 static Node* nextRenderedEditable(Node* node) |
55 { | 55 { |
56 for (node = node->nextLeafNode(); node; node = node->nextLeafNode()) { | 56 for (node = node->nextLeafNode(); node; node = node->nextLeafNode()) { |
57 LayoutObject* renderer = node->renderer(); | 57 LayoutObject* renderer = node->renderer(); |
58 if (!renderer) | 58 if (!renderer) |
59 continue; | 59 continue; |
60 if (!node->hasEditableStyle()) | 60 if (!node->hasEditableStyle()) |
61 continue; | 61 continue; |
62 if ((renderer->isBox() && toLayoutBox(renderer)->inlineBoxWrapper()) ||
(renderer->isText() && toRenderText(renderer)->firstTextBox())) | 62 if ((renderer->isBox() && toLayoutBox(renderer)->inlineBoxWrapper()) ||
(renderer->isText() && toLayoutText(renderer)->firstTextBox())) |
63 return node; | 63 return node; |
64 } | 64 } |
65 return 0; | 65 return 0; |
66 } | 66 } |
67 | 67 |
68 static Node* previousRenderedEditable(Node* node) | 68 static Node* previousRenderedEditable(Node* node) |
69 { | 69 { |
70 for (node = node->previousLeafNode(); node; node = node->previousLeafNode())
{ | 70 for (node = node->previousLeafNode(); node; node = node->previousLeafNode())
{ |
71 LayoutObject* renderer = node->renderer(); | 71 LayoutObject* renderer = node->renderer(); |
72 if (!renderer) | 72 if (!renderer) |
73 continue; | 73 continue; |
74 if (!node->hasEditableStyle()) | 74 if (!node->hasEditableStyle()) |
75 continue; | 75 continue; |
76 if ((renderer->isBox() && toLayoutBox(renderer)->inlineBoxWrapper()) ||
(renderer->isText() && toRenderText(renderer)->firstTextBox())) | 76 if ((renderer->isBox() && toLayoutBox(renderer)->inlineBoxWrapper()) ||
(renderer->isText() && toLayoutText(renderer)->firstTextBox())) |
77 return node; | 77 return node; |
78 } | 78 } |
79 return 0; | 79 return 0; |
80 } | 80 } |
81 | 81 |
82 const TreeScope* Position::commonAncestorTreeScope(const Position& a, const Posi
tion& b) | 82 const TreeScope* Position::commonAncestorTreeScope(const Position& a, const Posi
tion& b) |
83 { | 83 { |
84 if (!a.containerNode() || !b.containerNode()) | 84 if (!a.containerNode() || !b.containerNode()) |
85 return nullptr; | 85 return nullptr; |
86 return a.containerNode()->treeScope().commonAncestorTreeScope(b.containerNod
e()->treeScope()); | 86 return a.containerNode()->treeScope().commonAncestorTreeScope(b.containerNod
e()->treeScope()); |
(...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
460 | 460 |
461 int Position::renderedOffset() const | 461 int Position::renderedOffset() const |
462 { | 462 { |
463 if (!deprecatedNode()->isTextNode()) | 463 if (!deprecatedNode()->isTextNode()) |
464 return m_offset; | 464 return m_offset; |
465 | 465 |
466 if (!deprecatedNode()->renderer()) | 466 if (!deprecatedNode()->renderer()) |
467 return m_offset; | 467 return m_offset; |
468 | 468 |
469 int result = 0; | 469 int result = 0; |
470 RenderText* textRenderer = toRenderText(deprecatedNode()->renderer()); | 470 LayoutText* textRenderer = toLayoutText(deprecatedNode()->renderer()); |
471 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->next
TextBox()) { | 471 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->next
TextBox()) { |
472 int start = box->start(); | 472 int start = box->start(); |
473 int end = box->start() + box->len(); | 473 int end = box->start() + box->len(); |
474 if (m_offset < start) | 474 if (m_offset < start) |
475 return result; | 475 return result; |
476 if (m_offset <= end) { | 476 if (m_offset <= end) { |
477 result += m_offset - start; | 477 result += m_offset - start; |
478 return result; | 478 return result; |
479 } | 479 } |
480 result += box->len(); | 480 result += box->len(); |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
589 return lastVisible; | 589 return lastVisible; |
590 | 590 |
591 // Return position after tables and nodes which have content that can be
ignored. | 591 // Return position after tables and nodes which have content that can be
ignored. |
592 if (editingIgnoresContent(currentNode) || isRenderedHTMLTableElement(cur
rentNode)) { | 592 if (editingIgnoresContent(currentNode) || isRenderedHTMLTableElement(cur
rentNode)) { |
593 if (currentPos.atEndOfNode()) | 593 if (currentPos.atEndOfNode()) |
594 return positionAfterNode(currentNode); | 594 return positionAfterNode(currentNode); |
595 continue; | 595 continue; |
596 } | 596 } |
597 | 597 |
598 // return current position if it is in rendered text | 598 // return current position if it is in rendered text |
599 if (renderer->isText() && toRenderText(renderer)->firstTextBox()) { | 599 if (renderer->isText() && toLayoutText(renderer)->firstTextBox()) { |
600 if (currentNode != startNode) { | 600 if (currentNode != startNode) { |
601 // This assertion fires in layout tests in the case-transform.ht
ml test because | 601 // This assertion fires in layout tests in the case-transform.ht
ml test because |
602 // of a mix-up between offsets in the text in the DOM tree with
text in the | 602 // of a mix-up between offsets in the text in the DOM tree with
text in the |
603 // render tree which can have a different length due to case tra
nsformation. | 603 // render tree which can have a different length due to case tra
nsformation. |
604 // Until we resolve that, disable this so we can run the layout
tests! | 604 // Until we resolve that, disable this so we can run the layout
tests! |
605 //ASSERT(currentOffset >= renderer->caretMaxOffset()); | 605 //ASSERT(currentOffset >= renderer->caretMaxOffset()); |
606 return createLegacyEditingPosition(currentNode, renderer->caretM
axOffset()); | 606 return createLegacyEditingPosition(currentNode, renderer->caretM
axOffset()); |
607 } | 607 } |
608 | 608 |
609 unsigned textOffset = currentPos.offsetInLeafNode(); | 609 unsigned textOffset = currentPos.offsetInLeafNode(); |
610 RenderText* textRenderer = toRenderText(renderer); | 610 LayoutText* textRenderer = toLayoutText(renderer); |
611 InlineTextBox* lastTextBox = textRenderer->lastTextBox(); | 611 InlineTextBox* lastTextBox = textRenderer->lastTextBox(); |
612 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = b
ox->nextTextBox()) { | 612 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = b
ox->nextTextBox()) { |
613 if (textOffset <= box->start() + box->len()) { | 613 if (textOffset <= box->start() + box->len()) { |
614 if (textOffset > box->start()) | 614 if (textOffset > box->start()) |
615 return currentPos; | 615 return currentPos; |
616 continue; | 616 continue; |
617 } | 617 } |
618 | 618 |
619 if (box == lastTextBox || textOffset != box->start() + box->len(
) + 1) | 619 if (box == lastTextBox || textOffset != box->start() + box->len(
) + 1) |
620 continue; | 620 continue; |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 lastVisible = currentPos; | 717 lastVisible = currentPos; |
718 | 718 |
719 // Return position before tables and nodes which have content that can b
e ignored. | 719 // Return position before tables and nodes which have content that can b
e ignored. |
720 if (editingIgnoresContent(currentNode) || isRenderedHTMLTableElement(cur
rentNode)) { | 720 if (editingIgnoresContent(currentNode) || isRenderedHTMLTableElement(cur
rentNode)) { |
721 if (currentPos.offsetInLeafNode() <= renderer->caretMinOffset()) | 721 if (currentPos.offsetInLeafNode() <= renderer->caretMinOffset()) |
722 return createLegacyEditingPosition(currentNode, renderer->caretM
inOffset()); | 722 return createLegacyEditingPosition(currentNode, renderer->caretM
inOffset()); |
723 continue; | 723 continue; |
724 } | 724 } |
725 | 725 |
726 // return current position if it is in rendered text | 726 // return current position if it is in rendered text |
727 if (renderer->isText() && toRenderText(renderer)->firstTextBox()) { | 727 if (renderer->isText() && toLayoutText(renderer)->firstTextBox()) { |
728 if (currentNode != startNode) { | 728 if (currentNode != startNode) { |
729 ASSERT(currentPos.atStartOfNode()); | 729 ASSERT(currentPos.atStartOfNode()); |
730 return createLegacyEditingPosition(currentNode, renderer->caretM
inOffset()); | 730 return createLegacyEditingPosition(currentNode, renderer->caretM
inOffset()); |
731 } | 731 } |
732 | 732 |
733 unsigned textOffset = currentPos.offsetInLeafNode(); | 733 unsigned textOffset = currentPos.offsetInLeafNode(); |
734 RenderText* textRenderer = toRenderText(renderer); | 734 LayoutText* textRenderer = toLayoutText(renderer); |
735 InlineTextBox* lastTextBox = textRenderer->lastTextBox(); | 735 InlineTextBox* lastTextBox = textRenderer->lastTextBox(); |
736 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = b
ox->nextTextBox()) { | 736 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = b
ox->nextTextBox()) { |
737 if (textOffset <= box->end()) { | 737 if (textOffset <= box->end()) { |
738 if (textOffset >= box->start()) | 738 if (textOffset >= box->start()) |
739 return currentPos; | 739 return currentPos; |
740 continue; | 740 continue; |
741 } | 741 } |
742 | 742 |
743 if (box == lastTextBox || textOffset != box->start() + box->len(
)) | 743 if (box == lastTextBox || textOffset != box->start() + box->len(
)) |
744 continue; | 744 continue; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
777 static int boundingBoxLogicalHeight(LayoutObject *o, const IntRect &rect) | 777 static int boundingBoxLogicalHeight(LayoutObject *o, const IntRect &rect) |
778 { | 778 { |
779 return o->style()->isHorizontalWritingMode() ? rect.height() : rect.width(); | 779 return o->style()->isHorizontalWritingMode() ? rect.height() : rect.width(); |
780 } | 780 } |
781 | 781 |
782 bool Position::hasRenderedNonAnonymousDescendantsWithHeight(LayoutObject* render
er) | 782 bool Position::hasRenderedNonAnonymousDescendantsWithHeight(LayoutObject* render
er) |
783 { | 783 { |
784 LayoutObject* stop = renderer->nextInPreOrderAfterChildren(); | 784 LayoutObject* stop = renderer->nextInPreOrderAfterChildren(); |
785 for (LayoutObject *o = renderer->slowFirstChild(); o && o != stop; o = o->ne
xtInPreOrder()) | 785 for (LayoutObject *o = renderer->slowFirstChild(); o && o != stop; o = o->ne
xtInPreOrder()) |
786 if (o->nonPseudoNode()) { | 786 if (o->nonPseudoNode()) { |
787 if ((o->isText() && boundingBoxLogicalHeight(o, toRenderText(o)->lin
esBoundingBox())) | 787 if ((o->isText() && boundingBoxLogicalHeight(o, toLayoutText(o)->lin
esBoundingBox())) |
788 || (o->isBox() && toLayoutBox(o)->pixelSnappedLogicalHeight()) | 788 || (o->isBox() && toLayoutBox(o)->pixelSnappedLogicalHeight()) |
789 || (o->isLayoutInline() && isEmptyInline(o) && boundingBoxLogica
lHeight(o, toLayoutInline(o)->linesBoundingBox()))) | 789 || (o->isLayoutInline() && isEmptyInline(o) && boundingBoxLogica
lHeight(o, toLayoutInline(o)->linesBoundingBox()))) |
790 return true; | 790 return true; |
791 } | 791 } |
792 return false; | 792 return false; |
793 } | 793 } |
794 | 794 |
795 bool Position::nodeIsUserSelectNone(Node* node) | 795 bool Position::nodeIsUserSelectNone(Node* node) |
796 { | 796 { |
797 return node && node->renderer() && !node->renderer()->isSelectable(); | 797 return node && node->renderer() && !node->renderer()->isSelectable(); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
872 | 872 |
873 bool Position::inRenderedText() const | 873 bool Position::inRenderedText() const |
874 { | 874 { |
875 if (isNull() || !deprecatedNode()->isTextNode()) | 875 if (isNull() || !deprecatedNode()->isTextNode()) |
876 return false; | 876 return false; |
877 | 877 |
878 LayoutObject* renderer = deprecatedNode()->renderer(); | 878 LayoutObject* renderer = deprecatedNode()->renderer(); |
879 if (!renderer) | 879 if (!renderer) |
880 return false; | 880 return false; |
881 | 881 |
882 RenderText *textRenderer = toRenderText(renderer); | 882 LayoutText* textRenderer = toLayoutText(renderer); |
883 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->next
TextBox()) { | 883 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->next
TextBox()) { |
884 if (m_offset < static_cast<int>(box->start()) && !textRenderer->contains
ReversedText()) { | 884 if (m_offset < static_cast<int>(box->start()) && !textRenderer->contains
ReversedText()) { |
885 // The offset we're looking for is before this node | 885 // The offset we're looking for is before this node |
886 // this means the offset must be in content that is | 886 // this means the offset must be in content that is |
887 // not rendered. Return false. | 887 // not rendered. Return false. |
888 return false; | 888 return false; |
889 } | 889 } |
890 if (box->containsCaretOffset(m_offset)) | 890 if (box->containsCaretOffset(m_offset)) |
891 // Return false for offsets inside composed characters. | 891 // Return false for offsets inside composed characters. |
892 return m_offset == 0 || m_offset == textRenderer->nextOffset(textRen
derer->previousOffset(m_offset)); | 892 return m_offset == 0 || m_offset == textRenderer->nextOffset(textRen
derer->previousOffset(m_offset)); |
893 } | 893 } |
894 | 894 |
895 return false; | 895 return false; |
896 } | 896 } |
897 | 897 |
898 bool Position::isRenderedCharacter() const | 898 bool Position::isRenderedCharacter() const |
899 { | 899 { |
900 if (isNull() || !deprecatedNode()->isTextNode()) | 900 if (isNull() || !deprecatedNode()->isTextNode()) |
901 return false; | 901 return false; |
902 | 902 |
903 LayoutObject* renderer = deprecatedNode()->renderer(); | 903 LayoutObject* renderer = deprecatedNode()->renderer(); |
904 if (!renderer) | 904 if (!renderer) |
905 return false; | 905 return false; |
906 | 906 |
907 RenderText* textRenderer = toRenderText(renderer); | 907 LayoutText* textRenderer = toLayoutText(renderer); |
908 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->next
TextBox()) { | 908 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->next
TextBox()) { |
909 if (m_offset < static_cast<int>(box->start()) && !textRenderer->contains
ReversedText()) { | 909 if (m_offset < static_cast<int>(box->start()) && !textRenderer->contains
ReversedText()) { |
910 // The offset we're looking for is before this node | 910 // The offset we're looking for is before this node |
911 // this means the offset must be in content that is | 911 // this means the offset must be in content that is |
912 // not rendered. Return false. | 912 // not rendered. Return false. |
913 return false; | 913 return false; |
914 } | 914 } |
915 if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast
<int>(box->start() + box->len())) | 915 if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast
<int>(box->start() + box->len())) |
916 return true; | 916 return true; |
917 } | 917 } |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1025 for (LayoutObject* next = renderer->nextInPreOrder(container); next; next =
next->nextInPreOrder(container)) { | 1025 for (LayoutObject* next = renderer->nextInPreOrder(container); next; next =
next->nextInPreOrder(container)) { |
1026 if (next->isLayoutBlock()) | 1026 if (next->isLayoutBlock()) |
1027 return 0; | 1027 return 0; |
1028 if (next->isBR()) | 1028 if (next->isBR()) |
1029 return 0; | 1029 return 0; |
1030 if (isNonTextLeafChild(next)) | 1030 if (isNonTextLeafChild(next)) |
1031 return 0; | 1031 return 0; |
1032 if (next->isText()) { | 1032 if (next->isText()) { |
1033 InlineTextBox* match = 0; | 1033 InlineTextBox* match = 0; |
1034 int minOffset = INT_MAX; | 1034 int minOffset = INT_MAX; |
1035 for (InlineTextBox* box = toRenderText(next)->firstTextBox(); box; b
ox = box->nextTextBox()) { | 1035 for (InlineTextBox* box = toLayoutText(next)->firstTextBox(); box; b
ox = box->nextTextBox()) { |
1036 int caretMinOffset = box->caretMinOffset(); | 1036 int caretMinOffset = box->caretMinOffset(); |
1037 if (caretMinOffset < minOffset) { | 1037 if (caretMinOffset < minOffset) { |
1038 match = box; | 1038 match = box; |
1039 minOffset = caretMinOffset; | 1039 minOffset = caretMinOffset; |
1040 } | 1040 } |
1041 } | 1041 } |
1042 if (match) | 1042 if (match) |
1043 return match; | 1043 return match; |
1044 } | 1044 } |
1045 } | 1045 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1086 | 1086 |
1087 equivalent.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineB
ox, caretOffset); | 1087 equivalent.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineB
ox, caretOffset); |
1088 return; | 1088 return; |
1089 } | 1089 } |
1090 if (renderer->isBox()) { | 1090 if (renderer->isBox()) { |
1091 inlineBox = toLayoutBox(renderer)->inlineBoxWrapper(); | 1091 inlineBox = toLayoutBox(renderer)->inlineBoxWrapper(); |
1092 if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && care
tOffset < inlineBox->caretMaxOffset())) | 1092 if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && care
tOffset < inlineBox->caretMaxOffset())) |
1093 return; | 1093 return; |
1094 } | 1094 } |
1095 } else { | 1095 } else { |
1096 RenderText* textRenderer = toRenderText(renderer); | 1096 LayoutText* textRenderer = toLayoutText(renderer); |
1097 | 1097 |
1098 InlineTextBox* box; | 1098 InlineTextBox* box; |
1099 InlineTextBox* candidate = 0; | 1099 InlineTextBox* candidate = 0; |
1100 | 1100 |
1101 for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox())
{ | 1101 for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox())
{ |
1102 int caretMinOffset = box->caretMinOffset(); | 1102 int caretMinOffset = box->caretMinOffset(); |
1103 int caretMaxOffset = box->caretMaxOffset(); | 1103 int caretMaxOffset = box->caretMaxOffset(); |
1104 | 1104 |
1105 if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset ||
(caretOffset == caretMaxOffset && box->isLineBreak())) | 1105 if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset ||
(caretOffset == caretMaxOffset && box->isLineBreak())) |
1106 continue; | 1106 continue; |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1313 pos.showTreeForThis(); | 1313 pos.showTreeForThis(); |
1314 } | 1314 } |
1315 | 1315 |
1316 void showTree(const blink::Position* pos) | 1316 void showTree(const blink::Position* pos) |
1317 { | 1317 { |
1318 if (pos) | 1318 if (pos) |
1319 pos->showTreeForThis(); | 1319 pos->showTreeForThis(); |
1320 } | 1320 } |
1321 | 1321 |
1322 #endif | 1322 #endif |
OLD | NEW |