1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/events/IMEContentObserver.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,566 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 sw=2 et tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "ContentEventHandler.h" 1.11 +#include "IMEContentObserver.h" 1.12 +#include "mozilla/AsyncEventDispatcher.h" 1.13 +#include "mozilla/EventStateManager.h" 1.14 +#include "mozilla/IMEStateManager.h" 1.15 +#include "mozilla/TextComposition.h" 1.16 +#include "mozilla/dom/Element.h" 1.17 +#include "nsAutoPtr.h" 1.18 +#include "nsContentUtils.h" 1.19 +#include "nsGkAtoms.h" 1.20 +#include "nsIAtom.h" 1.21 +#include "nsIContent.h" 1.22 +#include "nsIDocument.h" 1.23 +#include "nsIDOMDocument.h" 1.24 +#include "nsIDOMRange.h" 1.25 +#include "nsIFrame.h" 1.26 +#include "nsINode.h" 1.27 +#include "nsIPresShell.h" 1.28 +#include "nsISelectionController.h" 1.29 +#include "nsISelectionPrivate.h" 1.30 +#include "nsISupports.h" 1.31 +#include "nsIWidget.h" 1.32 +#include "nsPresContext.h" 1.33 +#include "nsThreadUtils.h" 1.34 +#include "nsWeakReference.h" 1.35 + 1.36 +namespace mozilla { 1.37 + 1.38 +using namespace widget; 1.39 + 1.40 +NS_IMPL_CYCLE_COLLECTION(IMEContentObserver, 1.41 + mWidget, mSelection, 1.42 + mRootContent, mEditableNode, mDocShell) 1.43 + 1.44 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IMEContentObserver) 1.45 + NS_INTERFACE_MAP_ENTRY(nsISelectionListener) 1.46 + NS_INTERFACE_MAP_ENTRY(nsIMutationObserver) 1.47 + NS_INTERFACE_MAP_ENTRY(nsIReflowObserver) 1.48 + NS_INTERFACE_MAP_ENTRY(nsIScrollObserver) 1.49 + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) 1.50 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISelectionListener) 1.51 +NS_INTERFACE_MAP_END 1.52 + 1.53 +NS_IMPL_CYCLE_COLLECTING_ADDREF(IMEContentObserver) 1.54 +NS_IMPL_CYCLE_COLLECTING_RELEASE(IMEContentObserver) 1.55 + 1.56 +IMEContentObserver::IMEContentObserver() 1.57 + : mESM(nullptr) 1.58 +{ 1.59 +} 1.60 + 1.61 +void 1.62 +IMEContentObserver::Init(nsIWidget* aWidget, 1.63 + nsPresContext* aPresContext, 1.64 + nsIContent* aContent) 1.65 +{ 1.66 + mESM = aPresContext->EventStateManager(); 1.67 + mESM->OnStartToObserveContent(this); 1.68 + 1.69 + mWidget = aWidget; 1.70 + mEditableNode = IMEStateManager::GetRootEditableNode(aPresContext, aContent); 1.71 + if (!mEditableNode) { 1.72 + return; 1.73 + } 1.74 + 1.75 + nsIPresShell* presShell = aPresContext->PresShell(); 1.76 + 1.77 + // get selection and root content 1.78 + nsCOMPtr<nsISelectionController> selCon; 1.79 + if (mEditableNode->IsNodeOfType(nsINode::eCONTENT)) { 1.80 + nsIFrame* frame = 1.81 + static_cast<nsIContent*>(mEditableNode.get())->GetPrimaryFrame(); 1.82 + NS_ENSURE_TRUE_VOID(frame); 1.83 + 1.84 + frame->GetSelectionController(aPresContext, 1.85 + getter_AddRefs(selCon)); 1.86 + } else { 1.87 + // mEditableNode is a document 1.88 + selCon = do_QueryInterface(presShell); 1.89 + } 1.90 + NS_ENSURE_TRUE_VOID(selCon); 1.91 + 1.92 + selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, 1.93 + getter_AddRefs(mSelection)); 1.94 + NS_ENSURE_TRUE_VOID(mSelection); 1.95 + 1.96 + nsCOMPtr<nsIDOMRange> selDomRange; 1.97 + if (NS_SUCCEEDED(mSelection->GetRangeAt(0, getter_AddRefs(selDomRange)))) { 1.98 + nsRange* selRange = static_cast<nsRange*>(selDomRange.get()); 1.99 + NS_ENSURE_TRUE_VOID(selRange && selRange->GetStartParent()); 1.100 + 1.101 + mRootContent = selRange->GetStartParent()-> 1.102 + GetSelectionRootContent(presShell); 1.103 + } else { 1.104 + mRootContent = mEditableNode->GetSelectionRootContent(presShell); 1.105 + } 1.106 + if (!mRootContent && mEditableNode->IsNodeOfType(nsINode::eDOCUMENT)) { 1.107 + // The document node is editable, but there are no contents, this document 1.108 + // is not editable. 1.109 + return; 1.110 + } 1.111 + NS_ENSURE_TRUE_VOID(mRootContent); 1.112 + 1.113 + if (IMEStateManager::IsTestingIME()) { 1.114 + nsIDocument* doc = aPresContext->Document(); 1.115 + (new AsyncEventDispatcher(doc, NS_LITERAL_STRING("MozIMEFocusIn"), 1.116 + false, false))->RunDOMEventWhenSafe(); 1.117 + } 1.118 + 1.119 + aWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_FOCUS)); 1.120 + 1.121 + // NOTIFY_IME_OF_FOCUS might cause recreating IMEContentObserver 1.122 + // instance via IMEStateManager::UpdateIMEState(). So, this 1.123 + // instance might already have been destroyed, check it. 1.124 + if (!mRootContent) { 1.125 + return; 1.126 + } 1.127 + 1.128 + mDocShell = aPresContext->GetDocShell(); 1.129 + 1.130 + ObserveEditableNode(); 1.131 +} 1.132 + 1.133 +void 1.134 +IMEContentObserver::ObserveEditableNode() 1.135 +{ 1.136 + MOZ_ASSERT(mSelection); 1.137 + MOZ_ASSERT(mRootContent); 1.138 + 1.139 + mUpdatePreference = mWidget->GetIMEUpdatePreference(); 1.140 + if (mUpdatePreference.WantSelectionChange()) { 1.141 + // add selection change listener 1.142 + nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSelection)); 1.143 + NS_ENSURE_TRUE_VOID(selPrivate); 1.144 + nsresult rv = selPrivate->AddSelectionListener(this); 1.145 + NS_ENSURE_SUCCESS_VOID(rv); 1.146 + } 1.147 + 1.148 + if (mUpdatePreference.WantTextChange()) { 1.149 + // add text change observer 1.150 + mRootContent->AddMutationObserver(this); 1.151 + } 1.152 + 1.153 + if (mUpdatePreference.WantPositionChanged() && mDocShell) { 1.154 + // Add scroll position listener and reflow observer to detect position and 1.155 + // size changes 1.156 + mDocShell->AddWeakScrollObserver(this); 1.157 + mDocShell->AddWeakReflowObserver(this); 1.158 + } 1.159 +} 1.160 + 1.161 +void 1.162 +IMEContentObserver::Destroy() 1.163 +{ 1.164 + // If CreateTextStateManager failed, mRootContent will be null, 1.165 + // and we should not call NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR)) 1.166 + if (mRootContent) { 1.167 + if (IMEStateManager::IsTestingIME() && mEditableNode) { 1.168 + nsIDocument* doc = mEditableNode->OwnerDoc(); 1.169 + (new AsyncEventDispatcher(doc, NS_LITERAL_STRING("MozIMEFocusOut"), 1.170 + false, false))->RunDOMEventWhenSafe(); 1.171 + } 1.172 + mWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR)); 1.173 + } 1.174 + // Even if there are some pending notification, it'll never notify the widget. 1.175 + mWidget = nullptr; 1.176 + if (mUpdatePreference.WantSelectionChange() && mSelection) { 1.177 + nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSelection)); 1.178 + if (selPrivate) { 1.179 + selPrivate->RemoveSelectionListener(this); 1.180 + } 1.181 + } 1.182 + mSelection = nullptr; 1.183 + if (mUpdatePreference.WantTextChange() && mRootContent) { 1.184 + mRootContent->RemoveMutationObserver(this); 1.185 + } 1.186 + if (mUpdatePreference.WantPositionChanged() && mDocShell) { 1.187 + mDocShell->RemoveWeakScrollObserver(this); 1.188 + mDocShell->RemoveWeakReflowObserver(this); 1.189 + } 1.190 + mRootContent = nullptr; 1.191 + mEditableNode = nullptr; 1.192 + mDocShell = nullptr; 1.193 + mUpdatePreference.mWantUpdates = nsIMEUpdatePreference::NOTIFY_NOTHING; 1.194 + 1.195 + if (mESM) { 1.196 + mESM->OnStopObservingContent(this); 1.197 + mESM = nullptr; 1.198 + } 1.199 +} 1.200 + 1.201 +void 1.202 +IMEContentObserver::DisconnectFromEventStateManager() 1.203 +{ 1.204 + mESM = nullptr; 1.205 +} 1.206 + 1.207 +bool 1.208 +IMEContentObserver::IsManaging(nsPresContext* aPresContext, 1.209 + nsIContent* aContent) 1.210 +{ 1.211 + if (!mSelection || !mRootContent || !mEditableNode) { 1.212 + return false; // failed to initialize. 1.213 + } 1.214 + if (!mRootContent->IsInDoc()) { 1.215 + return false; // the focused editor has already been reframed. 1.216 + } 1.217 + return mEditableNode == IMEStateManager::GetRootEditableNode(aPresContext, 1.218 + aContent); 1.219 +} 1.220 + 1.221 +bool 1.222 +IMEContentObserver::IsEditorHandlingEventForComposition() const 1.223 +{ 1.224 + if (!mWidget) { 1.225 + return false; 1.226 + } 1.227 + nsRefPtr<TextComposition> composition = 1.228 + IMEStateManager::GetTextCompositionFor(mWidget); 1.229 + if (!composition) { 1.230 + return false; 1.231 + } 1.232 + return composition->IsEditorHandlingEvent(); 1.233 +} 1.234 + 1.235 +nsresult 1.236 +IMEContentObserver::GetSelectionAndRoot(nsISelection** aSelection, 1.237 + nsIContent** aRootContent) const 1.238 +{ 1.239 + if (!mEditableNode || !mSelection) { 1.240 + return NS_ERROR_NOT_AVAILABLE; 1.241 + } 1.242 + 1.243 + NS_ASSERTION(mSelection && mRootContent, "uninitialized content observer"); 1.244 + NS_ADDREF(*aSelection = mSelection); 1.245 + NS_ADDREF(*aRootContent = mRootContent); 1.246 + return NS_OK; 1.247 +} 1.248 + 1.249 +// Helper class, used for selection change notification 1.250 +class SelectionChangeEvent : public nsRunnable 1.251 +{ 1.252 +public: 1.253 + SelectionChangeEvent(IMEContentObserver* aDispatcher, 1.254 + bool aCausedByComposition) 1.255 + : mDispatcher(aDispatcher) 1.256 + , mCausedByComposition(aCausedByComposition) 1.257 + { 1.258 + MOZ_ASSERT(mDispatcher); 1.259 + } 1.260 + 1.261 + NS_IMETHOD Run() 1.262 + { 1.263 + if (mDispatcher->GetWidget()) { 1.264 + IMENotification notification(NOTIFY_IME_OF_SELECTION_CHANGE); 1.265 + notification.mSelectionChangeData.mCausedByComposition = 1.266 + mCausedByComposition; 1.267 + mDispatcher->GetWidget()->NotifyIME(notification); 1.268 + } 1.269 + return NS_OK; 1.270 + } 1.271 + 1.272 +private: 1.273 + nsRefPtr<IMEContentObserver> mDispatcher; 1.274 + bool mCausedByComposition; 1.275 +}; 1.276 + 1.277 +nsresult 1.278 +IMEContentObserver::NotifySelectionChanged(nsIDOMDocument* aDOMDocument, 1.279 + nsISelection* aSelection, 1.280 + int16_t aReason) 1.281 +{ 1.282 + bool causedByComposition = IsEditorHandlingEventForComposition(); 1.283 + if (causedByComposition && 1.284 + !mUpdatePreference.WantChangesCausedByComposition()) { 1.285 + return NS_OK; 1.286 + } 1.287 + 1.288 + int32_t count = 0; 1.289 + nsresult rv = aSelection->GetRangeCount(&count); 1.290 + NS_ENSURE_SUCCESS(rv, rv); 1.291 + if (count > 0 && mWidget) { 1.292 + nsContentUtils::AddScriptRunner( 1.293 + new SelectionChangeEvent(this, causedByComposition)); 1.294 + } 1.295 + return NS_OK; 1.296 +} 1.297 + 1.298 +// Helper class, used for position change notification 1.299 +class PositionChangeEvent MOZ_FINAL : public nsRunnable 1.300 +{ 1.301 +public: 1.302 + PositionChangeEvent(IMEContentObserver* aDispatcher) 1.303 + : mDispatcher(aDispatcher) 1.304 + { 1.305 + MOZ_ASSERT(mDispatcher); 1.306 + } 1.307 + 1.308 + NS_IMETHOD Run() 1.309 + { 1.310 + if (mDispatcher->GetWidget()) { 1.311 + mDispatcher->GetWidget()->NotifyIME( 1.312 + IMENotification(NOTIFY_IME_OF_POSITION_CHANGE)); 1.313 + } 1.314 + return NS_OK; 1.315 + } 1.316 + 1.317 +private: 1.318 + nsRefPtr<IMEContentObserver> mDispatcher; 1.319 +}; 1.320 + 1.321 +void 1.322 +IMEContentObserver::ScrollPositionChanged() 1.323 +{ 1.324 + if (mWidget) { 1.325 + nsContentUtils::AddScriptRunner(new PositionChangeEvent(this)); 1.326 + } 1.327 +} 1.328 + 1.329 +NS_IMETHODIMP 1.330 +IMEContentObserver::Reflow(DOMHighResTimeStamp aStart, 1.331 + DOMHighResTimeStamp aEnd) 1.332 +{ 1.333 + if (mWidget) { 1.334 + nsContentUtils::AddScriptRunner(new PositionChangeEvent(this)); 1.335 + } 1.336 + return NS_OK; 1.337 +} 1.338 + 1.339 +NS_IMETHODIMP 1.340 +IMEContentObserver::ReflowInterruptible(DOMHighResTimeStamp aStart, 1.341 + DOMHighResTimeStamp aEnd) 1.342 +{ 1.343 + if (mWidget) { 1.344 + nsContentUtils::AddScriptRunner(new PositionChangeEvent(this)); 1.345 + } 1.346 + return NS_OK; 1.347 +} 1.348 + 1.349 +// Helper class, used for text change notification 1.350 +class TextChangeEvent : public nsRunnable 1.351 +{ 1.352 +public: 1.353 + TextChangeEvent(IMEContentObserver* aDispatcher, 1.354 + uint32_t aStart, uint32_t aOldEnd, uint32_t aNewEnd, 1.355 + bool aCausedByComposition) 1.356 + : mDispatcher(aDispatcher) 1.357 + , mStart(aStart) 1.358 + , mOldEnd(aOldEnd) 1.359 + , mNewEnd(aNewEnd) 1.360 + , mCausedByComposition(aCausedByComposition) 1.361 + { 1.362 + MOZ_ASSERT(mDispatcher); 1.363 + } 1.364 + 1.365 + NS_IMETHOD Run() 1.366 + { 1.367 + if (mDispatcher->GetWidget()) { 1.368 + IMENotification notification(NOTIFY_IME_OF_TEXT_CHANGE); 1.369 + notification.mTextChangeData.mStartOffset = mStart; 1.370 + notification.mTextChangeData.mOldEndOffset = mOldEnd; 1.371 + notification.mTextChangeData.mNewEndOffset = mNewEnd; 1.372 + notification.mTextChangeData.mCausedByComposition = mCausedByComposition; 1.373 + mDispatcher->GetWidget()->NotifyIME(notification); 1.374 + } 1.375 + return NS_OK; 1.376 + } 1.377 + 1.378 +private: 1.379 + nsRefPtr<IMEContentObserver> mDispatcher; 1.380 + uint32_t mStart, mOldEnd, mNewEnd; 1.381 + bool mCausedByComposition; 1.382 +}; 1.383 + 1.384 +void 1.385 +IMEContentObserver::CharacterDataChanged(nsIDocument* aDocument, 1.386 + nsIContent* aContent, 1.387 + CharacterDataChangeInfo* aInfo) 1.388 +{ 1.389 + NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT), 1.390 + "character data changed for non-text node"); 1.391 + 1.392 + bool causedByComposition = IsEditorHandlingEventForComposition(); 1.393 + if (causedByComposition && 1.394 + !mUpdatePreference.WantChangesCausedByComposition()) { 1.395 + return; 1.396 + } 1.397 + 1.398 + uint32_t offset = 0; 1.399 + // get offsets of change and fire notification 1.400 + nsresult rv = 1.401 + ContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, aContent, 1.402 + aInfo->mChangeStart, 1.403 + &offset, 1.404 + LINE_BREAK_TYPE_NATIVE); 1.405 + NS_ENSURE_SUCCESS_VOID(rv); 1.406 + 1.407 + uint32_t oldEnd = offset + aInfo->mChangeEnd - aInfo->mChangeStart; 1.408 + uint32_t newEnd = offset + aInfo->mReplaceLength; 1.409 + 1.410 + nsContentUtils::AddScriptRunner( 1.411 + new TextChangeEvent(this, offset, oldEnd, newEnd, causedByComposition)); 1.412 +} 1.413 + 1.414 +void 1.415 +IMEContentObserver::NotifyContentAdded(nsINode* aContainer, 1.416 + int32_t aStartIndex, 1.417 + int32_t aEndIndex) 1.418 +{ 1.419 + bool causedByComposition = IsEditorHandlingEventForComposition(); 1.420 + if (causedByComposition && 1.421 + !mUpdatePreference.WantChangesCausedByComposition()) { 1.422 + return; 1.423 + } 1.424 + 1.425 + uint32_t offset = 0; 1.426 + nsresult rv = 1.427 + ContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, aContainer, 1.428 + aStartIndex, &offset, 1.429 + LINE_BREAK_TYPE_NATIVE); 1.430 + NS_ENSURE_SUCCESS_VOID(rv); 1.431 + 1.432 + // get offset at the end of the last added node 1.433 + nsIContent* childAtStart = aContainer->GetChildAt(aStartIndex); 1.434 + uint32_t addingLength = 0; 1.435 + rv = ContentEventHandler::GetFlatTextOffsetOfRange(childAtStart, aContainer, 1.436 + aEndIndex, &addingLength, 1.437 + LINE_BREAK_TYPE_NATIVE); 1.438 + NS_ENSURE_SUCCESS_VOID(rv); 1.439 + 1.440 + if (!addingLength) { 1.441 + return; 1.442 + } 1.443 + 1.444 + nsContentUtils::AddScriptRunner( 1.445 + new TextChangeEvent(this, offset, offset, offset + addingLength, 1.446 + causedByComposition)); 1.447 +} 1.448 + 1.449 +void 1.450 +IMEContentObserver::ContentAppended(nsIDocument* aDocument, 1.451 + nsIContent* aContainer, 1.452 + nsIContent* aFirstNewContent, 1.453 + int32_t aNewIndexInContainer) 1.454 +{ 1.455 + NotifyContentAdded(aContainer, aNewIndexInContainer, 1.456 + aContainer->GetChildCount()); 1.457 +} 1.458 + 1.459 +void 1.460 +IMEContentObserver::ContentInserted(nsIDocument* aDocument, 1.461 + nsIContent* aContainer, 1.462 + nsIContent* aChild, 1.463 + int32_t aIndexInContainer) 1.464 +{ 1.465 + NotifyContentAdded(NODE_FROM(aContainer, aDocument), 1.466 + aIndexInContainer, aIndexInContainer + 1); 1.467 +} 1.468 + 1.469 +void 1.470 +IMEContentObserver::ContentRemoved(nsIDocument* aDocument, 1.471 + nsIContent* aContainer, 1.472 + nsIContent* aChild, 1.473 + int32_t aIndexInContainer, 1.474 + nsIContent* aPreviousSibling) 1.475 +{ 1.476 + bool causedByComposition = IsEditorHandlingEventForComposition(); 1.477 + if (causedByComposition && 1.478 + !mUpdatePreference.WantChangesCausedByComposition()) { 1.479 + return; 1.480 + } 1.481 + 1.482 + uint32_t offset = 0; 1.483 + nsresult rv = 1.484 + ContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, 1.485 + NODE_FROM(aContainer, 1.486 + aDocument), 1.487 + aIndexInContainer, &offset, 1.488 + LINE_BREAK_TYPE_NATIVE); 1.489 + NS_ENSURE_SUCCESS_VOID(rv); 1.490 + 1.491 + // get offset at the end of the deleted node 1.492 + int32_t nodeLength = 1.493 + aChild->IsNodeOfType(nsINode::eTEXT) ? 1.494 + static_cast<int32_t>(aChild->TextLength()) : 1.495 + std::max(static_cast<int32_t>(aChild->GetChildCount()), 1); 1.496 + MOZ_ASSERT(nodeLength >= 0, "The node length is out of range"); 1.497 + uint32_t textLength = 0; 1.498 + rv = ContentEventHandler::GetFlatTextOffsetOfRange(aChild, aChild, 1.499 + nodeLength, &textLength, 1.500 + LINE_BREAK_TYPE_NATIVE); 1.501 + NS_ENSURE_SUCCESS_VOID(rv); 1.502 + 1.503 + if (!textLength) { 1.504 + return; 1.505 + } 1.506 + 1.507 + nsContentUtils::AddScriptRunner( 1.508 + new TextChangeEvent(this, offset, offset + textLength, offset, 1.509 + causedByComposition)); 1.510 +} 1.511 + 1.512 +static nsIContent* 1.513 +GetContentBR(dom::Element* aElement) 1.514 +{ 1.515 + if (!aElement->IsNodeOfType(nsINode::eCONTENT)) { 1.516 + return nullptr; 1.517 + } 1.518 + nsIContent* content = static_cast<nsIContent*>(aElement); 1.519 + return content->IsHTML(nsGkAtoms::br) ? content : nullptr; 1.520 +} 1.521 + 1.522 +void 1.523 +IMEContentObserver::AttributeWillChange(nsIDocument* aDocument, 1.524 + dom::Element* aElement, 1.525 + int32_t aNameSpaceID, 1.526 + nsIAtom* aAttribute, 1.527 + int32_t aModType) 1.528 +{ 1.529 + nsIContent *content = GetContentBR(aElement); 1.530 + mPreAttrChangeLength = content ? 1.531 + ContentEventHandler::GetNativeTextLength(content) : 0; 1.532 +} 1.533 + 1.534 +void 1.535 +IMEContentObserver::AttributeChanged(nsIDocument* aDocument, 1.536 + dom::Element* aElement, 1.537 + int32_t aNameSpaceID, 1.538 + nsIAtom* aAttribute, 1.539 + int32_t aModType) 1.540 +{ 1.541 + bool causedByComposition = IsEditorHandlingEventForComposition(); 1.542 + if (causedByComposition && 1.543 + !mUpdatePreference.WantChangesCausedByComposition()) { 1.544 + return; 1.545 + } 1.546 + 1.547 + nsIContent *content = GetContentBR(aElement); 1.548 + if (!content) { 1.549 + return; 1.550 + } 1.551 + 1.552 + uint32_t postAttrChangeLength = 1.553 + ContentEventHandler::GetNativeTextLength(content); 1.554 + if (postAttrChangeLength == mPreAttrChangeLength) { 1.555 + return; 1.556 + } 1.557 + uint32_t start; 1.558 + nsresult rv = 1.559 + ContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, content, 1.560 + 0, &start, 1.561 + LINE_BREAK_TYPE_NATIVE); 1.562 + NS_ENSURE_SUCCESS_VOID(rv); 1.563 + 1.564 + nsContentUtils::AddScriptRunner( 1.565 + new TextChangeEvent(this, start, start + mPreAttrChangeLength, 1.566 + start + postAttrChangeLength, causedByComposition)); 1.567 +} 1.568 + 1.569 +} // namespace mozilla