diff -r 000000000000 -r 6474c204b198 dom/base/CompositionStringSynthesizer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/base/CompositionStringSynthesizer.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,160 @@ +/* -*- 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_ISUPPORTS(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 window = do_QueryReferent(mWindow); + if (!window) { + return nullptr; + } + nsIDocShell *docShell = window->GetDocShell(); + if (!docShell) { + return nullptr; + } + nsCOMPtr 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 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 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 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 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