void IMEContentObserver::ContentRemoved(nsIDocument* aDocument, nsIContent* aContainer, nsIContent* aChild, int32_t aIndexInContainer, nsIContent* aPreviousSibling) { mEndOfAddedTextCache.Clear(); bool causedByComposition = IsEditorHandlingEventForComposition(); if (!mTextChangeData.IsValid() && causedByComposition && !mUpdatePreference.WantChangesCausedByComposition()) { return; } nsINode* containerNode = NODE_FROM(aContainer, aDocument); uint32_t offset = 0; nsresult rv = NS_OK; if (!mStartOfRemovingTextRangeCache.Match(containerNode, aIndexInContainer)) { rv = ContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, containerNode, aIndexInContainer, &offset, LINE_BREAK_TYPE_NATIVE); if (NS_WARN_IF(NS_FAILED(rv))) { mStartOfRemovingTextRangeCache.Clear(); return; } mStartOfRemovingTextRangeCache.Cache(containerNode, aIndexInContainer, offset); } else { offset = mStartOfRemovingTextRangeCache.mFlatTextLength; } // get offset at the end of the deleted node int32_t nodeLength = aChild->IsNodeOfType(nsINode::eTEXT) ? static_cast<int32_t>(aChild->TextLength()) : std::max(static_cast<int32_t>(aChild->GetChildCount()), 1); MOZ_ASSERT(nodeLength >= 0, "The node length is out of range"); uint32_t textLength = 0; rv = ContentEventHandler::GetFlatTextOffsetOfRange(aChild, aChild, nodeLength, &textLength, LINE_BREAK_TYPE_NATIVE); if (NS_WARN_IF(NS_FAILED(rv))) { mStartOfRemovingTextRangeCache.Clear(); return; } if (!textLength) { return; } TextChangeData data(offset, offset + textLength, offset, causedByComposition); MaybeNotifyIMEOfTextChange(data); }
void IMEContentObserver::NotifyContentAdded(nsINode* aContainer, int32_t aStartIndex, int32_t aEndIndex) { mStartOfRemovingTextRangeCache.Clear(); bool causedByComposition = IsEditorHandlingEventForComposition(); if (!mTextChangeData.IsValid() && causedByComposition && !mUpdatePreference.WantChangesCausedByComposition()) { return; } uint32_t offset = 0; 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); uint32_t addingLength = 0; rv = ContentEventHandler::GetFlatTextOffsetOfRange(childAtStart, aContainer, aEndIndex, &addingLength, LINE_BREAK_TYPE_NATIVE); 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; } TextChangeData data(offset, offset, offset + addingLength, causedByComposition); MaybeNotifyIMEOfTextChange(data); }
void IMEContentObserver::CharacterDataChanged(nsIDocument* aDocument, nsIContent* aContent, CharacterDataChangeInfo* aInfo) { NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT), "character data changed for non-text node"); mEndOfAddedTextCache.Clear(); mStartOfRemovingTextRangeCache.Clear(); int64_t removedLength = mPreCharacterDataChangeLength; mPreCharacterDataChangeLength = -1; bool causedByComposition = IsEditorHandlingEventForComposition(); if (!mTextChangeData.IsValid() && causedByComposition && !mUpdatePreference.WantChangesCausedByComposition()) { return; } MOZ_ASSERT(removedLength >= 0, "mPreCharacterDataChangeLength should've been set by " "CharacterDataWillChange()"); uint32_t offset = 0; // get offsets of change and fire notification nsresult rv = ContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, aContent, aInfo->mChangeStart, &offset, LINE_BREAK_TYPE_NATIVE); NS_ENSURE_SUCCESS_VOID(rv); uint32_t newLength = ContentEventHandler::GetNativeTextLength(aContent, aInfo->mChangeStart, aInfo->mChangeStart + aInfo->mReplaceLength); uint32_t oldEnd = offset + static_cast<uint32_t>(removedLength); uint32_t newEnd = offset + newLength; TextChangeData data(offset, oldEnd, newEnd, causedByComposition); MaybeNotifyIMEOfTextChange(data); }
void IMEContentObserver::AttributeChanged(nsIDocument* aDocument, dom::Element* aElement, int32_t aNameSpaceID, nsIAtom* aAttribute, int32_t aModType, const nsAttrValue* aOldValue) { mEndOfAddedTextCache.Clear(); mStartOfRemovingTextRangeCache.Clear(); bool causedByComposition = IsEditorHandlingEventForComposition(); if (!mTextChangeData.IsValid() && causedByComposition && !mUpdatePreference.WantChangesCausedByComposition()) { return; } nsIContent *content = GetContentBR(aElement); if (!content) { return; } uint32_t postAttrChangeLength = ContentEventHandler::GetNativeTextLength(content); if (postAttrChangeLength == mPreAttrChangeLength) { return; } uint32_t start; nsresult rv = ContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, content, 0, &start, LINE_BREAK_TYPE_NATIVE); NS_ENSURE_SUCCESS_VOID(rv); TextChangeData data(start, start + mPreAttrChangeLength, start + postAttrChangeLength, causedByComposition); MaybeNotifyIMEOfTextChange(data); }