Commit acef81d1 authored by justing's avatar justing
Browse files

LayoutTests:

        Reviewed by levi

        * editing/selection/editable-non-editable-crash-expected.checksum: Added.
        * editing/selection/editable-non-editable-crash-expected.png: Added.
        * editing/selection/editable-non-editable-crash-expected.txt: Added.
        * editing/selection/editable-non-editable-crash.html: Added.
        * editing/selection/skip-non-editable-1-expected.txt:
        * editing/selection/skip-non-editable-1.html:

WebCore:

        Reviewed by levi
        
        Fix Mail ToDo crashers.

        * dom/Range.cpp:
        (WebCore::Range::compareBoundaryPoints): Added an ASSERT that both
        containers are non-null and an early return.
        * editing/Selection.cpp:
        (WebCore::Selection::validate): Fix a dangling start/end.
        (WebCore::Selection::adjustForEditableContent): Added an early return if
        m_start or m_end are null.
        (WebCore::Selection::isContentEditable): Use isRichlyEditablePosition.
        (WebCore::Selection::isContentRichlyEditable): Ditto.
        * editing/Selection.h:
        * editing/VisiblePosition.cpp:
        (WebCore::VisiblePosition::next): Use the new highestEditableRoot.
        (WebCore::VisiblePosition::previous): Ditto.
        * editing/htmlediting.cpp:
        (WebCore::highestEditableRoot): Takes in a position.
        (WebCore::isEditablePosition): Added.
        (WebCore::isRichlyEditablePosition): Added.
        (WebCore::rootEditableElement): Added.
        (WebCore::nextCandidate): Moved and split out from nextVisiblePosition.
        (WebCore::nextVisuallyDistinctCandidate): Ditto.
        (WebCore::previousCandidate): Moved and split out from previousVisiblePosition.
        (WebCore::previousVisuallyDistinctCandidate): Ditto.
        (WebCore::firstEditablePositionAfterPositionInRoot): Iterate over positions,
        using nextVisuallyDistinctCandidate, skipping atomic nodes that are non-editable.
        (WebCore::lastEditablePositionBeforePositionInRoot): Ditto.
        * editing/htmlediting.h:
        * editing/visible_units.cpp:
        (WebCore::startOfWord): Added a FIXME.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@15226 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 2564df29
2006-07-07 Justin Garcia <justin.garcia@apple.com>
Reviewed by levi
* editing/selection/editable-non-editable-crash-expected.checksum: Added.
* editing/selection/editable-non-editable-crash-expected.png: Added.
* editing/selection/editable-non-editable-crash-expected.txt: Added.
* editing/selection/editable-non-editable-crash.html: Added.
* editing/selection/skip-non-editable-1-expected.txt:
* editing/selection/skip-non-editable-1.html:
2006-07-07 Levi Weintraub <lweintraub@apple.com>
 
