mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Bug 492233 [IMM32] Reimplement IME mouse handling r=VYV03354+roc, sr=roc
This commit is contained in:
parent
5064fd3c08
commit
54e13d1b23
@ -58,6 +58,7 @@
|
||||
#include "nsISelectionController.h"
|
||||
#include "nsISelectionPrivate.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsISelection2.h"
|
||||
#include "nsIMEStateManager.h"
|
||||
|
||||
@ -730,6 +731,46 @@ nsContentEventHandler::OnQuerySelectionAsTransferable(nsQueryContentEvent* aEven
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentEventHandler::OnQueryCharacterAtPoint(nsQueryContentEvent* aEvent)
|
||||
{
|
||||
nsresult rv = Init(aEvent);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsIFrame* rootFrame = mPresShell->GetRootFrame();
|
||||
nsPoint ptInRoot =
|
||||
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame);
|
||||
nsIFrame* targetFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, ptInRoot);
|
||||
if (!targetFrame || targetFrame->GetType() != nsGkAtoms::textFrame) {
|
||||
// there is no character at the point.
|
||||
aEvent->mReply.mOffset = nsQueryContentEvent::NOT_FOUND;
|
||||
aEvent->mSucceeded = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
nsPoint ptInTarget = ptInRoot - targetFrame->GetOffsetTo(rootFrame);
|
||||
nsTextFrame* textframe = static_cast<nsTextFrame*>(targetFrame);
|
||||
nsIFrame::ContentOffsets offsets =
|
||||
textframe->GetCharacterOffsetAtFramePoint(ptInTarget);
|
||||
NS_ENSURE_TRUE(offsets.content, NS_ERROR_FAILURE);
|
||||
PRUint32 nativeOffset;
|
||||
rv = GetFlatTextOffsetOfRange(mRootContent, offsets.content, offsets.offset,
|
||||
&nativeOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsQueryContentEvent textRect(PR_TRUE, NS_QUERY_TEXT_RECT, aEvent->widget);
|
||||
textRect.InitForQueryTextRect(nativeOffset, 1);
|
||||
rv = OnQueryTextRect(&textRect);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(textRect.mSucceeded, NS_ERROR_FAILURE);
|
||||
|
||||
// currently, we don't need to get the actual text.
|
||||
aEvent->mReply.mOffset = nativeOffset;
|
||||
aEvent->mReply.mRect = textRect.mReply.mRect;
|
||||
aEvent->mSucceeded = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentEventHandler::GetFlatTextOffsetOfRange(nsIContent* aRootContent,
|
||||
nsINode* aNode,
|
||||
|
@ -81,6 +81,8 @@ public:
|
||||
nsresult OnQueryContentState(nsQueryContentEvent* aEvent);
|
||||
// NS_QUERY_SELECTION_AS_TRANSFERABLE event handler
|
||||
nsresult OnQuerySelectionAsTransferable(nsQueryContentEvent* aEvent);
|
||||
// NS_QUERY_CHARACTER_AT_POINT event handler
|
||||
nsresult OnQueryCharacterAtPoint(nsQueryContentEvent* aEvent);
|
||||
|
||||
// NS_SELECTION_* event
|
||||
nsresult OnSelectionEvent(nsSelectionEvent* aEvent);
|
||||
|
@ -1758,6 +1758,12 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
handler.OnQuerySelectionAsTransferable(static_cast<nsQueryContentEvent*>(aEvent));
|
||||
}
|
||||
break;
|
||||
case NS_QUERY_CHARACTER_AT_POINT:
|
||||
{
|
||||
nsContentEventHandler handler(mPresContext);
|
||||
handler.OnQueryCharacterAtPoint(static_cast<nsQueryContentEvent*>(aEvent));
|
||||
}
|
||||
break;
|
||||
case NS_SELECTION_SET:
|
||||
{
|
||||
nsContentEventHandler handler(mPresContext);
|
||||
|
@ -630,7 +630,8 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(const nsEvent* aEvent, nsIFrame* aF
|
||||
if (!aEvent || (aEvent->eventStructType != NS_MOUSE_EVENT &&
|
||||
aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
|
||||
aEvent->eventStructType != NS_DRAG_EVENT &&
|
||||
aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT))
|
||||
aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT &&
|
||||
aEvent->eventStructType != NS_QUERY_CONTENT_EVENT))
|
||||
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
||||
|
||||
const nsGUIEvent* GUIEvent = static_cast<const nsGUIEvent*>(aEvent);
|
||||
|
@ -153,7 +153,8 @@ public:
|
||||
#endif
|
||||
|
||||
virtual ContentOffsets CalcContentOffsetsFromFramePoint(nsPoint aPoint);
|
||||
|
||||
ContentOffsets GetCharacterOffsetAtFramePoint(const nsPoint &aPoint);
|
||||
|
||||
NS_IMETHOD SetSelected(nsPresContext* aPresContext,
|
||||
nsIDOMRange *aRange,
|
||||
PRBool aSelected,
|
||||
@ -448,6 +449,9 @@ protected:
|
||||
nsRect& aRect);
|
||||
|
||||
PRBool IsFloatingFirstLetterChild();
|
||||
|
||||
ContentOffsets GetCharacterOffsetAtFramePointInternal(const nsPoint &aPoint,
|
||||
PRBool aForInsertionPoint);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -4812,7 +4812,21 @@ CountCharsFit(gfxTextRun* aTextRun, PRUint32 aStart, PRUint32 aLength,
|
||||
}
|
||||
|
||||
nsIFrame::ContentOffsets
|
||||
nsTextFrame::CalcContentOffsetsFromFramePoint(nsPoint aPoint) {
|
||||
nsTextFrame::CalcContentOffsetsFromFramePoint(nsPoint aPoint)
|
||||
{
|
||||
return GetCharacterOffsetAtFramePointInternal(aPoint, PR_TRUE);
|
||||
}
|
||||
|
||||
nsIFrame::ContentOffsets
|
||||
nsTextFrame::GetCharacterOffsetAtFramePoint(const nsPoint &aPoint)
|
||||
{
|
||||
return GetCharacterOffsetAtFramePointInternal(aPoint, PR_FALSE);
|
||||
}
|
||||
|
||||
nsIFrame::ContentOffsets
|
||||
nsTextFrame::GetCharacterOffsetAtFramePointInternal(const nsPoint &aPoint,
|
||||
PRBool aForInsertionPoint)
|
||||
{
|
||||
ContentOffsets offsets;
|
||||
|
||||
gfxSkipCharsIterator iter = EnsureTextRun();
|
||||
@ -4844,7 +4858,7 @@ nsTextFrame::CalcContentOffsetsFromFramePoint(nsPoint aPoint) {
|
||||
mTextRun->GetAdvanceWidth(extraCluster.GetSkippedOffset(),
|
||||
GetSkippedDistance(extraCluster, extraClusterLastChar) + 1,
|
||||
&provider);
|
||||
selectedOffset = width <= fitWidth + charWidth/2
|
||||
selectedOffset = !aForInsertionPoint || width <= fitWidth + charWidth/2
|
||||
? extraCluster.GetOriginalOffset()
|
||||
: extraClusterLastChar.GetOriginalOffset() + 1;
|
||||
} else {
|
||||
|
@ -362,12 +362,15 @@ class nsHashKey;
|
||||
#define NS_QUERY_TEXT_RECT (NS_QUERY_CONTENT_EVENT_START + 4)
|
||||
// Query for the bounding rect of the current focused frame. Result is relative
|
||||
// to top level widget coordinates
|
||||
#define NS_QUERY_EDITOR_RECT (NS_QUERY_CONTENT_EVENT_START + 5)
|
||||
#define NS_QUERY_EDITOR_RECT (NS_QUERY_CONTENT_EVENT_START + 5)
|
||||
// Query for the current state of the content. The particular members of
|
||||
// mReply that are set for each query content event will be valid on success.
|
||||
#define NS_QUERY_CONTENT_STATE (NS_QUERY_CONTENT_EVENT_START + 6)
|
||||
#define NS_QUERY_CONTENT_STATE (NS_QUERY_CONTENT_EVENT_START + 6)
|
||||
// Query for the selection in the form of a nsITransferable.
|
||||
#define NS_QUERY_SELECTION_AS_TRANSFERABLE (NS_QUERY_CONTENT_EVENT_START + 7)
|
||||
// Query for character at a point. This returns the character offset and its
|
||||
// rect. The point is specified by nsEvent::refPoint.
|
||||
#define NS_QUERY_CHARACTER_AT_POINT (NS_QUERY_CONTENT_EVENT_START + 8)
|
||||
|
||||
// Video events
|
||||
#ifdef MOZ_MEDIA
|
||||
@ -1124,6 +1127,10 @@ public:
|
||||
// used by NS_QUERY_SELECTION_AS_TRANSFERABLE
|
||||
nsCOMPtr<nsITransferable> mTransferable;
|
||||
} mReply;
|
||||
|
||||
enum {
|
||||
NOT_FOUND = PR_UINT32_MAX
|
||||
};
|
||||
};
|
||||
|
||||
class nsSelectionEvent : public nsGUIEvent
|
||||
@ -1381,7 +1388,10 @@ enum nsDragDropEventStatus {
|
||||
((evnt)->message == NS_QUERY_TEXT_CONTENT) || \
|
||||
((evnt)->message == NS_QUERY_CARET_RECT) || \
|
||||
((evnt)->message == NS_QUERY_TEXT_RECT) || \
|
||||
((evnt)->message == NS_QUERY_EDITOR_RECT))
|
||||
((evnt)->message == NS_QUERY_EDITOR_RECT) || \
|
||||
((evnt)->message == NS_QUERY_CONTENT_STATE) || \
|
||||
((evnt)->message == NS_QUERY_SELECTION_AS_TRANSFERABLE) || \
|
||||
((evnt)->message == NS_QUERY_CHARACTER_AT_POINT))
|
||||
|
||||
#define NS_IS_SELECTION_EVENT(evnt) \
|
||||
(((evnt)->message == NS_SELECTION_SET))
|
||||
|
@ -205,7 +205,7 @@ nsIMM32Handler::GetKeyboardCodePage()
|
||||
#define NO_IME_CARET -1
|
||||
|
||||
nsIMM32Handler::nsIMM32Handler() :
|
||||
mCursorPosition(NO_IME_CARET), mIsComposing(PR_FALSE),
|
||||
mCursorPosition(NO_IME_CARET), mCompositionStart(0), mIsComposing(PR_FALSE),
|
||||
mNativeCaretIsCreated(PR_FALSE)
|
||||
{
|
||||
PR_LOG(gIMM32Log, PR_LOG_ALWAYS, ("IMM32: nsIMM32Handler is created\n"));
|
||||
@ -645,42 +645,29 @@ nsIMM32Handler::HandleStartComposition(nsWindow* aWindow,
|
||||
NS_PRECONDITION(!aWindow->PluginHasFocus(),
|
||||
"HandleStartComposition should not be called when a plug-in has focus");
|
||||
|
||||
nsQueryContentEvent selection(PR_TRUE, NS_QUERY_SELECTED_TEXT, aWindow);
|
||||
aWindow->InitEvent(selection, &nsIntPoint(0, 0));
|
||||
aWindow->DispatchWindowEvent(&selection);
|
||||
if (!selection.mSucceeded) {
|
||||
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
|
||||
("IMM32: HandleStartComposition, FAILED (NS_QUERY_SELECTED_TEXT)\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
mCompositionStart = selection.mReply.mOffset;
|
||||
|
||||
nsCompositionEvent event(PR_TRUE, NS_COMPOSITION_START, aWindow);
|
||||
nsIntPoint point(0, 0);
|
||||
aWindow->InitEvent(event, &point);
|
||||
aWindow->DispatchWindowEvent(&event);
|
||||
|
||||
//
|
||||
// Post process event
|
||||
//
|
||||
|
||||
SetIMERelatedWindowsPos(aWindow, aIMEContext);
|
||||
|
||||
mIsComposing = PR_TRUE;
|
||||
|
||||
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
|
||||
("IMM32: HandleStartComposition, START composition\n"));
|
||||
|
||||
if (event.theReply.mCursorPosition.width <= 0 &&
|
||||
event.theReply.mCursorPosition.height <= 0) {
|
||||
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
|
||||
("IMM32: HandleStartComposition, mCursorPosition is empty\n"));
|
||||
// for some reason we don't know yet, theReply may contain invalid result
|
||||
// need more debugging in nsCaret to find out the reason
|
||||
// the best we can do now is to ignore the invalid result
|
||||
return;
|
||||
}
|
||||
|
||||
nsIntRect cursorPosition;
|
||||
ResolveIMECaretPos(event.theReply.mReferenceWidget,
|
||||
event.theReply.mCursorPosition, aWindow, cursorPosition);
|
||||
|
||||
#ifdef ENABLE_IME_MOUSE_HANDLING
|
||||
memset(mCompCharPos, -1, sizeof(RECT) * IME_MAX_CHAR_POS);
|
||||
mCompCharPos[0].left = cursorPosition.x;
|
||||
mCompCharPos[0].top = cursorPosition.y;
|
||||
mCompCharPos[0].bottom = cursorPosition.YMost();
|
||||
#endif // ENABLE_IME_MOUSE_HANDLING
|
||||
("IMM32: HandleStartComposition, START composition, mCompositionStart=%ld\n",
|
||||
mCompositionStart));
|
||||
}
|
||||
|
||||
PRBool
|
||||
@ -1126,45 +1113,7 @@ nsIMM32Handler::DispatchTextEvent(nsWindow* aWindow,
|
||||
|
||||
aWindow->DispatchWindowEvent(&event);
|
||||
|
||||
//
|
||||
// Post process event
|
||||
//
|
||||
|
||||
SetIMERelatedWindowsPos(aWindow, aIMEContext);
|
||||
|
||||
if (event.theReply.mCursorPosition.width <= 0 &&
|
||||
event.theReply.mCursorPosition.height <= 0) {
|
||||
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
|
||||
("IMM32: DispatchTextEvent, mCursorPosition is empty\n"));
|
||||
// for some reason we don't know yet, theReply may contain invalid result
|
||||
// need more debugging in nsCaret to find out the reason
|
||||
// the best we can do now is to ignore the invalid result
|
||||
return;
|
||||
}
|
||||
|
||||
nsIntRect cursorPosition;
|
||||
ResolveIMECaretPos(event.theReply.mReferenceWidget,
|
||||
event.theReply.mCursorPosition, aWindow, cursorPosition);
|
||||
|
||||
#ifdef ENABLE_IME_MOUSE_HANDLING
|
||||
if (mCursorPosition <= 0 || mCursorPosition >= IME_MAX_CHAR_POS) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Record previous composing char position
|
||||
// The cursor is always on the right char before it, but not necessarily on
|
||||
// the left of next char, as what happens in wrapping.
|
||||
mCompCharPos[mCursorPosition-1].right = cursorPosition.x;
|
||||
mCompCharPos[mCursorPosition-1].top = cursorPosition.y;
|
||||
mCompCharPos[mCursorPosition-1].bottom = cursorPosition.YMost();
|
||||
if (mCompCharPos[mCursorPosition-1].top != cursorPosition.y) {
|
||||
// wrapping, invalidate left position
|
||||
mCompCharPos[mCursorPosition-1].left = -1;
|
||||
}
|
||||
mCompCharPos[mCursorPosition].left = cursorPosition.x;
|
||||
mCompCharPos[mCursorPosition].top = cursorPosition.y;
|
||||
mCompCharPos[mCursorPosition].bottom = cursorPosition.YMost();
|
||||
#endif // ENABLE_IME_MOUSE_HANDLING
|
||||
}
|
||||
|
||||
void
|
||||
@ -1475,10 +1424,6 @@ nsIMM32Handler::ResolveIMECaretPos(nsIWidget* aReferenceWidget,
|
||||
|
||||
#ifdef ENABLE_IME_MOUSE_HANDLING
|
||||
|
||||
#define PT_IN_RECT(pt, rc) \
|
||||
((pt).x>(rc).left && (pt).x <(rc).right && \
|
||||
(pt).y>(rc).top && (pt).y<(rc).bottom)
|
||||
|
||||
PRBool
|
||||
nsIMM32Handler::OnMouseEvent(nsWindow* aWindow, LPARAM lParam, int aAction)
|
||||
{
|
||||
@ -1486,38 +1431,37 @@ nsIMM32Handler::OnMouseEvent(nsWindow* aWindow, LPARAM lParam, int aAction)
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
POINT ptPos;
|
||||
ptPos.x = (short)LOWORD(lParam);
|
||||
ptPos.y = (short)HIWORD(lParam);
|
||||
|
||||
if (!IMECompositionHitTest(ptPos)) {
|
||||
nsIntPoint cursor(LOWORD(lParam), HIWORD(lParam));
|
||||
nsQueryContentEvent charAtPt(PR_TRUE, NS_QUERY_CHARACTER_AT_POINT, aWindow);
|
||||
aWindow->InitEvent(charAtPt, &cursor);
|
||||
aWindow->DispatchWindowEvent(&charAtPt);
|
||||
if (!charAtPt.mSucceeded ||
|
||||
charAtPt.mReply.mOffset == nsQueryContentEvent::NOT_FOUND ||
|
||||
charAtPt.mReply.mOffset < mCompositionStart ||
|
||||
charAtPt.mReply.mOffset >
|
||||
mCompositionStart + mCompositionString.Length()) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
int positioning = 0;
|
||||
int offset = 0;
|
||||
|
||||
// calcurate positioning and offset
|
||||
// char : JCH1|JCH2|JCH3
|
||||
// offset: 0011 1122 2233
|
||||
// positioning: 2301 2301 2301
|
||||
nsIntRect cursorInTopLevel;
|
||||
ResolveIMECaretPos(aWindow, nsIntRect(cursor, nsIntSize(0, 0)),
|
||||
aWindow->GetTopLevelWindow(PR_FALSE), cursorInTopLevel);
|
||||
PRInt32 cursorXInChar = cursorInTopLevel.x - charAtPt.mReply.mRect.x;
|
||||
int positioning = cursorXInChar * 4 / charAtPt.mReply.mRect.width;
|
||||
positioning = (positioning + 2) % 4;
|
||||
|
||||
// Note: hitText has been done, so no check of mCompCharPos
|
||||
// and composing char maximum limit is necessary.
|
||||
PRUint32 len = mCompositionString.Length();
|
||||
PRUint32 i = 0;
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (PT_IN_RECT(ptPos, mCompCharPos[i]))
|
||||
break;
|
||||
}
|
||||
offset = i;
|
||||
if (ptPos.x - mCompCharPos[i].left > mCompCharPos[i].right - ptPos.x) {
|
||||
int offset = charAtPt.mReply.mOffset - mCompositionStart;
|
||||
if (positioning < 2) {
|
||||
offset++;
|
||||
}
|
||||
|
||||
positioning = (ptPos.x - mCompCharPos[i].left) * 4 /
|
||||
(mCompCharPos[i].right - mCompCharPos[i].left);
|
||||
positioning = (positioning + 2) % 4;
|
||||
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
|
||||
("IMM32: OnMouseEvent, x,y=%ld,%ld, offset=%ld, positioning=%ld\n",
|
||||
cursor.x, cursor.y, offset, positioning));
|
||||
|
||||
// send MS_MSIME_MOUSE message to default IME window.
|
||||
HWND imeWnd = ::ImmGetDefaultIMEWnd(aWindow->GetWindowHandle());
|
||||
@ -1527,45 +1471,4 @@ nsIMM32Handler::OnMouseEvent(nsWindow* aWindow, LPARAM lParam, int aAction)
|
||||
(LPARAM) IMEContext.get()) == 1;
|
||||
}
|
||||
|
||||
//The coordinate is relative to the upper-left corner of the client area.
|
||||
PRBool
|
||||
nsIMM32Handler::IMECompositionHitTest(const POINT& aPos)
|
||||
{
|
||||
// figure out how many char in composing string,
|
||||
// but keep it below the limit we can handle
|
||||
PRInt32 len = mCompositionString.Length();
|
||||
if (len > IME_MAX_CHAR_POS)
|
||||
len = IME_MAX_CHAR_POS;
|
||||
|
||||
PRInt32 i;
|
||||
PRInt32 aveWidth = 0;
|
||||
// found per char width
|
||||
for (i = 0; i < len; i++) {
|
||||
if (mCompCharPos[i].left >= 0 && mCompCharPos[i].right > 0) {
|
||||
aveWidth = mCompCharPos[i].right - mCompCharPos[i].left;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// validate each rect and test
|
||||
for (i = 0; i < len; i++) {
|
||||
if (mCompCharPos[i].left < 0) {
|
||||
if (i != 0 && mCompCharPos[i-1].top == mCompCharPos[i].top)
|
||||
mCompCharPos[i].left = mCompCharPos[i-1].right;
|
||||
else
|
||||
mCompCharPos[i].left = mCompCharPos[i].right - aveWidth;
|
||||
}
|
||||
if (mCompCharPos[i].right < 0)
|
||||
mCompCharPos[i].right = mCompCharPos[i].left + aveWidth;
|
||||
if (mCompCharPos[i].top < 0) {
|
||||
mCompCharPos[i].top = mCompCharPos[i-1].top;
|
||||
mCompCharPos[i].bottom = mCompCharPos[i-1].bottom;
|
||||
}
|
||||
|
||||
if (PT_IN_RECT(aPos, mCompCharPos[i])) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
#endif // ENABLE_IME_MOUSE_HANDLING
|
||||
|
@ -208,6 +208,7 @@ protected:
|
||||
nsTArray<PRUint8> mAttributeArray;
|
||||
|
||||
PRInt32 mCursorPosition;
|
||||
PRUint32 mCompositionStart;
|
||||
|
||||
PRPackedBool mIsComposing;
|
||||
PRPackedBool mNativeCaretIsCreated;
|
||||
@ -221,15 +222,7 @@ protected:
|
||||
#endif // #ifndef WINCE
|
||||
|
||||
#ifdef ENABLE_IME_MOUSE_HANDLING
|
||||
|
||||
#define IME_MAX_CHAR_POS 64
|
||||
// For describing composing frame
|
||||
// XXX mnakano - We should remove this, because its value may be wrong in
|
||||
// some cases, and we should query it when it is needed.
|
||||
RECT mCompCharPos[IME_MAX_CHAR_POS];
|
||||
|
||||
PRBool OnMouseEvent(nsWindow* aWindow, LPARAM lParam, int aAction);
|
||||
PRBool IMECompositionHitTest(const POINT& aPos);
|
||||
#endif // ENABLE_IME_MOUSE_HANDLING
|
||||
|
||||
};
|
||||
|
@ -169,7 +169,8 @@ private:
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// from http://msdn.microsoft.com/library/en-us/dnime/html/msime.asp
|
||||
// from http://download.microsoft.com/download/6/0/9/60908e9e-d2c1-47db-98f6-216af76a235f/msime.h
|
||||
// The document for this has been removed from MSDN...
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
|
@ -88,6 +88,7 @@ class nsAFlatCString;
|
||||
#include "nsISelectionController.h"
|
||||
#include "nsIViewManager.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsGUIEvent.h"
|
||||
|
||||
#ifndef MOZILLA_INTERNAL_API
|
||||
#undef nsString_h___
|
||||
@ -129,6 +130,7 @@ protected:
|
||||
PRBool TestExtents(void);
|
||||
PRBool TestComposition(void);
|
||||
PRBool TestNotification(void);
|
||||
PRBool TestContentEvents(void);
|
||||
|
||||
PRBool TestApp::TestSelectionInternal(char* aTestName,
|
||||
LONG aStart,
|
||||
@ -1642,6 +1644,10 @@ 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");
|
||||
|
||||
if (RunTest(&TestApp::TestFocus, PR_FALSE))
|
||||
passed("TestFocus");
|
||||
|
||||
@ -2704,6 +2710,155 @@ 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;
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
nsresult nsr = mWindow->GetDocShell(getter_AddRefs(docShell));
|
||||
if (NS_SUCCEEDED(nsr) && docShell) {
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
nsr = docShell->GetPresShell(getter_AddRefs(presShell));
|
||||
if (NS_SUCCEEDED(nsr) && presShell) {
|
||||
nsCOMPtr<nsIViewManager> viewManager = presShell->GetViewManager();
|
||||
if (viewManager) {
|
||||
nsr = viewManager->GetWidget(getter_AddRefs(widget));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (NS_FAILED(nsr) || !widget) {
|
||||
fail("TestContentEvents: get nsIWidget");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> topLevel = widget->GetTopLevelWidget(nsnull);
|
||||
if (!topLevel) {
|
||||
fail("TestContentEvents: get top level widget");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsIntRect widgetRect, topLevelRect;
|
||||
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;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TestApp::GetSelCon(nsISelectionController** aSelCon)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user