2001-09-26 02:53:13 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
1999-06-30 00:31:22 +04:00
|
|
|
|
2016-07-07 09:42:08 +03:00
|
|
|
#include "CompositionTransaction.h"
|
2014-08-29 15:43:24 +04:00
|
|
|
|
2016-07-08 07:10:13 +03:00
|
|
|
#include "mozilla/EditorBase.h" // mEditorBase
|
2016-11-12 08:56:33 +03:00
|
|
|
#include "mozilla/SelectionState.h" // RangeUpdater
|
2017-12-15 10:45:41 +03:00
|
|
|
#include "mozilla/TextComposition.h" // TextComposition
|
2014-08-29 15:43:24 +04:00
|
|
|
#include "mozilla/dom/Selection.h" // local var
|
|
|
|
#include "mozilla/dom/Text.h" // mTextNode
|
|
|
|
#include "nsAString.h" // params
|
2012-07-13 10:33:42 +04:00
|
|
|
#include "nsDebug.h" // for NS_ASSERTION, etc
|
|
|
|
#include "nsError.h" // for NS_SUCCEEDED, NS_FAILED, etc
|
2014-08-29 15:43:24 +04:00
|
|
|
#include "nsRange.h" // local var
|
2019-03-15 08:01:10 +03:00
|
|
|
#include "nsISelectionController.h" // for nsISelectionController constants
|
2015-04-15 19:47:03 +03:00
|
|
|
#include "nsQueryObject.h" // for do_QueryObject
|
1999-12-01 03:35:31 +03:00
|
|
|
|
2016-07-07 09:42:08 +03:00
|
|
|
namespace mozilla {
|
2013-10-01 11:22:59 +04:00
|
|
|
|
2016-07-07 09:42:08 +03:00
|
|
|
using namespace dom;
|
|
|
|
|
2017-12-15 12:26:37 +03:00
|
|
|
// static
|
|
|
|
already_AddRefed<CompositionTransaction> CompositionTransaction::Create(
|
|
|
|
EditorBase& aEditorBase, const nsAString& aStringToInsert, Text& aTextNode,
|
|
|
|
uint32_t aOffset) {
|
|
|
|
TextComposition* composition = aEditorBase.GetComposition();
|
|
|
|
MOZ_RELEASE_ASSERT(composition);
|
|
|
|
// XXX Actually, we get different text node and offset from editor in some
|
|
|
|
// cases. If composition stores text node, we should use it and offset
|
|
|
|
// in it.
|
|
|
|
Text* textNode = composition->GetContainerTextNode();
|
|
|
|
uint32_t offset;
|
|
|
|
if (textNode) {
|
|
|
|
offset = composition->XPOffsetInTextNode();
|
|
|
|
NS_WARNING_ASSERTION(
|
|
|
|
&aTextNode == composition->GetContainerTextNode(),
|
|
|
|
"The editor tries to insert composition string into different node");
|
|
|
|
NS_WARNING_ASSERTION(
|
|
|
|
aOffset == composition->XPOffsetInTextNode(),
|
|
|
|
"The editor tries to insert composition string into different offset");
|
|
|
|
} else {
|
|
|
|
textNode = &aTextNode;
|
|
|
|
offset = aOffset;
|
|
|
|
}
|
|
|
|
RefPtr<CompositionTransaction> transaction = new CompositionTransaction(
|
|
|
|
aEditorBase, aStringToInsert, *textNode, offset);
|
|
|
|
// XXX Now, it might be better to modify the text node information of
|
|
|
|
// the TextComposition instance in DoTransaction() because updating
|
|
|
|
// the information before changing actual DOM tree is pretty odd.
|
|
|
|
composition->OnCreateCompositionTransaction(aStringToInsert, textNode,
|
|
|
|
offset);
|
|
|
|
return transaction.forget();
|
|
|
|
}
|
|
|
|
|
2016-07-07 09:42:08 +03:00
|
|
|
CompositionTransaction::CompositionTransaction(EditorBase& aEditorBase,
|
2017-12-15 10:45:41 +03:00
|
|
|
const nsAString& aStringToInsert,
|
2017-12-15 12:26:37 +03:00
|
|
|
Text& aTextNode,
|
|
|
|
uint32_t aOffset)
|
|
|
|
: mTextNode(&aTextNode),
|
|
|
|
mOffset(aOffset),
|
|
|
|
mReplaceLength(aEditorBase.GetComposition()->XPLengthInTextNode()),
|
|
|
|
mRanges(aEditorBase.GetComposition()->GetRanges()),
|
2014-08-29 15:43:24 +04:00
|
|
|
mStringToInsert(aStringToInsert),
|
2017-03-21 13:00:36 +03:00
|
|
|
mEditorBase(&aEditorBase),
|
2014-08-29 15:43:24 +04:00
|
|
|
mFixed(false) {
|
2016-11-08 10:14:57 +03:00
|
|
|
MOZ_ASSERT(mTextNode->TextLength() >= mOffset);
|
2014-08-29 15:43:24 +04:00
|
|
|
}
|
|
|
|
|
2016-07-07 09:42:08 +03:00
|
|
|
CompositionTransaction::~CompositionTransaction() {}
|
1999-06-30 00:31:22 +04:00
|
|
|
|
2016-07-08 03:48:34 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_INHERITED(CompositionTransaction, EditTransactionBase,
|
2017-03-21 13:00:36 +03:00
|
|
|
mEditorBase, mTextNode)
|
2013-05-22 03:23:53 +04:00
|
|
|
// mRangeList can't lead to cycles
|
2009-05-09 08:59:25 +04:00
|
|
|
|
2016-07-07 09:42:08 +03:00
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CompositionTransaction)
|
2018-05-22 02:33:18 +03:00
|
|
|
NS_INTERFACE_MAP_ENTRY_CONCRETE(CompositionTransaction)
|
2016-07-08 03:48:34 +03:00
|
|
|
NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
|
2009-05-09 08:59:25 +04:00
|
|
|
|
2016-07-08 03:48:34 +03:00
|
|
|
NS_IMPL_ADDREF_INHERITED(CompositionTransaction, EditTransactionBase)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(CompositionTransaction, EditTransactionBase)
|
1999-06-30 00:31:22 +04:00
|
|
|
|
2014-08-29 15:43:24 +04:00
|
|
|
NS_IMETHODIMP
|
2016-07-07 09:42:08 +03:00
|
|
|
CompositionTransaction::DoTransaction() {
|
2017-03-21 13:00:36 +03:00
|
|
|
if (NS_WARN_IF(!mEditorBase)) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
2014-08-29 15:43:24 +04:00
|
|
|
// Fail before making any changes if there's no selection controller
|
2011-03-11 08:40:30 +03:00
|
|
|
nsCOMPtr<nsISelectionController> selCon;
|
2017-03-21 13:00:36 +03:00
|
|
|
mEditorBase->GetSelectionController(getter_AddRefs(selCon));
|
2010-06-17 23:41:16 +04:00
|
|
|
NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
|
1999-08-25 14:51:55 +04:00
|
|
|
|
2014-08-29 15:43:24 +04:00
|
|
|
// Advance caret: This requires the presentation shell to get the selection.
|
2003-06-30 18:31:48 +04:00
|
|
|
if (mReplaceLength == 0) {
|
2018-03-19 22:38:04 +03:00
|
|
|
ErrorResult rv;
|
|
|
|
mTextNode->InsertData(mOffset, mStringToInsert, rv);
|
|
|
|
if (NS_WARN_IF(rv.Failed())) {
|
|
|
|
return rv.StealNSResult();
|
2016-10-19 12:09:33 +03:00
|
|
|
}
|
2017-12-15 12:26:37 +03:00
|
|
|
mEditorBase->RangeUpdaterRef().SelAdjInsertText(*mTextNode, mOffset,
|
|
|
|
mStringToInsert);
|
1999-10-27 04:10:03 +04:00
|
|
|
} else {
|
2016-11-08 10:14:57 +03:00
|
|
|
uint32_t replaceableLength = mTextNode->TextLength() - mOffset;
|
2018-03-19 22:45:34 +03:00
|
|
|
ErrorResult rv;
|
|
|
|
mTextNode->ReplaceData(mOffset, mReplaceLength, mStringToInsert, rv);
|
|
|
|
if (NS_WARN_IF(rv.Failed())) {
|
|
|
|
return rv.StealNSResult();
|
2016-10-19 12:09:33 +03:00
|
|
|
}
|
2017-12-15 12:26:37 +03:00
|
|
|
mEditorBase->RangeUpdaterRef().SelAdjDeleteText(mTextNode, mOffset,
|
|
|
|
mReplaceLength);
|
|
|
|
mEditorBase->RangeUpdaterRef().SelAdjInsertText(*mTextNode, mOffset,
|
|
|
|
mStringToInsert);
|
2016-11-08 10:14:57 +03:00
|
|
|
|
|
|
|
// If IME text node is multiple node, ReplaceData doesn't remove all IME
|
|
|
|
// text. So we need remove remained text into other text node.
|
|
|
|
if (replaceableLength < mReplaceLength) {
|
|
|
|
int32_t remainLength = mReplaceLength - replaceableLength;
|
|
|
|
nsCOMPtr<nsINode> node = mTextNode->GetNextSibling();
|
2018-04-13 01:41:00 +03:00
|
|
|
while (node && node->IsText() && remainLength > 0) {
|
2016-11-08 10:14:57 +03:00
|
|
|
Text* text = static_cast<Text*>(node.get());
|
|
|
|
uint32_t textLength = text->TextLength();
|
2018-03-19 22:45:31 +03:00
|
|
|
text->DeleteData(0, remainLength, IgnoreErrors());
|
2017-12-15 12:26:37 +03:00
|
|
|
mEditorBase->RangeUpdaterRef().SelAdjDeleteText(text, 0, remainLength);
|
2016-11-08 10:14:57 +03:00
|
|
|
remainLength -= textLength;
|
|
|
|
node = node->GetNextSibling();
|
|
|
|
}
|
|
|
|
}
|
1999-08-25 14:51:55 +04:00
|
|
|
}
|
2014-08-29 15:43:24 +04:00
|
|
|
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv = SetSelectionForRanges();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
1999-08-25 14:51:55 +04:00
|
|
|
|
2014-08-29 15:43:24 +04:00
|
|
|
return NS_OK;
|
1999-06-30 00:31:22 +04:00
|
|
|
}
|
|
|
|
|
2014-08-29 15:43:24 +04:00
|
|
|
NS_IMETHODIMP
|
2016-07-07 09:42:08 +03:00
|
|
|
CompositionTransaction::UndoTransaction() {
|
2017-03-21 13:00:36 +03:00
|
|
|
if (NS_WARN_IF(!mEditorBase)) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
2014-08-29 15:43:24 +04:00
|
|
|
// Get the selection first so we'll fail before making any changes if we
|
|
|
|
// can't get it
|
2017-03-21 13:00:36 +03:00
|
|
|
RefPtr<Selection> selection = mEditorBase->GetSelection();
|
2014-08-29 15:43:24 +04:00
|
|
|
NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
|
2000-10-29 02:17:53 +04:00
|
|
|
|
2018-03-19 22:45:31 +03:00
|
|
|
ErrorResult err;
|
|
|
|
mTextNode->DeleteData(mOffset, mStringToInsert.Length(), err);
|
|
|
|
if (NS_WARN_IF(err.Failed())) {
|
|
|
|
return err.StealNSResult();
|
|
|
|
}
|
1999-08-25 14:51:55 +04:00
|
|
|
|
2014-08-29 15:43:24 +04:00
|
|
|
// set the selection to the insertion point where the string was removed
|
2018-03-19 22:45:31 +03:00
|
|
|
nsresult rv = selection->Collapse(mTextNode, mOffset);
|
2016-10-19 12:09:33 +03:00
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv),
|
2014-08-29 15:43:24 +04:00
|
|
|
"Selection could not be collapsed after undo of IME insert.");
|
2016-10-19 12:09:33 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-08-29 15:43:24 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
1999-06-30 00:31:22 +04:00
|
|
|
}
|
|
|
|
|
2014-08-29 15:43:24 +04:00
|
|
|
NS_IMETHODIMP
|
2016-07-07 09:42:08 +03:00
|
|
|
CompositionTransaction::Merge(nsITransaction* aTransaction, bool* aDidMerge) {
|
2014-08-29 15:43:24 +04:00
|
|
|
NS_ENSURE_ARG_POINTER(aTransaction && aDidMerge);
|
1999-06-30 00:31:22 +04:00
|
|
|
|
2014-08-29 15:43:24 +04:00
|
|
|
// Check to make sure we aren't fixed, if we are then nothing gets absorbed
|
1999-08-25 14:51:55 +04:00
|
|
|
if (mFixed) {
|
2011-10-17 18:59:28 +04:00
|
|
|
*aDidMerge = false;
|
1999-08-25 14:51:55 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-07-07 09:42:08 +03:00
|
|
|
// If aTransaction is another CompositionTransaction then absorb it
|
|
|
|
RefPtr<CompositionTransaction> otherTransaction =
|
|
|
|
do_QueryObject(aTransaction);
|
|
|
|
if (otherTransaction) {
|
2014-08-29 15:43:24 +04:00
|
|
|
// We absorb the next IME transaction by adopting its insert string
|
2016-07-07 09:42:08 +03:00
|
|
|
mStringToInsert = otherTransaction->mStringToInsert;
|
|
|
|
mRanges = otherTransaction->mRanges;
|
2011-10-17 18:59:28 +04:00
|
|
|
*aDidMerge = true;
|
1999-08-25 14:51:55 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
*aDidMerge = false;
|
1999-08-25 14:51:55 +04:00
|
|
|
return NS_OK;
|
1999-06-30 00:31:22 +04:00
|
|
|
}
|
|
|
|
|
2016-07-07 09:42:08 +03:00
|
|
|
void CompositionTransaction::MarkFixed() { mFixed = true; }
|
2000-07-11 23:51:36 +04:00
|
|
|
|
2014-08-29 15:43:24 +04:00
|
|
|
/* ============ private methods ================== */
|
1999-06-30 00:31:22 +04:00
|
|
|
|
2016-07-07 09:42:08 +03:00
|
|
|
nsresult CompositionTransaction::SetSelectionForRanges() {
|
2017-03-21 13:00:36 +03:00
|
|
|
if (NS_WARN_IF(!mEditorBase)) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
return SetIMESelection(*mEditorBase, mTextNode, mOffset,
|
2015-06-04 20:06:09 +03:00
|
|
|
mStringToInsert.Length(), mRanges);
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
2016-07-08 07:10:13 +03:00
|
|
|
nsresult CompositionTransaction::SetIMESelection(
|
2016-07-07 09:42:08 +03:00
|
|
|
EditorBase& aEditorBase, Text* aTextNode, uint32_t aOffsetInNode,
|
|
|
|
uint32_t aLengthOfCompositionString, const TextRangeArray* aRanges) {
|
2016-07-08 07:10:13 +03:00
|
|
|
RefPtr<Selection> selection = aEditorBase.GetSelection();
|
2014-08-29 15:43:24 +04:00
|
|
|
NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
|
1999-06-30 00:31:22 +04:00
|
|
|
|
2017-08-09 12:06:36 +03:00
|
|
|
SelectionBatcher selectionBatcher(selection);
|
2014-03-04 17:48:26 +04:00
|
|
|
|
|
|
|
// First, remove all selections of IME composition.
|
2016-06-07 16:42:06 +03:00
|
|
|
static const RawSelectionType kIMESelections[] = {
|
2014-03-04 17:48:26 +04:00
|
|
|
nsISelectionController::SELECTION_IME_RAWINPUT,
|
|
|
|
nsISelectionController::SELECTION_IME_SELECTEDRAWTEXT,
|
|
|
|
nsISelectionController::SELECTION_IME_CONVERTEDTEXT,
|
|
|
|
nsISelectionController::SELECTION_IME_SELECTEDCONVERTEDTEXT};
|
2014-08-29 15:43:24 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsISelectionController> selCon;
|
2016-07-08 07:10:13 +03:00
|
|
|
aEditorBase.GetSelectionController(getter_AddRefs(selCon));
|
2014-08-29 15:43:24 +04:00
|
|
|
NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
|
|
|
|
|
2017-08-09 12:06:36 +03:00
|
|
|
nsresult rv = NS_OK;
|
2014-03-04 17:48:26 +04:00
|
|
|
for (uint32_t i = 0; i < ArrayLength(kIMESelections); ++i) {
|
2018-05-08 20:52:36 +03:00
|
|
|
RefPtr<Selection> selectionOfIME = selCon->GetSelection(kIMESelections[i]);
|
2018-03-27 07:35:23 +03:00
|
|
|
if (!selectionOfIME) {
|
2014-03-04 17:48:26 +04:00
|
|
|
continue;
|
|
|
|
}
|
2018-03-27 07:35:23 +03:00
|
|
|
selectionOfIME->RemoveAllRanges(IgnoreErrors());
|
2014-03-04 17:48:26 +04:00
|
|
|
}
|
1999-10-27 04:10:03 +04:00
|
|
|
|
2014-03-04 17:48:26 +04:00
|
|
|
// Set caret position and selection of IME composition with TextRangeArray.
|
|
|
|
bool setCaret = false;
|
2015-06-04 20:06:09 +03:00
|
|
|
uint32_t countOfRanges = aRanges ? aRanges->Length() : 0;
|
2014-08-29 15:43:24 +04:00
|
|
|
|
2014-06-24 05:06:20 +04:00
|
|
|
#ifdef DEBUG
|
2014-08-29 15:43:24 +04:00
|
|
|
// Bounds-checking on debug builds
|
2015-06-04 20:06:09 +03:00
|
|
|
uint32_t maxOffset = aTextNode->Length();
|
2014-06-24 05:06:20 +04:00
|
|
|
#endif
|
2014-08-29 15:43:24 +04:00
|
|
|
|
2015-06-04 20:06:09 +03:00
|
|
|
// NOTE: composition string may be truncated when it's committed and
|
|
|
|
// maxlength attribute value doesn't allow input of all text of this
|
|
|
|
// composition.
|
2014-03-04 17:48:26 +04:00
|
|
|
for (uint32_t i = 0; i < countOfRanges; ++i) {
|
2015-06-04 20:06:09 +03:00
|
|
|
const TextRange& textRange = aRanges->ElementAt(i);
|
2014-03-04 17:48:26 +04:00
|
|
|
|
|
|
|
// Caret needs special handling since its length may be 0 and if it's not
|
|
|
|
// specified explicitly, we need to handle it ourselves later.
|
2016-06-03 12:40:06 +03:00
|
|
|
if (textRange.mRangeType == TextRangeType::eCaret) {
|
2014-03-04 17:48:26 +04:00
|
|
|
NS_ASSERTION(!setCaret, "The ranges already has caret position");
|
2016-07-08 07:10:13 +03:00
|
|
|
NS_ASSERTION(!textRange.Length(),
|
|
|
|
"EditorBase doesn't support wide caret");
|
2014-06-24 05:06:20 +04:00
|
|
|
int32_t caretOffset = static_cast<int32_t>(
|
2015-06-04 20:06:09 +03:00
|
|
|
aOffsetInNode +
|
|
|
|
std::min(textRange.mStartOffset, aLengthOfCompositionString));
|
2014-06-24 05:06:20 +04:00
|
|
|
MOZ_ASSERT(caretOffset >= 0 &&
|
|
|
|
static_cast<uint32_t>(caretOffset) <= maxOffset);
|
2015-06-04 20:06:09 +03:00
|
|
|
rv = selection->Collapse(aTextNode, caretOffset);
|
2014-03-04 17:48:26 +04:00
|
|
|
setCaret = setCaret || NS_SUCCEEDED(rv);
|
2015-08-17 14:58:38 +03:00
|
|
|
if (NS_WARN_IF(!setCaret)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// If caret range is specified explicitly, we should show the caret if
|
|
|
|
// it should be so.
|
2016-07-08 07:10:13 +03:00
|
|
|
aEditorBase.HideCaret(false);
|
2014-03-04 17:48:26 +04:00
|
|
|
continue;
|
|
|
|
}
|
1999-06-30 00:31:22 +04:00
|
|
|
|
2014-08-29 15:43:24 +04:00
|
|
|
// If the clause length is 0, it should be a bug.
|
2014-03-04 17:48:26 +04:00
|
|
|
if (!textRange.Length()) {
|
|
|
|
NS_WARNING("Any clauses must not be empty");
|
|
|
|
continue;
|
1999-08-25 14:51:55 +04:00
|
|
|
}
|
2000-04-27 11:37:12 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsRange> clauseRange;
|
2014-06-24 05:06:20 +04:00
|
|
|
int32_t startOffset = static_cast<int32_t>(
|
2015-06-04 20:06:09 +03:00
|
|
|
aOffsetInNode +
|
|
|
|
std::min(textRange.mStartOffset, aLengthOfCompositionString));
|
2014-06-24 05:06:20 +04:00
|
|
|
MOZ_ASSERT(startOffset >= 0 &&
|
|
|
|
static_cast<uint32_t>(startOffset) <= maxOffset);
|
|
|
|
int32_t endOffset = static_cast<int32_t>(
|
2015-06-04 20:06:09 +03:00
|
|
|
aOffsetInNode +
|
|
|
|
std::min(textRange.mEndOffset, aLengthOfCompositionString));
|
2014-06-24 05:06:20 +04:00
|
|
|
MOZ_ASSERT(endOffset >= startOffset &&
|
|
|
|
static_cast<uint32_t>(endOffset) <= maxOffset);
|
2019-06-28 10:47:29 +03:00
|
|
|
clauseRange = nsRange::Create(aTextNode, startOffset, aTextNode, endOffset,
|
|
|
|
IgnoreErrors());
|
|
|
|
if (!clauseRange) {
|
2014-03-04 17:48:26 +04:00
|
|
|
NS_WARNING("Failed to create a DOM range for a clause of composition");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the range of the clause to selection.
|
2017-08-24 10:56:12 +03:00
|
|
|
RefPtr<Selection> selectionOfIME =
|
2018-05-08 20:52:36 +03:00
|
|
|
selCon->GetSelection(ToRawSelectionType(textRange.mRangeType));
|
2017-08-24 10:56:12 +03:00
|
|
|
if (!selectionOfIME) {
|
2014-03-04 17:48:26 +04:00
|
|
|
NS_WARNING("Failed to get IME selection");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-03-27 07:35:22 +03:00
|
|
|
IgnoredErrorResult err;
|
|
|
|
selectionOfIME->AddRange(*clauseRange, err);
|
|
|
|
if (err.Failed()) {
|
2014-03-04 17:48:26 +04:00
|
|
|
NS_WARNING("Failed to add selection range for a clause of composition");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the style of the clause.
|
2017-08-24 10:56:12 +03:00
|
|
|
rv = selectionOfIME->SetTextRangeStyle(clauseRange, textRange.mRangeStyle);
|
2014-03-04 17:48:26 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("Failed to set selection style");
|
|
|
|
break; // but this is unexpected...
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the ranges doesn't include explicit caret position, let's set the
|
|
|
|
// caret to the end of composition string.
|
|
|
|
if (!setCaret) {
|
2015-06-04 20:06:09 +03:00
|
|
|
int32_t caretOffset =
|
|
|
|
static_cast<int32_t>(aOffsetInNode + aLengthOfCompositionString);
|
2014-06-24 05:06:20 +04:00
|
|
|
MOZ_ASSERT(caretOffset >= 0 &&
|
|
|
|
static_cast<uint32_t>(caretOffset) <= maxOffset);
|
2015-06-04 20:06:09 +03:00
|
|
|
rv = selection->Collapse(aTextNode, caretOffset);
|
2014-03-04 17:48:26 +04:00
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv),
|
|
|
|
"Failed to set caret at the end of composition string");
|
2015-12-01 23:25:06 +03:00
|
|
|
|
2015-08-17 14:58:38 +03:00
|
|
|
// If caret range isn't specified explicitly, we should hide the caret.
|
2016-05-04 12:05:35 +03:00
|
|
|
// Hiding the caret benefits a Windows build (see bug 555642 comment #6).
|
2016-08-27 07:26:42 +03:00
|
|
|
// However, when there is no range, we should keep showing caret.
|
|
|
|
if (countOfRanges) {
|
|
|
|
aEditorBase.HideCaret(true);
|
|
|
|
}
|
2014-03-04 17:48:26 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
1999-06-30 00:31:22 +04:00
|
|
|
}
|
2016-07-07 09:42:08 +03:00
|
|
|
|
|
|
|
} // namespace mozilla
|