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