зеркало из https://github.com/mozilla/gecko-dev.git
Bug 768748 part 2 - Rewrite nsHTMLEditRules::GetPromotedPoint; r=ehsan
This commit is contained in:
Родитель
37d4deed65
Коммит
2760d35ada
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html contenteditable="true">
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
var looseText = document.createTextNode("x");
|
||||
window.getSelection().collapse(looseText, 0);
|
||||
document.queryCommandState("insertorderedlist");
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="setTimeout(boom, 0)"></body>
|
||||
</html>
|
|
@ -33,3 +33,4 @@ load 766305.html
|
|||
load 766387.html
|
||||
load 766795.html
|
||||
load 767169.html
|
||||
load 768748.html
|
||||
|
|
|
@ -59,7 +59,7 @@ enum
|
|||
};
|
||||
|
||||
/********************************************************
|
||||
* first some helpful funcotrs we will use
|
||||
* first some helpful functors we will use
|
||||
********************************************************/
|
||||
|
||||
static bool IsBlockNode(nsIDOMNode* node)
|
||||
|
@ -5268,201 +5268,176 @@ nsHTMLEditRules::NormalizeSelection(nsISelection *inSelection)
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetPromotedPoint: figure out where a start or end point for a block
|
||||
// operation really is
|
||||
nsresult
|
||||
nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode,
|
||||
void
|
||||
nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode* aNode,
|
||||
PRInt32 aOffset,
|
||||
nsEditor::OperationID actionID,
|
||||
nsCOMPtr<nsIDOMNode> *outNode,
|
||||
PRInt32 *outOffset)
|
||||
nsCOMPtr<nsIDOMNode>* outNode,
|
||||
PRInt32* outOffset)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> nearNode, node = aNode;
|
||||
nsCOMPtr<nsIDOMNode> parent = aNode;
|
||||
PRInt32 pOffset, offset = aOffset;
|
||||
|
||||
// default values
|
||||
*outNode = node;
|
||||
*outOffset = offset;
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
|
||||
MOZ_ASSERT(node && outNode && outOffset);
|
||||
|
||||
// we do one thing for text actions, something else entirely for other actions
|
||||
// default values
|
||||
*outNode = node->AsDOMNode();
|
||||
*outOffset = aOffset;
|
||||
|
||||
// we do one thing for text actions, something else entirely for other
|
||||
// actions
|
||||
if (actionID == nsEditor::kOpInsertText ||
|
||||
actionID == nsEditor::kOpInsertIMEText ||
|
||||
actionID == nsEditor::kOpInsertBreak ||
|
||||
actionID == nsEditor::kOpDeleteText)
|
||||
{
|
||||
actionID == nsEditor::kOpDeleteText) {
|
||||
bool isSpace, isNBSP;
|
||||
nsCOMPtr<nsIContent> temp;
|
||||
// for text actions, we want to look backwards (or forwards, as appropriate)
|
||||
// for additional whitespace or nbsp's. We may have to act on these later even though
|
||||
// they are outside of the initial selection. Even if they are in another node!
|
||||
if (aWhere == kStart)
|
||||
{
|
||||
do
|
||||
{
|
||||
PRInt32 prevOffset;
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
|
||||
mHTMLEditor->IsPrevCharInNodeWhitespace(content, offset, &isSpace,
|
||||
&isNBSP, getter_AddRefs(temp),
|
||||
&prevOffset);
|
||||
if (isSpace || isNBSP) {
|
||||
node = temp->AsDOMNode();
|
||||
offset = prevOffset;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (node);
|
||||
|
||||
*outNode = node;
|
||||
*outOffset = offset;
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(node), temp;
|
||||
// for text actions, we want to look backwards (or forwards, as
|
||||
// appropriate) for additional whitespace or nbsp's. We may have to act on
|
||||
// these later even though they are outside of the initial selection. Even
|
||||
// if they are in another node!
|
||||
while (content) {
|
||||
PRInt32 offset;
|
||||
if (aWhere == kStart) {
|
||||
mHTMLEditor->IsPrevCharInNodeWhitespace(content, *outOffset,
|
||||
&isSpace, &isNBSP,
|
||||
getter_AddRefs(temp), &offset);
|
||||
} else {
|
||||
mHTMLEditor->IsNextCharInNodeWhitespace(content, *outOffset,
|
||||
&isSpace, &isNBSP,
|
||||
getter_AddRefs(temp), &offset);
|
||||
}
|
||||
if (isSpace || isNBSP) {
|
||||
content = temp;
|
||||
*outOffset = offset;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (aWhere == kEnd)
|
||||
{
|
||||
do
|
||||
{
|
||||
PRInt32 nextOffset;
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
|
||||
mHTMLEditor->IsNextCharInNodeWhitespace(content, offset, &isSpace,
|
||||
&isNBSP, getter_AddRefs(temp),
|
||||
&nextOffset);
|
||||
if (isSpace || isNBSP) {
|
||||
node = temp->AsDOMNode();
|
||||
offset = nextOffset;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (node);
|
||||
|
||||
*outNode = node;
|
||||
*outOffset = offset;
|
||||
}
|
||||
return NS_OK;
|
||||
*outNode = content->AsDOMNode();
|
||||
return;
|
||||
}
|
||||
|
||||
// else not a text section. In this case we want to see if we should
|
||||
// grab any adjacent inline nodes and/or parents and other ancestors
|
||||
nsresult res = NS_OK;
|
||||
if (aWhere == kStart)
|
||||
{
|
||||
PRInt32 offset = aOffset;
|
||||
|
||||
// else not a text section. In this case we want to see if we should grab
|
||||
// any adjacent inline nodes and/or parents and other ancestors
|
||||
if (aWhere == kStart) {
|
||||
// some special casing for text nodes
|
||||
if (nsEditor::IsTextNode(aNode))
|
||||
{
|
||||
res = nsEditor::GetNodeLocation(aNode, address_of(node), &offset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
if (node->IsNodeOfType(nsINode::eTEXT)) {
|
||||
if (!node->GetNodeParent()) {
|
||||
// Okay, can't promote any further
|
||||
return;
|
||||
}
|
||||
offset = node->GetNodeParent()->IndexOf(node);
|
||||
node = node->GetNodeParent();
|
||||
}
|
||||
|
||||
// look back through any further inline nodes that
|
||||
// aren't across a <br> from us, and that are enclosed in the same block.
|
||||
nsCOMPtr<nsIDOMNode> priorNode;
|
||||
res = mHTMLEditor->GetPriorHTMLNode(node, offset, address_of(priorNode), true);
|
||||
|
||||
while (priorNode && NS_SUCCEEDED(res))
|
||||
{
|
||||
if (mHTMLEditor->IsVisBreak(priorNode))
|
||||
break;
|
||||
if (IsBlockNode(priorNode))
|
||||
break;
|
||||
res = nsEditor::GetNodeLocation(priorNode, address_of(node), &offset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
res = mHTMLEditor->GetPriorHTMLNode(node, offset, address_of(priorNode), true);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
}
|
||||
|
||||
|
||||
// finding the real start for this point. look up the tree for as long as we are the
|
||||
// first node in the container, and as long as we haven't hit the body node.
|
||||
res = mHTMLEditor->GetPriorHTMLNode(node, offset, address_of(nearNode), true);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
while (!nearNode && !nsTextEditUtils::IsBody(node))
|
||||
{
|
||||
// some cutoffs are here: we don't need to also include them in the aWhere == kEnd case.
|
||||
// as long as they are in one or the other it will work.
|
||||
// special case for outdent: don't keep looking up
|
||||
// if we have found a blockquote element to act on
|
||||
if ((actionID == nsHTMLEditor::kOpOutdent) && nsHTMLEditUtils::IsBlockquote(node))
|
||||
break;
|
||||
// look back through any further inline nodes that aren't across a <br>
|
||||
// from us, and that are enclosed in the same block.
|
||||
nsCOMPtr<nsINode> priorNode =
|
||||
mHTMLEditor->GetPriorHTMLNode(node, offset, true);
|
||||
|
||||
res = nsEditor::GetNodeLocation(node, address_of(parent), &pOffset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
while (priorNode && priorNode->GetNodeParent() &&
|
||||
!mHTMLEditor->IsVisBreak(priorNode->AsDOMNode()) &&
|
||||
!IsBlockNode(priorNode->AsDOMNode())) {
|
||||
offset = priorNode->GetNodeParent()->IndexOf(priorNode);
|
||||
node = priorNode->GetNodeParent();
|
||||
priorNode = mHTMLEditor->GetPriorHTMLNode(node, offset, true);
|
||||
}
|
||||
|
||||
// finding the real start for this point. look up the tree for as long as
|
||||
// we are the first node in the container, and as long as we haven't hit
|
||||
// the body node.
|
||||
nsCOMPtr<nsIContent> nearNode =
|
||||
mHTMLEditor->GetPriorHTMLNode(node, offset, true);
|
||||
while (!nearNode && node->Tag() != nsGkAtoms::body &&
|
||||
node->GetNodeParent()) {
|
||||
// some cutoffs are here: we don't need to also include them in the
|
||||
// aWhere == kEnd case. as long as they are in one or the other it will
|
||||
// work. special case for outdent: don't keep looking up if we have
|
||||
// found a blockquote element to act on
|
||||
if (actionID == nsHTMLEditor::kOpOutdent &&
|
||||
node->Tag() == nsGkAtoms::blockquote) {
|
||||
break;
|
||||
}
|
||||
|
||||
PRInt32 parentOffset = node->GetNodeParent()->IndexOf(node);
|
||||
nsCOMPtr<nsINode> parent = node->GetNodeParent();
|
||||
|
||||
// Don't walk past the editable section. Note that we need to check
|
||||
// before walking up to a parent because we need to return the parent
|
||||
// object, so the parent itself might not be in the editable area, but
|
||||
// it's OK if we're not performing a block-level action.
|
||||
bool blockLevelAction = (actionID == nsHTMLEditor::kOpIndent)
|
||||
|| (actionID == nsHTMLEditor::kOpOutdent)
|
||||
|| (actionID == nsHTMLEditor::kOpAlign)
|
||||
|| (actionID == nsHTMLEditor::kOpMakeBasicBlock);
|
||||
bool blockLevelAction = actionID == nsHTMLEditor::kOpIndent ||
|
||||
actionID == nsHTMLEditor::kOpOutdent ||
|
||||
actionID == nsHTMLEditor::kOpAlign ||
|
||||
actionID == nsHTMLEditor::kOpMakeBasicBlock;
|
||||
if (!mHTMLEditor->IsDescendantOfEditorRoot(parent) &&
|
||||
(blockLevelAction || !mHTMLEditor->IsDescendantOfEditorRoot(node))) {
|
||||
break;
|
||||
}
|
||||
|
||||
node = parent;
|
||||
offset = pOffset;
|
||||
res = mHTMLEditor->GetPriorHTMLNode(node, offset, address_of(nearNode), true);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
}
|
||||
*outNode = node;
|
||||
offset = parentOffset;
|
||||
nearNode = mHTMLEditor->GetPriorHTMLNode(node, offset, true);
|
||||
}
|
||||
*outNode = node->AsDOMNode();
|
||||
*outOffset = offset;
|
||||
return res;
|
||||
return;
|
||||
}
|
||||
|
||||
if (aWhere == kEnd)
|
||||
{
|
||||
// some special casing for text nodes
|
||||
if (nsEditor::IsTextNode(aNode))
|
||||
{
|
||||
res = nsEditor::GetNodeLocation(aNode, address_of(node), &offset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
offset++; // want to be after the text node
|
||||
|
||||
// aWhere == kEnd
|
||||
// some special casing for text nodes
|
||||
if (node->IsNodeOfType(nsINode::eTEXT)) {
|
||||
if (!node->GetNodeParent()) {
|
||||
// Okay, can't promote any further
|
||||
return;
|
||||
}
|
||||
// want to be after the text node
|
||||
offset = 1 + node->GetNodeParent()->IndexOf(node);
|
||||
node = node->GetNodeParent();
|
||||
}
|
||||
|
||||
// look ahead through any further inline nodes that aren't across a <br> from
|
||||
// us, and that are enclosed in the same block.
|
||||
nsCOMPtr<nsIContent> nextNode =
|
||||
mHTMLEditor->GetNextHTMLNode(node, offset, true);
|
||||
|
||||
while (nextNode && !IsBlockNode(nextNode->AsDOMNode()) &&
|
||||
nextNode->GetNodeParent()) {
|
||||
offset = 1 + nextNode->GetNodeParent()->IndexOf(nextNode);
|
||||
node = nextNode->GetNodeParent();
|
||||
if (mHTMLEditor->IsVisBreak(nextNode->AsDOMNode())) {
|
||||
break;
|
||||
}
|
||||
nextNode = mHTMLEditor->GetNextHTMLNode(node, offset, true);
|
||||
}
|
||||
|
||||
// finding the real end for this point. look up the tree for as long as we
|
||||
// are the last node in the container, and as long as we haven't hit the body
|
||||
// node.
|
||||
nsCOMPtr<nsIContent> nearNode =
|
||||
mHTMLEditor->GetNextHTMLNode(node, offset, true);
|
||||
while (!nearNode && node->Tag() != nsGkAtoms::body &&
|
||||
node->GetNodeParent()) {
|
||||
PRInt32 parentOffset = node->GetNodeParent()->IndexOf(node);
|
||||
nsCOMPtr<nsINode> parent = node->GetNodeParent();
|
||||
|
||||
// Don't walk past the editable section. Note that we need to check before
|
||||
// walking up to a parent because we need to return the parent object, so
|
||||
// the parent itself might not be in the editable area, but it's OK.
|
||||
if (!mHTMLEditor->IsDescendantOfEditorRoot(node) &&
|
||||
!mHTMLEditor->IsDescendantOfEditorRoot(parent)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// look ahead through any further inline nodes that
|
||||
// aren't across a <br> from us, and that are enclosed in the same block.
|
||||
nsCOMPtr<nsIDOMNode> nextNode;
|
||||
res = mHTMLEditor->GetNextHTMLNode(node, offset, address_of(nextNode), true);
|
||||
|
||||
while (nextNode && NS_SUCCEEDED(res))
|
||||
{
|
||||
if (IsBlockNode(nextNode))
|
||||
break;
|
||||
res = nsEditor::GetNodeLocation(nextNode, address_of(node), &offset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
offset++;
|
||||
if (mHTMLEditor->IsVisBreak(nextNode))
|
||||
break;
|
||||
res = mHTMLEditor->GetNextHTMLNode(node, offset, address_of(nextNode), true);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
}
|
||||
|
||||
// finding the real end for this point. look up the tree for as long as we are the
|
||||
// last node in the container, and as long as we haven't hit the body node.
|
||||
res = mHTMLEditor->GetNextHTMLNode(node, offset, address_of(nearNode), true);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
while (!nearNode && !nsTextEditUtils::IsBody(node))
|
||||
{
|
||||
res = nsEditor::GetNodeLocation(node, address_of(parent), &pOffset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
// Don't walk past the editable section. Note that we need to check
|
||||
// before walking up to a parent because we need to return the parent
|
||||
// object, so the parent itself might not be in the editable area, but
|
||||
// it's OK.
|
||||
if (!mHTMLEditor->IsDescendantOfEditorRoot(node) &&
|
||||
!mHTMLEditor->IsDescendantOfEditorRoot(parent)) {
|
||||
break;
|
||||
}
|
||||
|
||||
node = parent;
|
||||
offset = pOffset+1; // we want to be AFTER nearNode
|
||||
res = mHTMLEditor->GetNextHTMLNode(node, offset, address_of(nearNode), true);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
}
|
||||
*outNode = node;
|
||||
*outOffset = offset;
|
||||
return res;
|
||||
node = parent;
|
||||
// we want to be AFTER nearNode
|
||||
offset = parentOffset + 1;
|
||||
nearNode = mHTMLEditor->GetNextHTMLNode(node, offset, true);
|
||||
}
|
||||
|
||||
return res;
|
||||
*outNode = node->AsDOMNode();
|
||||
*outOffset = offset;
|
||||
}
|
||||
|
||||
|
||||
|
@ -5575,10 +5550,10 @@ nsHTMLEditRules::PromoteRange(nsIDOMRange *inRange,
|
|||
PRInt32 opStartOffset, opEndOffset;
|
||||
nsCOMPtr<nsIDOMRange> opRange;
|
||||
|
||||
res = GetPromotedPoint( kStart, startNode, startOffset, inOperationType, address_of(opStartNode), &opStartOffset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
res = GetPromotedPoint( kEnd, endNode, endOffset, inOperationType, address_of(opEndNode), &opEndOffset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
GetPromotedPoint(kStart, startNode, startOffset, inOperationType,
|
||||
address_of(opStartNode), &opStartOffset);
|
||||
GetPromotedPoint(kEnd, endNode, endOffset, inOperationType,
|
||||
address_of(opEndNode), &opEndOffset);
|
||||
|
||||
// Make sure that the new range ends up to be in the editable section.
|
||||
if (!mHTMLEditor->IsDescendantOfEditorRoot(nsEditor::GetNodeAtRangeOffsetPoint(opStartNode, opStartOffset)) ||
|
||||
|
|
|
@ -211,9 +211,9 @@ protected:
|
|||
bool IsFirstNode(nsIDOMNode *aNode);
|
||||
bool IsLastNode(nsIDOMNode *aNode);
|
||||
nsresult NormalizeSelection(nsISelection *inSelection);
|
||||
nsresult GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode *aNode,
|
||||
PRInt32 aOffset, nsEditor::OperationID actionID,
|
||||
nsCOMPtr<nsIDOMNode> *outNode, PRInt32 *outOffset);
|
||||
void GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode* aNode,
|
||||
PRInt32 aOffset, nsEditor::OperationID actionID,
|
||||
nsCOMPtr<nsIDOMNode>* outNode, PRInt32* outOffset);
|
||||
nsresult GetPromotedRanges(nsISelection *inSelection,
|
||||
nsCOMArray<nsIDOMRange> &outArrayOfRanges,
|
||||
nsEditor::OperationID inOperationType);
|
||||
|
|
|
@ -4161,6 +4161,17 @@ nsHTMLEditor::GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetPriorHTMLNode: same as above but takes {parent,offset} instead of node
|
||||
//
|
||||
nsIContent*
|
||||
nsHTMLEditor::GetPriorHTMLNode(nsINode* aParent, PRInt32 aOffset,
|
||||
bool aNoBlockCrossing)
|
||||
{
|
||||
if (!GetActiveEditingHost()) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
return GetPriorNode(aParent, aOffset, true, aNoBlockCrossing);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLEditor::GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode, bool bNoBlockCrossing)
|
||||
{
|
||||
|
@ -4175,7 +4186,7 @@ nsHTMLEditor::GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<
|
|||
nsresult res = GetPriorNode(inParent, inOffset, true, address_of(*outNode),
|
||||
bNoBlockCrossing);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
|
||||
NS_ASSERTION(!*outNode || IsDescendantOfEditorRoot(*outNode),
|
||||
"GetPriorNode screwed up");
|
||||
return res;
|
||||
|
@ -4204,6 +4215,17 @@ nsHTMLEditor::GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode,
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetNHTMLextNode: same as above but takes {parent,offset} instead of node
|
||||
//
|
||||
nsIContent*
|
||||
nsHTMLEditor::GetNextHTMLNode(nsINode* aParent, PRInt32 aOffset,
|
||||
bool aNoBlockCrossing)
|
||||
{
|
||||
nsIContent* content = GetNextNode(aParent, aOffset, true, aNoBlockCrossing);
|
||||
if (content && !IsDescendantOfEditorRoot(content)) {
|
||||
return nsnull;
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLEditor::GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode, bool bNoBlockCrossing)
|
||||
{
|
||||
|
|
|
@ -693,7 +693,11 @@ protected:
|
|||
nsresult GetNextHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
|
||||
nsresult GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, bool bNoBlockCrossing = false);
|
||||
nsresult GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode, bool bNoBlockCrossing = false);
|
||||
nsIContent* GetPriorHTMLNode(nsINode* aParent, PRInt32 aOffset,
|
||||
bool aNoBlockCrossing = false);
|
||||
nsresult GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, bool bNoBlockCrossing = false);
|
||||
nsIContent* GetNextHTMLNode(nsINode* aParent, PRInt32 aOffset,
|
||||
bool aNoBlockCrossing = false);
|
||||
nsresult GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode, bool bNoBlockCrossing = false);
|
||||
|
||||
nsresult IsFirstEditableChild( nsIDOMNode *aNode, bool *aOutIsFirst);
|
||||
|
|
Загрузка…
Ссылка в новой задаче