Bug 1260651 part.47 Rename nsWSRunObject to mozilla::WSRunObject (and also their file names) r=mccr8

Perhaps, there may be better name like WhitespaceRunObject or something, however, for now keep using the term because I don't understand well what it does.

With this patch, following objects are renamed:

nsWSRunObject -> mozilla::WSRunObject
WSType -> mozilla::WSType
nsWSRunObject::WSFragment -> mozilla::WSRunObject::WSFragment
nsWSRunObject::WSPoint -> mozilla::WSRunObject::WSPoint

MozReview-Commit-ID: JgAWiPjOtMW
This commit is contained in:
Masayuki Nakano
2016-07-07 19:00:51 +09:00
parent cc1680b3d0
commit ad36fdc517
8 changed files with 623 additions and 601 deletions

View File

@@ -3,7 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsWSRunObject.h" #include "WSRunObject.h"
#include "EditorUtils.h" #include "EditorUtils.h"
#include "SelectionState.h" #include "SelectionState.h"
@@ -28,80 +28,60 @@
#include "nsString.h" #include "nsString.h"
#include "nsTextFragment.h" #include "nsTextFragment.h"
using namespace mozilla; namespace mozilla {
using namespace mozilla::dom;
using namespace dom;
const char16_t nbsp = 160; const char16_t nbsp = 160;
//- constructor / destructor ----------------------------------------------- WSRunObject::WSRunObject(nsHTMLEditor* aHTMLEditor,
nsWSRunObject::nsWSRunObject(nsHTMLEditor* aEd, nsINode* aNode, int32_t aOffset) nsINode* aNode,
int32_t aOffset)
: mNode(aNode) : mNode(aNode)
, mOffset(aOffset) , mOffset(aOffset)
, mPRE(false) , mPRE(false)
, mStartNode()
, mStartOffset(0) , mStartOffset(0)
, mStartReason()
, mStartReasonNode()
, mEndNode()
, mEndOffset(0) , mEndOffset(0)
, mEndReason()
, mEndReasonNode()
, mFirstNBSPNode()
, mFirstNBSPOffset(0) , mFirstNBSPOffset(0)
, mLastNBSPNode()
, mLastNBSPOffset(0) , mLastNBSPOffset(0)
, mNodeArray()
, mStartRun(nullptr) , mStartRun(nullptr)
, mEndRun(nullptr) , mEndRun(nullptr)
, mHTMLEditor(aEd) , mHTMLEditor(aHTMLEditor)
{ {
GetWSNodes(); GetWSNodes();
GetRuns(); GetRuns();
} }
nsWSRunObject::nsWSRunObject(nsHTMLEditor *aEd, nsIDOMNode *aNode, int32_t aOffset) : WSRunObject::WSRunObject(nsHTMLEditor* aHTMLEditor,
mNode(do_QueryInterface(aNode)) nsIDOMNode* aNode,
int32_t aOffset)
: mNode(do_QueryInterface(aNode))
, mOffset(aOffset) , mOffset(aOffset)
, mPRE(false) , mPRE(false)
,mStartNode()
, mStartOffset(0) , mStartOffset(0)
,mStartReason()
,mStartReasonNode()
,mEndNode()
, mEndOffset(0) , mEndOffset(0)
,mEndReason()
,mEndReasonNode()
,mFirstNBSPNode()
, mFirstNBSPOffset(0) , mFirstNBSPOffset(0)
,mLastNBSPNode()
, mLastNBSPOffset(0) , mLastNBSPOffset(0)
,mNodeArray()
, mStartRun(nullptr) , mStartRun(nullptr)
, mEndRun(nullptr) , mEndRun(nullptr)
,mHTMLEditor(aEd) , mHTMLEditor(aHTMLEditor)
{ {
GetWSNodes(); GetWSNodes();
GetRuns(); GetRuns();
} }
nsWSRunObject::~nsWSRunObject() WSRunObject::~WSRunObject()
{ {
ClearRuns(); ClearRuns();
} }
//--------------------------------------------------------------------------------------------
// public static methods
//--------------------------------------------------------------------------------------------
nsresult nsresult
nsWSRunObject::ScrubBlockBoundary(nsHTMLEditor* aHTMLEd, WSRunObject::ScrubBlockBoundary(nsHTMLEditor* aHTMLEditor,
BlockBoundary aBoundary, BlockBoundary aBoundary,
nsINode* aBlock, nsINode* aBlock,
int32_t aOffset) int32_t aOffset)
{ {
NS_ENSURE_TRUE(aHTMLEd && aBlock, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(aHTMLEditor && aBlock, NS_ERROR_NULL_POINTER);
int32_t offset; int32_t offset;
if (aBoundary == kBlockStart) { if (aBoundary == kBlockStart) {
@@ -115,80 +95,79 @@ nsWSRunObject::ScrubBlockBoundary(nsHTMLEditor* aHTMLEd,
offset = aOffset; offset = aOffset;
} }
nsWSRunObject theWSObj(aHTMLEd, aBlock, offset); WSRunObject theWSObj(aHTMLEditor, aBlock, offset);
return theWSObj.Scrub(); return theWSObj.Scrub();
} }
nsresult nsresult
nsWSRunObject::PrepareToJoinBlocks(nsHTMLEditor* aHTMLEd, WSRunObject::PrepareToJoinBlocks(nsHTMLEditor* aHTMLEditor,
Element* aLeftBlock, Element* aLeftBlock,
Element* aRightBlock) Element* aRightBlock)
{ {
NS_ENSURE_TRUE(aLeftBlock && aRightBlock && aHTMLEd, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(aLeftBlock && aRightBlock && aHTMLEditor,
NS_ERROR_NULL_POINTER);
nsWSRunObject leftWSObj(aHTMLEd, aLeftBlock, aLeftBlock->Length()); WSRunObject leftWSObj(aHTMLEditor, aLeftBlock, aLeftBlock->Length());
nsWSRunObject rightWSObj(aHTMLEd, aRightBlock, 0); WSRunObject rightWSObj(aHTMLEditor, aRightBlock, 0);
return leftWSObj.PrepareToDeleteRangePriv(&rightWSObj); return leftWSObj.PrepareToDeleteRangePriv(&rightWSObj);
} }
nsresult nsresult
nsWSRunObject::PrepareToDeleteRange(nsHTMLEditor* aHTMLEd, WSRunObject::PrepareToDeleteRange(nsHTMLEditor* aHTMLEditor,
nsCOMPtr<nsINode>* aStartNode, nsCOMPtr<nsINode>* aStartNode,
int32_t* aStartOffset, int32_t* aStartOffset,
nsCOMPtr<nsINode>* aEndNode, nsCOMPtr<nsINode>* aEndNode,
int32_t* aEndOffset) int32_t* aEndOffset)
{ {
NS_ENSURE_TRUE(aHTMLEd && aStartNode && *aStartNode && aStartOffset && NS_ENSURE_TRUE(aHTMLEditor && aStartNode && *aStartNode && aStartOffset &&
aEndNode && *aEndNode && aEndOffset, NS_ERROR_NULL_POINTER); aEndNode && *aEndNode && aEndOffset, NS_ERROR_NULL_POINTER);
AutoTrackDOMPoint trackerStart(aHTMLEd->mRangeUpdater, aStartNode, AutoTrackDOMPoint trackerStart(aHTMLEditor->mRangeUpdater,
aStartOffset); aStartNode, aStartOffset);
AutoTrackDOMPoint trackerEnd(aHTMLEd->mRangeUpdater, aEndNode, aEndOffset); AutoTrackDOMPoint trackerEnd(aHTMLEditor->mRangeUpdater,
aEndNode, aEndOffset);
nsWSRunObject leftWSObj(aHTMLEd, *aStartNode, *aStartOffset); WSRunObject leftWSObj(aHTMLEditor, *aStartNode, *aStartOffset);
nsWSRunObject rightWSObj(aHTMLEd, *aEndNode, *aEndOffset); WSRunObject rightWSObj(aHTMLEditor, *aEndNode, *aEndOffset);
return leftWSObj.PrepareToDeleteRangePriv(&rightWSObj); return leftWSObj.PrepareToDeleteRangePriv(&rightWSObj);
} }
nsresult nsresult
nsWSRunObject::PrepareToDeleteNode(nsHTMLEditor* aHTMLEd, WSRunObject::PrepareToDeleteNode(nsHTMLEditor* aHTMLEditor,
nsIContent* aContent) nsIContent* aContent)
{ {
NS_ENSURE_TRUE(aContent && aHTMLEd, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(aContent && aHTMLEditor, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsINode> parent = aContent->GetParentNode(); nsCOMPtr<nsINode> parent = aContent->GetParentNode();
NS_ENSURE_STATE(parent); NS_ENSURE_STATE(parent);
int32_t offset = parent->IndexOf(aContent); int32_t offset = parent->IndexOf(aContent);
nsWSRunObject leftWSObj(aHTMLEd, parent, offset); WSRunObject leftWSObj(aHTMLEditor, parent, offset);
nsWSRunObject rightWSObj(aHTMLEd, parent, offset + 1); WSRunObject rightWSObj(aHTMLEditor, parent, offset + 1);
return leftWSObj.PrepareToDeleteRangePriv(&rightWSObj); return leftWSObj.PrepareToDeleteRangePriv(&rightWSObj);
} }
nsresult nsresult
nsWSRunObject::PrepareToSplitAcrossBlocks(nsHTMLEditor* aHTMLEd, WSRunObject::PrepareToSplitAcrossBlocks(nsHTMLEditor* aHTMLEditor,
nsCOMPtr<nsINode>* aSplitNode, nsCOMPtr<nsINode>* aSplitNode,
int32_t* aSplitOffset) int32_t* aSplitOffset)
{ {
NS_ENSURE_TRUE(aHTMLEd && aSplitNode && *aSplitNode && aSplitOffset, NS_ENSURE_TRUE(aHTMLEditor && aSplitNode && *aSplitNode && aSplitOffset,
NS_ERROR_NULL_POINTER); NS_ERROR_NULL_POINTER);
AutoTrackDOMPoint tracker(aHTMLEd->mRangeUpdater, aSplitNode, aSplitOffset); AutoTrackDOMPoint tracker(aHTMLEditor->mRangeUpdater,
aSplitNode, aSplitOffset);
nsWSRunObject wsObj(aHTMLEd, *aSplitNode, *aSplitOffset); WSRunObject wsObj(aHTMLEditor, *aSplitNode, *aSplitOffset);
return wsObj.PrepareToSplitAcrossBlocksPriv(); return wsObj.PrepareToSplitAcrossBlocksPriv();
} }
//--------------------------------------------------------------------------------------------
// public instance methods
//--------------------------------------------------------------------------------------------
Element* Element*
nsWSRunObject::InsertBreak(nsCOMPtr<nsINode>* aInOutParent, WSRunObject::InsertBreak(nsCOMPtr<nsINode>* aInOutParent,
int32_t* aInOutOffset, int32_t* aInOutOffset,
nsIEditor::EDirection aSelect) nsIEditor::EDirection aSelect)
{ {
@@ -255,7 +234,7 @@ nsWSRunObject::InsertBreak(nsCOMPtr<nsINode>* aInOutParent,
} }
nsresult nsresult
nsWSRunObject::InsertText(const nsAString& aStringToInsert, WSRunObject::InsertText(const nsAString& aStringToInsert,
nsCOMPtr<nsINode>* aInOutParent, nsCOMPtr<nsINode>* aInOutParent,
int32_t* aInOutOffset, int32_t* aInOutOffset,
nsIDocument* aDoc) nsIDocument* aDoc)
@@ -384,7 +363,7 @@ nsWSRunObject::InsertText(const nsAString& aStringToInsert,
} }
nsresult nsresult
nsWSRunObject::DeleteWSBackward() WSRunObject::DeleteWSBackward()
{ {
WSPoint point = GetCharBefore(mNode, mOffset); WSPoint point = GetCharBefore(mNode, mOffset);
NS_ENSURE_TRUE(point.mTextNode, NS_OK); // nothing to delete NS_ENSURE_TRUE(point.mTextNode, NS_OK); // nothing to delete
@@ -410,7 +389,7 @@ nsWSRunObject::DeleteWSBackward()
nsCOMPtr<nsINode> startNode = startNodeText.get(); nsCOMPtr<nsINode> startNode = startNodeText.get();
nsCOMPtr<nsINode> endNode = endNodeText.get(); nsCOMPtr<nsINode> endNode = endNodeText.get();
nsresult res = nsresult res =
nsWSRunObject::PrepareToDeleteRange(mHTMLEditor, WSRunObject::PrepareToDeleteRange(mHTMLEditor,
address_of(startNode), &startOffset, address_of(startNode), &startOffset,
address_of(endNode), &endOffset); address_of(endNode), &endOffset);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
@@ -423,7 +402,7 @@ nsWSRunObject::DeleteWSBackward()
int32_t startOffset = point.mOffset; int32_t startOffset = point.mOffset;
int32_t endOffset = point.mOffset + 1; int32_t endOffset = point.mOffset + 1;
nsresult res = nsresult res =
nsWSRunObject::PrepareToDeleteRange(mHTMLEditor, WSRunObject::PrepareToDeleteRange(mHTMLEditor,
address_of(node), &startOffset, address_of(node), &startOffset,
address_of(node), &endOffset); address_of(node), &endOffset);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
@@ -435,7 +414,7 @@ nsWSRunObject::DeleteWSBackward()
} }
nsresult nsresult
nsWSRunObject::DeleteWSForward() WSRunObject::DeleteWSForward()
{ {
WSPoint point = GetCharAfter(mNode, mOffset); WSPoint point = GetCharAfter(mNode, mOffset);
NS_ENSURE_TRUE(point.mTextNode, NS_OK); // nothing to delete NS_ENSURE_TRUE(point.mTextNode, NS_OK); // nothing to delete
@@ -459,7 +438,7 @@ nsWSRunObject::DeleteWSForward()
// Adjust surrounding ws // Adjust surrounding ws
nsCOMPtr<nsINode> startNode(startNodeText), endNode(endNodeText); nsCOMPtr<nsINode> startNode(startNodeText), endNode(endNodeText);
nsresult res = nsWSRunObject::PrepareToDeleteRange(mHTMLEditor, nsresult res = WSRunObject::PrepareToDeleteRange(mHTMLEditor,
address_of(startNode), &startOffset, address_of(endNode), &endOffset); address_of(startNode), &startOffset, address_of(endNode), &endOffset);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
@@ -470,7 +449,7 @@ nsWSRunObject::DeleteWSForward()
// Adjust surrounding ws // Adjust surrounding ws
int32_t startOffset = point.mOffset; int32_t startOffset = point.mOffset;
int32_t endOffset = point.mOffset+1; int32_t endOffset = point.mOffset+1;
nsresult res = nsWSRunObject::PrepareToDeleteRange(mHTMLEditor, nsresult res = WSRunObject::PrepareToDeleteRange(mHTMLEditor,
address_of(node), &startOffset, address_of(node), &endOffset); address_of(node), &startOffset, address_of(node), &endOffset);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
@@ -481,7 +460,7 @@ nsWSRunObject::DeleteWSForward()
} }
void void
nsWSRunObject::PriorVisibleNode(nsINode* aNode, WSRunObject::PriorVisibleNode(nsINode* aNode,
int32_t aOffset, int32_t aOffset,
nsCOMPtr<nsINode>* outVisNode, nsCOMPtr<nsINode>* outVisNode,
int32_t* outVisOffset, int32_t* outVisOffset,
@@ -525,7 +504,7 @@ nsWSRunObject::PriorVisibleNode(nsINode* aNode,
void void
nsWSRunObject::NextVisibleNode(nsINode* aNode, WSRunObject::NextVisibleNode(nsINode* aNode,
int32_t aOffset, int32_t aOffset,
nsCOMPtr<nsINode>* outVisNode, nsCOMPtr<nsINode>* outVisNode,
int32_t* outVisOffset, int32_t* outVisOffset,
@@ -568,7 +547,7 @@ nsWSRunObject::NextVisibleNode(nsINode* aNode,
} }
nsresult nsresult
nsWSRunObject::AdjustWhitespace() WSRunObject::AdjustWhitespace()
{ {
// this routine examines a run of ws and tries to get rid of some unneeded nbsp's, // this routine examines a run of ws and tries to get rid of some unneeded nbsp's,
// replacing them with regualr ascii space if possible. Keeping things simple // replacing them with regualr ascii space if possible. Keeping things simple
@@ -597,7 +576,7 @@ nsWSRunObject::AdjustWhitespace()
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
nsINode* nsINode*
nsWSRunObject::GetWSBoundingParent() WSRunObject::GetWSBoundingParent()
{ {
NS_ENSURE_TRUE(mNode, nullptr); NS_ENSURE_TRUE(mNode, nullptr);
OwningNonNull<nsINode> wsBoundingParent = *mNode; OwningNonNull<nsINode> wsBoundingParent = *mNode;
@@ -612,7 +591,7 @@ nsWSRunObject::GetWSBoundingParent()
} }
nsresult nsresult
nsWSRunObject::GetWSNodes() WSRunObject::GetWSNodes()
{ {
// collect up an array of nodes that are contiguous with the insertion point // collect up an array of nodes that are contiguous with the insertion point
// and which contain only whitespace. Stop if you reach non-ws text or a new // and which contain only whitespace. Stop if you reach non-ws text or a new
@@ -838,7 +817,7 @@ nsWSRunObject::GetWSNodes()
} }
void void
nsWSRunObject::GetRuns() WSRunObject::GetRuns()
{ {
ClearRuns(); ClearRuns();
@@ -968,7 +947,7 @@ nsWSRunObject::GetRuns()
} }
void void
nsWSRunObject::ClearRuns() WSRunObject::ClearRuns()
{ {
WSFragment *tmp, *run; WSFragment *tmp, *run;
run = mStartRun; run = mStartRun;
@@ -983,7 +962,7 @@ nsWSRunObject::ClearRuns()
} }
void void
nsWSRunObject::MakeSingleWSRun(WSType aType) WSRunObject::MakeSingleWSRun(WSType aType)
{ {
mStartRun = new WSFragment(); mStartRun = new WSFragment();
@@ -999,7 +978,7 @@ nsWSRunObject::MakeSingleWSRun(WSType aType)
} }
nsIContent* nsIContent*
nsWSRunObject::GetPreviousWSNodeInner(nsINode* aStartNode, WSRunObject::GetPreviousWSNodeInner(nsINode* aStartNode,
nsINode* aBlockParent) nsINode* aBlockParent)
{ {
// Can't really recycle various getnext/prior routines because we have // Can't really recycle various getnext/prior routines because we have
@@ -1038,7 +1017,7 @@ nsWSRunObject::GetPreviousWSNodeInner(nsINode* aStartNode,
} }
nsIContent* nsIContent*
nsWSRunObject::GetPreviousWSNode(EditorDOMPoint aPoint, WSRunObject::GetPreviousWSNode(EditorDOMPoint aPoint,
nsINode* aBlockParent) nsINode* aBlockParent)
{ {
// Can't really recycle various getnext/prior routines because we // Can't really recycle various getnext/prior routines because we
@@ -1083,7 +1062,7 @@ nsWSRunObject::GetPreviousWSNode(EditorDOMPoint aPoint,
} }
nsIContent* nsIContent*
nsWSRunObject::GetNextWSNodeInner(nsINode* aStartNode, WSRunObject::GetNextWSNodeInner(nsINode* aStartNode,
nsINode* aBlockParent) nsINode* aBlockParent)
{ {
// Can't really recycle various getnext/prior routines because we have // Can't really recycle various getnext/prior routines because we have
@@ -1122,7 +1101,8 @@ nsWSRunObject::GetNextWSNodeInner(nsINode* aStartNode,
} }
nsIContent* nsIContent*
nsWSRunObject::GetNextWSNode(EditorDOMPoint aPoint, nsINode* aBlockParent) WSRunObject::GetNextWSNode(EditorDOMPoint aPoint,
nsINode* aBlockParent)
{ {
// Can't really recycle various getnext/prior routines because we have // Can't really recycle various getnext/prior routines because we have
// special needs here. Need to step into inline containers but not block // special needs here. Need to step into inline containers but not block
@@ -1166,7 +1146,7 @@ nsWSRunObject::GetNextWSNode(EditorDOMPoint aPoint, nsINode* aBlockParent)
} }
nsresult nsresult
nsWSRunObject::PrepareToDeleteRangePriv(nsWSRunObject* aEndObject) WSRunObject::PrepareToDeleteRangePriv(WSRunObject* aEndObject)
{ {
// this routine adjust whitespace before *this* and after aEndObject // this routine adjust whitespace before *this* and after aEndObject
// in preperation for the two areas to become adjacent after the // in preperation for the two areas to become adjacent after the
@@ -1234,7 +1214,7 @@ nsWSRunObject::PrepareToDeleteRangePriv(nsWSRunObject* aEndObject)
} }
nsresult nsresult
nsWSRunObject::PrepareToSplitAcrossBlocksPriv() WSRunObject::PrepareToSplitAcrossBlocksPriv()
{ {
// used to prepare ws to be split across two blocks. The main issue // used to prepare ws to be split across two blocks. The main issue
// here is make sure normalWS doesn't end up becoming non-significant // here is make sure normalWS doesn't end up becoming non-significant
@@ -1278,8 +1258,10 @@ nsWSRunObject::PrepareToSplitAcrossBlocksPriv()
} }
nsresult nsresult
nsWSRunObject::DeleteChars(nsINode* aStartNode, int32_t aStartOffset, WSRunObject::DeleteChars(nsINode* aStartNode,
nsINode* aEndNode, int32_t aEndOffset, int32_t aStartOffset,
nsINode* aEndNode,
int32_t aEndOffset,
AreaRestriction aAR) AreaRestriction aAR)
{ {
// MOOSE: this routine needs to be modified to preserve the integrity of the // MOOSE: this routine needs to be modified to preserve the integrity of the
@@ -1367,8 +1349,9 @@ nsWSRunObject::DeleteChars(nsINode* aStartNode, int32_t aStartOffset,
return NS_OK; return NS_OK;
} }
nsWSRunObject::WSPoint WSRunObject::WSPoint
nsWSRunObject::GetCharAfter(nsINode* aNode, int32_t aOffset) WSRunObject::GetCharAfter(nsINode* aNode,
int32_t aOffset)
{ {
MOZ_ASSERT(aNode); MOZ_ASSERT(aNode);
@@ -1382,8 +1365,9 @@ nsWSRunObject::GetCharAfter(nsINode* aNode, int32_t aOffset)
} }
} }
nsWSRunObject::WSPoint WSRunObject::WSPoint
nsWSRunObject::GetCharBefore(nsINode* aNode, int32_t aOffset) WSRunObject::GetCharBefore(nsINode* aNode,
int32_t aOffset)
{ {
MOZ_ASSERT(aNode); MOZ_ASSERT(aNode);
@@ -1397,8 +1381,8 @@ nsWSRunObject::GetCharBefore(nsINode* aNode, int32_t aOffset)
} }
} }
nsWSRunObject::WSPoint WSRunObject::WSPoint
nsWSRunObject::GetCharAfter(const WSPoint &aPoint) WSRunObject::GetCharAfter(const WSPoint &aPoint)
{ {
MOZ_ASSERT(aPoint.mTextNode); MOZ_ASSERT(aPoint.mTextNode);
@@ -1427,8 +1411,8 @@ nsWSRunObject::GetCharAfter(const WSPoint &aPoint)
return outPoint; return outPoint;
} }
nsWSRunObject::WSPoint WSRunObject::WSPoint
nsWSRunObject::GetCharBefore(const WSPoint &aPoint) WSRunObject::GetCharBefore(const WSPoint &aPoint)
{ {
MOZ_ASSERT(aPoint.mTextNode); MOZ_ASSERT(aPoint.mTextNode);
@@ -1461,7 +1445,7 @@ nsWSRunObject::GetCharBefore(const WSPoint &aPoint)
} }
nsresult nsresult
nsWSRunObject::ConvertToNBSP(WSPoint aPoint, AreaRestriction aAR) WSRunObject::ConvertToNBSP(WSPoint aPoint, AreaRestriction aAR)
{ {
// MOOSE: this routine needs to be modified to preserve the integrity of the // MOOSE: this routine needs to be modified to preserve the integrity of the
// wsFragment info. // wsFragment info.
@@ -1500,9 +1484,13 @@ nsWSRunObject::ConvertToNBSP(WSPoint aPoint, AreaRestriction aAR)
} }
void void
nsWSRunObject::GetAsciiWSBounds(int16_t aDir, nsINode* aNode, int32_t aOffset, WSRunObject::GetAsciiWSBounds(int16_t aDir,
Text** outStartNode, int32_t* outStartOffset, nsINode* aNode,
Text** outEndNode, int32_t* outEndOffset) int32_t aOffset,
Text** outStartNode,
int32_t* outStartOffset,
Text** outEndNode,
int32_t* outEndOffset)
{ {
MOZ_ASSERT(aNode && outStartNode && outStartOffset && outEndNode && MOZ_ASSERT(aNode && outStartNode && outStartOffset && outEndNode &&
outEndOffset); outEndOffset);
@@ -1559,7 +1547,9 @@ nsWSRunObject::GetAsciiWSBounds(int16_t aDir, nsINode* aNode, int32_t aOffset,
* needs * needs
*/ */
void void
nsWSRunObject::FindRun(nsINode* aNode, int32_t aOffset, WSFragment** outRun, WSRunObject::FindRun(nsINode* aNode,
int32_t aOffset,
WSFragment** outRun,
bool after) bool after)
{ {
MOZ_ASSERT(aNode && outRun); MOZ_ASSERT(aNode && outRun);
@@ -1604,7 +1594,8 @@ nsWSRunObject::FindRun(nsINode* aNode, int32_t aOffset, WSFragment** outRun,
} }
char16_t char16_t
nsWSRunObject::GetCharAt(Text* aTextNode, int32_t aOffset) WSRunObject::GetCharAt(Text* aTextNode,
int32_t aOffset)
{ {
// return 0 if we can't get a char, for whatever reason // return 0 if we can't get a char, for whatever reason
NS_ENSURE_TRUE(aTextNode, 0); NS_ENSURE_TRUE(aTextNode, 0);
@@ -1616,8 +1607,9 @@ nsWSRunObject::GetCharAt(Text* aTextNode, int32_t aOffset)
return aTextNode->GetText()->CharAt(aOffset); return aTextNode->GetText()->CharAt(aOffset);
} }
nsWSRunObject::WSPoint WSRunObject::WSPoint
nsWSRunObject::GetWSPointAfter(nsINode* aNode, int32_t aOffset) WSRunObject::GetWSPointAfter(nsINode* aNode,
int32_t aOffset)
{ {
// Note: only to be called if aNode is not a ws node. // Note: only to be called if aNode is not a ws node.
@@ -1665,8 +1657,9 @@ nsWSRunObject::GetWSPointAfter(nsINode* aNode, int32_t aOffset)
} }
} }
nsWSRunObject::WSPoint WSRunObject::WSPoint
nsWSRunObject::GetWSPointBefore(nsINode* aNode, int32_t aOffset) WSRunObject::GetWSPointBefore(nsINode* aNode,
int32_t aOffset)
{ {
// Note: only to be called if aNode is not a ws node. // Note: only to be called if aNode is not a ws node.
@@ -1717,7 +1710,7 @@ nsWSRunObject::GetWSPointBefore(nsINode* aNode, int32_t aOffset)
} }
nsresult nsresult
nsWSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun) WSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun)
{ {
// Try to change an nbsp to a space, if possible, just to prevent nbsp // Try to change an nbsp to a space, if possible, just to prevent nbsp
// proliferation. Examine what is before and after the trailing nbsp, if // proliferation. Examine what is before and after the trailing nbsp, if
@@ -1833,7 +1826,8 @@ nsWSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun)
} }
nsresult nsresult
nsWSRunObject::CheckTrailingNBSP(WSFragment* aRun, nsINode* aNode, WSRunObject::CheckTrailingNBSP(WSFragment* aRun,
nsINode* aNode,
int32_t aOffset) int32_t aOffset)
{ {
// Try to change an nbsp to a space, if possible, just to prevent nbsp // Try to change an nbsp to a space, if possible, just to prevent nbsp
@@ -1872,7 +1866,8 @@ nsWSRunObject::CheckTrailingNBSP(WSFragment* aRun, nsINode* aNode,
} }
nsresult nsresult
nsWSRunObject::CheckLeadingNBSP(WSFragment* aRun, nsINode* aNode, WSRunObject::CheckLeadingNBSP(WSFragment* aRun,
nsINode* aNode,
int32_t aOffset) int32_t aOffset)
{ {
// Try to change an nbsp to a space, if possible, just to prevent nbsp // Try to change an nbsp to a space, if possible, just to prevent nbsp
@@ -1914,7 +1909,7 @@ nsWSRunObject::CheckLeadingNBSP(WSFragment* aRun, nsINode* aNode,
nsresult nsresult
nsWSRunObject::Scrub() WSRunObject::Scrub()
{ {
WSFragment *run = mStartRun; WSFragment *run = mStartRun;
while (run) while (run)
@@ -1930,8 +1925,10 @@ nsWSRunObject::Scrub()
} }
bool bool
nsWSRunObject::IsBlockNode(nsINode* aNode) WSRunObject::IsBlockNode(nsINode* aNode)
{ {
return aNode && aNode->IsElement() && return aNode && aNode->IsElement() &&
nsHTMLEditor::NodeIsBlockStatic(aNode->AsElement()); nsHTMLEditor::NodeIsBlockStatic(aNode->AsElement());
} }
} // namespace mozilla

View File

@@ -0,0 +1,411 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef WSRunObject_h
#define WSRunObject_h
#include "nsCOMPtr.h"
#include "nsIEditor.h" // for EDirection
#include "nsINode.h"
#include "nscore.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/Text.h"
class nsHTMLEditor;
class nsHTMLEditRules;
class nsIDOMNode;
namespace mozilla {
struct EditorDOMPoint;
// class WSRunObject represents the entire whitespace situation
// around a given point. It collects up a list of nodes that contain
// whitespace and categorizes in up to 3 different WSFragments (detailed
// below). Each WSFragment is a collection of whitespace that is
// either all insignificant, or that is significant. A WSFragment could
// consist of insignificant whitespace because it is after a block
// boundary or after a break. Or it could be insignificant because it
// is before a block. Or it could be significant because it is
// surrounded by text, or starts and ends with nbsps, etc.
// Throughout I refer to LeadingWS, NormalWS, TrailingWS. LeadingWS & TrailingWS
// are runs of ascii ws that are insignificant (do not render) because they
// are adjacent to block boundaries, or after a break. NormalWS is ws that
// does cause soem rendering. Note that not all the ws in a NormalWS run need
// render. For example, two ascii spaces surrounded by text on both sides
// will only render as one space (in non-preformatted stlye html), yet both
// spaces count as NormalWS. Together, they render as the one visible space.
/**
* A type-safe bitfield indicating various types of whitespace or other things.
* Used as a member variable in WSRunObject and WSFragment.
*
* XXX: If this idea is useful in other places, we should generalize it using a
* template.
*/
class WSType
{
public:
enum Enum
{
none = 0,
leadingWS = 1, // leading insignificant ws, ie, after block or br
trailingWS = 1 << 1, // trailing insignificant ws, ie, before block
normalWS = 1 << 2, // normal significant ws, ie, after text, image, ...
text = 1 << 3, // indicates regular (non-ws) text
special = 1 << 4, // indicates an inline non-container, like image
br = 1 << 5, // indicates a br node
otherBlock = 1 << 6, // indicates a block other than one ws run is in
thisBlock = 1 << 7, // indicates the block ws run is in
block = otherBlock | thisBlock // block found
};
/**
* Implicit constructor, because the enums are logically just WSTypes
* themselves, and are only a separate type because there's no other obvious
* way to name specific WSType values.
*/
MOZ_IMPLICIT WSType(const Enum& aEnum = none)
: mEnum(aEnum)
{}
// operator==, &, and | need to access mEnum
friend bool operator==(const WSType& aLeft, const WSType& aRight);
friend const WSType operator&(const WSType& aLeft, const WSType& aRight);
friend const WSType operator|(const WSType& aLeft, const WSType& aRight);
WSType& operator=(const WSType& aOther)
{
// This handles self-assignment fine
mEnum = aOther.mEnum;
return *this;
}
WSType& operator&=(const WSType& aOther)
{
mEnum &= aOther.mEnum;
return *this;
}
WSType& operator|=(const WSType& aOther)
{
mEnum |= aOther.mEnum;
return *this;
}
private:
uint16_t mEnum;
void bool_conversion_helper() {}
public:
// Allow boolean conversion with no numeric conversion
typedef void (WSType::*bool_type)();
operator bool_type() const
{
return mEnum ? &WSType::bool_conversion_helper : nullptr;
}
};
/**
* These are declared as global functions so "WSType::Enum == WSType" et al.
* will work using the implicit constructor.
*/
inline bool operator==(const WSType& aLeft, const WSType& aRight)
{
return aLeft.mEnum == aRight.mEnum;
}
inline bool operator!=(const WSType& aLeft, const WSType& aRight)
{
return !(aLeft == aRight);
}
inline const WSType operator&(const WSType& aLeft, const WSType& aRight)
{
WSType ret;
ret.mEnum = aLeft.mEnum & aRight.mEnum;
return ret;
}
inline const WSType operator|(const WSType& aLeft, const WSType& aRight)
{
WSType ret;
ret.mEnum = aLeft.mEnum | aRight.mEnum;
return ret;
}
/**
* Make sure that & and | of WSType::Enum creates a WSType instead of an int,
* because operators between WSType and int shouldn't work
*/
inline const WSType operator&(const WSType::Enum& aLeft,
const WSType::Enum& aRight)
{
return WSType(aLeft) & WSType(aRight);
}
inline const WSType operator|(const WSType::Enum& aLeft,
const WSType::Enum& aRight)
{
return WSType(aLeft) | WSType(aRight);
}
class MOZ_STACK_CLASS WSRunObject final
{
public:
enum BlockBoundary
{
kBeforeBlock,
kBlockStart,
kBlockEnd,
kAfterBlock
};
enum {eBefore = 1};
enum {eAfter = 1 << 1};
enum {eBoth = eBefore | eAfter};
WSRunObject(nsHTMLEditor* aHTMLEditor, nsINode* aNode, int32_t aOffset);
WSRunObject(nsHTMLEditor* aHTMLEditor, nsIDOMNode* aNode, int32_t aOffset);
~WSRunObject();
// ScrubBlockBoundary removes any non-visible whitespace at the specified
// location relative to a block node.
static nsresult ScrubBlockBoundary(nsHTMLEditor* aHTMLEditor,
BlockBoundary aBoundary,
nsINode* aBlock,
int32_t aOffset = -1);
// PrepareToJoinBlocks fixes up ws at the end of aLeftBlock and the
// beginning of aRightBlock in preperation for them to be joined. Example
// of fixup: trailingws in aLeftBlock needs to be removed.
static nsresult PrepareToJoinBlocks(nsHTMLEditor* aHTMLEditor,
dom::Element* aLeftBlock,
dom::Element* aRightBlock);
// PrepareToDeleteRange fixes up ws before {aStartNode,aStartOffset}
// and after {aEndNode,aEndOffset} in preperation for content
// in that range to be deleted. Note that the nodes and offsets
// are adjusted in response to any dom changes we make while
// adjusting ws.
// example of fixup: trailingws before {aStartNode,aStartOffset}
// needs to be removed.
static nsresult PrepareToDeleteRange(nsHTMLEditor* aHTMLEditor,
nsCOMPtr<nsINode>* aStartNode,
int32_t* aStartOffset,
nsCOMPtr<nsINode>* aEndNode,
int32_t* aEndOffset);
// PrepareToDeleteNode fixes up ws before and after aContent in preparation
// for aContent to be deleted. Example of fixup: trailingws before
// aContent needs to be removed.
static nsresult PrepareToDeleteNode(nsHTMLEditor* aHTMLEditor,
nsIContent* aContent);
// PrepareToSplitAcrossBlocks fixes up ws before and after
// {aSplitNode,aSplitOffset} in preparation for a block parent to be split.
// Note that the aSplitNode and aSplitOffset are adjusted in response to
// any DOM changes we make while adjusting ws. Example of fixup: normalws
// before {aSplitNode,aSplitOffset} needs to end with nbsp.
static nsresult PrepareToSplitAcrossBlocks(nsHTMLEditor* aHTMLEditor,
nsCOMPtr<nsINode>* aSplitNode,
int32_t* aSplitOffset);
// InsertBreak inserts a br node at {aInOutParent,aInOutOffset}
// and makes any needed adjustments to ws around that point.
// example of fixup: normalws after {aInOutParent,aInOutOffset}
// needs to begin with nbsp.
dom::Element* InsertBreak(nsCOMPtr<nsINode>* aInOutParent,
int32_t* aInOutOffset,
nsIEditor::EDirection aSelect);
// InsertText inserts a string at {aInOutParent,aInOutOffset} and makes any
// needed adjustments to ws around that point. Example of fixup:
// trailingws before {aInOutParent,aInOutOffset} needs to be removed.
nsresult InsertText(const nsAString& aStringToInsert,
nsCOMPtr<nsINode>* aInOutNode,
int32_t* aInOutOffset,
nsIDocument* aDoc);
// DeleteWSBackward deletes a single visible piece of ws before the ws
// point (the point to create the wsRunObject, passed to its constructor).
// It makes any needed conversion to adjacent ws to retain its
// significance.
nsresult DeleteWSBackward();
// DeleteWSForward deletes a single visible piece of ws after the ws point
// (the point to create the wsRunObject, passed to its constructor). It
// makes any needed conversion to adjacent ws to retain its significance.
nsresult DeleteWSForward();
// PriorVisibleNode returns the first piece of visible thing before
// {aNode,aOffset}. If there is no visible ws qualifying it returns what
// is before the ws run. Note that {outVisNode,outVisOffset} is set to
// just AFTER the visible object.
void PriorVisibleNode(nsINode* aNode,
int32_t aOffset,
nsCOMPtr<nsINode>* outVisNode,
int32_t* outVisOffset,
WSType* outType);
// NextVisibleNode returns the first piece of visible thing after
// {aNode,aOffset}. If there is no visible ws qualifying it returns what
// is after the ws run. Note that {outVisNode,outVisOffset} is set to just
// BEFORE the visible object.
void NextVisibleNode(nsINode* aNode,
int32_t aOffset,
nsCOMPtr<nsINode>* outVisNode,
int32_t* outVisOffset,
WSType* outType);
// AdjustWhitespace examines the ws object for nbsp's that can
// be safely converted to regular ascii space and converts them.
nsresult AdjustWhitespace();
protected:
// WSFragment represents a single run of ws (all leadingws, or all normalws,
// or all trailingws, or all leading+trailingws). Note that this single run
// may still span multiple nodes.
struct WSFragment final
{
nsCOMPtr<nsINode> mStartNode; // node where ws run starts
nsCOMPtr<nsINode> mEndNode; // node where ws run ends
int32_t mStartOffset; // offset where ws run starts
int32_t mEndOffset; // offset where ws run ends
// type of ws, and what is to left and right of it
WSType mType, mLeftType, mRightType;
// other ws runs to left or right. may be null.
WSFragment *mLeft, *mRight;
WSFragment()
: mStartOffset(0)
, mEndOffset(0)
, mLeft(nullptr)
, mRight(nullptr)
{}
};
// A WSPoint struct represents a unique location within the ws run. It is
// always within a textnode that is one of the nodes stored in the list
// in the wsRunObject. For convenience, the character at that point is also
// stored in the struct.
struct MOZ_STACK_CLASS WSPoint final
{
RefPtr<dom::Text> mTextNode;
uint32_t mOffset;
char16_t mChar;
WSPoint()
: mTextNode(0)
, mOffset(0)
, mChar(0)
{}
WSPoint(dom::Text* aTextNode, int32_t aOffset, char16_t aChar)
: mTextNode(aTextNode)
, mOffset(aOffset)
, mChar(aChar)
{}
};
enum AreaRestriction
{
eAnywhere, eOutsideUserSelectAll
};
/**
* Return the node which we will handle white-space under. This is the
* closest block within the DOM subtree we're editing, or if none is
* found, the (inline) root of the editable subtree.
*/
nsINode* GetWSBoundingParent();
nsresult GetWSNodes();
void GetRuns();
void ClearRuns();
void MakeSingleWSRun(WSType aType);
nsIContent* GetPreviousWSNodeInner(nsINode* aStartNode,
nsINode* aBlockParent);
nsIContent* GetPreviousWSNode(EditorDOMPoint aPoint, nsINode* aBlockParent);
nsIContent* GetNextWSNodeInner(nsINode* aStartNode, nsINode* aBlockParent);
nsIContent* GetNextWSNode(EditorDOMPoint aPoint, nsINode* aBlockParent);
nsresult PrepareToDeleteRangePriv(WSRunObject* aEndObject);
nsresult PrepareToSplitAcrossBlocksPriv();
nsresult DeleteChars(nsINode* aStartNode, int32_t aStartOffset,
nsINode* aEndNode, int32_t aEndOffset,
AreaRestriction aAR = eAnywhere);
WSPoint GetCharAfter(nsINode* aNode, int32_t aOffset);
WSPoint GetCharBefore(nsINode* aNode, int32_t aOffset);
WSPoint GetCharAfter(const WSPoint& aPoint);
WSPoint GetCharBefore(const WSPoint& aPoint);
nsresult ConvertToNBSP(WSPoint aPoint,
AreaRestriction aAR = eAnywhere);
void GetAsciiWSBounds(int16_t aDir, nsINode* aNode, int32_t aOffset,
dom::Text** outStartNode, int32_t* outStartOffset,
dom::Text** outEndNode, int32_t* outEndOffset);
void FindRun(nsINode* aNode, int32_t aOffset, WSFragment** outRun,
bool after);
char16_t GetCharAt(dom::Text* aTextNode, int32_t aOffset);
WSPoint GetWSPointAfter(nsINode* aNode, int32_t aOffset);
WSPoint GetWSPointBefore(nsINode* aNode, int32_t aOffset);
nsresult CheckTrailingNBSPOfRun(WSFragment *aRun);
nsresult CheckTrailingNBSP(WSFragment* aRun, nsINode* aNode,
int32_t aOffset);
nsresult CheckLeadingNBSP(WSFragment* aRun, nsINode* aNode,
int32_t aOffset);
nsresult Scrub();
bool IsBlockNode(nsINode* aNode);
// The node passed to our constructor.
nsCOMPtr<nsINode> mNode;
// The offset passed to our contructor.
int32_t mOffset;
// Together, the above represent the point at which we are building up ws info.
// true if we are in preformatted whitespace context.
bool mPRE;
// Node/offset where ws starts.
nsCOMPtr<nsINode> mStartNode;
int32_t mStartOffset;
// Reason why ws starts (eText, eOtherBlock, etc).
WSType mStartReason;
// The node that implicated by start reason.
nsCOMPtr<nsINode> mStartReasonNode;
// Node/offset where ws ends.
nsCOMPtr<nsINode> mEndNode;
int32_t mEndOffset;
// Reason why ws ends (eText, eOtherBlock, etc).
WSType mEndReason;
// The node that implicated by end reason.
nsCOMPtr<nsINode> mEndReasonNode;
// Location of first nbsp in ws run, if any.
RefPtr<dom::Text> mFirstNBSPNode;
int32_t mFirstNBSPOffset;
// Location of last nbsp in ws run, if any.
RefPtr<dom::Text> mLastNBSPNode;
int32_t mLastNBSPOffset;
// The list of nodes containing ws in this run.
nsTArray<RefPtr<dom::Text>> mNodeArray;
// The first WSFragment in the run.
WSFragment* mStartRun;
// The last WSFragment in the run, may be same as first.
WSFragment* mEndRun;
// Non-owning.
nsHTMLEditor* mHTMLEditor;
// Opening this class up for pillaging.
friend class nsHTMLEditRules;
// Opening this class up for more pillaging.
friend class nsHTMLEditor;
};
} // namespace mozilla
#endif // #ifndef WSRunObject_h

View File

@@ -53,7 +53,6 @@ UNIFIED_SOURCES += [
'nsTableEditor.cpp', 'nsTableEditor.cpp',
'nsTextEditRules.cpp', 'nsTextEditRules.cpp',
'nsTextEditRulesBidi.cpp', 'nsTextEditRulesBidi.cpp',
'nsWSRunObject.cpp',
'PlaceholderTransaction.cpp', 'PlaceholderTransaction.cpp',
'SelectionState.cpp', 'SelectionState.cpp',
'SetDocumentTitleTransaction.cpp', 'SetDocumentTitleTransaction.cpp',
@@ -62,6 +61,7 @@ UNIFIED_SOURCES += [
'TextEditorTest.cpp', 'TextEditorTest.cpp',
'TextEditUtils.cpp', 'TextEditUtils.cpp',
'TypeInState.cpp', 'TypeInState.cpp',
'WSRunObject.cpp',
] ]
LOCAL_INCLUDES += [ LOCAL_INCLUDES += [

View File

@@ -10,6 +10,7 @@
#include "HTMLEditUtils.h" #include "HTMLEditUtils.h"
#include "SelectionState.h" #include "SelectionState.h"
#include "TextEditUtils.h" #include "TextEditUtils.h"
#include "WSRunObject.h"
#include "mozilla/dom/DataTransfer.h" #include "mozilla/dom/DataTransfer.h"
#include "mozilla/dom/DocumentFragment.h" #include "mozilla/dom/DocumentFragment.h"
#include "mozilla/dom/DOMStringList.h" #include "mozilla/dom/DOMStringList.h"
@@ -81,7 +82,6 @@
#include "nsSubstringTuple.h" #include "nsSubstringTuple.h"
#include "nsTextEditRules.h" #include "nsTextEditRules.h"
#include "nsTreeSanitizer.h" #include "nsTreeSanitizer.h"
#include "nsWSRunObject.h"
#include "nsXPCOM.h" #include "nsXPCOM.h"
#include "nscore.h" #include "nscore.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
@@ -389,7 +389,7 @@ nsHTMLEditor::DoInsertHTMLWithContext(const nsAString & aInputString,
// if there are any invisible br's after our insertion point, remove them. // if there are any invisible br's after our insertion point, remove them.
// this is because if there is a br at end of what we paste, it will make // this is because if there is a br at end of what we paste, it will make
// the invisible br visible. // the invisible br visible.
nsWSRunObject wsObj(this, parentNode, offsetOfNewNode); WSRunObject wsObj(this, parentNode, offsetOfNewNode);
if (wsObj.mEndReasonNode && if (wsObj.mEndReasonNode &&
TextEditUtils::IsBreak(wsObj.mEndReasonNode) && TextEditUtils::IsBreak(wsObj.mEndReasonNode) &&
!IsVisBreak(wsObj.mEndReasonNode)) { !IsVisBreak(wsObj.mEndReasonNode)) {
@@ -647,7 +647,7 @@ nsHTMLEditor::DoInsertHTMLWithContext(const nsAString & aInputString,
} }
// make sure we don't end up with selection collapsed after an invisible break node // make sure we don't end up with selection collapsed after an invisible break node
nsWSRunObject wsRunObj(this, selNode, selOffset); WSRunObject wsRunObj(this, selNode, selOffset);
nsCOMPtr<nsINode> visNode; nsCOMPtr<nsINode> visNode;
int32_t outVisOffset=0; int32_t outVisOffset=0;
WSType visType; WSType visType;
@@ -658,14 +658,14 @@ nsHTMLEditor::DoInsertHTMLWithContext(const nsAString & aInputString,
// we are after a break. Is it visible? Despite the name, // we are after a break. Is it visible? Despite the name,
// PriorVisibleNode does not make that determination for breaks. // PriorVisibleNode does not make that determination for breaks.
// It also may not return the break in visNode. We have to pull it // It also may not return the break in visNode. We have to pull it
// out of the nsWSRunObject's state. // out of the WSRunObject's state.
if (!IsVisBreak(wsRunObj.mStartReasonNode)) if (!IsVisBreak(wsRunObj.mStartReasonNode))
{ {
// don't leave selection past an invisible break; // don't leave selection past an invisible break;
// reset {selNode,selOffset} to point before break // reset {selNode,selOffset} to point before break
selNode = GetNodeLocation(GetAsDOMNode(wsRunObj.mStartReasonNode), &selOffset); selNode = GetNodeLocation(GetAsDOMNode(wsRunObj.mStartReasonNode), &selOffset);
// we want to be inside any inline style prior to break // we want to be inside any inline style prior to break
nsWSRunObject wsRunObj(this, selNode, selOffset); WSRunObject wsRunObj(this, selNode, selOffset);
selNode_ = do_QueryInterface(selNode); selNode_ = do_QueryInterface(selNode);
wsRunObj.PriorVisibleNode(selNode_, selOffset, address_of(visNode), wsRunObj.PriorVisibleNode(selNode_, selOffset, address_of(visNode),
&outVisOffset, &visType); &outVisOffset, &visType);

View File

@@ -12,6 +12,7 @@
#include "EditorUtils.h" #include "EditorUtils.h"
#include "HTMLEditUtils.h" #include "HTMLEditUtils.h"
#include "TextEditUtils.h" #include "TextEditUtils.h"
#include "WSRunObject.h"
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "mozilla/MathAlgorithms.h" #include "mozilla/MathAlgorithms.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
@@ -53,7 +54,6 @@
#include "nsTextNode.h" #include "nsTextNode.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "nsUnicharUtils.h" #include "nsUnicharUtils.h"
#include "nsWSRunObject.h"
#include <algorithm> #include <algorithm>
// Workaround for windows headers // Workaround for windows headers
@@ -514,13 +514,13 @@ nsHTMLEditRules::AfterEditInner(EditAction action,
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
NS_ENSURE_STATE(mRangeItem->startNode); NS_ENSURE_STATE(mRangeItem->startNode);
NS_ENSURE_STATE(mRangeItem->endNode); NS_ENSURE_STATE(mRangeItem->endNode);
nsWSRunObject(mHTMLEditor, mRangeItem->startNode, WSRunObject(mHTMLEditor, mRangeItem->startNode,
mRangeItem->startOffset).AdjustWhitespace(); mRangeItem->startOffset).AdjustWhitespace();
// we only need to handle old selection endpoint if it was different from start // we only need to handle old selection endpoint if it was different from start
if (mRangeItem->startNode != mRangeItem->endNode || if (mRangeItem->startNode != mRangeItem->endNode ||
mRangeItem->startOffset != mRangeItem->endOffset) { mRangeItem->startOffset != mRangeItem->endOffset) {
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
nsWSRunObject(mHTMLEditor, mRangeItem->endNode, WSRunObject(mHTMLEditor, mRangeItem->endNode,
mRangeItem->endOffset).AdjustWhitespace(); mRangeItem->endOffset).AdjustWhitespace();
} }
} }
@@ -1304,7 +1304,7 @@ nsHTMLEditRules::WillInsertText(EditAction aAction,
} }
if (aAction == EditAction::insertIMEText) { if (aAction == EditAction::insertIMEText) {
// Right now the nsWSRunObject code bails on empty strings, but IME needs // Right now the WSRunObject code bails on empty strings, but IME needs
// the InsertTextImpl() call to still happen since empty strings are meaningful there. // the InsertTextImpl() call to still happen since empty strings are meaningful there.
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
// If there is one or more IME selections, its minimum offset should be // If there is one or more IME selections, its minimum offset should be
@@ -1321,7 +1321,7 @@ nsHTMLEditRules::WillInsertText(EditAction aAction,
} }
else else
{ {
nsWSRunObject wsObj(mHTMLEditor, selNode, selOffset); WSRunObject wsObj(mHTMLEditor, selNode, selOffset);
res = wsObj.InsertText(*inString, address_of(selNode), &selOffset, doc); res = wsObj.InsertText(*inString, address_of(selNode), &selOffset, doc);
} }
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
@@ -1424,7 +1424,7 @@ nsHTMLEditRules::WillInsertText(EditAction aAction,
nsDependentSubstring subStr(tString, oldPos, subStrLen); nsDependentSubstring subStr(tString, oldPos, subStrLen);
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
nsWSRunObject wsObj(mHTMLEditor, curNode, curOffset); WSRunObject wsObj(mHTMLEditor, curNode, curOffset);
// is it a tab? // is it a tab?
if (subStr.Equals(tabStr)) if (subStr.Equals(tabStr))
@@ -1604,7 +1604,7 @@ nsHTMLEditRules::StandardBreakImpl(nsINode& aNode, int32_t aOffset,
brNode = mHTMLEditor->CreateBR(node, aOffset); brNode = mHTMLEditor->CreateBR(node, aOffset);
NS_ENSURE_STATE(brNode); NS_ENSURE_STATE(brNode);
} else { } else {
nsWSRunObject wsObj(mHTMLEditor, node, aOffset); WSRunObject wsObj(mHTMLEditor, node, aOffset);
int32_t visOffset = 0; int32_t visOffset = 0;
WSType wsType; WSType wsType;
nsCOMPtr<nsINode> visNode; nsCOMPtr<nsINode> visNode;
@@ -1644,7 +1644,7 @@ nsHTMLEditRules::StandardBreakImpl(nsINode& aNode, int32_t aOffset,
res = aSelection.Collapse(node, offset); res = aSelection.Collapse(node, offset);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
} else { } else {
nsWSRunObject wsObj(mHTMLEditor, node, offset + 1); WSRunObject wsObj(mHTMLEditor, node, offset + 1);
nsCOMPtr<nsINode> secondBR; nsCOMPtr<nsINode> secondBR;
int32_t visOffset = 0; int32_t visOffset = 0;
WSType wsType; WSType wsType;
@@ -1714,7 +1714,7 @@ nsHTMLEditRules::SplitMailCites(Selection* aSelection, bool* aHandled)
// The latter can confuse a user if they click there and start typing, // The latter can confuse a user if they click there and start typing,
// because being in the mailquote may affect wrapping behavior, or font color, etc. // because being in the mailquote may affect wrapping behavior, or font color, etc.
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
nsWSRunObject wsObj(mHTMLEditor, selNode, selOffset); WSRunObject wsObj(mHTMLEditor, selNode, selOffset);
nsCOMPtr<nsINode> visNode; nsCOMPtr<nsINode> visNode;
int32_t visOffset=0; int32_t visOffset=0;
WSType wsType; WSType wsType;
@@ -1750,7 +1750,7 @@ nsHTMLEditRules::SplitMailCites(Selection* aSelection, bool* aHandled)
// then we will need a 2nd br added to achieve blank line that user expects. // then we will need a 2nd br added to achieve blank line that user expects.
if (IsInlineNode(*citeNode)) { if (IsInlineNode(*citeNode)) {
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
nsWSRunObject wsObj(mHTMLEditor, selNode, newOffset); WSRunObject wsObj(mHTMLEditor, selNode, newOffset);
nsCOMPtr<nsINode> visNode; nsCOMPtr<nsINode> visNode;
int32_t visOffset=0; int32_t visOffset=0;
WSType wsType; WSType wsType;
@@ -1759,7 +1759,7 @@ nsHTMLEditRules::SplitMailCites(Selection* aSelection, bool* aHandled)
if (wsType == WSType::normalWS || wsType == WSType::text || if (wsType == WSType::normalWS || wsType == WSType::text ||
wsType == WSType::special) { wsType == WSType::special) {
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
nsWSRunObject wsObjAfterBR(mHTMLEditor, selNode, newOffset+1); WSRunObject wsObjAfterBR(mHTMLEditor, selNode, newOffset+1);
wsObjAfterBR.NextVisibleNode(selNode, newOffset + 1, wsObjAfterBR.NextVisibleNode(selNode, newOffset + 1,
address_of(visNode), &visOffset, &wsType); address_of(visNode), &visOffset, &wsType);
if (wsType == WSType::normalWS || wsType == WSType::text || if (wsType == WSType::normalWS || wsType == WSType::text ||
@@ -1895,7 +1895,7 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection,
if (bCollapsed) { if (bCollapsed) {
// What's in the direction we are deleting? // What's in the direction we are deleting?
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
nsWSRunObject wsObj(mHTMLEditor, startNode, startOffset); WSRunObject wsObj(mHTMLEditor, startNode, startOffset);
nsCOMPtr<nsINode> visNode; nsCOMPtr<nsINode> visNode;
int32_t visOffset; int32_t visOffset;
WSType wsType; WSType wsType;
@@ -1960,7 +1960,7 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection,
eo = range->EndOffset(); eo = range->EndOffset();
} }
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
res = nsWSRunObject::PrepareToDeleteRange(mHTMLEditor, res = WSRunObject::PrepareToDeleteRange(mHTMLEditor,
address_of(visNode), &so, address_of(visNode), &eo); address_of(visNode), &so, address_of(visNode), &eo);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
@@ -2051,7 +2051,7 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection,
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
nsCOMPtr<nsIContent> otherContent(do_QueryInterface(otherNode)); nsCOMPtr<nsIContent> otherContent(do_QueryInterface(otherNode));
res = nsWSRunObject::PrepareToDeleteNode(mHTMLEditor, otherContent); res = WSRunObject::PrepareToDeleteNode(mHTMLEditor, otherContent);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
res = mHTMLEditor->DeleteNode(otherNode); res = mHTMLEditor->DeleteNode(otherNode);
@@ -2066,7 +2066,7 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection,
// Found break or image, or hr. // Found break or image, or hr.
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
NS_ENSURE_STATE(visNode->IsContent()); NS_ENSURE_STATE(visNode->IsContent());
res = nsWSRunObject::PrepareToDeleteNode(mHTMLEditor, res = WSRunObject::PrepareToDeleteNode(mHTMLEditor,
visNode->AsContent()); visNode->AsContent());
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
// Remember sibling to visnode, if any // Remember sibling to visnode, if any
@@ -2254,7 +2254,7 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection,
if (!IsPlaintextEditor()) { if (!IsPlaintextEditor()) {
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
AutoTransactionsConserveSelection dontSpazMySelection(mHTMLEditor); AutoTransactionsConserveSelection dontSpazMySelection(mHTMLEditor);
res = nsWSRunObject::PrepareToDeleteRange(mHTMLEditor, res = WSRunObject::PrepareToDeleteRange(mHTMLEditor,
address_of(startNode), &startOffset, address_of(startNode), &startOffset,
address_of(endNode), &endOffset); address_of(endNode), &endOffset);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
@@ -2492,7 +2492,7 @@ nsHTMLEditRules::InsertBRIfNeeded(Selection* aSelection)
// examine selection // examine selection
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
nsWSRunObject wsObj(mHTMLEditor, node, offset); WSRunObject wsObj(mHTMLEditor, node, offset);
if (((wsObj.mStartReason & WSType::block) || if (((wsObj.mStartReason & WSType::block) ||
(wsObj.mStartReason & WSType::br)) && (wsObj.mStartReason & WSType::br)) &&
(wsObj.mEndReason & WSType::block)) { (wsObj.mEndReason & WSType::block)) {
@@ -2629,8 +2629,8 @@ nsHTMLEditRules::JoinBlocks(nsIContent& aLeftNode, nsIContent& aRightNode,
// Tricky case. Left block is inside right block. Do ws adjustment. This // Tricky case. Left block is inside right block. Do ws adjustment. This
// just destroys non-visible ws at boundaries we will be joining. // just destroys non-visible ws at boundaries we will be joining.
rightOffset++; rightOffset++;
res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor, res = WSRunObject::ScrubBlockBoundary(mHTMLEditor,
nsWSRunObject::kBlockEnd, WSRunObject::kBlockEnd,
leftBlock); leftBlock);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
@@ -2639,8 +2639,8 @@ nsHTMLEditRules::JoinBlocks(nsIContent& aLeftNode, nsIContent& aRightNode,
nsCOMPtr<nsINode> trackingRightBlock(rightBlock); nsCOMPtr<nsINode> trackingRightBlock(rightBlock);
AutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, AutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater,
address_of(trackingRightBlock), &rightOffset); address_of(trackingRightBlock), &rightOffset);
res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor, res = WSRunObject::ScrubBlockBoundary(mHTMLEditor,
nsWSRunObject::kAfterBlock, WSRunObject::kAfterBlock,
rightBlock, rightOffset); rightBlock, rightOffset);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
if (trackingRightBlock->IsElement()) { if (trackingRightBlock->IsElement()) {
@@ -2672,8 +2672,8 @@ nsHTMLEditRules::JoinBlocks(nsIContent& aLeftNode, nsIContent& aRightNode,
} else if (EditorUtils::IsDescendantOf(rightBlock, leftBlock, &leftOffset)) { } else if (EditorUtils::IsDescendantOf(rightBlock, leftBlock, &leftOffset)) {
// Tricky case. Right block is inside left block. Do ws adjustment. This // Tricky case. Right block is inside left block. Do ws adjustment. This
// just destroys non-visible ws at boundaries we will be joining. // just destroys non-visible ws at boundaries we will be joining.
res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor, res = WSRunObject::ScrubBlockBoundary(mHTMLEditor,
nsWSRunObject::kBlockStart, WSRunObject::kBlockStart,
rightBlock); rightBlock);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
{ {
@@ -2682,8 +2682,8 @@ nsHTMLEditRules::JoinBlocks(nsIContent& aLeftNode, nsIContent& aRightNode,
nsCOMPtr<nsINode> trackingLeftBlock(leftBlock); nsCOMPtr<nsINode> trackingLeftBlock(leftBlock);
AutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, AutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater,
address_of(trackingLeftBlock), &leftOffset); address_of(trackingLeftBlock), &leftOffset);
res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor, res = WSRunObject::ScrubBlockBoundary(mHTMLEditor,
nsWSRunObject::kBeforeBlock, WSRunObject::kBeforeBlock,
leftBlock, leftOffset); leftBlock, leftOffset);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
if (trackingLeftBlock->IsElement()) { if (trackingLeftBlock->IsElement()) {
@@ -2766,7 +2766,7 @@ nsHTMLEditRules::JoinBlocks(nsIContent& aLeftNode, nsIContent& aRightNode,
// if you backspace from li into p. // if you backspace from li into p.
// Adjust whitespace at block boundaries // Adjust whitespace at block boundaries
res = nsWSRunObject::PrepareToJoinBlocks(mHTMLEditor, leftBlock, rightBlock); res = WSRunObject::PrepareToJoinBlocks(mHTMLEditor, leftBlock, rightBlock);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
// Do br adjustment. // Do br adjustment.
nsCOMPtr<Element> brNode = nsCOMPtr<Element> brNode =
@@ -4893,7 +4893,7 @@ nsHTMLEditRules::CheckForInvisibleBR(Element& aBlock, BRLocation aWhere,
return nullptr; return nullptr;
} }
nsWSRunObject wsTester(mHTMLEditor, testNode, testOffset); WSRunObject wsTester(mHTMLEditor, testNode, testOffset);
if (WSType::br == wsTester.mStartReason) { if (WSType::br == wsTester.mStartReason) {
return wsTester.mStartReasonNode->AsElement(); return wsTester.mStartReasonNode->AsElement();
} }
@@ -4972,7 +4972,7 @@ nsHTMLEditRules::ExpandSelectionForDeletion(Selection& aSelection)
// Find previous visible thingy before start of selection // Find previous visible thingy before start of selection
if (selStartNode != selCommon && selStartNode != root) { if (selStartNode != selCommon && selStartNode != root) {
while (true) { while (true) {
nsWSRunObject wsObj(mHTMLEditor, selStartNode, selStartOffset); WSRunObject wsObj(mHTMLEditor, selStartNode, selStartOffset);
wsObj.PriorVisibleNode(selStartNode, selStartOffset, address_of(unused), wsObj.PriorVisibleNode(selStartNode, selStartOffset, address_of(unused),
&visOffset, &wsType); &visOffset, &wsType);
if (wsType != WSType::thisBlock) { if (wsType != WSType::thisBlock) {
@@ -4994,7 +4994,7 @@ nsHTMLEditRules::ExpandSelectionForDeletion(Selection& aSelection)
// Find next visible thingy after end of selection // Find next visible thingy after end of selection
if (selEndNode != selCommon && selEndNode != root) { if (selEndNode != selCommon && selEndNode != root) {
while (true) { while (true) {
nsWSRunObject wsObj(mHTMLEditor, selEndNode, selEndOffset); WSRunObject wsObj(mHTMLEditor, selEndNode, selEndOffset);
wsObj.NextVisibleNode(selEndNode, selEndOffset, address_of(unused), wsObj.NextVisibleNode(selEndNode, selEndOffset, address_of(unused),
&visOffset, &wsType); &visOffset, &wsType);
if (wsType == WSType::br) { if (wsType == WSType::br) {
@@ -5117,7 +5117,7 @@ nsHTMLEditRules::NormalizeSelection(Selection* inSelection)
WSType wsType; WSType wsType;
// let the whitespace code do the heavy lifting // let the whitespace code do the heavy lifting
nsWSRunObject wsEndObj(mHTMLEditor, endNode, endOffset); WSRunObject wsEndObj(mHTMLEditor, endNode, endOffset);
// is there any intervening visible whitespace? if so we can't push selection past that, // is there any intervening visible whitespace? if so we can't push selection past that,
// it would visibly change maening of users selection // it would visibly change maening of users selection
nsCOMPtr<nsINode> endNode_(do_QueryInterface(endNode)); nsCOMPtr<nsINode> endNode_(do_QueryInterface(endNode));
@@ -5157,7 +5157,7 @@ nsHTMLEditRules::NormalizeSelection(Selection* inSelection)
// similar dealio for start of range // similar dealio for start of range
nsWSRunObject wsStartObj(mHTMLEditor, startNode, startOffset); WSRunObject wsStartObj(mHTMLEditor, startNode, startOffset);
// is there any intervening visible whitespace? if so we can't push selection past that, // is there any intervening visible whitespace? if so we can't push selection past that,
// it would visibly change maening of users selection // it would visibly change maening of users selection
nsCOMPtr<nsINode> startNode_(do_QueryInterface(startNode)); nsCOMPtr<nsINode> startNode_(do_QueryInterface(startNode));
@@ -6143,7 +6143,7 @@ nsHTMLEditRules::ReturnInHeader(Selection& aSelection,
// Get ws code to adjust any ws // Get ws code to adjust any ws
nsCOMPtr<nsINode> node = &aNode; nsCOMPtr<nsINode> node = &aNode;
nsresult res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, nsresult res = WSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor,
address_of(node), address_of(node),
&aOffset); &aOffset);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
@@ -6340,7 +6340,8 @@ nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
nsCOMPtr<nsIContent> leftPara, rightPara; nsCOMPtr<nsIContent> leftPara, rightPara;
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
nsCOMPtr<nsINode> selNode(do_QueryInterface(*aSelNode)); nsCOMPtr<nsINode> selNode(do_QueryInterface(*aSelNode));
res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, address_of(selNode), aOffset); res = WSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor,
address_of(selNode), aOffset);
*aSelNode = GetAsDOMNode(selNode); *aSelNode = GetAsDOMNode(selNode);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
// split the paragraph // split the paragraph
@@ -6465,7 +6466,7 @@ nsHTMLEditRules::ReturnInListItem(Selection& aSelection,
// Else we want a new list item at the same list level. Get ws code to // Else we want a new list item at the same list level. Get ws code to
// adjust any ws. // adjust any ws.
nsCOMPtr<nsINode> selNode = &aNode; nsCOMPtr<nsINode> selNode = &aNode;
res = nsWSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor, res = WSRunObject::PrepareToSplitAcrossBlocks(mHTMLEditor,
address_of(selNode), address_of(selNode),
&aOffset); &aOffset);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
@@ -6519,7 +6520,7 @@ nsHTMLEditRules::ReturnInListItem(Selection& aSelection,
return NS_OK; return NS_OK;
} }
} else { } else {
nsWSRunObject wsObj(mHTMLEditor, &aListItem, 0); WSRunObject wsObj(mHTMLEditor, &aListItem, 0);
nsCOMPtr<nsINode> visNode; nsCOMPtr<nsINode> visNode;
int32_t visOffset = 0; int32_t visOffset = 0;
WSType wsType; WSType wsType;
@@ -7131,7 +7132,7 @@ nsHTMLEditRules::AdjustWhitespace(Selection* aSelection)
// ask whitespace object to tweak nbsp's // ask whitespace object to tweak nbsp's
NS_ENSURE_STATE(mHTMLEditor); NS_ENSURE_STATE(mHTMLEditor);
return nsWSRunObject(mHTMLEditor, selNode, selOffset).AdjustWhitespace(); return WSRunObject(mHTMLEditor, selNode, selOffset).AdjustWhitespace();
} }
nsresult nsresult

View File

@@ -59,7 +59,7 @@
// Misc // Misc
#include "EditorUtils.h" #include "EditorUtils.h"
#include "TextEditorTest.h" #include "TextEditorTest.h"
#include "nsWSRunObject.h" #include "WSRunObject.h"
#include "nsGkAtoms.h" #include "nsGkAtoms.h"
#include "nsIWidget.h" #include "nsIWidget.h"
@@ -549,7 +549,7 @@ nsHTMLEditor::BeginningOfDocument()
nsCOMPtr<nsINode> curNode = rootElement.get(), selNode; nsCOMPtr<nsINode> curNode = rootElement.get(), selNode;
int32_t curOffset = 0, selOffset = 0; int32_t curOffset = 0, selOffset = 0;
while (!done) { while (!done) {
nsWSRunObject wsObj(this, curNode, curOffset); WSRunObject wsObj(this, curNode, curOffset);
int32_t visOffset = 0; int32_t visOffset = 0;
WSType visType; WSType visType;
nsCOMPtr<nsINode> visNode; nsCOMPtr<nsINode> visNode;
@@ -564,7 +564,7 @@ nsHTMLEditor::BeginningOfDocument()
selOffset = selNode ? selNode->IndexOf(visNode) : -1; selOffset = selNode ? selNode->IndexOf(visNode) : -1;
done = true; done = true;
} else if (visType == WSType::otherBlock) { } else if (visType == WSType::otherBlock) {
// By definition of nsWSRunObject, a block element terminates a // By definition of WSRunObject, a block element terminates a
// whitespace run. That is, although we are calling a method that is // whitespace run. That is, although we are calling a method that is
// named "NextVisibleNode", the node returned might not be // named "NextVisibleNode", the node returned might not be
// visible/editable! // visible/editable!
@@ -983,7 +983,7 @@ nsHTMLEditor::IsVisBreak(nsINode* aNode)
nsCOMPtr<nsINode> selNode = GetNodeLocation(aNode, &selOffset); nsCOMPtr<nsINode> selNode = GetNodeLocation(aNode, &selOffset);
// Let's look after the break // Let's look after the break
selOffset++; selOffset++;
nsWSRunObject wsObj(this, selNode, selOffset); WSRunObject wsObj(this, selNode, selOffset);
nsCOMPtr<nsINode> unused; nsCOMPtr<nsINode> unused;
int32_t visOffset = 0; int32_t visOffset = 0;
WSType visType; WSType visType;
@@ -1444,7 +1444,7 @@ nsHTMLEditor::NormalizeEOLInsertPosition(nsINode* firstNodeToInsert,
if (!IsBlockNode(firstNodeToInsert)) if (!IsBlockNode(firstNodeToInsert))
return; return;
nsWSRunObject wsObj(this, *insertParentNode, *insertOffset); WSRunObject wsObj(this, *insertParentNode, *insertOffset);
nsCOMPtr<nsINode> nextVisNode, prevVisNode; nsCOMPtr<nsINode> nextVisNode, prevVisNode;
int32_t nextVisOffset=0; int32_t nextVisOffset=0;
WSType nextVisType; WSType nextVisType;
@@ -4245,7 +4245,7 @@ nsHTMLEditor::IsVisTextNode(nsIContent* aNode,
{ {
if (aNode->TextIsOnlyWhitespace()) if (aNode->TextIsOnlyWhitespace())
{ {
nsWSRunObject wsRunObj(this, aNode, 0); WSRunObject wsRunObj(this, aNode, 0);
nsCOMPtr<nsINode> visNode; nsCOMPtr<nsINode> visNode;
int32_t outVisOffset=0; int32_t outVisOffset=0;
WSType visType; WSType visType;

View File

@@ -55,6 +55,7 @@ class nsRange;
namespace mozilla { namespace mozilla {
class TypeInState; class TypeInState;
class WSRunObject;
struct PropItem; struct PropItem;
template<class T> class OwningNonNull; template<class T> class OwningNonNull;
namespace dom { namespace dom {
@@ -973,9 +974,9 @@ protected:
public: public:
// friends // friends
friend class mozilla::WSRunObject;
friend class nsHTMLEditRules; friend class nsHTMLEditRules;
friend class nsTextEditRules; friend class nsTextEditRules;
friend class nsWSRunObject;
friend class nsHTMLEditorEventListener; friend class nsHTMLEditorEventListener;
private: private:

View File

@@ -1,388 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __wsrunobject_h__
#define __wsrunobject_h__
#include "nsCOMPtr.h"
#include "nsIEditor.h" // for EDirection
#include "nsINode.h"
#include "nscore.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/Text.h"
class nsHTMLEditor;
class nsIDOMNode;
namespace mozilla {
struct EditorDOMPoint;
} // namespace mozilla
// class nsWSRunObject represents the entire whitespace situation
// around a given point. It collects up a list of nodes that contain
// whitespace and categorizes in up to 3 different WSFragments (detailed
// below). Each WSFragment is a collection of whitespace that is
// either all insignificant, or that is significant. A WSFragment could
// consist of insignificant whitespace because it is after a block
// boundary or after a break. Or it could be insignificant because it
// is before a block. Or it could be significant because it is
// surrounded by text, or starts and ends with nbsps, etc.
// Throughout I refer to LeadingWS, NormalWS, TrailingWS. LeadingWS & TrailingWS
// are runs of ascii ws that are insignificant (do not render) because they
// are adjacent to block boundaries, or after a break. NormalWS is ws that
// does cause soem rendering. Note that not all the ws in a NormalWS run need
// render. For example, two ascii spaces surrounded by text on both sides
// will only render as one space (in non-preformatted stlye html), yet both
// spaces count as NormalWS. Together, they render as the one visible space.
/**
* A type-safe bitfield indicating various types of whitespace or other things.
* Used as a member variable in nsWSRunObject and WSFragment.
*
* XXX: If this idea is useful in other places, we should generalize it using a
* template.
*/
class WSType {
public:
enum Enum {
none = 0,
leadingWS = 1, // leading insignificant ws, ie, after block or br
trailingWS = 1 << 1, // trailing insignificant ws, ie, before block
normalWS = 1 << 2, // normal significant ws, ie, after text, image, ...
text = 1 << 3, // indicates regular (non-ws) text
special = 1 << 4, // indicates an inline non-container, like image
br = 1 << 5, // indicates a br node
otherBlock = 1 << 6, // indicates a block other than one ws run is in
thisBlock = 1 << 7, // indicates the block ws run is in
block = otherBlock | thisBlock // block found
};
/**
* Implicit constructor, because the enums are logically just WSTypes
* themselves, and are only a separate type because there's no other obvious
* way to name specific WSType values.
*/
MOZ_IMPLICIT WSType(const Enum& aEnum = none) : mEnum(aEnum) {}
// operator==, &, and | need to access mEnum
friend bool operator==(const WSType& aLeft, const WSType& aRight);
friend const WSType operator&(const WSType& aLeft, const WSType& aRight);
friend const WSType operator|(const WSType& aLeft, const WSType& aRight);
WSType& operator=(const WSType& aOther) {
// This handles self-assignment fine
mEnum = aOther.mEnum;
return *this;
}
WSType& operator&=(const WSType& aOther) {
mEnum &= aOther.mEnum;
return *this;
}
WSType& operator|=(const WSType& aOther) {
mEnum |= aOther.mEnum;
return *this;
}
private:
uint16_t mEnum;
void bool_conversion_helper() {}
public:
// Allow boolean conversion with no numeric conversion
typedef void (WSType::*bool_type)();
operator bool_type() const
{
return mEnum ? &WSType::bool_conversion_helper : nullptr;
}
};
/**
* These are declared as global functions so "WSType::Enum == WSType" et al.
* will work using the implicit constructor.
*/
inline bool operator==(const WSType& aLeft, const WSType& aRight)
{
return aLeft.mEnum == aRight.mEnum;
}
inline bool operator!=(const WSType& aLeft, const WSType& aRight)
{
return !(aLeft == aRight);
}
inline const WSType operator&(const WSType& aLeft, const WSType& aRight)
{
WSType ret;
ret.mEnum = aLeft.mEnum & aRight.mEnum;
return ret;
}
inline const WSType operator|(const WSType& aLeft, const WSType& aRight)
{
WSType ret;
ret.mEnum = aLeft.mEnum | aRight.mEnum;
return ret;
}
/**
* Make sure that & and | of WSType::Enum creates a WSType instead of an int,
* because operators between WSType and int shouldn't work
*/
inline const WSType operator&(const WSType::Enum& aLeft,
const WSType::Enum& aRight)
{
return WSType(aLeft) & WSType(aRight);
}
inline const WSType operator|(const WSType::Enum& aLeft,
const WSType::Enum& aRight)
{
return WSType(aLeft) | WSType(aRight);
}
class MOZ_STACK_CLASS nsWSRunObject
{
public:
// public enums ---------------------------------------------------------
enum BlockBoundary
{
kBeforeBlock,
kBlockStart,
kBlockEnd,
kAfterBlock
};
enum {eBefore = 1};
enum {eAfter = 1 << 1};
enum {eBoth = eBefore | eAfter};
// constructor / destructor -----------------------------------------------
nsWSRunObject(nsHTMLEditor* aEd, nsINode* aNode, int32_t aOffset);
nsWSRunObject(nsHTMLEditor *aEd, nsIDOMNode *aNode, int32_t aOffset);
~nsWSRunObject();
// public methods ---------------------------------------------------------
// ScrubBlockBoundary removes any non-visible whitespace at the specified
// location relative to a block node.
static nsresult ScrubBlockBoundary(nsHTMLEditor* aHTMLEd,
BlockBoundary aBoundary,
nsINode* aBlock,
int32_t aOffset = -1);
// PrepareToJoinBlocks fixes up ws at the end of aLeftBlock and the
// beginning of aRightBlock in preperation for them to be joined. Example
// of fixup: trailingws in aLeftBlock needs to be removed.
static nsresult PrepareToJoinBlocks(nsHTMLEditor* aEd,
mozilla::dom::Element* aLeftBlock,
mozilla::dom::Element* aRightBlock);
// PrepareToDeleteRange fixes up ws before {aStartNode,aStartOffset}
// and after {aEndNode,aEndOffset} in preperation for content
// in that range to be deleted. Note that the nodes and offsets
// are adjusted in response to any dom changes we make while
// adjusting ws.
// example of fixup: trailingws before {aStartNode,aStartOffset}
// needs to be removed.
static nsresult PrepareToDeleteRange(nsHTMLEditor* aHTMLEd,
nsCOMPtr<nsINode>* aStartNode,
int32_t* aStartOffset,
nsCOMPtr<nsINode>* aEndNode,
int32_t* aEndOffset);
// PrepareToDeleteNode fixes up ws before and after aContent in preparation
// for aContent to be deleted. Example of fixup: trailingws before
// aContent needs to be removed.
static nsresult PrepareToDeleteNode(nsHTMLEditor *aHTMLEd,
nsIContent* aContent);
// PrepareToSplitAcrossBlocks fixes up ws before and after
// {aSplitNode,aSplitOffset} in preparation for a block parent to be split.
// Note that the aSplitNode and aSplitOffset are adjusted in response to
// any DOM changes we make while adjusting ws. Example of fixup: normalws
// before {aSplitNode,aSplitOffset} needs to end with nbsp.
static nsresult PrepareToSplitAcrossBlocks(nsHTMLEditor* aHTMLEd,
nsCOMPtr<nsINode>* aSplitNode,
int32_t* aSplitOffset);
// InsertBreak inserts a br node at {aInOutParent,aInOutOffset}
// and makes any needed adjustments to ws around that point.
// example of fixup: normalws after {aInOutParent,aInOutOffset}
// needs to begin with nbsp.
mozilla::dom::Element* InsertBreak(nsCOMPtr<nsINode>* aInOutParent,
int32_t* aInOutOffset,
nsIEditor::EDirection aSelect);
// InsertText inserts a string at {aInOutParent,aInOutOffset} and makes any
// needed adjustments to ws around that point. Example of fixup:
// trailingws before {aInOutParent,aInOutOffset} needs to be removed.
nsresult InsertText(const nsAString& aStringToInsert,
nsCOMPtr<nsINode>* aInOutNode,
int32_t* aInOutOffset,
nsIDocument* aDoc);
// DeleteWSBackward deletes a single visible piece of ws before the ws
// point (the point to create the wsRunObject, passed to its constructor).
// It makes any needed conversion to adjacent ws to retain its
// significance.
nsresult DeleteWSBackward();
// DeleteWSForward deletes a single visible piece of ws after the ws point
// (the point to create the wsRunObject, passed to its constructor). It
// makes any needed conversion to adjacent ws to retain its significance.
nsresult DeleteWSForward();
// PriorVisibleNode returns the first piece of visible thing before
// {aNode,aOffset}. If there is no visible ws qualifying it returns what
// is before the ws run. Note that {outVisNode,outVisOffset} is set to
// just AFTER the visible object.
void PriorVisibleNode(nsINode* aNode,
int32_t aOffset,
nsCOMPtr<nsINode>* outVisNode,
int32_t* outVisOffset,
WSType* outType);
// NextVisibleNode returns the first piece of visible thing after
// {aNode,aOffset}. If there is no visible ws qualifying it returns what
// is after the ws run. Note that {outVisNode,outVisOffset} is set to just
// BEFORE the visible object.
void NextVisibleNode(nsINode* aNode,
int32_t aOffset,
nsCOMPtr<nsINode>* outVisNode,
int32_t* outVisOffset,
WSType* outType);
// AdjustWhitespace examines the ws object for nbsp's that can
// be safely converted to regular ascii space and converts them.
nsresult AdjustWhitespace();
protected:
// WSFragment struct ---------------------------------------------------------
// WSFragment represents a single run of ws (all leadingws, or all normalws,
// or all trailingws, or all leading+trailingws). Note that this single run may
// still span multiple nodes.
struct WSFragment
{
nsCOMPtr<nsINode> mStartNode; // node where ws run starts
nsCOMPtr<nsINode> mEndNode; // node where ws run ends
int32_t mStartOffset; // offset where ws run starts
int32_t mEndOffset; // offset where ws run ends
// type of ws, and what is to left and right of it
WSType mType, mLeftType, mRightType;
// other ws runs to left or right. may be null.
WSFragment *mLeft, *mRight;
WSFragment() : mStartNode(0), mEndNode(0),
mStartOffset(0), mEndOffset(0),
mType(), mLeftType(), mRightType(),
mLeft(0), mRight(0)
{
}
};
// WSPoint struct ------------------------------------------------------------
// A WSPoint struct represents a unique location within the ws run. It is
// always within a textnode that is one of the nodes stored in the list
// in the wsRunObject. For convenience, the character at that point is also
// stored in the struct.
struct MOZ_STACK_CLASS WSPoint
{
RefPtr<mozilla::dom::Text> mTextNode;
uint32_t mOffset;
char16_t mChar;
WSPoint() : mTextNode(0),mOffset(0),mChar(0) {}
WSPoint(mozilla::dom::Text* aTextNode, int32_t aOffset, char16_t aChar) :
mTextNode(aTextNode),mOffset(aOffset),mChar(aChar) {}
};
enum AreaRestriction
{
eAnywhere, eOutsideUserSelectAll
};
// protected methods ---------------------------------------------------------
// tons of utility methods.
/**
* Return the node which we will handle white-space under. This is the
* closest block within the DOM subtree we're editing, or if none is
* found, the (inline) root of the editable subtree.
*/
nsINode* GetWSBoundingParent();
nsresult GetWSNodes();
void GetRuns();
void ClearRuns();
void MakeSingleWSRun(WSType aType);
nsIContent* GetPreviousWSNodeInner(nsINode* aStartNode,
nsINode* aBlockParent);
nsIContent* GetPreviousWSNode(mozilla::EditorDOMPoint aPoint,
nsINode* aBlockParent);
nsIContent* GetNextWSNodeInner(nsINode* aStartNode, nsINode* aBlockParent);
nsIContent* GetNextWSNode(mozilla::EditorDOMPoint aPoint,
nsINode* aBlockParent);
nsresult PrepareToDeleteRangePriv(nsWSRunObject* aEndObject);
nsresult PrepareToSplitAcrossBlocksPriv();
nsresult DeleteChars(nsINode* aStartNode, int32_t aStartOffset,
nsINode* aEndNode, int32_t aEndOffset,
AreaRestriction aAR = eAnywhere);
WSPoint GetCharAfter(nsINode* aNode, int32_t aOffset);
WSPoint GetCharBefore(nsINode* aNode, int32_t aOffset);
WSPoint GetCharAfter(const WSPoint& aPoint);
WSPoint GetCharBefore(const WSPoint& aPoint);
nsresult ConvertToNBSP(WSPoint aPoint,
AreaRestriction aAR = eAnywhere);
void GetAsciiWSBounds(int16_t aDir, nsINode* aNode, int32_t aOffset,
mozilla::dom::Text** outStartNode,
int32_t* outStartOffset,
mozilla::dom::Text** outEndNode,
int32_t* outEndOffset);
void FindRun(nsINode* aNode, int32_t aOffset, WSFragment** outRun,
bool after);
char16_t GetCharAt(mozilla::dom::Text* aTextNode, int32_t aOffset);
WSPoint GetWSPointAfter(nsINode* aNode, int32_t aOffset);
WSPoint GetWSPointBefore(nsINode* aNode, int32_t aOffset);
nsresult CheckTrailingNBSPOfRun(WSFragment *aRun);
nsresult CheckTrailingNBSP(WSFragment* aRun, nsINode* aNode,
int32_t aOffset);
nsresult CheckLeadingNBSP(WSFragment* aRun, nsINode* aNode,
int32_t aOffset);
nsresult Scrub();
bool IsBlockNode(nsINode* aNode);
// member variables ---------------------------------------------------------
nsCOMPtr<nsINode> mNode; // the node passed to our constructor
int32_t mOffset; // the offset passed to our contructor
// together, the above represent the point at which we are building up ws info.
bool mPRE; // true if we are in preformatted whitespace context
nsCOMPtr<nsINode> mStartNode; // node/offset where ws starts
int32_t mStartOffset; // ...
WSType mStartReason; // reason why ws starts (eText, eOtherBlock, etc)
nsCOMPtr<nsINode> mStartReasonNode;// the node that implicated by start reason
nsCOMPtr<nsINode> mEndNode; // node/offset where ws ends
int32_t mEndOffset; // ...
WSType mEndReason; // reason why ws ends (eText, eOtherBlock, etc)
nsCOMPtr<nsINode> mEndReasonNode; // the node that implicated by end reason
RefPtr<mozilla::dom::Text> mFirstNBSPNode; // location of first nbsp in ws run, if any
int32_t mFirstNBSPOffset; // ...
RefPtr<mozilla::dom::Text> mLastNBSPNode; // location of last nbsp in ws run, if any
int32_t mLastNBSPOffset; // ...
// the list of nodes containing ws in this run
nsTArray<RefPtr<mozilla::dom::Text>> mNodeArray;
WSFragment *mStartRun; // the first WSFragment in the run
WSFragment *mEndRun; // the last WSFragment in the run, may be same as first
nsHTMLEditor *mHTMLEditor; // non-owning.
friend class nsHTMLEditRules; // opening this class up for pillaging
friend class nsHTMLEditor; // opening this class up for more pillaging
};
#endif