зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1384915 - Part 3: Avoid using node indices in IMEContentObserver, r=masayuki
MozReview-Commit-ID: 4iaNideXEFl
This commit is contained in:
Родитель
9601431bf2
Коммит
74e8b70a80
|
@ -48,6 +48,29 @@ ToChar(bool aBool)
|
|||
return aBool ? "true" : "false";
|
||||
}
|
||||
|
||||
// This method determines the node to use for the point before the current node.
|
||||
// If you have the following aContent and aContainer, and want to represent the
|
||||
// following point for `NodePosition` or `RangeBoundary`:
|
||||
//
|
||||
// <parent> {node} {node} | {node} </parent>
|
||||
// ^ ^ ^
|
||||
// aContainer point aContent
|
||||
//
|
||||
// This function will shift `aContent` to the left into the format which
|
||||
// `NodePosition` and `RangeBoundary` use:
|
||||
//
|
||||
// <parent> {node} {node} | {node} </parent>
|
||||
// ^ ^ ^
|
||||
// aContainer result point
|
||||
static nsIContent*
|
||||
PointBefore(nsINode* aContainer, nsIContent* aContent)
|
||||
{
|
||||
if (aContent) {
|
||||
return aContent->GetPreviousSibling();
|
||||
}
|
||||
return aContainer->GetLastChild();
|
||||
}
|
||||
|
||||
class WritingModeToString final : public nsAutoCString
|
||||
{
|
||||
public:
|
||||
|
@ -123,8 +146,8 @@ public:
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(IMEContentObserver)
|
||||
|
||||
// Note that we don't need to add mFirstAddedNodeContainer nor
|
||||
// mLastAddedNodeContainer to cycle collection because they are non-null only
|
||||
// Note that we don't need to add mFirstAddedContainer nor
|
||||
// mLastAddedContainer to cycle collection because they are non-null only
|
||||
// during short time and shouldn't be touched while they are non-null.
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IMEContentObserver)
|
||||
|
@ -174,9 +197,7 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(IMEContentObserver)
|
|||
NS_IMPL_CYCLE_COLLECTING_RELEASE(IMEContentObserver)
|
||||
|
||||
IMEContentObserver::IMEContentObserver()
|
||||
: mFirstAddedNodeOffset(0)
|
||||
, mLastAddedNodeOffset(0)
|
||||
, mESM(nullptr)
|
||||
: mESM(nullptr)
|
||||
, mIMENotificationRequests(nullptr)
|
||||
, mSuppressNotifications(0)
|
||||
, mPreCharacterDataChangeLength(-1)
|
||||
|
@ -1001,13 +1022,16 @@ IMEContentObserver::CharacterDataChanged(nsIDocument* aDocument,
|
|||
|
||||
void
|
||||
IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
|
||||
int32_t aStartIndex,
|
||||
int32_t aEndIndex)
|
||||
nsIContent* aFirstContent,
|
||||
nsIContent* aLastContent)
|
||||
{
|
||||
if (!NeedsTextChangeNotification()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(aFirstContent, aFirstContent->GetParentNode() == aContainer);
|
||||
MOZ_ASSERT_IF(aLastContent, aLastContent->GetParentNode() == aContainer);
|
||||
|
||||
mStartOfRemovingTextRangeCache.Clear();
|
||||
|
||||
// If it's in a document change, nodes are added consecutively. Therefore,
|
||||
|
@ -1019,9 +1043,9 @@ IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
|
|||
// the last node in mEndOfAddedTextCache. Clear it.
|
||||
mEndOfAddedTextCache.Clear();
|
||||
if (!HasAddedNodesDuringDocumentChange()) {
|
||||
mFirstAddedNodeContainer = mLastAddedNodeContainer = aContainer;
|
||||
mFirstAddedNodeOffset = aStartIndex;
|
||||
mLastAddedNodeOffset = aEndIndex;
|
||||
mFirstAddedContainer = mLastAddedContainer = aContainer;
|
||||
mFirstAddedContent = aFirstContent;
|
||||
mLastAddedContent = aLastContent;
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::NotifyContentAdded(), starts to store "
|
||||
"consecutive added nodes", this));
|
||||
|
@ -1030,17 +1054,17 @@ IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
|
|||
// If first node being added is not next node of the last node,
|
||||
// notify IME of the previous range first, then, restart to cache the
|
||||
// range.
|
||||
if (NS_WARN_IF(!IsNextNodeOfLastAddedNode(aContainer, aStartIndex))) {
|
||||
if (NS_WARN_IF(!IsNextNodeOfLastAddedNode(aContainer, aFirstContent))) {
|
||||
// Flush the old range first.
|
||||
MaybeNotifyIMEOfAddedTextDuringDocumentChange();
|
||||
mFirstAddedNodeContainer = aContainer;
|
||||
mFirstAddedNodeOffset = aStartIndex;
|
||||
mFirstAddedContainer = aContainer;
|
||||
mFirstAddedContent = aFirstContent;
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::NotifyContentAdded(), starts to store "
|
||||
"consecutive added nodes", this));
|
||||
}
|
||||
mLastAddedNodeContainer = aContainer;
|
||||
mLastAddedNodeOffset = aEndIndex;
|
||||
mLastAddedContainer = aContainer;
|
||||
mLastAddedContent = aLastContent;
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(!HasAddedNodesDuringDocumentChange(),
|
||||
|
@ -1048,11 +1072,14 @@ IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
|
|||
|
||||
uint32_t offset = 0;
|
||||
nsresult rv = NS_OK;
|
||||
if (!mEndOfAddedTextCache.Match(aContainer, aStartIndex)) {
|
||||
if (!mEndOfAddedTextCache.Match(aContainer,
|
||||
aFirstContent->GetPreviousSibling())) {
|
||||
mEndOfAddedTextCache.Clear();
|
||||
rv = ContentEventHandler::GetFlatTextLengthInRange(
|
||||
NodePosition(mRootContent, 0),
|
||||
NodePositionBefore(aContainer, aStartIndex),
|
||||
NodePositionBefore(aContainer,
|
||||
PointBefore(aContainer,
|
||||
aFirstContent)),
|
||||
mRootContent, &offset, LINE_BREAK_TYPE_NATIVE);
|
||||
if (NS_WARN_IF(NS_FAILED((rv)))) {
|
||||
return;
|
||||
|
@ -1064,8 +1091,10 @@ IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
|
|||
// get offset at the end of the last added node
|
||||
uint32_t addingLength = 0;
|
||||
rv = ContentEventHandler::GetFlatTextLengthInRange(
|
||||
NodePositionBefore(aContainer, aStartIndex),
|
||||
NodePosition(aContainer, aEndIndex),
|
||||
NodePositionBefore(aContainer,
|
||||
PointBefore(aContainer,
|
||||
aFirstContent)),
|
||||
NodePosition(aContainer, aLastContent),
|
||||
mRootContent, &addingLength,
|
||||
LINE_BREAK_TYPE_NATIVE);
|
||||
if (NS_WARN_IF(NS_FAILED((rv)))) {
|
||||
|
@ -1077,7 +1106,7 @@ IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
|
|||
// NotifyContentAdded() is for adding next node. Therefore, caching the text
|
||||
// length can skip to compute the text length before the adding node and
|
||||
// before of it.
|
||||
mEndOfAddedTextCache.Cache(aContainer, aEndIndex, offset + addingLength);
|
||||
mEndOfAddedTextCache.Cache(aContainer, aLastContent, offset + addingLength);
|
||||
|
||||
if (!addingLength) {
|
||||
return;
|
||||
|
@ -1093,27 +1122,27 @@ void
|
|||
IMEContentObserver::ContentAppended(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aFirstNewContent,
|
||||
int32_t aNewIndexInContainer)
|
||||
int32_t /* unused */)
|
||||
{
|
||||
NotifyContentAdded(aContainer, aNewIndexInContainer,
|
||||
aContainer->GetChildCount());
|
||||
NotifyContentAdded(NODE_FROM(aContainer, aDocument),
|
||||
aFirstNewContent, aContainer->GetLastChild());
|
||||
}
|
||||
|
||||
void
|
||||
IMEContentObserver::ContentInserted(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild,
|
||||
int32_t aIndexInContainer)
|
||||
int32_t /* unused */)
|
||||
{
|
||||
NotifyContentAdded(NODE_FROM(aContainer, aDocument),
|
||||
aIndexInContainer, aIndexInContainer + 1);
|
||||
aChild, aChild);
|
||||
}
|
||||
|
||||
void
|
||||
IMEContentObserver::ContentRemoved(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild,
|
||||
int32_t aIndexInContainer,
|
||||
int32_t /* unused */,
|
||||
nsIContent* aPreviousSibling)
|
||||
{
|
||||
if (!NeedsTextChangeNotification()) {
|
||||
|
@ -1127,18 +1156,19 @@ IMEContentObserver::ContentRemoved(nsIDocument* aDocument,
|
|||
|
||||
uint32_t offset = 0;
|
||||
nsresult rv = NS_OK;
|
||||
if (!mStartOfRemovingTextRangeCache.Match(containerNode, aIndexInContainer)) {
|
||||
if (!mStartOfRemovingTextRangeCache.Match(containerNode, aPreviousSibling)) {
|
||||
// At removing a child node of aContainer, we need the line break caused
|
||||
// by open tag of aContainer. Be careful when aIndexInContainer is 0.
|
||||
// by open tag of aContainer. Be careful when aPreviousSibling is nullptr.
|
||||
|
||||
rv = ContentEventHandler::GetFlatTextLengthInRange(
|
||||
NodePosition(mRootContent, 0),
|
||||
NodePosition(containerNode, aIndexInContainer),
|
||||
NodePosition(containerNode, aPreviousSibling),
|
||||
mRootContent, &offset, LINE_BREAK_TYPE_NATIVE);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mStartOfRemovingTextRangeCache.Clear();
|
||||
return;
|
||||
}
|
||||
mStartOfRemovingTextRangeCache.Cache(containerNode, aIndexInContainer,
|
||||
mStartOfRemovingTextRangeCache.Cache(containerNode, aPreviousSibling,
|
||||
offset);
|
||||
} else {
|
||||
offset = mStartOfRemovingTextRangeCache.mFlatTextLength;
|
||||
|
@ -1230,8 +1260,8 @@ IMEContentObserver::AttributeChanged(nsIDocument* aDocument,
|
|||
void
|
||||
IMEContentObserver::ClearAddedNodesDuringDocumentChange()
|
||||
{
|
||||
mFirstAddedNodeContainer = mLastAddedNodeContainer = nullptr;
|
||||
mFirstAddedNodeOffset = mLastAddedNodeOffset = 0;
|
||||
mFirstAddedContainer = mLastAddedContainer = nullptr;
|
||||
mFirstAddedContent = mLastAddedContent = nullptr;
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::ClearAddedNodesDuringDocumentChange()"
|
||||
", finished storing consecutive nodes", this));
|
||||
|
@ -1256,66 +1286,46 @@ IMEContentObserver::GetChildNode(nsINode* aParent, int32_t aOffset)
|
|||
|
||||
bool
|
||||
IMEContentObserver::IsNextNodeOfLastAddedNode(nsINode* aParent,
|
||||
int32_t aOffset) const
|
||||
nsIContent* aChild) const
|
||||
{
|
||||
MOZ_ASSERT(aParent);
|
||||
MOZ_ASSERT(aOffset >= 0 &&
|
||||
aOffset <= static_cast<int32_t>(aParent->Length()));
|
||||
MOZ_ASSERT(aChild && aChild->GetParentNode() == aParent);
|
||||
MOZ_ASSERT(mRootContent);
|
||||
MOZ_ASSERT(HasAddedNodesDuringDocumentChange());
|
||||
|
||||
// If the parent node isn't changed, we can check it only with offset.
|
||||
if (aParent == mLastAddedNodeContainer) {
|
||||
if (NS_WARN_IF(mLastAddedNodeOffset != aOffset)) {
|
||||
// If the parent node isn't changed, we can check that mLastAddedContent has
|
||||
// aChild as its next sibling.
|
||||
if (aParent == mLastAddedContainer) {
|
||||
if (NS_WARN_IF(mLastAddedContent->GetNextSibling() != aChild)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the parent node is changed, that means that given offset should be the
|
||||
// last added node not having next sibling.
|
||||
if (NS_WARN_IF(mLastAddedNodeOffset !=
|
||||
static_cast<int32_t>(mLastAddedNodeContainer->Length()))) {
|
||||
// If the parent node is changed, that means that the recorded last added node
|
||||
// shouldn't have a sibling.
|
||||
if (NS_WARN_IF(mLastAddedContent->GetNextSibling())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the node is aParent is a descendant of mLastAddedNodeContainer,
|
||||
// aOffset should be 0.
|
||||
if (mLastAddedNodeContainer == aParent->GetParent()) {
|
||||
if (NS_WARN_IF(aOffset)) {
|
||||
// If the node is aParent is a descendant of mLastAddedContainer,
|
||||
// aChild should be the first child in the new container.
|
||||
if (mLastAddedContainer == aParent->GetParent()) {
|
||||
if (NS_WARN_IF(aChild->GetPreviousSibling())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, we need to check it even with slow path.
|
||||
nsIContent* lastAddedContent =
|
||||
GetChildNode(mLastAddedNodeContainer, mLastAddedNodeOffset - 1);
|
||||
if (NS_WARN_IF(!lastAddedContent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIContent* nextContentOfLastAddedContent =
|
||||
lastAddedContent->GetNextNode(mRootContent->GetParentNode());
|
||||
mLastAddedContent->GetNextNode(mRootContent->GetParentNode());
|
||||
if (NS_WARN_IF(!nextContentOfLastAddedContent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIContent* startContent = GetChildNode(aParent, aOffset);
|
||||
if (NS_WARN_IF(!startContent) ||
|
||||
NS_WARN_IF(nextContentOfLastAddedContent != startContent)) {
|
||||
if (NS_WARN_IF(nextContentOfLastAddedContent != aChild)) {
|
||||
return false;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
NS_WARNING_ASSERTION(
|
||||
!aOffset || aOffset == static_cast<int32_t>(aParent->Length() - 1),
|
||||
"Used slow path for aParent");
|
||||
NS_WARNING_ASSERTION(
|
||||
!(mLastAddedNodeOffset - 1) ||
|
||||
mLastAddedNodeOffset ==
|
||||
static_cast<int32_t>(mLastAddedNodeContainer->Length()),
|
||||
"Used slow path for mLastAddedNodeContainer");
|
||||
#endif // #ifdef DEBUG
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1338,8 +1348,9 @@ IMEContentObserver::MaybeNotifyIMEOfAddedTextDuringDocumentChange()
|
|||
nsresult rv =
|
||||
ContentEventHandler::GetFlatTextLengthInRange(
|
||||
NodePosition(mRootContent, 0),
|
||||
NodePosition(mFirstAddedNodeContainer,
|
||||
mFirstAddedNodeOffset),
|
||||
NodePosition(mFirstAddedContainer,
|
||||
PointBefore(mFirstAddedContainer,
|
||||
mFirstAddedContent)),
|
||||
mRootContent, &offset, LINE_BREAK_TYPE_NATIVE);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
ClearAddedNodesDuringDocumentChange();
|
||||
|
@ -1350,10 +1361,10 @@ IMEContentObserver::MaybeNotifyIMEOfAddedTextDuringDocumentChange()
|
|||
uint32_t length;
|
||||
rv =
|
||||
ContentEventHandler::GetFlatTextLengthInRange(
|
||||
NodePosition(mFirstAddedNodeContainer,
|
||||
mFirstAddedNodeOffset),
|
||||
NodePosition(mLastAddedNodeContainer,
|
||||
mLastAddedNodeOffset),
|
||||
NodePosition(mFirstAddedContainer,
|
||||
PointBefore(mFirstAddedContainer,
|
||||
mFirstAddedContent)),
|
||||
NodePosition(mLastAddedContainer, mLastAddedContent),
|
||||
mRootContent, &length, LINE_BREAK_TYPE_NATIVE);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
ClearAddedNodesDuringDocumentChange();
|
||||
|
|
|
@ -202,9 +202,9 @@ private:
|
|||
|
||||
/**
|
||||
* MaybeNotifyIMEOfAddedTextDuringDocumentChange() may send text change
|
||||
* notification caused by the nodes added between mFirstAddedNodeOffset in
|
||||
* mFirstAddedNodeContainer and mLastAddedNodeOffset in
|
||||
* mLastAddedNodeContainer and forgets the range.
|
||||
* notification caused by the nodes added between mFirstAddedContent in
|
||||
* mFirstAddedContainer and mLastAddedContent in
|
||||
* mLastAddedContainer and forgets the range.
|
||||
*/
|
||||
void MaybeNotifyIMEOfAddedTextDuringDocumentChange();
|
||||
|
||||
|
@ -232,15 +232,14 @@ private:
|
|||
*/
|
||||
bool HasAddedNodesDuringDocumentChange() const
|
||||
{
|
||||
return mFirstAddedNodeContainer && mLastAddedNodeContainer;
|
||||
return mFirstAddedContainer && mLastAddedContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the node at aOffset in aParent is next node of the node at
|
||||
* mLastAddedNodeOffset in mLastAddedNodeContainer in pre-order tree
|
||||
* traversal of the DOM.
|
||||
* Returns true if the passed-in node in aParent is the next node of
|
||||
* mLastAddedContent in pre-order tree traversal of the DOM.
|
||||
*/
|
||||
bool IsNextNodeOfLastAddedNode(nsINode* aParent, int32_t aOffset) const;
|
||||
bool IsNextNodeOfLastAddedNode(nsINode* aParent, nsIContent* aChild) const;
|
||||
|
||||
void PostFocusSetNotification();
|
||||
void MaybeNotifyIMEOfFocusSet();
|
||||
|
@ -256,7 +255,9 @@ private:
|
|||
void CancelNotifyingIMEOfPositionChange();
|
||||
void PostCompositionEventHandledNotification();
|
||||
|
||||
void NotifyContentAdded(nsINode* aContainer, int32_t aStart, int32_t aEnd);
|
||||
void NotifyContentAdded(nsINode* aContainer,
|
||||
nsIContent* aFirstContent,
|
||||
nsIContent* aLastContent);
|
||||
void ObserveEditableNode();
|
||||
/**
|
||||
* NotifyIMEOfBlur() notifies IME of blur.
|
||||
|
@ -431,42 +432,43 @@ private:
|
|||
*/
|
||||
struct FlatTextCache
|
||||
{
|
||||
// mContainerNode and mNodeOffset represent a point in DOM tree. E.g.,
|
||||
// if mContainerNode is a div element, mNodeOffset is index of its child.
|
||||
// mContainerNode and mNode represent a point in DOM tree. E.g.,
|
||||
// if mContainerNode is a div element, mNode is a child.
|
||||
nsCOMPtr<nsINode> mContainerNode;
|
||||
int32_t mNodeOffset;
|
||||
// mNode points to the last child which participates in the current
|
||||
// mFlatTextLength. If mNode is null, then that means that the end point for
|
||||
// mFlatTextLength is immediately before the first child of mContainerNode.
|
||||
nsCOMPtr<nsINode> mNode;
|
||||
// Length of flat text generated from contents between the start of content
|
||||
// and a child node whose index is mNodeOffset of mContainerNode.
|
||||
uint32_t mFlatTextLength;
|
||||
|
||||
FlatTextCache()
|
||||
: mNodeOffset(0)
|
||||
, mFlatTextLength(0)
|
||||
: mFlatTextLength(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
mContainerNode = nullptr;
|
||||
mNodeOffset = 0;
|
||||
mNode = nullptr;
|
||||
mFlatTextLength = 0;
|
||||
}
|
||||
|
||||
void Cache(nsINode* aContainer, int32_t aNodeOffset,
|
||||
void Cache(nsINode* aContainer, nsINode* aNode,
|
||||
uint32_t aFlatTextLength)
|
||||
{
|
||||
MOZ_ASSERT(aContainer, "aContainer must not be null");
|
||||
MOZ_ASSERT(
|
||||
aNodeOffset <= static_cast<int32_t>(aContainer->GetChildCount()),
|
||||
"aNodeOffset must be same as or less than the count of children");
|
||||
MOZ_ASSERT(!aNode || aNode->GetParentNode() == aContainer,
|
||||
"aNode must be either null or a child of aContainer");
|
||||
mContainerNode = aContainer;
|
||||
mNodeOffset = aNodeOffset;
|
||||
mNode = aNode;
|
||||
mFlatTextLength = aFlatTextLength;
|
||||
}
|
||||
|
||||
bool Match(nsINode* aContainer, int32_t aNodeOffset) const
|
||||
bool Match(nsINode* aContainer, nsINode* aNode) const
|
||||
{
|
||||
return aContainer == mContainerNode && aNodeOffset == mNodeOffset;
|
||||
return aContainer == mContainerNode && aNode == mNode;
|
||||
}
|
||||
};
|
||||
// mEndOfAddedTextCache caches text length from the start of content to
|
||||
|
@ -479,26 +481,25 @@ private:
|
|||
// handled by the editor and no other mutation (e.g., adding node) occur.
|
||||
FlatTextCache mStartOfRemovingTextRangeCache;
|
||||
|
||||
// mFirstAddedNodeContainer is parent node of first added node in current
|
||||
// mFirstAddedContainer is parent node of first added node in current
|
||||
// document change. So, this is not nullptr only when a node was added
|
||||
// during a document change and the change has not been included into
|
||||
// mTextChangeData yet.
|
||||
// Note that this shouldn't be in cycle collection since this is not nullptr
|
||||
// only during a document change.
|
||||
nsCOMPtr<nsINode> mFirstAddedNodeContainer;
|
||||
// mLastAddedNodeContainer is parent node of last added node in current
|
||||
nsCOMPtr<nsINode> mFirstAddedContainer;
|
||||
// mLastAddedContainer is parent node of last added node in current
|
||||
// document change. So, this is not nullptr only when a node was added
|
||||
// during a document change and the change has not been included into
|
||||
// mTextChangeData yet.
|
||||
// Note that this shouldn't be in cycle collection since this is not nullptr
|
||||
// only during a document change.
|
||||
nsCOMPtr<nsINode> mLastAddedNodeContainer;
|
||||
// mFirstAddedNodeOffset is offset of first added node in
|
||||
// mFirstAddedNodeContainer.
|
||||
int32_t mFirstAddedNodeOffset;
|
||||
// mLastAddedNodeOffset is offset of *after* last added node in
|
||||
// mLastAddedNodeContainer. I.e., the index of last added node + 1.
|
||||
int32_t mLastAddedNodeOffset;
|
||||
nsCOMPtr<nsINode> mLastAddedContainer;
|
||||
|
||||
// mFirstAddedContent is the first node added in mFirstAddedContainer.
|
||||
nsCOMPtr<nsIContent> mFirstAddedContent;
|
||||
// mLastAddedContent is the last node added in mLastAddedContainer;
|
||||
nsCOMPtr<nsIContent> mLastAddedContent;
|
||||
|
||||
TextChangeData mTextChangeData;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче