Bug 496360 part.4 Don't recompute text length of before the insertion point at adding multiple lines into an HTML editor r=smaug

This commit is contained in:
Masayuki Nakano 2014-07-31 13:38:00 +09:00
parent 05b13e9288
commit 6ff8050b75
2 changed files with 83 additions and 6 deletions

View File

@ -48,6 +48,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IMEContentObserver)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditableNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditor)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEndOfAddedTextCache.mContainerNode)
tmp->mUpdatePreference.mWantUpdates = nsIMEUpdatePreference::NOTIFY_NOTHING;
tmp->mESM = nullptr;
@ -60,6 +61,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IMEContentObserver)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEditableNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEditor)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndOfAddedTextCache.mContainerNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IMEContentObserver)
@ -643,6 +645,8 @@ IMEContentObserver::CharacterDataChanged(nsIDocument* aDocument,
NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
"character data changed for non-text node");
mEndOfAddedTextCache.Clear();
bool causedByComposition = IsEditorHandlingEventForComposition();
if (!mTextChangeData.mStored && causedByComposition &&
!mUpdatePreference.WantChangesCausedByComposition()) {
@ -677,11 +681,18 @@ IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
}
uint32_t offset = 0;
nsresult rv =
ContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, aContainer,
aStartIndex, &offset,
LINE_BREAK_TYPE_NATIVE);
NS_ENSURE_SUCCESS_VOID(rv);
nsresult rv = NS_OK;
if (!mEndOfAddedTextCache.Match(aContainer, aStartIndex)) {
mEndOfAddedTextCache.Clear();
rv = ContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, aContainer,
aStartIndex, &offset,
LINE_BREAK_TYPE_NATIVE);
if (NS_WARN_IF(NS_FAILED((rv)))) {
return;
}
} else {
offset = mEndOfAddedTextCache.mFlatTextLength;
}
// get offset at the end of the last added node
nsIContent* childAtStart = aContainer->GetChildAt(aStartIndex);
@ -689,7 +700,16 @@ IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
rv = ContentEventHandler::GetFlatTextOffsetOfRange(childAtStart, aContainer,
aEndIndex, &addingLength,
LINE_BREAK_TYPE_NATIVE);
NS_ENSURE_SUCCESS_VOID(rv);
if (NS_WARN_IF(NS_FAILED((rv)))) {
mEndOfAddedTextCache.Clear();
return;
}
// If multiple lines are being inserted in an HTML editor, next call of
// 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);
if (!addingLength) {
return;
@ -727,6 +747,8 @@ IMEContentObserver::ContentRemoved(nsIDocument* aDocument,
int32_t aIndexInContainer,
nsIContent* aPreviousSibling)
{
mEndOfAddedTextCache.Clear();
bool causedByComposition = IsEditorHandlingEventForComposition();
if (!mTextChangeData.mStored && causedByComposition &&
!mUpdatePreference.WantChangesCausedByComposition()) {
@ -791,6 +813,8 @@ IMEContentObserver::AttributeChanged(nsIDocument* aDocument,
nsIAtom* aAttribute,
int32_t aModType)
{
mEndOfAddedTextCache.Clear();
bool causedByComposition = IsEditorHandlingEventForComposition();
if (!mTextChangeData.mStored && causedByComposition &&
!mUpdatePreference.WantChangesCausedByComposition()) {
@ -823,6 +847,7 @@ NS_IMETHODIMP
IMEContentObserver::EditAction()
{
mIsEditorInTransaction = false;
mEndOfAddedTextCache.Clear();
FlushMergeableNotifications();
return NS_OK;
}
@ -831,6 +856,7 @@ NS_IMETHODIMP
IMEContentObserver::BeforeEditAction()
{
mIsEditorInTransaction = true;
mEndOfAddedTextCache.Clear();
return NS_OK;
}
@ -838,6 +864,7 @@ NS_IMETHODIMP
IMEContentObserver::CancelEditAction()
{
mIsEditorInTransaction = false;
mEndOfAddedTextCache.Clear();
FlushMergeableNotifications();
return NS_OK;
}

View File

@ -152,6 +152,56 @@ private:
nsCOMPtr<nsIDocShell> mDocShell;
nsCOMPtr<nsIEditor> mEditor;
/**
* FlatTextCache stores flat text length from start of the content to
* mNodeOffset of mContainerNode.
*/
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.
nsCOMPtr<nsINode> mContainerNode;
int32_t mNodeOffset;
// 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)
{
}
void Clear()
{
mContainerNode = nullptr;
mNodeOffset = 0;
mFlatTextLength = 0;
}
void Cache(nsINode* aContainer, int32_t aNodeOffset,
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");
mContainerNode = aContainer;
mNodeOffset = aNodeOffset;
mFlatTextLength = aFlatTextLength;
}
bool Match(nsINode* aContainer, int32_t aNodeOffset) const
{
return aContainer == mContainerNode && aNodeOffset == mNodeOffset;
}
};
// mEndOfAddedTextCache caches text length from the start of content to
// the end of the last added content only while an edit action is being
// handled by the editor and no other mutation (e.g., removing node)
// occur.
FlatTextCache mEndOfAddedTextCache;
TextChangeData mTextChangeData;
EventStateManager* mESM;