mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 200416 - Account for blocks inside inlines when deleting; r=ehsan
This commit is contained in:
parent
4d4eaaac51
commit
838796da5f
@ -2072,7 +2072,7 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection,
|
||||
&otherOffset, &otherWSType);
|
||||
|
||||
// first find the adjacent node in the block
|
||||
nsCOMPtr<nsIDOMNode> leafNode, leftNode, rightNode, leftParent, rightParent;
|
||||
nsCOMPtr<nsIDOMNode> leafNode, leftNode, rightNode;
|
||||
if (aAction == nsIEditor::ePrevious)
|
||||
{
|
||||
res = mHTMLEditor->GetLastEditableLeaf( visNode, address_of(leafNode));
|
||||
@ -2113,29 +2113,14 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection,
|
||||
}
|
||||
|
||||
// else we are joining content to block
|
||||
|
||||
// find the relavent blocks
|
||||
if (IsBlockNode(leftNode))
|
||||
leftParent = leftNode;
|
||||
else if (leftNode)
|
||||
leftParent = mHTMLEditor->GetBlockNodeParent(leftNode);
|
||||
if (IsBlockNode(rightNode))
|
||||
rightParent = rightNode;
|
||||
else
|
||||
rightParent = mHTMLEditor->GetBlockNodeParent(rightNode);
|
||||
|
||||
// sanity checks
|
||||
NS_ENSURE_TRUE(leftParent && rightParent, NS_ERROR_NULL_POINTER);
|
||||
if (leftParent == rightParent)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// now join them
|
||||
|
||||
nsCOMPtr<nsIDOMNode> selPointNode = startNode;
|
||||
int32_t selPointOffset = startOffset;
|
||||
{
|
||||
nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, address_of(selPointNode), &selPointOffset);
|
||||
res = JoinBlocks(address_of(leftParent), address_of(rightParent), aCancel);
|
||||
res = JoinBlocks(leftNode, rightNode, aCancel);
|
||||
*aHandled = true;
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
}
|
||||
aSelection->Collapse(selPointNode, selPointOffset);
|
||||
return res;
|
||||
@ -2151,7 +2136,7 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection,
|
||||
}
|
||||
|
||||
// first find the relavent nodes
|
||||
nsCOMPtr<nsIDOMNode> leftNode, rightNode, leftParent, rightParent;
|
||||
nsCOMPtr<nsIDOMNode> leftNode, rightNode;
|
||||
if (aAction == nsIEditor::ePrevious)
|
||||
{
|
||||
res = mHTMLEditor->GetPriorHTMLNode(visNode, address_of(leftNode));
|
||||
@ -2178,28 +2163,13 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// find the relavent blocks
|
||||
if (IsBlockNode(leftNode))
|
||||
leftParent = leftNode;
|
||||
else
|
||||
leftParent = mHTMLEditor->GetBlockNodeParent(leftNode);
|
||||
if (IsBlockNode(rightNode))
|
||||
rightParent = rightNode;
|
||||
else
|
||||
rightParent = mHTMLEditor->GetBlockNodeParent(rightNode);
|
||||
|
||||
// sanity checks
|
||||
NS_ENSURE_TRUE(leftParent && rightParent, NS_ERROR_NULL_POINTER);
|
||||
if (leftParent == rightParent)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// now join them
|
||||
nsCOMPtr<nsIDOMNode> selPointNode = startNode;
|
||||
int32_t selPointOffset = startOffset;
|
||||
{
|
||||
nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, address_of(selPointNode), &selPointOffset);
|
||||
res = JoinBlocks(address_of(leftParent), address_of(rightParent), aCancel);
|
||||
res = JoinBlocks(leftNode, rightNode, aCancel);
|
||||
*aHandled = true;
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
}
|
||||
aSelection->Collapse(selPointNode, selPointOffset);
|
||||
return res;
|
||||
@ -2414,8 +2384,7 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection,
|
||||
}
|
||||
|
||||
if (join) {
|
||||
res = JoinBlocks(address_of(leftParent), address_of(rightParent),
|
||||
aCancel);
|
||||
res = JoinBlocks(leftParent, rightParent, aCancel);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
}
|
||||
}
|
||||
@ -2531,44 +2500,61 @@ nsHTMLEditRules::GetGoodSelPointForNode(nsIDOMNode *aNode, nsIEditor::EDirection
|
||||
* bool *aCanceled return TRUE if we had to cancel operation
|
||||
*/
|
||||
nsresult
|
||||
nsHTMLEditRules::JoinBlocks(nsCOMPtr<nsIDOMNode> *aLeftBlock,
|
||||
nsCOMPtr<nsIDOMNode> *aRightBlock,
|
||||
nsHTMLEditRules::JoinBlocks(nsIDOMNode *aLeftNode,
|
||||
nsIDOMNode *aRightNode,
|
||||
bool *aCanceled)
|
||||
{
|
||||
NS_ENSURE_TRUE(aLeftBlock && aRightBlock && *aLeftBlock && *aRightBlock, NS_ERROR_NULL_POINTER);
|
||||
if (nsHTMLEditUtils::IsTableElement(*aLeftBlock) || nsHTMLEditUtils::IsTableElement(*aRightBlock))
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aLeftNode && aRightNode);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> aLeftBlock, aRightBlock;
|
||||
|
||||
if (IsBlockNode(aLeftNode)) {
|
||||
aLeftBlock = aLeftNode;
|
||||
} else if (aLeftNode) {
|
||||
aLeftBlock = mHTMLEditor->GetBlockNodeParent(aLeftNode);
|
||||
}
|
||||
|
||||
if (IsBlockNode(aRightNode)) {
|
||||
aRightBlock = aRightNode;
|
||||
} else if (aRightNode) {
|
||||
aRightBlock = mHTMLEditor->GetBlockNodeParent(aRightNode);
|
||||
}
|
||||
|
||||
// sanity checks
|
||||
NS_ENSURE_TRUE(aLeftBlock && aRightBlock, NS_ERROR_NULL_POINTER);
|
||||
NS_ENSURE_STATE(aLeftBlock != aRightBlock);
|
||||
|
||||
if (nsHTMLEditUtils::IsTableElement(aLeftBlock) ||
|
||||
nsHTMLEditUtils::IsTableElement(aRightBlock)) {
|
||||
// do not try to merge table elements
|
||||
*aCanceled = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// make sure we don't try to move thing's into HR's, which look like blocks but aren't containers
|
||||
if (nsHTMLEditUtils::IsHR(*aLeftBlock))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> realLeft = mHTMLEditor->GetBlockNodeParent(*aLeftBlock);
|
||||
*aLeftBlock = realLeft;
|
||||
if (nsHTMLEditUtils::IsHR(aLeftBlock)) {
|
||||
nsCOMPtr<nsIDOMNode> realLeft = mHTMLEditor->GetBlockNodeParent(aLeftBlock);
|
||||
aLeftBlock = realLeft;
|
||||
}
|
||||
if (nsHTMLEditUtils::IsHR(*aRightBlock))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> realRight = mHTMLEditor->GetBlockNodeParent(*aRightBlock);
|
||||
*aRightBlock = realRight;
|
||||
if (nsHTMLEditUtils::IsHR(aRightBlock)) {
|
||||
nsCOMPtr<nsIDOMNode> realRight = mHTMLEditor->GetBlockNodeParent(aRightBlock);
|
||||
aRightBlock = realRight;
|
||||
}
|
||||
|
||||
// bail if both blocks the same
|
||||
if (*aLeftBlock == *aRightBlock)
|
||||
{
|
||||
if (aLeftBlock == aRightBlock) {
|
||||
*aCanceled = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Joining a list item to its parent is a NOP.
|
||||
if (nsHTMLEditUtils::IsList(*aLeftBlock) && nsHTMLEditUtils::IsListItem(*aRightBlock))
|
||||
{
|
||||
if (nsHTMLEditUtils::IsList(aLeftBlock) &&
|
||||
nsHTMLEditUtils::IsListItem(aRightBlock)) {
|
||||
nsCOMPtr<nsIDOMNode> rightParent;
|
||||
(*aRightBlock)->GetParentNode(getter_AddRefs(rightParent));
|
||||
if (rightParent == *aLeftBlock)
|
||||
aRightBlock->GetParentNode(getter_AddRefs(rightParent));
|
||||
if (rightParent == aLeftBlock) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// special rule here: if we are trying to join list items, and they are in different lists,
|
||||
@ -2577,21 +2563,21 @@ nsHTMLEditRules::JoinBlocks(nsCOMPtr<nsIDOMNode> *aLeftBlock,
|
||||
nsIAtom* existingList = nsGkAtoms::_empty;
|
||||
int32_t theOffset;
|
||||
nsCOMPtr<nsIDOMNode> leftList, rightList;
|
||||
if (nsHTMLEditUtils::IsListItem(*aLeftBlock) && nsHTMLEditUtils::IsListItem(*aRightBlock))
|
||||
{
|
||||
(*aLeftBlock)->GetParentNode(getter_AddRefs(leftList));
|
||||
(*aRightBlock)->GetParentNode(getter_AddRefs(rightList));
|
||||
if (nsHTMLEditUtils::IsListItem(aLeftBlock) &&
|
||||
nsHTMLEditUtils::IsListItem(aRightBlock)) {
|
||||
aLeftBlock->GetParentNode(getter_AddRefs(leftList));
|
||||
aRightBlock->GetParentNode(getter_AddRefs(rightList));
|
||||
if (leftList && rightList && (leftList!=rightList))
|
||||
{
|
||||
// there are some special complications if the lists are descendants of
|
||||
// the other lists' items. Note that it is ok for them to be descendants
|
||||
// of the other lists themselves, which is the usual case for sublists
|
||||
// in our impllementation.
|
||||
if (!nsEditorUtils::IsDescendantOf(leftList, *aRightBlock, &theOffset) &&
|
||||
!nsEditorUtils::IsDescendantOf(rightList, *aLeftBlock, &theOffset))
|
||||
if (!nsEditorUtils::IsDescendantOf(leftList, aRightBlock, &theOffset) &&
|
||||
!nsEditorUtils::IsDescendantOf(rightList, aLeftBlock, &theOffset))
|
||||
{
|
||||
*aLeftBlock = leftList;
|
||||
*aRightBlock = rightList;
|
||||
aLeftBlock = leftList;
|
||||
aRightBlock = rightList;
|
||||
bMergeLists = true;
|
||||
existingList = mHTMLEditor->GetTag(leftList);
|
||||
}
|
||||
@ -2606,18 +2592,22 @@ nsHTMLEditRules::JoinBlocks(nsCOMPtr<nsIDOMNode> *aLeftBlock,
|
||||
|
||||
// theOffset below is where you find yourself in aRightBlock when you traverse upwards
|
||||
// from aLeftBlock
|
||||
if (nsEditorUtils::IsDescendantOf(*aLeftBlock, *aRightBlock, &rightOffset))
|
||||
{
|
||||
if (nsEditorUtils::IsDescendantOf(aLeftBlock, aRightBlock, &rightOffset)) {
|
||||
// tricky case. left block is inside right block.
|
||||
// Do ws adjustment. This just destroys non-visible ws at boundaries we will be joining.
|
||||
rightOffset++;
|
||||
res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor, aLeftBlock, nsWSRunObject::kBlockEnd);
|
||||
res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor,
|
||||
address_of(aLeftBlock),
|
||||
nsWSRunObject::kBlockEnd);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor, aRightBlock, nsWSRunObject::kAfterBlock, &rightOffset);
|
||||
res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor,
|
||||
address_of(aRightBlock),
|
||||
nsWSRunObject::kAfterBlock,
|
||||
&rightOffset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
// Do br adjustment.
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
res = CheckForInvisibleBR(*aLeftBlock, kBlockEnd, address_of(brNode));
|
||||
res = CheckForInvisibleBR(aLeftBlock, kBlockEnd, address_of(brNode));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
if (bMergeLists)
|
||||
{
|
||||
@ -2639,23 +2629,27 @@ nsHTMLEditRules::JoinBlocks(nsCOMPtr<nsIDOMNode> *aLeftBlock,
|
||||
}
|
||||
else
|
||||
{
|
||||
res = MoveBlock(*aLeftBlock, *aRightBlock, leftOffset, rightOffset);
|
||||
res = MoveBlock(aLeftBlock, aRightBlock, leftOffset, rightOffset);
|
||||
}
|
||||
if (brNode) mHTMLEditor->DeleteNode(brNode);
|
||||
}
|
||||
// theOffset below is where you find yourself in aLeftBlock when you traverse upwards
|
||||
// from aRightBlock
|
||||
else if (nsEditorUtils::IsDescendantOf(*aRightBlock, *aLeftBlock, &leftOffset))
|
||||
{
|
||||
} else if (nsEditorUtils::IsDescendantOf(aRightBlock, aLeftBlock, &leftOffset)) {
|
||||
// tricky case. right block is inside left block.
|
||||
// Do ws adjustment. This just destroys non-visible ws at boundaries we will be joining.
|
||||
res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor, aRightBlock, nsWSRunObject::kBlockStart);
|
||||
res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor,
|
||||
address_of(aRightBlock),
|
||||
nsWSRunObject::kBlockStart);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor, aLeftBlock, nsWSRunObject::kBeforeBlock, &leftOffset);
|
||||
res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor,
|
||||
address_of(aLeftBlock),
|
||||
nsWSRunObject::kBeforeBlock,
|
||||
&leftOffset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
// Do br adjustment.
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
res = CheckForInvisibleBR(*aLeftBlock, kBeforeBlock, address_of(brNode), leftOffset);
|
||||
res = CheckForInvisibleBR(aLeftBlock, kBeforeBlock, address_of(brNode),
|
||||
leftOffset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
if (bMergeLists)
|
||||
{
|
||||
@ -2663,7 +2657,58 @@ nsHTMLEditRules::JoinBlocks(nsCOMPtr<nsIDOMNode> *aLeftBlock,
|
||||
}
|
||||
else
|
||||
{
|
||||
res = MoveBlock(*aLeftBlock, *aRightBlock, leftOffset, rightOffset);
|
||||
// Left block is a parent of right block, and the parent of the previous
|
||||
// visible content. Right block is a child and contains the contents we
|
||||
// want to move.
|
||||
|
||||
int32_t previousContentOffset;
|
||||
nsCOMPtr<nsIDOMNode> previousContentParent;
|
||||
|
||||
if (aLeftNode == aLeftBlock) {
|
||||
// We are working with valid HTML, aLeftNode is a block node, and is
|
||||
// therefore allowed to contain aRightBlock. This is the simple case,
|
||||
// we will simply move the content in aRightBlock out of its block.
|
||||
previousContentParent = aLeftBlock;
|
||||
previousContentOffset = leftOffset;
|
||||
} else {
|
||||
// We try to work as well as possible with HTML that's already invalid.
|
||||
// Although "right block" is a block, and a block must not be contained
|
||||
// in inline elements, reality is that broken documents do exist. The
|
||||
// DIRECT parent of "left NODE" might be an inline element. Previous
|
||||
// versions of this code skipped inline parents until the first block
|
||||
// parent was found (and used "left block" as the destination).
|
||||
// However, in some situations this strategy moves the content to an
|
||||
// unexpected position. (see bug 200416) The new idea is to make the
|
||||
// moving content a sibling, next to the previous visible content.
|
||||
|
||||
previousContentParent =
|
||||
nsEditor::GetNodeLocation(aLeftNode, &previousContentOffset);
|
||||
|
||||
// We want to move our content just after the previous visible node.
|
||||
previousContentOffset++;
|
||||
}
|
||||
|
||||
// Because we don't want the moving content to receive the style of the
|
||||
// previous content, we split the previous content's style.
|
||||
|
||||
nsCOMPtr<nsINode> editorRoot = mHTMLEditor->GetEditorRoot();
|
||||
if (!editorRoot || aLeftNode != editorRoot->AsDOMNode()) {
|
||||
nsCOMPtr<nsIDOMNode> splittedPreviousContent;
|
||||
res = mHTMLEditor->SplitStyleAbovePoint(address_of(previousContentParent),
|
||||
&previousContentOffset,
|
||||
nullptr, nullptr, nullptr,
|
||||
address_of(splittedPreviousContent));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
if (splittedPreviousContent) {
|
||||
previousContentParent =
|
||||
nsEditor::GetNodeLocation(splittedPreviousContent,
|
||||
&previousContentOffset);
|
||||
}
|
||||
}
|
||||
|
||||
res = MoveBlock(previousContentParent, aRightBlock,
|
||||
previousContentOffset, rightOffset);
|
||||
}
|
||||
if (brNode) mHTMLEditor->DeleteNode(brNode);
|
||||
}
|
||||
@ -2675,29 +2720,28 @@ nsHTMLEditRules::JoinBlocks(nsCOMPtr<nsIDOMNode> *aLeftBlock,
|
||||
// from li into p.
|
||||
|
||||
// adjust whitespace at block boundaries
|
||||
res = nsWSRunObject::PrepareToJoinBlocks(mHTMLEditor, *aLeftBlock, *aRightBlock);
|
||||
res = nsWSRunObject::PrepareToJoinBlocks(mHTMLEditor, aLeftBlock, aRightBlock);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
// Do br adjustment.
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
res = CheckForInvisibleBR(*aLeftBlock, kBlockEnd, address_of(brNode));
|
||||
res = CheckForInvisibleBR(aLeftBlock, kBlockEnd, address_of(brNode));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
if (bMergeLists || mHTMLEditor->NodesSameType(*aLeftBlock, *aRightBlock))
|
||||
{
|
||||
if (bMergeLists || mHTMLEditor->NodesSameType(aLeftBlock, aRightBlock)) {
|
||||
// nodes are same type. merge them.
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
int32_t offset;
|
||||
res = JoinNodesSmart(*aLeftBlock, *aRightBlock, address_of(parent), &offset);
|
||||
res = JoinNodesSmart(aLeftBlock, aRightBlock, address_of(parent), &offset);
|
||||
if (NS_SUCCEEDED(res) && bMergeLists)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> newBlock;
|
||||
res = ConvertListType(*aRightBlock, address_of(newBlock),
|
||||
res = ConvertListType(aRightBlock, address_of(newBlock),
|
||||
existingList, nsGkAtoms::li);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// nodes are disimilar types.
|
||||
res = MoveBlock(*aLeftBlock, *aRightBlock, leftOffset, rightOffset);
|
||||
res = MoveBlock(aLeftBlock, aRightBlock, leftOffset, rightOffset);
|
||||
}
|
||||
if (NS_SUCCEEDED(res) && brNode)
|
||||
{
|
||||
|
@ -150,7 +150,7 @@ protected:
|
||||
nsresult InsertBRIfNeeded(nsISelection *aSelection);
|
||||
nsresult GetGoodSelPointForNode(nsIDOMNode *aNode, nsIEditor::EDirection aAction,
|
||||
nsCOMPtr<nsIDOMNode> *outSelNode, int32_t *outSelOffset);
|
||||
nsresult JoinBlocks(nsCOMPtr<nsIDOMNode> *aLeftBlock, nsCOMPtr<nsIDOMNode> *aRightBlock, bool *aCanceled);
|
||||
nsresult JoinBlocks(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, bool *aCanceled);
|
||||
nsresult MoveBlock(nsIDOMNode *aLeft, nsIDOMNode *aRight, int32_t aLeftOffset, int32_t aRightOffset);
|
||||
nsresult MoveNodeSmart(nsIDOMNode *aSource, nsIDOMNode *aDest, int32_t *aOffset);
|
||||
nsresult MoveContents(nsIDOMNode *aSource, nsIDOMNode *aDest, int32_t *aOffset);
|
||||
|
Loading…
Reference in New Issue
Block a user