mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 528396 Create XP level IME transaction tests r=roc+mats, sr=jst
This commit is contained in:
parent
4655d34ca9
commit
bb7a62d1cf
@ -77,17 +77,12 @@ nsContentEventHandler::nsContentEventHandler(
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentEventHandler::Init(nsQueryContentEvent* aEvent)
|
||||
nsContentEventHandler::InitCommon()
|
||||
{
|
||||
NS_ASSERTION(aEvent, "aEvent must not be null");
|
||||
|
||||
if (mSelection)
|
||||
return NS_OK;
|
||||
|
||||
aEvent->mSucceeded = PR_FALSE;
|
||||
|
||||
if (!mPresShell)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
// If text frame which has overflowing selection underline is dirty,
|
||||
// we need to flush the pending reflow here.
|
||||
@ -99,11 +94,6 @@ nsContentEventHandler::Init(nsQueryContentEvent* aEvent)
|
||||
NS_ASSERTION(mSelection,
|
||||
"GetSelectionForCopy succeeded, but the result is null");
|
||||
|
||||
PRBool isCollapsed;
|
||||
rv = mSelection->GetIsCollapsed(&isCollapsed);
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
aEvent->mReply.mHasSelection = !isCollapsed;
|
||||
|
||||
nsCOMPtr<nsIDOMRange> firstRange;
|
||||
rv = mSelection->GetRangeAt(0, getter_AddRefs(firstRange));
|
||||
@ -126,9 +116,26 @@ nsContentEventHandler::Init(nsQueryContentEvent* aEvent)
|
||||
|
||||
mRootContent = startNode->GetSelectionRootContent(mPresShell);
|
||||
NS_ENSURE_TRUE(mRootContent, NS_ERROR_FAILURE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentEventHandler::Init(nsQueryContentEvent* aEvent)
|
||||
{
|
||||
NS_ASSERTION(aEvent, "aEvent must not be null");
|
||||
|
||||
nsresult rv = InitCommon();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aEvent->mSucceeded = PR_FALSE;
|
||||
|
||||
aEvent->mReply.mContentsRoot = mRootContent.get();
|
||||
|
||||
PRBool isCollapsed;
|
||||
rv = mSelection->GetIsCollapsed(&isCollapsed);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_NOT_AVAILABLE);
|
||||
aEvent->mReply.mHasSelection = !isCollapsed;
|
||||
|
||||
nsRefPtr<nsCaret> caret;
|
||||
rv = mPresShell->GetCaret(getter_AddRefs(caret));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -143,6 +150,19 @@ nsContentEventHandler::Init(nsQueryContentEvent* aEvent)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentEventHandler::Init(nsSelectionEvent* aEvent)
|
||||
{
|
||||
NS_ASSERTION(aEvent, "aEvent must not be null");
|
||||
|
||||
nsresult rv = InitCommon();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aEvent->mSucceeded = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Editor places a bogus BR node under its root content if the editor doesn't
|
||||
// have any text. This happens even for single line editors.
|
||||
// When we get text content and when we change the selection,
|
||||
@ -664,9 +684,8 @@ nsContentEventHandler::OnQueryCaretRect(nsQueryContentEvent* aEvent)
|
||||
nsIFrame* caretFrame = caret->GetGeometry(mSelection, &rect);
|
||||
if (!caretFrame)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsPoint windowOffset(0, 0);
|
||||
caretFrame->GetWindowOffset(windowOffset);
|
||||
rect.MoveBy(windowOffset);
|
||||
rv = ConvertToRootViewRelativeOffset(caretFrame, rect);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
aEvent->mReply.mRect =
|
||||
rect.ToOutsidePixels(caretFrame->PresContext()->AppUnitsPerDevPixel());
|
||||
aEvent->mSucceeded = PR_TRUE;
|
||||
@ -747,8 +766,32 @@ nsContentEventHandler::OnQueryCharacterAtPoint(nsQueryContentEvent* aEvent)
|
||||
return rv;
|
||||
|
||||
nsIFrame* rootFrame = mPresShell->GetRootFrame();
|
||||
NS_ENSURE_TRUE(rootFrame, NS_ERROR_FAILURE);
|
||||
nsIWidget* rootWidget = rootFrame->GetWindow();
|
||||
NS_ENSURE_TRUE(rootWidget, NS_ERROR_FAILURE);
|
||||
|
||||
// The root frame's widget might be different, e.g., the event was fired on
|
||||
// a popup but the rootFrame is the document root.
|
||||
if (rootWidget != aEvent->widget) {
|
||||
NS_PRECONDITION(aEvent->widget, "The event must have the widget");
|
||||
nsIView* view = nsIView::GetViewFor(aEvent->widget);
|
||||
NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
|
||||
rootFrame = nsLayoutUtils::GetFrameFor(view);
|
||||
NS_ENSURE_TRUE(rootFrame, NS_ERROR_FAILURE);
|
||||
rootWidget = rootFrame->GetWindow();
|
||||
NS_ENSURE_TRUE(rootWidget, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
nsQueryContentEvent eventOnRoot(PR_TRUE, NS_QUERY_CHARACTER_AT_POINT,
|
||||
rootWidget);
|
||||
eventOnRoot.refPoint = aEvent->refPoint;
|
||||
if (rootWidget != aEvent->widget) {
|
||||
eventOnRoot.refPoint += aEvent->widget->WidgetToScreenOffset();
|
||||
eventOnRoot.refPoint -= rootWidget->WidgetToScreenOffset();
|
||||
}
|
||||
nsPoint ptInRoot =
|
||||
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame);
|
||||
nsLayoutUtils::GetEventCoordinatesRelativeTo(&eventOnRoot, rootFrame);
|
||||
|
||||
nsIFrame* targetFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, ptInRoot);
|
||||
if (!targetFrame || targetFrame->GetType() != nsGkAtoms::textFrame) {
|
||||
// there is no character at the point.
|
||||
@ -882,11 +925,17 @@ nsContentEventHandler::OnSelectionEvent(nsSelectionEvent* aEvent)
|
||||
aEvent->mSucceeded = PR_FALSE;
|
||||
|
||||
// Get selection to manipulate
|
||||
nsCOMPtr<nsISelection> sel;
|
||||
// XXX why do we need to get them from ISM? This method should work fine
|
||||
// without ISM.
|
||||
nsresult rv = nsIMEStateManager::
|
||||
GetFocusSelectionAndRoot(getter_AddRefs(sel),
|
||||
GetFocusSelectionAndRoot(getter_AddRefs(mSelection),
|
||||
getter_AddRefs(mRootContent));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (rv != NS_ERROR_NOT_AVAILABLE) {
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
rv = Init(aEvent);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Get range from offset and length
|
||||
nsRefPtr<nsRange> range = new nsRange();
|
||||
@ -906,32 +955,32 @@ nsContentEventHandler::OnSelectionEvent(nsSelectionEvent* aEvent)
|
||||
nsCOMPtr<nsIDOMNode> endDomNode(do_QueryInterface(endNode));
|
||||
NS_ENSURE_TRUE(startDomNode && endDomNode, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(sel);
|
||||
nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(mSelection);
|
||||
NS_ENSURE_TRUE(selPrivate, NS_ERROR_UNEXPECTED);
|
||||
selPrivate->StartBatchChanges();
|
||||
|
||||
// Clear selection first before setting
|
||||
rv = sel->RemoveAllRanges();
|
||||
rv = mSelection->RemoveAllRanges();
|
||||
// Need to call EndBatchChanges at the end even if call failed
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (aEvent->mReversed) {
|
||||
rv = sel->Collapse(endDomNode, endOffset);
|
||||
rv = mSelection->Collapse(endDomNode, endOffset);
|
||||
} else {
|
||||
rv = sel->Collapse(startDomNode, startOffset);
|
||||
rv = mSelection->Collapse(startDomNode, startOffset);
|
||||
}
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
(startDomNode != endDomNode || startOffset != endOffset)) {
|
||||
if (aEvent->mReversed) {
|
||||
rv = sel->Extend(startDomNode, startOffset);
|
||||
rv = mSelection->Extend(startDomNode, startOffset);
|
||||
} else {
|
||||
rv = sel->Extend(endDomNode, endOffset);
|
||||
rv = mSelection->Extend(endDomNode, endOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
selPrivate->EndBatchChanges();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsISelection2>(do_QueryInterface(sel))->ScrollIntoView(
|
||||
nsCOMPtr<nsISelection2>(do_QueryInterface(mSelection))->ScrollIntoView(
|
||||
nsISelectionController::SELECTION_FOCUS_REGION, PR_FALSE, -1, -1);
|
||||
aEvent->mSucceeded = PR_TRUE;
|
||||
return NS_OK;
|
||||
|
@ -95,6 +95,10 @@ protected:
|
||||
nsCOMPtr<nsIContent> mRootContent;
|
||||
|
||||
nsresult Init(nsQueryContentEvent* aEvent);
|
||||
nsresult Init(nsSelectionEvent* aEvent);
|
||||
|
||||
// InitCommon() is called from each Init().
|
||||
nsresult InitCommon();
|
||||
|
||||
public:
|
||||
// FlatText means the text that is generated from DOM tree. The BR elements
|
||||
|
@ -99,6 +99,7 @@ CPPSRCS = \
|
||||
nsDOMClassInfo.cpp \
|
||||
nsScriptNameSpaceManager.cpp \
|
||||
nsDOMScriptObjectFactory.cpp \
|
||||
nsQueryContentEventResult.cpp \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/dom/dom-config.mk
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "nsIDOMNSEvent.h"
|
||||
#include "nsIPrivateDOMEvent.h"
|
||||
#include "nsDOMWindowUtils.h"
|
||||
#include "nsQueryContentEventResult.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsFocusManager.h"
|
||||
@ -50,6 +51,7 @@
|
||||
#include "nsIScrollableFrame.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIWidget.h"
|
||||
@ -70,6 +72,15 @@
|
||||
#include <gdk/gdkx.h>
|
||||
#endif
|
||||
|
||||
static PRBool IsUniversalXPConnectCapable()
|
||||
{
|
||||
PRBool hasCap = PR_FALSE;
|
||||
nsresult rv = nsContentUtils::GetSecurityManager()->
|
||||
IsCapabilityEnabled("UniversalXPConnect", &hasCap);
|
||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
||||
return hasCap;
|
||||
}
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsDOMWindowUtils)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMWindowUtils)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMWindowUtils)
|
||||
@ -918,6 +929,236 @@ nsDOMWindowUtils::DispatchDOMEventViaPresShell(nsIDOMNode* aTarget,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
InitEvent(nsGUIEvent &aEvent, nsIntPoint *aPt = nsnull)
|
||||
{
|
||||
if (aPt) {
|
||||
aEvent.refPoint = *aPt;
|
||||
}
|
||||
aEvent.time = PR_IntervalNow();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SendCompositionEvent(const nsAString& aType)
|
||||
{
|
||||
if (!IsUniversalXPConnectCapable()) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
// get the widget to send the event to
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
PRUint32 msg;
|
||||
if (aType.EqualsLiteral("compositionstart")) {
|
||||
msg = NS_COMPOSITION_START;
|
||||
} else if (aType.EqualsLiteral("compositionend")) {
|
||||
msg = NS_COMPOSITION_END;
|
||||
} else {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCompositionEvent compositionEvent(PR_TRUE, msg, widget);
|
||||
InitEvent(compositionEvent);
|
||||
|
||||
nsEventStatus status;
|
||||
nsresult rv = widget->DispatchEvent(&compositionEvent, status);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
AppendClause(PRInt32 aClauseLength, PRUint32 aClauseAttr,
|
||||
nsTArray<nsTextRange>* aRanges)
|
||||
{
|
||||
NS_PRECONDITION(aRanges, "aRange is null");
|
||||
if (aClauseLength == 0) {
|
||||
return;
|
||||
}
|
||||
nsTextRange range;
|
||||
range.mStartOffset = aRanges->Length() == 0 ? 0 :
|
||||
aRanges->ElementAt(aRanges->Length() - 1).mEndOffset + 1;
|
||||
range.mEndOffset = range.mStartOffset + aClauseLength;
|
||||
NS_ASSERTION(range.mStartOffset <= range.mEndOffset, "range is invalid");
|
||||
NS_PRECONDITION(aClauseAttr == NS_TEXTRANGE_RAWINPUT ||
|
||||
aClauseAttr == NS_TEXTRANGE_SELECTEDRAWTEXT ||
|
||||
aClauseAttr == NS_TEXTRANGE_CONVERTEDTEXT ||
|
||||
aClauseAttr == NS_TEXTRANGE_SELECTEDCONVERTEDTEXT,
|
||||
"aClauseAttr is invalid value");
|
||||
range.mRangeType = aClauseAttr;
|
||||
aRanges->AppendElement(range);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SendTextEvent(const nsAString& aCompositionString,
|
||||
PRInt32 aFirstClauseLength,
|
||||
PRUint32 aFirstClauseAttr,
|
||||
PRInt32 aSecondClauseLength,
|
||||
PRUint32 aSecondClauseAttr,
|
||||
PRInt32 aThirdClauseLength,
|
||||
PRUint32 aThirdClauseAttr,
|
||||
PRInt32 aCaretStart,
|
||||
PRInt32 aCaretLength)
|
||||
{
|
||||
if (!IsUniversalXPConnectCapable()) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
// get the widget to send the event to
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsTextEvent textEvent(PR_TRUE, NS_TEXT_TEXT, widget);
|
||||
InitEvent(textEvent);
|
||||
|
||||
nsAutoTArray<nsTextRange, 4> textRanges;
|
||||
NS_ENSURE_TRUE(aFirstClauseLength >= 0, NS_ERROR_INVALID_ARG);
|
||||
NS_ENSURE_TRUE(aSecondClauseLength >= 0, NS_ERROR_INVALID_ARG);
|
||||
NS_ENSURE_TRUE(aThirdClauseLength >= 0, NS_ERROR_INVALID_ARG);
|
||||
AppendClause(aFirstClauseLength, aFirstClauseAttr, &textRanges);
|
||||
AppendClause(aSecondClauseLength, aSecondClauseAttr, &textRanges);
|
||||
AppendClause(aThirdClauseLength, aThirdClauseAttr, &textRanges);
|
||||
PRInt32 len = aFirstClauseLength + aSecondClauseLength + aThirdClauseLength;
|
||||
NS_ENSURE_TRUE(len == 0 || len == aCompositionString.Length(),
|
||||
NS_ERROR_FAILURE);
|
||||
|
||||
if (aCaretStart >= 0) {
|
||||
nsTextRange range;
|
||||
range.mStartOffset = aCaretStart;
|
||||
range.mEndOffset = range.mStartOffset + aCaretLength;
|
||||
range.mRangeType = NS_TEXTRANGE_CARETPOSITION;
|
||||
textRanges.AppendElement(range);
|
||||
}
|
||||
|
||||
textEvent.theText = aCompositionString;
|
||||
|
||||
textEvent.rangeCount = textRanges.Length();
|
||||
textEvent.rangeArray = textRanges.Elements();
|
||||
|
||||
nsEventStatus status;
|
||||
nsresult rv = widget->DispatchEvent(&textEvent, status);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SendQueryContentEvent(PRUint32 aType,
|
||||
PRUint32 aOffset, PRUint32 aLength,
|
||||
PRInt32 aX, PRInt32 aY,
|
||||
nsIQueryContentEventResult **aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
|
||||
if (!IsUniversalXPConnectCapable()) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
// get the widget to send the event to
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (aType != NS_QUERY_SELECTED_TEXT &&
|
||||
aType != NS_QUERY_TEXT_CONTENT &&
|
||||
aType != NS_QUERY_CARET_RECT &&
|
||||
aType != NS_QUERY_TEXT_RECT &&
|
||||
aType != NS_QUERY_EDITOR_RECT &&
|
||||
aType != NS_QUERY_CHARACTER_AT_POINT) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> targetWidget = widget;
|
||||
nsIntPoint pt(aX, aY);
|
||||
|
||||
if (aType == QUERY_CHARACTER_AT_POINT) {
|
||||
// Looking for the widget at the point.
|
||||
nsQueryContentEvent dummyEvent(PR_TRUE, NS_QUERY_CONTENT_STATE, widget);
|
||||
InitEvent(dummyEvent, &pt);
|
||||
nsIFrame* popupFrame =
|
||||
nsLayoutUtils::GetPopupFrameForEventCoordinates(&dummyEvent);
|
||||
|
||||
nsIntRect widgetBounds;
|
||||
nsresult rv = widget->GetClientBounds(widgetBounds);
|
||||
|
||||
// There is no popup frame at the point and the point isn't in our widget,
|
||||
// we cannot process this request.
|
||||
NS_ENSURE_TRUE(popupFrame || widgetBounds.Contains(pt),
|
||||
NS_ERROR_FAILURE);
|
||||
|
||||
// Fire the event on the widget at the point
|
||||
if (popupFrame) {
|
||||
targetWidget = popupFrame->GetWindow();
|
||||
}
|
||||
}
|
||||
|
||||
pt += widget->WidgetToScreenOffset() - targetWidget->WidgetToScreenOffset();
|
||||
|
||||
nsQueryContentEvent queryEvent(PR_TRUE, aType, targetWidget);
|
||||
InitEvent(queryEvent, &pt);
|
||||
|
||||
switch (aType) {
|
||||
case NS_QUERY_TEXT_CONTENT:
|
||||
queryEvent.InitForQueryTextContent(aOffset, aLength);
|
||||
break;
|
||||
case NS_QUERY_CARET_RECT:
|
||||
queryEvent.InitForQueryCaretRect(aOffset);
|
||||
break;
|
||||
case NS_QUERY_TEXT_RECT:
|
||||
queryEvent.InitForQueryTextRect(aOffset, aLength);
|
||||
break;
|
||||
}
|
||||
|
||||
nsEventStatus status;
|
||||
nsresult rv = targetWidget->DispatchEvent(&queryEvent, status);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsQueryContentEventResult* result = new nsQueryContentEventResult();
|
||||
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
|
||||
result->SetEventResult(widget, queryEvent);
|
||||
NS_ADDREF(*aResult = result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SendSelectionSetEvent(PRUint32 aOffset,
|
||||
PRUint32 aLength,
|
||||
PRBool aReverse,
|
||||
PRBool *aResult)
|
||||
{
|
||||
*aResult = PR_FALSE;
|
||||
|
||||
if (!IsUniversalXPConnectCapable()) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
// get the widget to send the event to
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsSelectionEvent selectionEvent(PR_TRUE, NS_SELECTION_SET, widget);
|
||||
InitEvent(selectionEvent);
|
||||
|
||||
selectionEvent.mOffset = aOffset;
|
||||
selectionEvent.mLength = aLength;
|
||||
selectionEvent.mReversed = aReverse;
|
||||
|
||||
nsEventStatus status;
|
||||
nsresult rv = widget->DispatchEvent(&selectionEvent, status);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aResult = selectionEvent.mSucceeded;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SendContentCommandEvent(const nsAString& aType,
|
||||
nsITransferable * aTransferable)
|
||||
|
184
dom/base/nsQueryContentEventResult.cpp
Normal file
184
dom/base/nsQueryContentEventResult.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Japan.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Masayuki Nakano <masayuki@d-toybox.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsQueryContentEventResult.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsPoint.h"
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsQueryContentEventResult)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIQueryContentEventResult)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIQueryContentEventResult)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(nsQueryContentEventResult)
|
||||
NS_IMPL_RELEASE(nsQueryContentEventResult)
|
||||
|
||||
nsQueryContentEventResult::nsQueryContentEventResult() :
|
||||
mEventID(0), mSucceeded(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
nsQueryContentEventResult::~nsQueryContentEventResult()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsQueryContentEventResult::GetOffset(PRUint32 *aOffset)
|
||||
{
|
||||
PRBool notFound;
|
||||
nsresult rv = GetNotFound(¬Found);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(!notFound, NS_ERROR_NOT_AVAILABLE);
|
||||
*aOffset = mOffset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static PRBool IsRectEnabled(PRUint32 aEventID)
|
||||
{
|
||||
return aEventID == NS_QUERY_CARET_RECT ||
|
||||
aEventID == NS_QUERY_TEXT_RECT ||
|
||||
aEventID == NS_QUERY_EDITOR_RECT ||
|
||||
aEventID == NS_QUERY_CHARACTER_AT_POINT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsQueryContentEventResult::GetReversed(PRBool *aReversed)
|
||||
{
|
||||
NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE);
|
||||
NS_ENSURE_TRUE(mEventID == NS_QUERY_SELECTED_TEXT,
|
||||
NS_ERROR_NOT_AVAILABLE);
|
||||
*aReversed = mReversed;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsQueryContentEventResult::GetLeft(PRInt32 *aLeft)
|
||||
{
|
||||
NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE);
|
||||
NS_ENSURE_TRUE(IsRectEnabled(mEventID),
|
||||
NS_ERROR_NOT_AVAILABLE);
|
||||
*aLeft = mRect.x;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsQueryContentEventResult::GetWidth(PRInt32 *aWidth)
|
||||
{
|
||||
NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE);
|
||||
NS_ENSURE_TRUE(IsRectEnabled(mEventID),
|
||||
NS_ERROR_NOT_AVAILABLE);
|
||||
*aWidth = mRect.width;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsQueryContentEventResult::GetTop(PRInt32 *aTop)
|
||||
{
|
||||
NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE);
|
||||
NS_ENSURE_TRUE(IsRectEnabled(mEventID),
|
||||
NS_ERROR_NOT_AVAILABLE);
|
||||
*aTop = mRect.y;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsQueryContentEventResult::GetHeight(PRInt32 *aHeight)
|
||||
{
|
||||
NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE);
|
||||
NS_ENSURE_TRUE(IsRectEnabled(mEventID),
|
||||
NS_ERROR_NOT_AVAILABLE);
|
||||
*aHeight = mRect.height;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsQueryContentEventResult::GetText(nsAString &aText)
|
||||
{
|
||||
NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE);
|
||||
NS_ENSURE_TRUE(mEventID == NS_QUERY_SELECTED_TEXT ||
|
||||
mEventID == NS_QUERY_TEXT_CONTENT,
|
||||
NS_ERROR_NOT_AVAILABLE);
|
||||
aText = mString;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsQueryContentEventResult::GetSucceeded(PRBool *aSucceeded)
|
||||
{
|
||||
NS_ENSURE_TRUE(mEventID != 0, NS_ERROR_NOT_INITIALIZED);
|
||||
*aSucceeded = mSucceeded;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsQueryContentEventResult::GetNotFound(PRBool *aNotFound)
|
||||
{
|
||||
NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE);
|
||||
NS_ENSURE_TRUE(mEventID == NS_QUERY_SELECTED_TEXT ||
|
||||
mEventID == NS_QUERY_CHARACTER_AT_POINT,
|
||||
NS_ERROR_NOT_AVAILABLE);
|
||||
*aNotFound = (mOffset == nsQueryContentEvent::NOT_FOUND);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsQueryContentEventResult::SetEventResult(nsIWidget* aWidget,
|
||||
const nsQueryContentEvent &aEvent)
|
||||
{
|
||||
mEventID = aEvent.message;
|
||||
mSucceeded = aEvent.mSucceeded;
|
||||
mReversed = aEvent.mReply.mReversed;
|
||||
mRect = aEvent.mReply.mRect;
|
||||
mOffset = aEvent.mReply.mOffset;
|
||||
mString = aEvent.mReply.mString;
|
||||
|
||||
if (!IsRectEnabled(mEventID) || !aWidget || !mSucceeded) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIWidget* topWidget = aWidget->GetTopLevelWidget();
|
||||
if (!topWidget || topWidget == aWidget) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the top widget related coordinates to the given widget's.
|
||||
nsIntPoint offset =
|
||||
aWidget->WidgetToScreenOffset() - topWidget->WidgetToScreenOffset();
|
||||
mRect.MoveBy(-offset);
|
||||
}
|
65
dom/base/nsQueryContentEventResult.h
Normal file
65
dom/base/nsQueryContentEventResult.h
Normal file
@ -0,0 +1,65 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Japan.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Masayuki Nakano <masayuki@d-toybox.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsIQueryContentEventResult.h"
|
||||
#include "nsString.h"
|
||||
#include "nsRect.h"
|
||||
|
||||
class nsQueryContentEvent;
|
||||
class nsIWidget;
|
||||
|
||||
class nsQueryContentEventResult : public nsIQueryContentEventResult
|
||||
{
|
||||
public:
|
||||
nsQueryContentEventResult();
|
||||
~nsQueryContentEventResult();
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIQUERYCONTENTEVENTRESULT
|
||||
|
||||
void SetEventResult(nsIWidget* aWidget, const nsQueryContentEvent &aEvent);
|
||||
|
||||
protected:
|
||||
PRUint32 mEventID;
|
||||
|
||||
PRUint32 mOffset;
|
||||
nsString mString;
|
||||
nsIntRect mRect;
|
||||
|
||||
PRPackedBool mSucceeded;
|
||||
PRPackedBool mReversed;
|
||||
};
|
@ -80,6 +80,7 @@ XPIDLSRCS = \
|
||||
nsIDOMClientRect.idl \
|
||||
nsIDOMClientRectList.idl \
|
||||
nsIFocusManager.idl \
|
||||
nsIQueryContentEventResult.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -50,8 +50,9 @@ interface nsIDOMElement;
|
||||
interface nsIDOMHTMLCanvasElement;
|
||||
interface nsIDOMEvent;
|
||||
interface nsITransferable;
|
||||
interface nsIQueryContentEventResult;
|
||||
|
||||
[scriptable, uuid(5ab44028-20ed-499a-bbe4-1805a1f350c8)]
|
||||
[scriptable, uuid(00ca8d4f-61f1-4d9c-a7c1-82651b0cf02b)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
@ -443,4 +444,173 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||
*/
|
||||
void sendContentCommandEvent(in AString aType,
|
||||
[optional] in nsITransferable aTransferable);
|
||||
|
||||
/**
|
||||
* Synthesize a composition event to the window.
|
||||
*
|
||||
* Cannot be accessed from unprivileged context (not content-accessible)
|
||||
* Will throw a DOM security error if called without UniversalXPConnect
|
||||
* privileges.
|
||||
*
|
||||
* @param aType The event type: "compositionstart" or "compositionend".
|
||||
*/
|
||||
void sendCompositionEvent(in AString aType);
|
||||
|
||||
/**
|
||||
* Synthesize a text event to the window.
|
||||
*
|
||||
* Cannot be accessed from unprivileged context (not content-accessible)
|
||||
* Will throw a DOM security error if called without UniversalXPConnect
|
||||
* privileges.
|
||||
*
|
||||
* Currently, this method doesn't support 4 or more clauses composition
|
||||
* string.
|
||||
*
|
||||
* @param aCompositionString composition string
|
||||
* @param a*ClauseLengh the length of nth clause, set 0 when you
|
||||
* don't need second or third clause.
|
||||
* @param a*ClauseAttr the attribute of nth clause, uese following
|
||||
* const values.
|
||||
* @param aCaretStart the caret position in the composition string,
|
||||
* if you set negative value, this method don't
|
||||
* set the caret position to the event.
|
||||
* @param aCaretLength the caret length, if this is one or more,
|
||||
* the caret will be wide caret, otherwise,
|
||||
* it's collapsed.
|
||||
* XXX nsEditor doesn't support wide caret yet.
|
||||
*/
|
||||
|
||||
// NOTE: These values must be same to NS_TEXTRANGE_* in nsGUIEvent.h
|
||||
|
||||
const unsigned long COMPOSITION_ATTR_RAWINPUT = 0x02;
|
||||
const unsigned long COMPOSITION_ATTR_SELECTEDRAWTEXT = 0x03;
|
||||
const unsigned long COMPOSITION_ATTR_CONVERTEDTEXT = 0x04;
|
||||
const unsigned long COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT = 0x05;
|
||||
|
||||
void sendTextEvent(in AString aCompositionString,
|
||||
in long aFirstClauseLength,
|
||||
in unsigned long aFirstClauseAttr,
|
||||
in long aSecondClauseLength,
|
||||
in unsigned long aSecondClauseAttr,
|
||||
in long aThirdClauseLength,
|
||||
in unsigned long aThirdClauseAttr,
|
||||
in long aCaretStart,
|
||||
in long aCaretLength);
|
||||
|
||||
/**
|
||||
* Synthesize a query content event.
|
||||
*
|
||||
* @param aType On of the following const values. And see also each comment
|
||||
* for the other parameters and the result.
|
||||
*/
|
||||
nsIQueryContentEventResult sendQueryContentEvent(in unsigned long aType,
|
||||
in unsigned long aOffset,
|
||||
in unsigned long aLength,
|
||||
in long aX,
|
||||
in long aY);
|
||||
|
||||
// NOTE: following values are same as NS_QUERY_* in nsGUIEvent.h
|
||||
|
||||
/**
|
||||
* QUERY_SELECTED_TEXT queries the first selection range's information.
|
||||
*
|
||||
* @param aOffset Not used.
|
||||
* @param aLength Not used.
|
||||
* @param aX Not used.
|
||||
* @param aY Not used.
|
||||
*
|
||||
* @return offset, reversed and text properties of the result are available.
|
||||
*/
|
||||
const unsigned long QUERY_SELECTED_TEXT = 3200;
|
||||
|
||||
/**
|
||||
* QUERY_TEXT_CONTENT queries the text at the specified range.
|
||||
*
|
||||
* @param aOffset The first character's offset. 0 is the first character.
|
||||
* @param aLength The length of getting text. If the aLength is too long,
|
||||
* the result text is shorter than this value.
|
||||
* @param aX Not used.
|
||||
* @param aY Not used.
|
||||
*
|
||||
* @return text property of the result is available.
|
||||
*/
|
||||
const unsigned long QUERY_TEXT_CONTENT = 3201;
|
||||
|
||||
/**
|
||||
* QUERY_CARET_RECT queries the (collapsed) caret rect of the offset.
|
||||
* If the actual caret is there at the specified offset, this returns the
|
||||
* actual caret rect. Otherwise, this guesses the caret rect from the
|
||||
* metrics of the text.
|
||||
*
|
||||
* @param aOffset The caret offset. 0 is the left side of the first
|
||||
* caracter in LTR text.
|
||||
* @param aLength Not used.
|
||||
* @param aX Not used.
|
||||
* @param aY Not used.
|
||||
*
|
||||
* @return left, top, width and height properties of the result are available.
|
||||
* The left and the top properties are offset in the client area of
|
||||
* the DOM window.
|
||||
*/
|
||||
const unsigned long QUERY_CARET_RECT = 3203;
|
||||
|
||||
/**
|
||||
* QUERY_TEXT_RECT queries the specified text's rect.
|
||||
*
|
||||
* @param aOffset The first character's offset. 0 is the first character.
|
||||
* @param aLength The length of getting text. If the aLength is too long,
|
||||
* the extra length is ignored.
|
||||
* @param aX Not used.
|
||||
* @param aY Not used.
|
||||
*
|
||||
* @return left, top, width and height properties of the result are available.
|
||||
* The left and the top properties are offset in the client area of
|
||||
* the DOM window.
|
||||
*/
|
||||
const unsigned long QUERY_TEXT_RECT = 3204;
|
||||
|
||||
/**
|
||||
* QUERY_TEXT_RECT queries the focused editor's rect.
|
||||
*
|
||||
* @param aOffset Not used.
|
||||
* @param aLength Not used.
|
||||
* @param aX Not used.
|
||||
* @param aY Not used.
|
||||
*
|
||||
* @return left, top, width and height properties of the result are available.
|
||||
*/
|
||||
const unsigned long QUERY_EDITOR_RECT = 3205;
|
||||
|
||||
/**
|
||||
* QUERY_CHARACTER_AT_POINT queries the character information at the
|
||||
* specified point. The point is offset in the window.
|
||||
* NOTE: If there are some panels at the point, this method send the query
|
||||
* event to the panel's widget automatically.
|
||||
*
|
||||
* @param aOffset Not used.
|
||||
* @param aLength Not used.
|
||||
* @param aX X offset in the widget.
|
||||
* @param aY Y offset in the widget.
|
||||
*
|
||||
* @return offset, notFound, left, top, width and height properties of the
|
||||
* result are available.
|
||||
*/
|
||||
const unsigned long QUERY_CHARACTER_AT_POINT = 3208;
|
||||
|
||||
/**
|
||||
* Synthesize a selection set event to the window.
|
||||
*
|
||||
* This sets the selection as the specified information.
|
||||
*
|
||||
* @param aOffset The caret offset of the selection start.
|
||||
* @param aLength The length of the selection. If this is too long, the
|
||||
* extra length is ignored.
|
||||
* @param aReverse If true, the selection set from |aOffset + aLength| to
|
||||
* |aOffset|. Otherwise, set from |aOffset| to
|
||||
* |aOffset + aLength|.
|
||||
* @return True, if succeeded. Otherwise, false.
|
||||
*/
|
||||
boolean sendSelectionSetEvent(in unsigned long aOffset,
|
||||
in unsigned long aLength,
|
||||
in boolean aReverse);
|
||||
};
|
||||
|
61
dom/interfaces/base/nsIQueryContentEventResult.idl
Normal file
61
dom/interfaces/base/nsIQueryContentEventResult.idl
Normal file
@ -0,0 +1,61 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Japan.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Masayuki Nakano <masayuki@d-toybox.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* The result of query content events. succeeded propery can be used always.
|
||||
* Whether other properties can be used or not depends on the event.
|
||||
* See nsIDOMWindowUtils.idl, which properites can be used was documented.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(4b4ba266-b51e-4f0f-8d0e-9f13cb2a0056)]
|
||||
interface nsIQueryContentEventResult : nsISupports
|
||||
{
|
||||
readonly attribute unsigned long offset;
|
||||
readonly attribute boolean reversed;
|
||||
|
||||
readonly attribute long left;
|
||||
readonly attribute long top;
|
||||
readonly attribute long width;
|
||||
readonly attribute long height;
|
||||
readonly attribute AString text;
|
||||
|
||||
readonly attribute boolean succeeded;
|
||||
readonly attribute boolean notFound;
|
||||
};
|
@ -98,6 +98,10 @@
|
||||
#include "nsSVGOuterSVGFrame.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsXULPopupManager.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla::layers;
|
||||
|
||||
/**
|
||||
@ -779,6 +783,28 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(const nsEvent* aEvent, nsIFrame* aF
|
||||
return widgetToView - aFrame->GetOffsetTo(rootFrame);
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsLayoutUtils::GetPopupFrameForEventCoordinates(const nsEvent* aEvent)
|
||||
{
|
||||
#ifdef MOZ_XUL
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (!pm) {
|
||||
return nsnull;
|
||||
}
|
||||
nsTArray<nsIFrame*> popups = pm->GetVisiblePopups();
|
||||
PRUint32 i;
|
||||
// Search from top to bottom
|
||||
for (i = 0; i < popups.Length(); i++) {
|
||||
nsIFrame* popup = popups[i];
|
||||
if (popup->GetOverflowRect().Contains(
|
||||
GetEventCoordinatesRelativeTo(aEvent, popup))) {
|
||||
return popup;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
gfxMatrix
|
||||
nsLayoutUtils::ChangeMatrixBasis(const gfxPoint &aOrigin,
|
||||
const gfxMatrix &aMatrix)
|
||||
|
@ -388,6 +388,14 @@ public:
|
||||
nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Get the popup frame of a given native mouse event.
|
||||
* @param aEvent the event.
|
||||
* @return Null, if there is no popup frame at the point, otherwise,
|
||||
* returns top-most popup frame at the point.
|
||||
*/
|
||||
static nsIFrame* GetPopupFrameForEventCoordinates(const nsEvent* aEvent);
|
||||
|
||||
/**
|
||||
* Translate from widget coordinates to the view's coordinates
|
||||
* @param aPresContext the PresContext for the view
|
||||
* @param aWidget the widget
|
||||
|
@ -6156,27 +6156,16 @@ PresShell::HandleEvent(nsIView *aView,
|
||||
// list.
|
||||
if (framePresContext == rootPresContext &&
|
||||
frame == FrameManager()->GetRootFrame()) {
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm) {
|
||||
nsTArray<nsIFrame*> popups = pm->GetVisiblePopups();
|
||||
PRUint32 i;
|
||||
// Search from top to bottom
|
||||
nsIDocument* doc = framePresContext->GetPresShell()->GetDocument();
|
||||
for (i = 0; i < popups.Length(); i++) {
|
||||
nsIFrame* popup = popups[i];
|
||||
if (popup->GetOverflowRect().Contains(
|
||||
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, popup)) &&
|
||||
!nsContentUtils::ContentIsCrossDocDescendantOf(
|
||||
doc, popup->GetContent())) {
|
||||
// The event should target the popup
|
||||
frame = popup;
|
||||
break;
|
||||
}
|
||||
}
|
||||
nsIFrame* popupFrame =
|
||||
nsLayoutUtils::GetPopupFrameForEventCoordinates(aEvent);
|
||||
// If the popupFrame is an ancestor of the 'frame', the frame should
|
||||
// handle the event, otherwise, the popup should handle it.
|
||||
if (popupFrame &&
|
||||
!nsContentUtils::ContentIsCrossDocDescendantOf(
|
||||
framePresContext->GetPresShell()->GetDocument(),
|
||||
popupFrame->GetContent())) {
|
||||
frame = popupFrame;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PRBool captureRetarget = PR_FALSE;
|
||||
|
@ -546,3 +546,261 @@ function disableNonTestMouseEvents(aDisable)
|
||||
if (utils)
|
||||
utils.disableNonTestMouseEvents(aDisable);
|
||||
}
|
||||
|
||||
function _getDOMWindowUtils(aWindow)
|
||||
{
|
||||
if (!aWindow) {
|
||||
aWindow = window;
|
||||
}
|
||||
return aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synthesize a composition event.
|
||||
*
|
||||
* @param aIsCompositionStart If true, this synthesize compositionstart event.
|
||||
* Otherwise, compositionend event.
|
||||
* @param aWindow Optional (If null, current |window| will be used)
|
||||
*/
|
||||
function synthesizeComposition(aIsCompositionStart, aWindow)
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
var utils = _getDOMWindowUtils(aWindow);
|
||||
if (!utils) {
|
||||
return;
|
||||
}
|
||||
|
||||
utils.sendCompositionEvent(aIsCompositionStart ?
|
||||
"compositionstart" : "compositionend");
|
||||
}
|
||||
|
||||
/**
|
||||
* Synthesize a text event.
|
||||
*
|
||||
* @param aEvent The text event's information, this has |composition|
|
||||
* and |caret| members. |composition| has |string| and
|
||||
* |clauses| members. |clauses| must be array object. Each
|
||||
* object has |length| and |attr|. And |caret| has |start| and
|
||||
* |length|. See the following tree image.
|
||||
*
|
||||
* aEvent
|
||||
* +-- composition
|
||||
* | +-- string
|
||||
* | +-- clauses[]
|
||||
* | +-- length
|
||||
* | +-- attr
|
||||
* +-- caret
|
||||
* +-- start
|
||||
* +-- length
|
||||
*
|
||||
* Set the composition string to |composition.string|. Set its
|
||||
* clauses information to the |clauses| array.
|
||||
*
|
||||
* When it's composing, set the each clauses' length to the
|
||||
* |composition.clauses[n].length|. The sum of the all length
|
||||
* values must be same as the length of |composition.string|.
|
||||
* Set nsIDOMWindowUtils.COMPOSITION_ATTR_* to the
|
||||
* |composition.clauses[n].attr|.
|
||||
*
|
||||
* When it's not composing, set 0 to the
|
||||
* |composition.clauses[0].length| and
|
||||
* |composition.clauses[0].attr|.
|
||||
*
|
||||
* Set caret position to the |caret.start|. It's offset from
|
||||
* the start of the composition string. Set caret length to
|
||||
* |caret.length|. If it's larger than 0, it should be wide
|
||||
* caret. However, current nsEditor doesn't support wide
|
||||
* caret, therefore, you should always set 0 now.
|
||||
*
|
||||
* @param aWindow Optional (If null, current |window| will be used)
|
||||
*/
|
||||
function synthesizeText(aEvent, aWindow)
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
var utils = _getDOMWindowUtils(aWindow);
|
||||
if (!utils) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aEvent.composition || !aEvent.composition.clauses ||
|
||||
!aEvent.composition.clauses[0]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var firstClauseLength = aEvent.composition.clauses[0].length;
|
||||
var firstClauseAttr = aEvent.composition.clauses[0].attr;
|
||||
var secondClauseLength = 0;
|
||||
var secondClauseAttr = 0;
|
||||
var thirdClauseLength = 0;
|
||||
var thirdClauseAttr = 0;
|
||||
if (aEvent.composition.clauses[1]) {
|
||||
secondClauseLength = aEvent.composition.clauses[1].length;
|
||||
secondClauseAttr = aEvent.composition.clauses[1].attr;
|
||||
if (aEvent.composition.clauses[2]) {
|
||||
thirdClauseLength = aEvent.composition.clauses[2].length;
|
||||
thirdClauseAttr = aEvent.composition.clauses[2].attr;
|
||||
}
|
||||
}
|
||||
|
||||
var caretStart = -1;
|
||||
var caretLength = 0;
|
||||
if (aEvent.caret) {
|
||||
caretStart = aEvent.caret.start;
|
||||
caretLength = aEvent.caret.length;
|
||||
}
|
||||
|
||||
utils.sendTextEvent(aEvent.composition.string,
|
||||
firstClauseLength, firstClauseAttr,
|
||||
secondClauseLength, secondClauseAttr,
|
||||
thirdClauseLength, thirdClauseAttr,
|
||||
caretStart, caretLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synthesize a query selected text event.
|
||||
*
|
||||
* @param aWindow Optional (If null, current |window| will be used)
|
||||
* @return An nsIQueryContentEventResult object. If this failed,
|
||||
* the result might be null.
|
||||
*/
|
||||
function synthesizeQuerySelectedText(aWindow)
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
var utils = _getDOMWindowUtils(aWindow);
|
||||
if (!utils) {
|
||||
return nsnull;
|
||||
}
|
||||
return utils.sendQueryContentEvent(utils.QUERY_SELECTED_TEXT, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synthesize a query text content event.
|
||||
*
|
||||
* @param aOffset The character offset. 0 means the first character in the
|
||||
* selection root.
|
||||
* @param aLength The length of getting text. If the length is too long,
|
||||
* the extra length is ignored.
|
||||
* @param aWindow Optional (If null, current |window| will be used)
|
||||
* @return An nsIQueryContentEventResult object. If this failed,
|
||||
* the result might be null.
|
||||
*/
|
||||
function synthesizeQueryTextContent(aOffset, aLength, aWindow)
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
var utils = _getDOMWindowUtils(aWindow);
|
||||
if (!utils) {
|
||||
return nsnull;
|
||||
}
|
||||
return utils.sendQueryContentEvent(utils.QUERY_TEXT_CONTENT,
|
||||
aOffset, aLength, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synthesize a query caret rect event.
|
||||
*
|
||||
* @param aOffset The caret offset. 0 means left side of the first character
|
||||
* in the selection root.
|
||||
* @param aWindow Optional (If null, current |window| will be used)
|
||||
* @return An nsIQueryContentEventResult object. If this failed,
|
||||
* the result might be null.
|
||||
*/
|
||||
function synthesizeQueryCaretRect(aOffset, aWindow)
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
var utils = _getDOMWindowUtils(aWindow);
|
||||
if (!utils) {
|
||||
return nsnull;
|
||||
}
|
||||
return utils.sendQueryContentEvent(utils.QUERY_CARET_RECT,
|
||||
aOffset, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synthesize a query text rect event.
|
||||
*
|
||||
* @param aOffset The character offset. 0 means the first character in the
|
||||
* selection root.
|
||||
* @param aLength The length of the text. If the length is too long,
|
||||
* the extra length is ignored.
|
||||
* @param aWindow Optional (If null, current |window| will be used)
|
||||
* @return An nsIQueryContentEventResult object. If this failed,
|
||||
* the result might be null.
|
||||
*/
|
||||
function synthesizeQueryTextRect(aOffset, aLength, aWindow)
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
var utils = _getDOMWindowUtils(aWindow);
|
||||
if (!utils) {
|
||||
return nsnull;
|
||||
}
|
||||
return utils.sendQueryContentEvent(utils.QUERY_TEXT_RECT,
|
||||
aOffset, aLength, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synthesize a query editor rect event.
|
||||
*
|
||||
* @param aWindow Optional (If null, current |window| will be used)
|
||||
* @return An nsIQueryContentEventResult object. If this failed,
|
||||
* the result might be null.
|
||||
*/
|
||||
function synthesizeQueryEditorRect(aWindow)
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
var utils = _getDOMWindowUtils(aWindow);
|
||||
if (!utils) {
|
||||
return nsnull;
|
||||
}
|
||||
return utils.sendQueryContentEvent(utils.QUERY_EDITOR_RECT, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synthesize a character at point event.
|
||||
*
|
||||
* @param aX, aY The offset in the client area of the DOM window.
|
||||
* @param aWindow Optional (If null, current |window| will be used)
|
||||
* @return An nsIQueryContentEventResult object. If this failed,
|
||||
* the result might be null.
|
||||
*/
|
||||
function synthesizeCharAtPoint(aX, aY, aWindow)
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
var utils = _getDOMWindowUtils(aWindow);
|
||||
if (!utils) {
|
||||
return nsnull;
|
||||
}
|
||||
return utils.sendQueryContentEvent(utils.QUERY_CHARACTER_AT_POINT,
|
||||
0, 0, aX, aY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synthesize a selection set event.
|
||||
*
|
||||
* @param aOffset The character offset. 0 means the first character in the
|
||||
* selection root.
|
||||
* @param aLength The length of the text. If the length is too long,
|
||||
* the extra length is ignored.
|
||||
* @param aReverse If true, the selection is from |aOffset + aLength| to
|
||||
* |aOffset|. Otherwise, from |aOffset| to |aOffset + aLength|.
|
||||
* @param aWindow Optional (If null, current |window| will be used)
|
||||
* @return True, if succeeded. Otherwise false.
|
||||
*/
|
||||
function synthesizeSelectionSet(aOffset, aLength, aReverse, aWindow)
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
var utils = _getDOMWindowUtils(aWindow);
|
||||
if (!utils) {
|
||||
return false;
|
||||
}
|
||||
return utils.sendSelectionSetEvent(aOffset, aLength, aReverse);
|
||||
}
|
||||
|
@ -70,6 +70,8 @@ _CHROME_FILES = test_bug343416.xul \
|
||||
window_wheeltransaction.xul \
|
||||
test_imestate.html \
|
||||
test_plugin_scroll_consistency.html \
|
||||
test_composition_text_querycontent.xul \
|
||||
window_composition_text_querycontent.xul \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
|
||||
|
@ -143,7 +143,6 @@ protected:
|
||||
PRBool TestExtents(void);
|
||||
PRBool TestComposition(void);
|
||||
PRBool TestNotification(void);
|
||||
PRBool TestContentEvents(void);
|
||||
PRBool TestEditMessages(void);
|
||||
PRBool TestScrollMessages(void);
|
||||
|
||||
@ -1157,7 +1156,7 @@ public:
|
||||
PRInt32 mFocusCount;
|
||||
|
||||
TSFMgrImpl(TestApp* test) : mTestApp(test), mTest(nsnull), mRefCnt(0),
|
||||
mDeactivated(PR_FALSE), mFocusCount(0)
|
||||
mDeactivated(PR_FALSE), mFocusedDocument(nsnull), mFocusCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1661,9 +1660,9 @@ TestApp::OnStateChange(nsIWebProgress *aWebProgress,
|
||||
NS_ASSERTION(aStateFlags & nsIWebProgressListener::STATE_IS_WINDOW &&
|
||||
aStateFlags & nsIWebProgressListener::STATE_STOP, "wrong state");
|
||||
if (NS_SUCCEEDED(Init())) {
|
||||
printf("Testing content events...\n");
|
||||
if (TestContentEvents())
|
||||
passed("TestContentEvents");
|
||||
mCurrentNode = mTextArea;
|
||||
mTextArea->Focus();
|
||||
|
||||
if (RunTest(&TestApp::TestEditMessages))
|
||||
passed("TestEditMessages");
|
||||
if (RunTest(&TestApp::TestScrollMessages))
|
||||
@ -2719,143 +2718,6 @@ TestApp::TestNotification(void)
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
TestApp::TestContentEvents(void)
|
||||
{
|
||||
mTestString = NS_LITERAL_STRING(
|
||||
"This is a test of the\r\nContent Events");
|
||||
// 0123456789012345678901 2 34567890123456
|
||||
// 0 1 2 3
|
||||
mTextArea->SetValue(mTestString);
|
||||
mTextArea->Focus();
|
||||
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
if (!GetWidget(getter_AddRefs(widget))) {
|
||||
fail("TestContentEvents: get nsIWidget");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> topLevel = widget->GetTopLevelWidget();
|
||||
if (!topLevel) {
|
||||
fail("TestContentEvents: get top level widget");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsIntRect widgetRect, topLevelRect;
|
||||
nsresult nsr = widget->GetScreenBounds(widgetRect);
|
||||
if (NS_FAILED(nsr)) {
|
||||
fail("TestContentEvents: get widget rect");
|
||||
return PR_FALSE;
|
||||
}
|
||||
nsr = topLevel->GetScreenBounds(topLevelRect);
|
||||
if (NS_FAILED(nsr)) {
|
||||
fail("TestContentEvents: get top level widget rect");
|
||||
return PR_FALSE;
|
||||
}
|
||||
nsIntPoint widgetOffset = widgetRect.TopLeft() - topLevelRect.TopLeft();
|
||||
nsEventStatus eventStatus;
|
||||
PRBool result = PR_TRUE;
|
||||
|
||||
const PRUint32 kNone = nsQueryContentEvent::NOT_FOUND;
|
||||
PRUint32 testingOffset[] = { 0, 10, 20, 23, 36 };
|
||||
PRUint32 leftSideOffset[] = { kNone, 9, 19, kNone, 35 };
|
||||
PRUint32 rightSideOffset[] = { 1, 11, kNone, 24, kNone };
|
||||
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(testingOffset); i++) {
|
||||
nsQueryContentEvent textRect(PR_TRUE, NS_QUERY_TEXT_RECT, widget);
|
||||
textRect.InitForQueryTextRect(testingOffset[i], 1);
|
||||
nsr = widget->DispatchEvent(&textRect, eventStatus);
|
||||
if (NS_FAILED(nsr) || !textRect.mSucceeded ||
|
||||
textRect.mReply.mRect.IsEmpty()) {
|
||||
fail("TestContentEvents: get text rect");
|
||||
return PR_FALSE;
|
||||
}
|
||||
nsIntRect &charRect = textRect.mReply.mRect;
|
||||
charRect.MoveBy(widgetOffset);
|
||||
// Note that charRect might be inflated at rounding to pixels!
|
||||
printf("TestContentEvents: testing... i=%lu, pt={ %ld, %ld }, size={ %ld, %ld }\n",
|
||||
i, charRect.x, charRect.y, charRect.width, charRect.height);
|
||||
|
||||
nsQueryContentEvent charAtPt1(PR_TRUE, NS_QUERY_CHARACTER_AT_POINT, widget);
|
||||
charAtPt1.refPoint.x = charRect.x + 1;
|
||||
charAtPt1.refPoint.y = charRect.y + 1;
|
||||
nsr = widget->DispatchEvent(&charAtPt1, eventStatus);
|
||||
if (NS_FAILED(nsr) || !charAtPt1.mSucceeded) {
|
||||
fail(" TestContentEvents: get char at point1");
|
||||
return PR_FALSE;
|
||||
}
|
||||
printf(" NS_QUERY_CHARACTER_AT_POINT: pt={ %ld, %ld }, offset=%lu, rect={ %ld, %ld, %ld, %ld }\n",
|
||||
charAtPt1.refPoint.x, charAtPt1.refPoint.y,
|
||||
charAtPt1.mReply.mOffset, charAtPt1.mReply.mRect.x,
|
||||
charAtPt1.mReply.mRect.y, charAtPt1.mReply.mRect.width,
|
||||
charAtPt1.mReply.mRect.height);
|
||||
if (charAtPt1.mReply.mOffset != testingOffset[i]) {
|
||||
fail(" TestContentEvents: get char at point1 (wrong offset)");
|
||||
result = PR_FALSE;
|
||||
} else if (charAtPt1.mReply.mRect != textRect.mReply.mRect) {
|
||||
fail(" TestContentEvents: get char at point1 (rect mismatch)");
|
||||
result = PR_FALSE;
|
||||
}
|
||||
|
||||
nsQueryContentEvent charAtPt2(PR_TRUE, NS_QUERY_CHARACTER_AT_POINT, widget);
|
||||
charAtPt2.refPoint.x = charRect.XMost() - 2;
|
||||
charAtPt2.refPoint.y = charRect.YMost() - 2;
|
||||
nsr = widget->DispatchEvent(&charAtPt2, eventStatus);
|
||||
if (NS_FAILED(nsr) || !charAtPt2.mSucceeded) {
|
||||
fail(" TestContentEvents: get char at point2");
|
||||
return PR_FALSE;
|
||||
}
|
||||
printf(" NS_QUERY_CHARACTER_AT_POINT: pt={ %ld, %ld }, offset=%lu, rect={ %ld, %ld, %ld, %ld }\n",
|
||||
charAtPt2.refPoint.x, charAtPt2.refPoint.y,
|
||||
charAtPt2.mReply.mOffset, charAtPt2.mReply.mRect.x,
|
||||
charAtPt2.mReply.mRect.y, charAtPt2.mReply.mRect.width,
|
||||
charAtPt2.mReply.mRect.height);
|
||||
if (charAtPt2.mReply.mOffset != testingOffset[i]) {
|
||||
fail(" TestContentEvents: get char at point2 (wrong offset)");
|
||||
result = PR_FALSE;
|
||||
} else if (charAtPt2.mReply.mRect != textRect.mReply.mRect) {
|
||||
fail(" TestContentEvents: get char at point2 (rect mismatch)");
|
||||
result = PR_FALSE;
|
||||
}
|
||||
|
||||
nsQueryContentEvent charAtPt3(PR_TRUE, NS_QUERY_CHARACTER_AT_POINT, widget);
|
||||
charAtPt3.refPoint.x = charRect.x - 2;
|
||||
charAtPt3.refPoint.y = charRect.y + 1;
|
||||
nsr = widget->DispatchEvent(&charAtPt3, eventStatus);
|
||||
if (NS_FAILED(nsr) || !charAtPt3.mSucceeded) {
|
||||
fail(" TestContentEvents: get char at point3");
|
||||
return PR_FALSE;
|
||||
}
|
||||
printf(" NS_QUERY_CHARACTER_AT_POINT: pt={ %ld, %ld }, offset=%lu, rect={ %ld, %ld, %ld, %ld }\n",
|
||||
charAtPt3.refPoint.x, charAtPt3.refPoint.y,
|
||||
charAtPt3.mReply.mOffset, charAtPt3.mReply.mRect.x,
|
||||
charAtPt3.mReply.mRect.y, charAtPt3.mReply.mRect.width,
|
||||
charAtPt3.mReply.mRect.height);
|
||||
if (charAtPt3.mReply.mOffset != leftSideOffset[i]) {
|
||||
fail(" TestContentEvents: get left side char at point (wrong offset)");
|
||||
result = PR_FALSE;
|
||||
}
|
||||
|
||||
nsQueryContentEvent charAtPt4(PR_TRUE, NS_QUERY_CHARACTER_AT_POINT, widget);
|
||||
charAtPt4.refPoint.x = charRect.XMost() + 1;
|
||||
charAtPt4.refPoint.y = charRect.YMost() - 2;
|
||||
nsr = widget->DispatchEvent(&charAtPt4, eventStatus);
|
||||
if (NS_FAILED(nsr) || !charAtPt4.mSucceeded) {
|
||||
fail(" TestContentEvents: get char at point4");
|
||||
return PR_FALSE;
|
||||
}
|
||||
printf(" NS_QUERY_CHARACTER_AT_POINT: pt={ %ld, %ld }, offset=%lu, rect={ %ld, %ld, %ld, %ld }\n",
|
||||
charAtPt4.refPoint.x, charAtPt4.refPoint.y,
|
||||
charAtPt4.mReply.mOffset, charAtPt4.mReply.mRect.x,
|
||||
charAtPt4.mReply.mRect.y, charAtPt4.mReply.mRect.width,
|
||||
charAtPt4.mReply.mRect.height);
|
||||
if (charAtPt4.mReply.mOffset != rightSideOffset[i]) {
|
||||
fail(" TestContentEvents: get right side char at point4 (wrong offset)");
|
||||
result = PR_FALSE;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
PRBool
|
||||
TestApp::TestEditMessages(void)
|
||||
{
|
||||
|
30
widget/tests/test_composition_text_querycontent.xul
Normal file
30
widget/tests/test_composition_text_querycontent.xul
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<window title="Testing composition, text and query content events"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
window.open("window_composition_text_querycontent.xul", "_blank",
|
||||
"chrome,width=600,height=600");
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
986
widget/tests/window_composition_text_querycontent.xul
Normal file
986
widget/tests/window_composition_text_querycontent.xul
Normal file
@ -0,0 +1,986 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<window title="Testing composition, text and query content events"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onunload="onunload();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
|
||||
|
||||
<panel id="panel" hidden="true"
|
||||
orient="vertical"
|
||||
onpopupshown="onPanelShown(event);"
|
||||
onpopuphidden="onPanelHidden(event);">
|
||||
<vbox id="vbox">
|
||||
<textbox id="textbox" onfocus="onFocusPanelTextbox(event);"
|
||||
multiline="true" cols="20" rows="4"/>
|
||||
</vbox>
|
||||
</panel>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display">
|
||||
<textarea id="textarea" cols="20" rows="4"></textarea>
|
||||
<iframe id="iframe" width="300" height="150"
|
||||
src="data:text/html,<textarea id='textarea' cols='20' rows='4'></textarea>"></iframe>
|
||||
</p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
window.opener.wrappedJSObject.SimpleTest.waitForFocus(runTest, window);
|
||||
|
||||
function ok(aCondition, aMessage)
|
||||
{
|
||||
window.opener.wrappedJSObject.SimpleTest.ok(aCondition, aMessage);
|
||||
}
|
||||
|
||||
function is(aLeft, aRight, aMessage)
|
||||
{
|
||||
window.opener.wrappedJSObject.SimpleTest.is(aLeft, aRight, aMessage);
|
||||
}
|
||||
|
||||
function isnot(aLeft, aRight, aMessage)
|
||||
{
|
||||
window.opener.wrappedJSObject.SimpleTest.isnot(aLeft, aRight, aMessage);
|
||||
}
|
||||
|
||||
function finish()
|
||||
{
|
||||
window.close();
|
||||
}
|
||||
|
||||
function onunload()
|
||||
{
|
||||
window.opener.wrappedJSObject.SimpleTest.finish();
|
||||
}
|
||||
|
||||
var textarea = document.getElementById("textarea");
|
||||
var panel = document.getElementById("panel");
|
||||
var textbox = document.getElementById("textbox");
|
||||
var iframe = document.getElementById("iframe");
|
||||
var textareaInFrame;
|
||||
|
||||
const nsIDOMWindowUtils = Components.interfaces.nsIDOMWindowUtils;
|
||||
|
||||
const kIsWin = (navigator.platform.indexOf("Win") == 0);
|
||||
const kIsMac = (navigator.platform.indexOf("Mac") == 0);
|
||||
|
||||
function checkQueryContentResult(aResult, aMessage, aID)
|
||||
{
|
||||
ok(aResult, aMessage + ": the result is null");
|
||||
if (!aResult) {
|
||||
return false;
|
||||
}
|
||||
ok(aResult.succeeded, aMessage + ": the query content failed");
|
||||
return aResult.succeeded;
|
||||
}
|
||||
|
||||
function checkContent(aExpectedText, aMessage, aID)
|
||||
{
|
||||
var textContent = synthesizeQueryTextContent(0, 100);
|
||||
if (!checkQueryContentResult(textContent, aMessage +
|
||||
": synthesizeQueryTextContent " + aID)) {
|
||||
return false;
|
||||
}
|
||||
is(textContent.text, aExpectedText,
|
||||
aMessage + ": composition string is wrong" + aID);
|
||||
return textContent.text == aExpectedText;
|
||||
}
|
||||
|
||||
function checkSelection(aExpectedOffset, aExpectedText, aMessage, aID)
|
||||
{
|
||||
var selectedText = synthesizeQuerySelectedText();
|
||||
if (!checkQueryContentResult(selectedText, aMessage +
|
||||
": synthesizeQuerySelectedText " + aID)) {
|
||||
return false;
|
||||
}
|
||||
is(selectedText.offset, aExpectedOffset,
|
||||
aMessage + ": selection offset is wrong" + aID);
|
||||
is(selectedText.text, aExpectedText,
|
||||
aMessage + ": selected text is wrong" + aID);
|
||||
return selectedText.offset == aExpectedOffset &&
|
||||
selectedText.text == aExpectedText;
|
||||
}
|
||||
|
||||
function checkRect(aRect, aExpectedRect, aMessage)
|
||||
{
|
||||
is(aRect.left, aExpectedRect.left, aMessage + ": left is wrong");
|
||||
is(aRect.top, aExpectedRect.top, aMessage + " top is wrong");
|
||||
is(aRect.width, aExpectedRect.width, aMessage + ": width is wrong");
|
||||
is(aRect.height, aExpectedRect.height, aMessage + ": height is wrong");
|
||||
return aRect.left == aExpectedRect.left &&
|
||||
aRect.top == aExpectedRect.top &&
|
||||
aRect.width == aExpectedRect.width &&
|
||||
aRect.height == aExpectedRect.height;
|
||||
}
|
||||
|
||||
function checkRectContainsRect(aRect, aContainer, aMessage)
|
||||
{
|
||||
var container = { left: Math.ceil(aContainer.left),
|
||||
top: Math.ceil(aContainer.top),
|
||||
width: Math.floor(aContainer.width),
|
||||
height: Math.floor(aContainer.height) };
|
||||
|
||||
var ret = container.left <= aRect.left &&
|
||||
container.top <= aRect.top &&
|
||||
container.left + container.width >= aRect.left + aRect.width &&
|
||||
container.top + container.height >= aRect.top + aRect.height;
|
||||
ret = ret && aMessage;
|
||||
ok(ret, aMessage + " container={ left=" + container.left + ", top=" +
|
||||
container.top + ", width=" + container.width + ", height=" +
|
||||
container.height + " } rect={ left=" + aRect.left + ", top=" + aRect.top +
|
||||
", width=" + aRect.width + ", height=" + aRect.height + " }");
|
||||
return ret;
|
||||
}
|
||||
|
||||
function runCompositionTest()
|
||||
{
|
||||
textarea.value = "";
|
||||
textarea.focus();
|
||||
var caretRects = [];
|
||||
|
||||
var caretRect = synthesizeQueryCaretRect(0);
|
||||
if (!checkQueryContentResult(caretRect,
|
||||
"runCompositionTest: synthesizeQueryCaretRect #0")) {
|
||||
return false;
|
||||
}
|
||||
caretRects[0] = caretRect;
|
||||
|
||||
// start composition
|
||||
synthesizeComposition(true);
|
||||
|
||||
// input first character
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3089",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u3089", "runCompositionTest", "#1-1") ||
|
||||
!checkSelection(1, "", "runCompositionTest", "#1-1")) {
|
||||
return;
|
||||
}
|
||||
|
||||
caretRect = synthesizeQueryCaretRect(1);
|
||||
if (!checkQueryContentResult(caretRect,
|
||||
"runCompositionTest: synthesizeQueryCaretRect #1-1")) {
|
||||
return false;
|
||||
}
|
||||
caretRects[1] = caretRect;
|
||||
|
||||
// input second character
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3089\u30FC",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 2, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u3089\u30FC", "runCompositionTest", "#1-2") ||
|
||||
!checkSelection(2, "", "runCompositionTest", "#1-2")) {
|
||||
return;
|
||||
}
|
||||
|
||||
caretRect = synthesizeQueryCaretRect(2);
|
||||
if (!checkQueryContentResult(caretRect,
|
||||
"runCompositionTest: synthesizeQueryCaretRect #1-2")) {
|
||||
return false;
|
||||
}
|
||||
caretRects[2] = caretRect;
|
||||
|
||||
isnot(caretRects[2].left, caretRects[1].left,
|
||||
"runCompositionTest: caret isn't moved (#1-2)");
|
||||
is(caretRects[2].top, caretRects[1].top,
|
||||
"runCompositionTest: caret is moved to another line (#1-2)");
|
||||
is(caretRects[2].width, caretRects[1].width,
|
||||
"runCompositionTest: caret width is wrong (#1-2)");
|
||||
is(caretRects[2].height, caretRects[1].height,
|
||||
"runCompositionTest: caret width is wrong (#1-2)");
|
||||
|
||||
// input third character
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3089\u30FC\u3081",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 3, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 3, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-3") ||
|
||||
!checkSelection(3, "", "runCompositionTest", "#1-3")) {
|
||||
return;
|
||||
}
|
||||
|
||||
caretRect = synthesizeQueryCaretRect(3);
|
||||
if (!checkQueryContentResult(caretRect,
|
||||
"runCompositionTest: synthesizeQueryCaretRect #1-3")) {
|
||||
return false;
|
||||
}
|
||||
caretRects[3] = caretRect;
|
||||
|
||||
isnot(caretRects[3].left, caretRects[2].left,
|
||||
"runCompositionTest: caret isn't moved (#1-3)");
|
||||
is(caretRects[3].top, caretRects[2].top,
|
||||
"runCompositionTest: caret is moved to another line (#1-3)");
|
||||
is(caretRects[3].width, caretRects[2].width,
|
||||
"runCompositionTest: caret width is wrong (#1-3)");
|
||||
is(caretRects[3].height, caretRects[2].height,
|
||||
"runCompositionTest: caret height is wrong (#1-3)");
|
||||
|
||||
// moves the caret left
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3089\u30FC\u3081",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 3, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-3-1") ||
|
||||
!checkSelection(2, "", "runCompositionTest", "#1-3-1")) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
caretRect = synthesizeQueryCaretRect(2);
|
||||
if (!checkQueryContentResult(caretRect,
|
||||
"runCompositionTest: synthesizeQueryCaretRect #1-3-1")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
is(caretRect.left, caretRects[2].left,
|
||||
"runCompositionTest: caret rects are different (#1-3-1, left)");
|
||||
is(caretRect.top, caretRects[2].top,
|
||||
"runCompositionTest: caret rects are different (#1-3-1, top)");
|
||||
// by bug 335359, the caret width depends on the right side's character.
|
||||
is(caretRect.width, caretRects[2].width + 1,
|
||||
"runCompositionTest: caret rects are different (#1-3-1, width)");
|
||||
is(caretRect.height, caretRects[2].height,
|
||||
"runCompositionTest: caret rects are different (#1-3-1, height)");
|
||||
|
||||
// moves the caret left
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3089\u30FC\u3081",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 3, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-3-2") ||
|
||||
!checkSelection(1, "", "runCompositionTest", "#1-3-2")) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
caretRect = synthesizeQueryCaretRect(1);
|
||||
if (!checkQueryContentResult(caretRect,
|
||||
"runCompositionTest: synthesizeQueryCaretRect #1-3-2")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
is(caretRect.left, caretRects[1].left,
|
||||
"runCompositionTest: caret rects are different (#1-3-2, left)");
|
||||
is(caretRect.top, caretRects[1].top,
|
||||
"runCompositionTest: caret rects are different (#1-3-2, top)");
|
||||
// by bug 335359, the caret width depends on the right side's character.
|
||||
is(caretRect.width, caretRects[1].width + 1,
|
||||
"runCompositionTest: caret rects are different (#1-3-2, width)");
|
||||
is(caretRect.height, caretRects[1].height,
|
||||
"runCompositionTest: caret rects are different (#1-3-2, height)");
|
||||
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3089\u30FC\u3081\u3093",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 4, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 4, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u3089\u30FC\u3081\u3093", "runCompositionTest", "#1-4") ||
|
||||
!checkSelection(4, "", "runCompositionTest", "#1-4")) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// backspace
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3089\u30FC\u3081",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 3, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 3, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u3089\u30FC\u3081", "runCompositionTest", "#1-5") ||
|
||||
!checkSelection(3, "", "runCompositionTest", "#1-5")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// re-input
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3089\u30FC\u3081\u3093",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 4, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 4, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u3089\u30FC\u3081\u3093", "runCompositionTest", "#1-6") ||
|
||||
!checkSelection(4, "", "runCompositionTest", "#1-6")) {
|
||||
return;
|
||||
}
|
||||
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3089\u30FC\u3081\u3093\u3055",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 5, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 5, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u3089\u30FC\u3081\u3093\u3055", "runCompositionTest", "#1-7") ||
|
||||
!checkSelection(5, "", "runCompositionTest", "#1-7")) {
|
||||
return;
|
||||
}
|
||||
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3089\u30FC\u3081\u3093\u3055\u3044",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 6, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 6, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044", "runCompositionTest", "#1-8") ||
|
||||
!checkSelection(6, "", "runCompositionTest", "#1-8")) {
|
||||
return;
|
||||
}
|
||||
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 7, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 7, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044\u3053", "runCompositionTest", "#1-8") ||
|
||||
!checkSelection(7, "", "runCompositionTest", "#1-8")) {
|
||||
return;
|
||||
}
|
||||
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 8, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 8, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u3089\u30FC\u3081\u3093\u3055\u3044\u3053\u3046",
|
||||
"runCompositionTest", "#1-9") ||
|
||||
!checkSelection(8, "", "runCompositionTest", "#1-9")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// convert
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 4,
|
||||
"attr": nsIDOMWindowUtils.COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT },
|
||||
{ "length": 2,
|
||||
"attr": nsIDOMWindowUtils.COMPOSITION_ATTR_CONVERTEDTEXT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 4, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
|
||||
"runCompositionTest", "#1-10") ||
|
||||
!checkSelection(6, "", "runCompositionTest", "#1-10")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// change the selected clause
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 4,
|
||||
"attr": nsIDOMWindowUtils.COMPOSITION_ATTR_CONVERTEDTEXT },
|
||||
{ "length": 2,
|
||||
"attr": nsIDOMWindowUtils.COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 6, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u6700\u9AD8",
|
||||
"runCompositionTest", "#1-11") ||
|
||||
!checkSelection(6, "", "runCompositionTest", "#1-11")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// reset clauses
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 5,
|
||||
"attr": nsIDOMWindowUtils.COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT },
|
||||
{ "length": 3,
|
||||
"attr": nsIDOMWindowUtils.COMPOSITION_ATTR_CONVERTEDTEXT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 5, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046",
|
||||
"runCompositionTest", "#1-12") ||
|
||||
!checkSelection(8, "", "runCompositionTest", "#1-12")) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var textRect1 = synthesizeQueryTextRect(0, 1);
|
||||
var textRect2 = synthesizeQueryTextRect(1, 1);
|
||||
if (!checkQueryContentResult(textRect1,
|
||||
"runCompositionTest: synthesizeQueryTextRect #1-12-1") ||
|
||||
!checkQueryContentResult(textRect2,
|
||||
"runCompositionTest: synthesizeQueryTextRect #1-12-2")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// commit the composition string
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 8, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046",
|
||||
"runCompositionTest", "#1-13") ||
|
||||
!checkSelection(8, "", "runCompositionTest", "#1-13")) {
|
||||
return;
|
||||
}
|
||||
|
||||
synthesizeComposition(false);
|
||||
|
||||
var textRect3 = synthesizeQueryTextRect(0, 1);
|
||||
var textRect4 = synthesizeQueryTextRect(1, 1);
|
||||
|
||||
if (!checkQueryContentResult(textRect3,
|
||||
"runCompositionTest: synthesizeQueryTextRect #1-13-1") ||
|
||||
!checkQueryContentResult(textRect4,
|
||||
"runCompositionTest: synthesizeQueryTextRect #1-13-2")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
checkRect(textRect3, textRect1, "runCompositionTest: textRect #1-13-1");
|
||||
checkRect(textRect4, textRect2, "runCompositionTest: textRect #1-13-2");
|
||||
|
||||
// restart composition
|
||||
synthesizeComposition(true);
|
||||
|
||||
// input characters
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3057",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3057",
|
||||
"runCompositionTest", "#2-1") ||
|
||||
!checkSelection(8 + 1, "", "runCompositionTest", "#2-1")) {
|
||||
return;
|
||||
}
|
||||
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3058",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058",
|
||||
"runCompositionTest", "#2-2") ||
|
||||
!checkSelection(8 + 1, "", "runCompositionTest", "#2-2")) {
|
||||
return;
|
||||
}
|
||||
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3058\u3087",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 2, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058\u3087",
|
||||
"runCompositionTest", "#2-3") ||
|
||||
!checkSelection(8 + 2, "", "runCompositionTest", "#2-3")) {
|
||||
return;
|
||||
}
|
||||
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3058\u3087\u3046",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 3, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 3, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058\u3087\u3046",
|
||||
"runCompositionTest", "#2-4") ||
|
||||
!checkSelection(8 + 3, "", "runCompositionTest", "#2-4")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// commit the composition string
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3058\u3087\u3046",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 3, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3055\u884C\u3053\u3046\u3058\u3087\u3046",
|
||||
"runCompositionTest", "#2-4") ||
|
||||
!checkSelection(8 + 3, "", "runCompositionTest", "#2-4")) {
|
||||
return;
|
||||
}
|
||||
|
||||
synthesizeComposition(false);
|
||||
|
||||
// set selection
|
||||
var selectionSetTest = synthesizeSelectionSet(4, 7, false);
|
||||
ok(selectionSetTest, "runCompositionTest: selectionSetTest failed");
|
||||
|
||||
if (!checkSelection(4, "\u3055\u884C\u3053\u3046\u3058\u3087\u3046", "runCompositionTest", "#3-1")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// start composition with selection
|
||||
synthesizeComposition(true);
|
||||
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u304A",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u304A",
|
||||
"runCompositionTest", "#3-2") ||
|
||||
!checkSelection(4 + 1, "", "runCompositionTest", "#3-2")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove the composition string
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 0, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
|
||||
"runCompositionTest", "#3-3") ||
|
||||
!checkSelection(4, "", "runCompositionTest", "#3-3")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// re-input the composition string
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3046",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 1, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 1, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u30E9\u30FC\u30E1\u30F3\u3046",
|
||||
"runCompositionTest", "#3-4") ||
|
||||
!checkSelection(4 + 1, "", "runCompositionTest", "#3-4")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// cancel the composition
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 0, "length": 0 }
|
||||
});
|
||||
|
||||
synthesizeComposition(false);
|
||||
|
||||
if (!checkContent("\u30E9\u30FC\u30E1\u30F3",
|
||||
"runCompositionTest", "#3-5") ||
|
||||
!checkSelection(4, "", "runCompositionTest", "#3-5")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function runCharAtPointTest(aFocusedEditor, aTargetName)
|
||||
{
|
||||
aFocusedEditor.value = "This is a test of the\nContent Events";
|
||||
// 012345678901234567890 12345678901234
|
||||
// 0 1 2 3
|
||||
|
||||
const kLFLen = kIsWin ? 2 : 1;
|
||||
|
||||
const kNone = -1;
|
||||
const kTestingOffset = [ 0, 10, 20, 21 + kLFLen, 34 + kLFLen];
|
||||
const kLeftSideOffset = [ kNone, 9, 19, kNone, 33 + kLFLen];
|
||||
const kRightSideOffset = [ 1, 11, kNone, 22 + kLFLen, kNone];
|
||||
|
||||
var editorRect = synthesizeQueryEditorRect();
|
||||
if (!checkQueryContentResult(editorRect,
|
||||
"runCharAtPointTest (" + aTargetName + "): editorRect")) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < kTestingOffset.length; i++) {
|
||||
var textRect = synthesizeQueryTextRect(kTestingOffset[i], 1);
|
||||
if (!checkQueryContentResult(textRect,
|
||||
"runCharAtPointTest (" + aTargetName + "): textRect", "i=" + i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
checkRectContainsRect(textRect, editorRect,
|
||||
"runCharAtPointTest (" + aTargetName +
|
||||
"): the text rect isn't in the editor");
|
||||
|
||||
// Test #1, getting same character rect by the point near the top-left.
|
||||
var charAtPt1 = synthesizeCharAtPoint(textRect.left + 1,
|
||||
textRect.top + 1);
|
||||
if (checkQueryContentResult(charAtPt1,
|
||||
"runCharAtPointTest (" + aTargetName + "): charAtPt1", "i=" + i)) {
|
||||
ok(!charAtPt1.notFound,
|
||||
"runCharAtPointTest (" + aTargetName + "): charAtPt1 isn't found: i=" + i);
|
||||
if (!charAtPt1.notFound) {
|
||||
is(charAtPt1.offset, kTestingOffset[i],
|
||||
"runCharAtPointTest (" + aTargetName + "): charAtPt1 offset is wrong: i=" + i);
|
||||
checkRect(charAtPt1, textRect, "runCharAtPointTest (" + aTargetName +
|
||||
"): charAtPt1 left is wrong: i=" + i);
|
||||
}
|
||||
}
|
||||
|
||||
// Test #2, getting same character rect by the point near the bottom-right.
|
||||
var charAtPt2 = synthesizeCharAtPoint(textRect.left + textRect.width - 2,
|
||||
textRect.top + textRect.height - 2);
|
||||
if (checkQueryContentResult(charAtPt2,
|
||||
"runCharAtPointTest (" + aTargetName + "): charAtPt2", "i=" + i)) {
|
||||
ok(!charAtPt2.notFound,
|
||||
"runCharAtPointTest (" + aTargetName + "): charAtPt2 isn't found: i=" + i);
|
||||
if (!charAtPt2.notFound) {
|
||||
is(charAtPt2.offset, kTestingOffset[i],
|
||||
"runCharAtPointTest (" + aTargetName + "): charAtPt2 offset is wrong: i=" + i);
|
||||
checkRect(charAtPt2, textRect, "runCharAtPointTest (" + aTargetName +
|
||||
"): charAtPt1 left is wrong: i=" + i);
|
||||
}
|
||||
}
|
||||
|
||||
// Test #3, getting left character offset.
|
||||
var charAtPt3 = synthesizeCharAtPoint(textRect.left - 2,
|
||||
textRect.top + 1);
|
||||
if (checkQueryContentResult(charAtPt3,
|
||||
"runCharAtPointTest (" + aTargetName + "): charAtPt3", "i=" + i)) {
|
||||
is(charAtPt3.notFound, kLeftSideOffset[i] == kNone,
|
||||
kLeftSideOffset[i] == kNone ?
|
||||
"runCharAtPointTest (" + aTargetName + "): charAtPt3 is found: i=" + i :
|
||||
"runCharAtPointTest (" + aTargetName + "): charAtPt3 isn't found: i=" + i);
|
||||
if (!charAtPt3.notFound) {
|
||||
is(charAtPt3.offset, kLeftSideOffset[i],
|
||||
"runCharAtPointTest (" + aTargetName + "): charAtPt3 offset is wrong: i=" + i);
|
||||
}
|
||||
}
|
||||
|
||||
// Test #4, getting right character offset.
|
||||
var charAtPt4 = synthesizeCharAtPoint(textRect.left + textRect.width + 1,
|
||||
textRect.top + textRect.height - 2);
|
||||
if (checkQueryContentResult(charAtPt4,
|
||||
"runCharAtPointTest (" + aTargetName + "): charAtPt4", "i=" + i)) {
|
||||
is(charAtPt4.notFound, kRightSideOffset[i] == kNone,
|
||||
kRightSideOffset[i] == kNone ?
|
||||
"runCharAtPointTest (" + aTargetName + "): charAtPt4 is found: i=" + i :
|
||||
"runCharAtPointTest (" + aTargetName + "): charAtPt4 isn't found: i=" + i);
|
||||
if (!charAtPt4.notFound) {
|
||||
is(charAtPt4.offset, kRightSideOffset[i],
|
||||
"runCharAtPointTest (" + aTargetName + "): charAtPt4 offset is wrong: i=" + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function runTestOnAnotherContext(aPanelOrFrame, aFocusedEditor, aTestName)
|
||||
{
|
||||
aFocusedEditor.value = "";
|
||||
|
||||
var editorRect = synthesizeQueryEditorRect();
|
||||
if (!checkQueryContentResult(editorRect, aTestName + ": editorRect")) {
|
||||
return;
|
||||
}
|
||||
|
||||
var r = aPanelOrFrame.getBoundingClientRect();
|
||||
var parentRect = { "left": r.left, "top": r.top, "width": r.right - r.left,
|
||||
"height": r.bottom - r.top };
|
||||
checkRectContainsRect(editorRect, parentRect, aTestName +
|
||||
": the editor rect coordinates are wrong");
|
||||
|
||||
// start composition
|
||||
synthesizeComposition(true);
|
||||
|
||||
// input characters
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u3078\u3093\u3057\u3093",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 4, "attr": nsIDOMWindowUtils.COMPOSITION_ATTR_RAWINPUT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 4, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u3078\u3093\u3057\u3093", aTestName, "#1-1") ||
|
||||
!checkSelection(4, "", aTestName, "#1-1")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// convert them #1
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u8FD4\u4FE1",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 2,
|
||||
"attr": nsIDOMWindowUtils.COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u8FD4\u4FE1", aTestName, "#1-2") ||
|
||||
!checkSelection(2, "", aTestName, "#1-2")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// convert them #2
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u5909\u8EAB",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 2,
|
||||
"attr": nsIDOMWindowUtils.COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u5909\u8EAB", aTestName, "#1-3") ||
|
||||
!checkSelection(2, "", aTestName, "#1-3")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// commit them
|
||||
synthesizeText(
|
||||
{ "composition":
|
||||
{ "string": "\u5909\u8EAB",
|
||||
"clauses":
|
||||
[
|
||||
{ "length": 0, "attr": 0 }
|
||||
]
|
||||
},
|
||||
"caret": { "start": 2, "length": 0 }
|
||||
});
|
||||
|
||||
if (!checkContent("\u5909\u8EAB", aTestName, "#1-4") ||
|
||||
!checkSelection(2, "", aTestName, "#1-4")) {
|
||||
return;
|
||||
}
|
||||
|
||||
synthesizeComposition(false);
|
||||
|
||||
is(aFocusedEditor.value, "\u5909\u8EAB",
|
||||
aTestName + ": composition isn't in the focused editor");
|
||||
if (aFocusedEditor.value != "\u5909\u8EAB") {
|
||||
return;
|
||||
}
|
||||
|
||||
var textRect = synthesizeQueryTextRect(0, 1);
|
||||
var caretRect = synthesizeQueryCaretRect(2);
|
||||
if (!checkQueryContentResult(textRect,
|
||||
aTestName + ": synthesizeQueryTextRect") ||
|
||||
!checkQueryContentResult(caretRect,
|
||||
aTestName + ": synthesizeQueryCaretRect")) {
|
||||
return;
|
||||
}
|
||||
checkRectContainsRect(textRect, editorRect, aTestName + ":testRect");
|
||||
checkRectContainsRect(caretRect, editorRect, aTestName + ":caretRect");
|
||||
}
|
||||
|
||||
function runFrameTest()
|
||||
{
|
||||
var textareaInFrame = iframe.contentDocument.getElementById("textarea");
|
||||
textareaInFrame.focus();
|
||||
runTestOnAnotherContext(iframe, textareaInFrame, "runFrameTest");
|
||||
runCharAtPointTest(textareaInFrame, "textarea in the iframe");
|
||||
}
|
||||
|
||||
var gPanelShown = false;
|
||||
var gPanelFocused = false;
|
||||
function onPanelShown(aEvent)
|
||||
{
|
||||
gPanelShown = true;
|
||||
textbox.focus();
|
||||
setTimeout(doPanelTest, 0);
|
||||
}
|
||||
|
||||
function onFocusPanelTextbox(aEvent)
|
||||
{
|
||||
gPanelFocused = true;
|
||||
setTimeout(doPanelTest, 0);
|
||||
}
|
||||
|
||||
var gIsPanelHiding = false;
|
||||
var gIsRunPanelTestInternal = false;
|
||||
function doPanelTest()
|
||||
{
|
||||
if (!gPanelFocused || !gPanelShown) {
|
||||
return;
|
||||
}
|
||||
if (gIsRunPanelTestInternal) {
|
||||
return;
|
||||
}
|
||||
gIsRunPanelTestInternal = true;
|
||||
runTestOnAnotherContext(panel, textbox, "runPanelTest");
|
||||
runCharAtPointTest(textbox, "textbox in the panel");
|
||||
gIsPanelHiding = true;
|
||||
panel.hidePopup();
|
||||
}
|
||||
|
||||
function onPanelHidden(aEvent)
|
||||
{
|
||||
panel.hidden = true;
|
||||
ok(gIsPanelHiding, "runPanelTest: the panel is hidden unexpectedly");
|
||||
finish();
|
||||
}
|
||||
|
||||
function runPanelTest()
|
||||
{
|
||||
panel.hidden = false;
|
||||
panel.openPopupAtScreen(window.screenX + window.outerWidth, 0, false);
|
||||
}
|
||||
|
||||
function runTest()
|
||||
{
|
||||
runCompositionTest();
|
||||
runCharAtPointTest(textarea, "textarea in the document");
|
||||
runFrameTest();
|
||||
runPanelTest();
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
</window>
|
Loading…
Reference in New Issue
Block a user