Reviewed by NOBODY
ebd6d307301e73acdbf6f85451b4e575
\ No newline at end of file
EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 1 of DIV > BODY > HTML > #document
EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x600
RenderBlock {HTML} at (0,0) size 800x600
RenderBody {BODY} at (8,8) size 784x584
RenderBlock {DIV} at (0,0) size 784x46
RenderTable {TABLE} at (0,0) size 784x46 [border: (1px solid #AAAAAA)]
RenderTableSection {TBODY} at (1,1) size 782x44
RenderTableRow {TR} at (0,2) size 782x40
RenderTableCell {TD} at (2,2) size 778x40 [border: (1px solid #AAAAAA)] [r=0 c=0 rs=1 cs=1]
RenderText {#text} at (2,2) size 773x36
text run at (2,2) width 773: "This tests for a Mail crasher that happened when a selection was created with one endpoint in non-editable content and the "
text run at (2,20) width 155: "other in editable content."
caret: position 0 of child 0 {TABLE} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
<head><style>
table, td {
border: 1px solid #aaa;
}
</style></head>
<body>
<div contenteditable="true"><table style="border: 1px solid #aaa" id="base"><tr><td id="extent" contenteditable="false">This tests for a Mail crasher that happened when a selection was created with one endpoint in non-editable content and the other in editable content.</td></tr></table></div>
<script>
var s = window.getSelection();
var b = document.getElementById("base");
var e = document.getElementById("extent");
s.setBaseAndExtent(b, 0, e, 0);
</script>
</body>
\ No newline at end of file
EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of BODY > HTML > #document to 13 of BODY > HTML > #document
EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldEndEditingInDOMRange:range from 0 of BODY > HTML > #document to 13 of BODY > HTML > #document
EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification
EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of TD > TR > TBODY > TABLE > BODY > HTML > #document to 1 of TD > TR > TBODY > TABLE > BODY > HTML > #document
EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldEndEditingInDOMRange:range from 0 of TD > TR > TBODY > TABLE > BODY > HTML > #document to 1 of TD > TR > TBODY > TABLE > BODY > HTML > #document
EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification
EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of BODY > HTML > #document to 13 of BODY > HTML > #document
......@@ -16,11 +18,13 @@ EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification
EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of TD > TR > TBODY > TABLE > BODY > HTML > #document to 1 of TD > TR > TBODY > TABLE > BODY > HTML > #document
EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldEndEditingInDOMRange:range from 0 of TD > TR > TBODY > TABLE > BODY > HTML > #document to 1 of TD > TR > TBODY > TABLE > BODY > HTML > #document
EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification
EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of BODY > HTML > #document to 13 of BODY > HTML > #document
EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
EDITING DELEGATE: shouldEndEditingInDOMRange:range from 0 of BODY > HTML > #document to 13 of BODY > HTML > #document
EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification
EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of TD > TR > TBODY > TABLE > BODY > HTML > #document to 1 of TD > TR > TBODY > TABLE > BODY > HTML > #document
......
......@@ -47,15 +47,19 @@ var e3 = document.getElementById("e3");
s.setPosition(e1.firstChild, e1.firstChild.length);
s.modify("move", "forward", "character");
s.modify("move", "forward", "character");
assert(s.anchorNode == e2.firstChild && s.anchorOffset == 0);
s.modify("move", "backward", "character");
s.modify("move", "backward", "character");
assert(s.anchorNode == e1.firstChild && s.anchorOffset == e1.firstChild.length);
s.setPosition(e2.firstChild, e2.firstChild.length);
s.modify("move", "forward", "character");
s.modify("move", "forward", "character");
assert(s.anchorNode == e3.firstChild && s.anchorOffset == 0);
s.modify("move", "backward", "character");
s.modify("move", "backward", "character");
assert(s.anchorNode == e2.firstChild && s.anchorOffset == e2.firstChild.length)
</script>
\ No newline at end of file
2006-07-07 Justin Garcia <justin.garcia@apple.com>
Reviewed by levi
Fix Mail ToDo crashers.
* dom/Range.cpp:
(WebCore::Range::compareBoundaryPoints): Added an ASSERT that both
containers are non-null and an early return.
* editing/Selection.cpp:
(WebCore::Selection::validate): Fix a dangling start/end.
(WebCore::Selection::adjustForEditableContent): Added an early return if
m_start or m_end are null.
(WebCore::Selection::isContentEditable): Use isRichlyEditablePosition.
(WebCore::Selection::isContentRichlyEditable): Ditto.
* editing/Selection.h:
* editing/VisiblePosition.cpp:
(WebCore::VisiblePosition::next): Use the new highestEditableRoot.
(WebCore::VisiblePosition::previous): Ditto.
* editing/htmlediting.cpp:
(WebCore::highestEditableRoot): Takes in a position.
(WebCore::isEditablePosition): Added.
(WebCore::isRichlyEditablePosition): Added.
(WebCore::rootEditableElement): Added.
(WebCore::nextCandidate): Moved and split out from nextVisiblePosition.
(WebCore::nextVisuallyDistinctCandidate): Ditto.
(WebCore::previousCandidate): Moved and split out from previousVisiblePosition.
(WebCore::previousVisuallyDistinctCandidate): Ditto.
(WebCore::firstEditablePositionAfterPositionInRoot): Iterate over positions,
using nextVisuallyDistinctCandidate, skipping atomic nodes that are non-editable.
(WebCore::lastEditablePositionBeforePositionInRoot): Ditto.
* editing/htmlediting.h:
* editing/visible_units.cpp:
(WebCore::startOfWord): Added a FIXME.
2006-07-07 Levi Weintraub <lweintraub@apple.com>
Reviewed by justin
......
......@@ -1586,6 +1586,23 @@
FAE04190097596C9000540BE /* SVGImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = FAE0418E097596C9000540BE /* SVGImageLoader.h */; };
/* End PBXBuildFile section */
 
/* Begin PBXBuildStyle section */
D041FC250A5E04A700841F7F /* Development */ = {
isa = PBXBuildStyle;
buildSettings = {
COPY_PHASE_STRIP = NO;
};
name = Development;
};
D041FC260A5E04A700841F7F /* Deployment */ = {
isa = PBXBuildStyle;
buildSettings = {
COPY_PHASE_STRIP = YES;
};
name = Deployment;
};
/* End PBXBuildStyle section */
/* Begin PBXContainerItemProxy section */
DD041FF009D9E3250010AF2A /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
......@@ -6441,6 +6458,12 @@
0867D690FE84028FC02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 149C284308902B11008A9EFC /* Build configuration list for PBXProject "WebCore" */;
buildSettings = {
};
buildStyles = (
D041FC250A5E04A700841F7F /* Development */,
D041FC260A5E04A700841F7F /* Deployment */,
);
hasScannedForEncodings = 1;
knownRegions = (
English,
......
......@@ -388,6 +388,11 @@ short Range::compareBoundaryPoints(CompareHow how, const Range *sourceRange, Exc
short Range::compareBoundaryPoints( Node *containerA, int offsetA, Node *containerB, int offsetB )
{
ASSERT(containerA && containerB);
if (!containerA)
return -1;
if (!containerB)
return 1;
// see DOM2 traversal & range section 2.5
// case 1: both points have the same container
......
......@@ -160,7 +160,7 @@ void Selection::validate()
if (m_extent.isNotNull() && !baseAndExtentEqual)
m_extent = VisiblePosition(m_extent, m_affinity).deepEquivalent();
// Make sure we do not have a dangling start or end
// Make sure we do not have a dangling base or extent.
if (m_base.isNull() && m_extent.isNull())
m_baseIsFirst = true;
else if (m_base.isNull()) {
......@@ -258,6 +258,12 @@ void Selection::validate()
break;
}
// Make sure we do not have a dangling start or end.
if (m_start.isNull())
m_start = m_end;
if (m_end.isNull())
m_end = m_start;
adjustForEditableContent();
// adjust the state
......@@ -290,7 +296,7 @@ void Selection::validate()
void Selection::adjustForEditableContent()
{
if (m_base.isNull())
if (m_base.isNull() || m_start.isNull() || m_end.isNull())
return;
Node *baseRoot = m_base.node()->rootEditableElement();
......@@ -372,6 +378,21 @@ void Selection::adjustForEditableContent()
m_extent = m_baseIsFirst ? m_end : m_start;
}
bool Selection::isContentEditable() const
{
return isEditablePosition(start());
}
bool Selection::isContentRichlyEditable() const
{
return isRichlyEditablePosition(start());
}
Element* Selection::rootEditableElement() const
{
return editableRootForPosition(start());
}
void Selection::debugPosition() const
{
if (!m_start.node())
......
......@@ -75,9 +75,9 @@ public:
PassRefPtr<Range> toRange() const;
Element* rootEditableElement() const { return start().node() ? start().node()->rootEditableElement() : 0; }
bool isContentEditable() const { return start().node() ? start().node()->isContentEditable() : false; }
bool isContentRichlyEditable() const { return start().node() ? start().node()->isContentRichlyEditable() : false; }
Element* rootEditableElement() const;
bool isContentEditable() const;
bool isContentRichlyEditable() const;
void debugPosition() const;
......
......@@ -67,12 +67,12 @@ VisiblePosition VisiblePosition::next(bool stayInEditableContent) const
if (!stayInEditableContent || next.isNull())
return next;
Node* highestRoot = highestEditableRoot(deepEquivalent().node());
Node* highestRoot = highestEditableRoot(deepEquivalent());
if (!next.deepEquivalent().node()->isAncestor(highestRoot))
return VisiblePosition();
if (highestEditableRoot(next.deepEquivalent().node()) == highestRoot)
if (highestEditableRoot(next.deepEquivalent()) == highestRoot)
return next;
return firstEditablePositionAfterPositionInRoot(next.deepEquivalent(), highestRoot);
......@@ -103,12 +103,12 @@ VisiblePosition VisiblePosition::previous(bool stayInEditableContent) const
if (!stayInEditableContent || prev.isNull())
return prev;
Node* highestRoot = highestEditableRoot(deepEquivalent().node());
Node* highestRoot = highestEditableRoot(deepEquivalent());
if (!prev.deepEquivalent().node()->isAncestor(highestRoot))
return VisiblePosition();
if (highestEditableRoot(prev.deepEquivalent().node()) == highestRoot)
if (highestEditableRoot(prev.deepEquivalent()) == highestRoot)
return prev;
return lastEditablePositionBeforePositionInRoot(prev.deepEquivalent(), highestRoot);
......
......@@ -120,12 +120,13 @@ int comparePositions(const Position& a, const Position& b)
return Range::compareBoundaryPoints(nodeA, offsetA, nodeB, offsetB);
}
Node* highestEditableRoot(Node* node)
Node* highestEditableRoot(const Position& position)
{
Node* node = position.node();
if (!node)
return 0;
Node* highestRoot = node->rootEditableElement();
Node* highestRoot = editableRootForPosition(position);
if (!highestRoot)
return 0;
......@@ -158,40 +159,110 @@ Node* lowestEditableAncestor(Node* node)
return lowestRoot;
}
bool isEditablePosition(const Position& p)
{
Node* node = p.node();
if (!node)
return false;
if (node->renderer() && node->renderer()->isTable())
node = node->parentNode();
return node->isContentEditable();
}
bool isRichlyEditablePosition(const Position& p)
{
Node* node = p.node();
if (!node)
return false;
if (node->renderer() && node->renderer()->isTable())
node = node->parentNode();
return node->isContentRichlyEditable();
}
Element* editableRootForPosition(const Position& p)
{
Node* node = p.node();
if (!node)
return 0;
if (node->renderer() && node->renderer()->isTable())
node = node->parentNode();
return node->rootEditableElement();
}
Position nextCandidate(const Position& position)
{
Position p = position;
while (!p.atEnd()) {
p = p.next(UsingComposedCharacters);
if (p.inRenderedContent())
return p;
}
return Position();
}
Position nextVisuallyDistinctCandidate(const Position& position)
{
Position p = position;
Position downstreamStart = p.downstream();
while (!p.atEnd()) {
p = p.next(UsingComposedCharacters);
if (p.inRenderedContent() && p.downstream() != downstreamStart)
return p;
}
return Position();
}
Position previousCandidate(const Position& position)
{
Position p = position;
while (!p.atStart()) {
p = p.previous(UsingComposedCharacters);
if (p.inRenderedContent())
return p;
}
return Position();
}
Position previousVisuallyDistinctCandidate(const Position& position)
{
Position p = position;
Position downstreamStart = p.downstream();
while (!p.atStart()) {
p = p.previous(UsingComposedCharacters);
if (p.inRenderedContent() && p.downstream() != downstreamStart)
return p;
}
return Position();
}
VisiblePosition firstEditablePositionAfterPositionInRoot(const Position& position, Node* highestRoot)
{
if (comparePositions(position, Position(highestRoot, 0)) == -1)
return VisiblePosition(Position(highestRoot, 0));
Node* node = position.node();
Node* child = node->childNode(position.offset());
node = child ? child : node->traverseNextSibling(highestRoot);
while (node && !node->isContentEditable())
node = node->traverseNextNode(highestRoot);
if (!node)
return VisiblePosition();
Position p = nextVisuallyDistinctCandidate(position);
while (p.isNotNull() && !isEditablePosition(p) && p.node()->isAncestor(highestRoot))
p = isAtomicNode(p.node()) ? positionAfterNode(p.node()) : nextVisuallyDistinctCandidate(p);
return VisiblePosition(Position(node, 0));
return VisiblePosition(p);
}
VisiblePosition lastEditablePositionBeforePositionInRoot(const Position& position, Node* highestRoot)
{
if (comparePositions(position, Position(highestRoot, maxDeepOffset(highestRoot))) == 1)
return VisiblePosition(Position(highestRoot, maxDeepOffset(highestRoot)));
Node* node = position.node();
Node* child = node->firstChild() && position.offset() > 1 ? node->childNode(position.offset() - 1) : 0;
node = child ? child : node->traversePreviousNode(highestRoot);
while (node && !node->isContentEditable())
node = node->traversePreviousNodePostOrder(highestRoot);
if (!node)
return VisiblePosition();
return VisiblePosition(Position(node, maxDeepOffset(node)));
Position p = previousVisuallyDistinctCandidate(position);
while (p.isNotNull() && !isEditablePosition(p) && p.node()->isAncestor(highestRoot))
p = isAtomicNode(p.node()) ? positionBeforeNode(p.node()) : previousVisuallyDistinctCandidate(p);
return VisiblePosition(p);
}
// antidote for maxDeepOffset()
......
......@@ -46,11 +46,18 @@ int maxDeepOffset(const Node*);
bool isAtomicNode(const Node*);
bool editingIgnoresContent(const Node*);
bool canHaveChildrenForEditing(const Node*);
Node* highestEditableRoot(Node*);
Node* highestEditableRoot(const Position&);
VisiblePosition firstEditablePositionAfterPositionInRoot(const Position&, Node*);
VisiblePosition lastEditablePositionBeforePositionInRoot(const Position&, Node*);
int comparePositions(const Position&, const Position&);
Node* lowestEditableAncestor(Node*);
Position nextCandidate(const Position&);
Position nextVisuallyDistinctCandidate(const Position&);
Position previousCandidate(const Position&);
Position previousVisuallyDistinctCandidate(const Position&);
bool isEditablePosition(const Position&);
bool isRichlyEditablePosition(const Position&);
Element* editableRootForPosition(const Position&);
void rebalanceWhitespaceInTextNode(Node*, unsigned start, unsigned length);
const String& nonBreakingSpaceString();
......
......@@ -193,6 +193,8 @@ static unsigned startWordBoundary(const UChar* characters, unsigned length)
VisiblePosition startOfWord(const VisiblePosition &c, EWordSide side)
{
// FIXME: This returns a null VP for c at the start of the document
// and side == LeftWordIfOnBoundary
VisiblePosition p = c;
if (side == RightWordIfOnBoundary) {
// at paragraph end, the startofWord is the current position
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment