gecko-dev/dom/base/CompositionStringSynthesizer.cpp

161 lines
4.3 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "CompositionStringSynthesizer.h"
#include "nsContentUtils.h"
#include "nsIDocShell.h"
#include "nsIFrame.h"
#include "nsIPresShell.h"
#include "nsIWidget.h"
#include "nsPIDOMWindow.h"
#include "nsView.h"
#include "mozilla/TextEvents.h"
namespace mozilla {
namespace dom {
NS_IMPL_ISUPPORTS1(CompositionStringSynthesizer,
nsICompositionStringSynthesizer)
CompositionStringSynthesizer::CompositionStringSynthesizer(
nsPIDOMWindow* aWindow)
{
mWindow = do_GetWeakReference(aWindow);
mClauses = new TextRangeArray();
ClearInternal();
}
CompositionStringSynthesizer::~CompositionStringSynthesizer()
{
}
void
CompositionStringSynthesizer::ClearInternal()
{
mString.Truncate();
mClauses->Clear();
mCaret.mRangeType = 0;
}
nsIWidget*
CompositionStringSynthesizer::GetWidget()
{
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
if (!window) {
return nullptr;
}
nsIDocShell *docShell = window->GetDocShell();
if (!docShell) {
return nullptr;
}
nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
if (!presShell) {
return nullptr;
}
nsIFrame* frame = presShell->GetRootFrame();
if (!frame) {
return nullptr;
}
return frame->GetView()->GetNearestWidget(nullptr);
}
NS_IMETHODIMP
CompositionStringSynthesizer::SetString(const nsAString& aString)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
NS_ENSURE_TRUE(widget && !widget->Destroyed(), NS_ERROR_NOT_AVAILABLE);
mString = aString;
return NS_OK;
}
NS_IMETHODIMP
CompositionStringSynthesizer::AppendClause(uint32_t aLength,
uint32_t aAttribute)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
NS_ENSURE_TRUE(widget && !widget->Destroyed(), NS_ERROR_NOT_AVAILABLE);
switch (aAttribute) {
case ATTR_RAWINPUT:
case ATTR_SELECTEDRAWTEXT:
case ATTR_CONVERTEDTEXT:
case ATTR_SELECTEDCONVERTEDTEXT: {
TextRange textRange;
textRange.mStartOffset =
mClauses->IsEmpty() ? 0 : mClauses->LastElement().mEndOffset;
textRange.mEndOffset = textRange.mStartOffset + aLength;
textRange.mRangeType = aAttribute;
mClauses->AppendElement(textRange);
return NS_OK;
}
default:
return NS_ERROR_INVALID_ARG;
}
}
NS_IMETHODIMP
CompositionStringSynthesizer::SetCaret(uint32_t aOffset, uint32_t aLength)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
NS_ENSURE_TRUE(widget && !widget->Destroyed(), NS_ERROR_NOT_AVAILABLE);
mCaret.mStartOffset = aOffset;
mCaret.mEndOffset = mCaret.mStartOffset + aLength;
mCaret.mRangeType = NS_TEXTRANGE_CARETPOSITION;
return NS_OK;
}
NS_IMETHODIMP
CompositionStringSynthesizer::DispatchEvent(bool* aDefaultPrevented)
{
NS_ENSURE_ARG_POINTER(aDefaultPrevented);
nsCOMPtr<nsIWidget> widget = GetWidget();
NS_ENSURE_TRUE(widget && !widget->Destroyed(), NS_ERROR_NOT_AVAILABLE);
if (!nsContentUtils::IsCallerChrome()) {
return NS_ERROR_DOM_SECURITY_ERR;
}
if (!mClauses->IsEmpty() &&
mClauses->LastElement().mEndOffset != mString.Length()) {
NS_WARNING("Sum of length of the all clauses must be same as the string "
"length");
ClearInternal();
return NS_ERROR_ILLEGAL_VALUE;
}
if (mCaret.mRangeType == NS_TEXTRANGE_CARETPOSITION) {
if (mCaret.mEndOffset > mString.Length()) {
NS_WARNING("Caret position is out of the composition string");
ClearInternal();
return NS_ERROR_ILLEGAL_VALUE;
}
mClauses->AppendElement(mCaret);
}
WidgetTextEvent textEvent(true, NS_TEXT_TEXT, widget);
textEvent.time = PR_IntervalNow();
textEvent.theText = mString;
if (!mClauses->IsEmpty()) {
textEvent.mRanges = mClauses;
}
// XXX How should we set false for this on b2g?
textEvent.mFlags.mIsSynthesizedForTests = true;
nsEventStatus status = nsEventStatus_eIgnore;
nsresult rv = widget->DispatchEvent(&textEvent, status);
*aDefaultPrevented = (status == nsEventStatus_eConsumeNoDefault);
ClearInternal();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
} // namespace dom
} // namespace mozilla