зеркало из https://github.com/mozilla/pjs.git
Bug 88831 Support new IME API "Text Services Framework" from Office XP and Windows XP r=masayuki+peterv, sr=roc
--HG-- rename : content/events/src/nsQueryContentEventHandler.cpp => content/events/src/nsContentEventHandler.cpp rename : content/events/src/nsQueryContentEventHandler.h => content/events/src/nsContentEventHandler.h
This commit is contained in:
Родитель
8f0b3e7aff
Коммит
096291dfe5
|
@ -118,7 +118,7 @@
|
||||||
#include "nsIDOMNSFeatureFactory.h"
|
#include "nsIDOMNSFeatureFactory.h"
|
||||||
#include "nsIDOMDocumentType.h"
|
#include "nsIDOMDocumentType.h"
|
||||||
#include "nsIDOMUserDataHandler.h"
|
#include "nsIDOMUserDataHandler.h"
|
||||||
#include "nsIDOMNSEditableElement.h"
|
#include "nsGenericHTMLElement.h"
|
||||||
#include "nsIEditor.h"
|
#include "nsIEditor.h"
|
||||||
#include "nsIEditorDocShell.h"
|
#include "nsIEditorDocShell.h"
|
||||||
#include "nsEventDispatcher.h"
|
#include "nsEventDispatcher.h"
|
||||||
|
@ -343,13 +343,15 @@ nsINode::GetTextEditorRootContent(nsIEditor** aEditor)
|
||||||
if (aEditor)
|
if (aEditor)
|
||||||
*aEditor = nsnull;
|
*aEditor = nsnull;
|
||||||
for (nsINode* node = this; node; node = node->GetNodeParent()) {
|
for (nsINode* node = this; node; node = node->GetNodeParent()) {
|
||||||
nsCOMPtr<nsIDOMNSEditableElement> editableElement(do_QueryInterface(node));
|
if (!node->IsNodeOfType(eHTML))
|
||||||
if (!editableElement)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
nsCOMPtr<nsIEditor> editor;
|
nsCOMPtr<nsIEditor> editor;
|
||||||
editableElement->GetEditor(getter_AddRefs(editor));
|
static_cast<nsGenericHTMLElement*>(node)->
|
||||||
NS_ENSURE_TRUE(editor, nsnull);
|
GetEditorInternal(getter_AddRefs(editor));
|
||||||
|
if (!editor)
|
||||||
|
continue;
|
||||||
|
|
||||||
nsIContent* rootContent = GetEditorRootContent(editor);
|
nsIContent* rootContent = GetEditorRootContent(editor);
|
||||||
if (aEditor)
|
if (aEditor)
|
||||||
editor.swap(*aEditor);
|
editor.swap(*aEditor);
|
||||||
|
|
|
@ -62,7 +62,9 @@
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
GK_ATOM(_empty, "")
|
GK_ATOM(_empty, "")
|
||||||
|
GK_ATOM(moz, "_moz")
|
||||||
GK_ATOM(mozdirty, "_moz_dirty")
|
GK_ATOM(mozdirty, "_moz_dirty")
|
||||||
|
GK_ATOM(mozeditorbogusnode, "_moz_editor_bogus_node")
|
||||||
GK_ATOM(mozgeneratedcontentbefore, "_moz_generated_content_before")
|
GK_ATOM(mozgeneratedcontentbefore, "_moz_generated_content_before")
|
||||||
GK_ATOM(mozgeneratedcontentafter, "_moz_generated_content_after")
|
GK_ATOM(mozgeneratedcontentafter, "_moz_generated_content_after")
|
||||||
GK_ATOM(mozgeneratedcontentimage, "_moz_generated_content_image")
|
GK_ATOM(mozgeneratedcontentimage, "_moz_generated_content_image")
|
||||||
|
|
|
@ -91,7 +91,7 @@ CPPSRCS = \
|
||||||
nsPLDOMEvent.cpp \
|
nsPLDOMEvent.cpp \
|
||||||
nsEventDispatcher.cpp \
|
nsEventDispatcher.cpp \
|
||||||
nsIMEStateManager.cpp \
|
nsIMEStateManager.cpp \
|
||||||
nsQueryContentEventHandler.cpp \
|
nsContentEventHandler.cpp \
|
||||||
nsDOMProgressEvent.cpp \
|
nsDOMProgressEvent.cpp \
|
||||||
nsDOMDataTransfer.cpp \
|
nsDOMDataTransfer.cpp \
|
||||||
nsDOMNotifyPaintEvent.cpp \
|
nsDOMNotifyPaintEvent.cpp \
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Masayuki Nakano <masayuki@d-toybox.com>
|
* Masayuki Nakano <masayuki@d-toybox.com>
|
||||||
|
* Ningjie Chen <chenn@email.uc.edu>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* 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"),
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
@ -37,7 +38,7 @@
|
||||||
*
|
*
|
||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
#include "nsQueryContentEventHandler.h"
|
#include "nsContentEventHandler.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsPresContext.h"
|
#include "nsPresContext.h"
|
||||||
#include "nsIPresShell.h"
|
#include "nsIPresShell.h"
|
||||||
|
@ -53,14 +54,19 @@
|
||||||
#include "nsIContentIterator.h"
|
#include "nsIContentIterator.h"
|
||||||
#include "nsTextFragment.h"
|
#include "nsTextFragment.h"
|
||||||
#include "nsTextFrame.h"
|
#include "nsTextFrame.h"
|
||||||
|
#include "nsISelectionController.h"
|
||||||
|
#include "nsISelectionPrivate.h"
|
||||||
|
#include "nsContentUtils.h"
|
||||||
|
#include "nsISelection2.h"
|
||||||
|
#include "nsIMEStateManager.h"
|
||||||
|
|
||||||
nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult);
|
nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult);
|
||||||
|
|
||||||
/******************************************************************/
|
/******************************************************************/
|
||||||
/* nsQueryContentEventHandler */
|
/* nsContentEventHandler */
|
||||||
/******************************************************************/
|
/******************************************************************/
|
||||||
|
|
||||||
nsQueryContentEventHandler::nsQueryContentEventHandler(
|
nsContentEventHandler::nsContentEventHandler(
|
||||||
nsPresContext* aPresContext) :
|
nsPresContext* aPresContext) :
|
||||||
mPresContext(aPresContext),
|
mPresContext(aPresContext),
|
||||||
mPresShell(aPresContext->GetPresShell()), mSelection(nsnull),
|
mPresShell(aPresContext->GetPresShell()), mSelection(nsnull),
|
||||||
|
@ -69,7 +75,7 @@ nsQueryContentEventHandler::nsQueryContentEventHandler(
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsQueryContentEventHandler::Init(nsQueryContentEvent* aEvent)
|
nsContentEventHandler::Init(nsQueryContentEvent* aEvent)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(aEvent, "aEvent must not be null");
|
NS_ASSERTION(aEvent, "aEvent must not be null");
|
||||||
|
|
||||||
|
@ -117,6 +123,24 @@ nsQueryContentEventHandler::Init(nsQueryContentEvent* aEvent)
|
||||||
return NS_OK;
|
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,
|
||||||
|
// we don't want to include the bogus BRs at the end.
|
||||||
|
static PRBool IsContentBR(nsIContent* aContent)
|
||||||
|
{
|
||||||
|
return aContent->IsNodeOfType(nsINode::eHTML) &&
|
||||||
|
aContent->Tag() == nsGkAtoms::br &&
|
||||||
|
!aContent->AttrValueIs(kNameSpaceID_None,
|
||||||
|
nsGkAtoms::type,
|
||||||
|
nsGkAtoms::moz,
|
||||||
|
eIgnoreCase) &&
|
||||||
|
!aContent->AttrValueIs(kNameSpaceID_None,
|
||||||
|
nsGkAtoms::mozeditorbogusnode,
|
||||||
|
nsGkAtoms::_true,
|
||||||
|
eIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
static void ConvertToNativeNewlines(nsAFlatString& aString)
|
static void ConvertToNativeNewlines(nsAFlatString& aString)
|
||||||
{
|
{
|
||||||
#if defined(XP_MACOSX)
|
#if defined(XP_MACOSX)
|
||||||
|
@ -161,8 +185,7 @@ static PRUint32 GetNativeTextLength(nsIContent* aContent)
|
||||||
nsAutoString str;
|
nsAutoString str;
|
||||||
if (aContent->IsNodeOfType(nsINode::eTEXT))
|
if (aContent->IsNodeOfType(nsINode::eTEXT))
|
||||||
AppendString(str, aContent);
|
AppendString(str, aContent);
|
||||||
else if (aContent->IsNodeOfType(nsINode::eHTML) &&
|
else if (IsContentBR(aContent))
|
||||||
aContent->Tag() == nsGkAtoms::br)
|
|
||||||
str.Assign(PRUnichar('\n'));
|
str.Assign(PRUnichar('\n'));
|
||||||
ConvertToNativeNewlines(str);
|
ConvertToNativeNewlines(str);
|
||||||
return str.Length();
|
return str.Length();
|
||||||
|
@ -181,9 +204,8 @@ static PRUint32 ConvertToXPOffset(nsIContent* aContent, PRUint32 aNativeOffset)
|
||||||
return str.Length();
|
return str.Length();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
static nsresult GenerateFlatTextContent(nsIRange* aRange,
|
||||||
nsQueryContentEventHandler::GenerateFlatTextContent(nsIRange* aRange,
|
nsAFlatString& aString)
|
||||||
nsAFlatString& aString)
|
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIContentIterator> iter;
|
nsCOMPtr<nsIContentIterator> iter;
|
||||||
nsresult rv = NS_NewContentIterator(getter_AddRefs(iter));
|
nsresult rv = NS_NewContentIterator(getter_AddRefs(iter));
|
||||||
|
@ -221,8 +243,7 @@ nsQueryContentEventHandler::GenerateFlatTextContent(nsIRange* aRange,
|
||||||
AppendSubString(aString, content, 0, aRange->EndOffset());
|
AppendSubString(aString, content, 0, aRange->EndOffset());
|
||||||
else
|
else
|
||||||
AppendString(aString, content);
|
AppendString(aString, content);
|
||||||
} else if (content->IsNodeOfType(nsINode::eHTML) &&
|
} else if (IsContentBR(content))
|
||||||
content->Tag() == nsGkAtoms::br)
|
|
||||||
aString.Append(PRUnichar('\n'));
|
aString.Append(PRUnichar('\n'));
|
||||||
}
|
}
|
||||||
ConvertToNativeNewlines(aString);
|
ConvertToNativeNewlines(aString);
|
||||||
|
@ -230,18 +251,19 @@ nsQueryContentEventHandler::GenerateFlatTextContent(nsIRange* aRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsQueryContentEventHandler::ExpandToClusterBoundary(nsIContent* aContent,
|
nsContentEventHandler::ExpandToClusterBoundary(nsIContent* aContent,
|
||||||
PRBool aForward,
|
PRBool aForward,
|
||||||
PRUint32* aXPOffset)
|
PRUint32* aXPOffset)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(*aXPOffset >= 0 && *aXPOffset <= aContent->TextLength(),
|
|
||||||
"offset is out of range.");
|
|
||||||
|
|
||||||
// XXX This method assumes that the frame boundaries must be cluster
|
// XXX This method assumes that the frame boundaries must be cluster
|
||||||
// boundaries. It's false, but no problem now, maybe.
|
// boundaries. It's false, but no problem now, maybe.
|
||||||
if (!aContent->IsNodeOfType(nsINode::eTEXT) ||
|
if (!aContent->IsNodeOfType(nsINode::eTEXT) ||
|
||||||
*aXPOffset == 0 || *aXPOffset == aContent->TextLength())
|
*aXPOffset == 0 || *aXPOffset == aContent->TextLength())
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
|
NS_ASSERTION(*aXPOffset >= 0 && *aXPOffset <= aContent->TextLength(),
|
||||||
|
"offset is out of range.");
|
||||||
|
|
||||||
nsCOMPtr<nsFrameSelection> fs = mPresShell->FrameSelection();
|
nsCOMPtr<nsFrameSelection> fs = mPresShell->FrameSelection();
|
||||||
PRInt32 offsetInFrame;
|
PRInt32 offsetInFrame;
|
||||||
nsFrameSelection::HINT hint =
|
nsFrameSelection::HINT hint =
|
||||||
|
@ -265,7 +287,7 @@ nsQueryContentEventHandler::ExpandToClusterBoundary(nsIContent* aContent,
|
||||||
if (frame->GetType() != nsGkAtoms::textFrame)
|
if (frame->GetType() != nsGkAtoms::textFrame)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
|
nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
|
||||||
PRInt32 newOffsetInFrame = offsetInFrame;
|
PRInt32 newOffsetInFrame = *aXPOffset - startOffset;
|
||||||
newOffsetInFrame += aForward ? -1 : 1;
|
newOffsetInFrame += aForward ? -1 : 1;
|
||||||
textFrame->PeekOffsetCharacter(aForward, &newOffsetInFrame);
|
textFrame->PeekOffsetCharacter(aForward, &newOffsetInFrame);
|
||||||
*aXPOffset = startOffset + newOffsetInFrame;
|
*aXPOffset = startOffset + newOffsetInFrame;
|
||||||
|
@ -273,7 +295,7 @@ nsQueryContentEventHandler::ExpandToClusterBoundary(nsIContent* aContent,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsQueryContentEventHandler::SetRangeFromFlatTextOffset(
|
nsContentEventHandler::SetRangeFromFlatTextOffset(
|
||||||
nsIRange* aRange,
|
nsIRange* aRange,
|
||||||
PRUint32 aNativeOffset,
|
PRUint32 aNativeOffset,
|
||||||
PRUint32 aNativeLength,
|
PRUint32 aNativeLength,
|
||||||
|
@ -369,7 +391,7 @@ nsQueryContentEventHandler::SetRangeFromFlatTextOffset(
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsQueryContentEventHandler::OnQuerySelectedText(nsQueryContentEvent* aEvent)
|
nsContentEventHandler::OnQuerySelectedText(nsQueryContentEvent* aEvent)
|
||||||
{
|
{
|
||||||
nsresult rv = Init(aEvent);
|
nsresult rv = Init(aEvent);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
|
@ -378,21 +400,32 @@ nsQueryContentEventHandler::OnQuerySelectedText(nsQueryContentEvent* aEvent)
|
||||||
NS_ASSERTION(aEvent->mReply.mString.IsEmpty(),
|
NS_ASSERTION(aEvent->mReply.mString.IsEmpty(),
|
||||||
"The reply string must be empty");
|
"The reply string must be empty");
|
||||||
|
|
||||||
rv = GetFlatTextOffsetOfRange(mFirstSelectedRange, &aEvent->mReply.mOffset);
|
rv = GetFlatTextOffsetOfRange(mRootContent,
|
||||||
|
mFirstSelectedRange, &aEvent->mReply.mOffset);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
PRBool isCollapsed;
|
nsCOMPtr<nsIDOMNode> anchorDomNode, focusDomNode;
|
||||||
rv = mSelection->GetIsCollapsed(&isCollapsed);
|
rv = mSelection->GetAnchorNode(getter_AddRefs(anchorDomNode));
|
||||||
|
NS_ENSURE_TRUE(anchorDomNode, NS_ERROR_FAILURE);
|
||||||
|
rv = mSelection->GetFocusNode(getter_AddRefs(focusDomNode));
|
||||||
|
NS_ENSURE_TRUE(focusDomNode, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
|
PRInt32 anchorOffset, focusOffset;
|
||||||
|
rv = mSelection->GetAnchorOffset(&anchorOffset);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
rv = mSelection->GetFocusOffset(&focusOffset);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (!isCollapsed) {
|
nsCOMPtr<nsINode> anchorNode(do_QueryInterface(anchorDomNode));
|
||||||
nsCOMPtr<nsIDOMRange> domRange;
|
nsCOMPtr<nsINode> focusNode(do_QueryInterface(focusDomNode));
|
||||||
rv = mSelection->GetRangeAt(0, getter_AddRefs(domRange));
|
NS_ENSURE_TRUE(anchorNode && focusNode, NS_ERROR_UNEXPECTED);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
NS_ASSERTION(domRange, "GetRangeAt succeeded, but the result is null");
|
|
||||||
|
|
||||||
nsCOMPtr<nsIRange> range(do_QueryInterface(domRange));
|
PRInt16 compare = nsContentUtils::ComparePoints(anchorNode, anchorOffset,
|
||||||
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
|
focusNode, focusOffset);
|
||||||
|
aEvent->mReply.mReversed = compare > 0;
|
||||||
|
|
||||||
|
if (compare) {
|
||||||
|
nsCOMPtr<nsIRange> range = mFirstSelectedRange;
|
||||||
rv = GenerateFlatTextContent(range, aEvent->mReply.mString);
|
rv = GenerateFlatTextContent(range, aEvent->mReply.mString);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
@ -402,7 +435,7 @@ nsQueryContentEventHandler::OnQuerySelectedText(nsQueryContentEvent* aEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsQueryContentEventHandler::OnQueryTextContent(nsQueryContentEvent* aEvent)
|
nsContentEventHandler::OnQueryTextContent(nsQueryContentEvent* aEvent)
|
||||||
{
|
{
|
||||||
nsresult rv = Init(aEvent);
|
nsresult rv = Init(aEvent);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
|
@ -425,65 +458,168 @@ nsQueryContentEventHandler::OnQueryTextContent(nsQueryContentEvent* aEvent)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
// Adjust to use a child node if possible
|
||||||
nsQueryContentEventHandler::QueryRectFor(nsQueryContentEvent* aEvent,
|
// to make the returned rect more accurate
|
||||||
nsIRange* aRange,
|
static nsINode* AdjustTextRectNode(nsINode* aNode,
|
||||||
nsCaret* aCaret)
|
PRInt32& aOffset)
|
||||||
{
|
{
|
||||||
PRInt32 offsetInFrame;
|
PRInt32 childCount = PRInt32(aNode->GetChildCount());
|
||||||
nsIFrame* frame;
|
nsINode* node = aNode;
|
||||||
nsresult rv = GetStartFrameAndOffset(aRange, &frame, &offsetInFrame);
|
if (childCount) {
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
if (aOffset < childCount) {
|
||||||
|
node = aNode->GetChildAt(aOffset);
|
||||||
nsPoint posInFrame;
|
aOffset = 0;
|
||||||
rv = frame->GetPointFromOffset(aRange->StartOffset(), &posInFrame);
|
} else if (aOffset == childCount) {
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
node = aNode->GetChildAt(childCount - 1);
|
||||||
|
aOffset = node->IsNodeOfType(nsINode::eTEXT) ?
|
||||||
nsRect rect;
|
static_cast<nsIContent*>(node)->TextLength() : 1;
|
||||||
rect.y = posInFrame.y;
|
}
|
||||||
rect.height = frame->GetSize().height;
|
|
||||||
|
|
||||||
if (aEvent->message == NS_QUERY_CHARACTER_RECT) {
|
|
||||||
nsPoint nextPos;
|
|
||||||
rv = frame->GetPointFromOffset(aRange->EndOffset(), &nextPos);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
rect.x = PR_MIN(posInFrame.x, nextPos.x);
|
|
||||||
rect.width = PR_ABS(posInFrame.x - nextPos.x);
|
|
||||||
} else {
|
|
||||||
rect.x = posInFrame.x;
|
|
||||||
rect.width = aCaret->GetCaretRect().width;
|
|
||||||
}
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
rv = ConvertToRootViewRelativeOffset(frame, rect);
|
// Similar to nsFrameSelection::GetFrameForNodeOffset,
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
// but this is more flexible for OnQueryTextRect to use
|
||||||
|
static nsresult GetFrameForTextRect(nsIPresShell* aPresShell,
|
||||||
aEvent->mReply.mRect = nsRect::ToOutsidePixels(rect, mPresContext->AppUnitsPerDevPixel());
|
nsINode* aNode,
|
||||||
aEvent->mSucceeded = PR_TRUE;
|
PRInt32 aOffset,
|
||||||
return NS_OK;
|
PRBool aHint,
|
||||||
|
nsIFrame** aReturnFrame)
|
||||||
|
{
|
||||||
|
NS_ENSURE_TRUE(aNode && aNode->IsNodeOfType(nsINode::eCONTENT),
|
||||||
|
NS_ERROR_UNEXPECTED);
|
||||||
|
nsIContent* content = static_cast<nsIContent*>(aNode);
|
||||||
|
nsIFrame* frame = aPresShell->GetPrimaryFrameFor(content);
|
||||||
|
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
||||||
|
PRInt32 childOffset = 0;
|
||||||
|
return frame->GetChildFrameContainingOffset(aOffset, aHint, &childOffset,
|
||||||
|
aReturnFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsQueryContentEventHandler::OnQueryCharacterRect(nsQueryContentEvent* aEvent)
|
nsContentEventHandler::OnQueryTextRect(nsQueryContentEvent* aEvent)
|
||||||
{
|
{
|
||||||
nsresult rv = Init(aEvent);
|
nsresult rv = Init(aEvent);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
nsCOMPtr<nsIRange> range = new nsRange();
|
nsRefPtr<nsRange> range = new nsRange();
|
||||||
NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY);
|
if (!range) {
|
||||||
rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset, 1, PR_TRUE);
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset,
|
||||||
|
aEvent->mInput.mLength, PR_TRUE);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (range->Collapsed()) {
|
// used to iterate over all contents and their frames
|
||||||
// There is no character at the offset.
|
nsCOMPtr<nsIContentIterator> iter;
|
||||||
return NS_OK;
|
rv = NS_NewContentIterator(getter_AddRefs(iter));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
iter->Init(range);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// get the starting frame
|
||||||
|
PRInt32 offset = range->StartOffset();
|
||||||
|
nsINode* node = iter->GetCurrentNode();
|
||||||
|
if (!node) {
|
||||||
|
node = AdjustTextRectNode(range->GetStartParent(), offset);
|
||||||
|
}
|
||||||
|
nsIFrame* firstFrame = nsnull;
|
||||||
|
rv = GetFrameForTextRect(mPresShell, node, offset,
|
||||||
|
PR_TRUE, &firstFrame);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// get the starting frame rect
|
||||||
|
nsRect rect(nsPoint(0, 0), firstFrame->GetRect().Size());
|
||||||
|
rv = ConvertToRootViewRelativeOffset(firstFrame, rect);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
nsRect frameRect = rect;
|
||||||
|
nsPoint ptOffset;
|
||||||
|
firstFrame->GetPointFromOffset(offset, &ptOffset);
|
||||||
|
// minus 1 to avoid creating an empty rect
|
||||||
|
rect.x += ptOffset.x - 1;
|
||||||
|
rect.width -= ptOffset.x - 1;
|
||||||
|
|
||||||
|
// get the ending frame
|
||||||
|
offset = range->EndOffset();
|
||||||
|
node = AdjustTextRectNode(range->GetEndParent(), offset);
|
||||||
|
nsIFrame* lastFrame = nsnull;
|
||||||
|
rv = GetFrameForTextRect(mPresShell, node, offset,
|
||||||
|
range->Collapsed(), &lastFrame);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// iterate over all covered frames
|
||||||
|
for (nsIFrame* frame = firstFrame; frame != lastFrame;) {
|
||||||
|
frame = frame->GetNextContinuation();
|
||||||
|
if (!frame) {
|
||||||
|
do {
|
||||||
|
iter->Next();
|
||||||
|
node = iter->GetCurrentNode();
|
||||||
|
if (!node || !node->IsNodeOfType(nsINode::eCONTENT))
|
||||||
|
continue;
|
||||||
|
frame = mPresShell->GetPrimaryFrameFor(static_cast<nsIContent*>(node));
|
||||||
|
} while (!frame && !iter->IsDone());
|
||||||
|
if (!frame) {
|
||||||
|
// this can happen when the end offset of the range is 0.
|
||||||
|
frame = lastFrame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frameRect.SetRect(nsPoint(0, 0), frame->GetRect().Size());
|
||||||
|
rv = ConvertToRootViewRelativeOffset(frame, frameRect);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
if (frame != lastFrame) {
|
||||||
|
// not last frame, so just add rect to previous result
|
||||||
|
rect.UnionRect(rect, frameRect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return QueryRectFor(aEvent, range, nsnull);
|
// get the ending frame rect
|
||||||
|
lastFrame->GetPointFromOffset(offset, &ptOffset);
|
||||||
|
// minus 1 to avoid creating an empty rect
|
||||||
|
frameRect.width -= lastFrame->GetRect().width - ptOffset.x - 1;
|
||||||
|
|
||||||
|
if (firstFrame == lastFrame) {
|
||||||
|
rect.IntersectRect(rect, frameRect);
|
||||||
|
} else {
|
||||||
|
rect.UnionRect(rect, frameRect);
|
||||||
|
}
|
||||||
|
aEvent->mReply.mRect =
|
||||||
|
nsRect::ToOutsidePixels(rect, mPresContext->AppUnitsPerDevPixel());
|
||||||
|
aEvent->mSucceeded = PR_TRUE;
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsQueryContentEventHandler::OnQueryCaretRect(nsQueryContentEvent* aEvent)
|
nsContentEventHandler::OnQueryEditorRect(nsQueryContentEvent* aEvent)
|
||||||
|
{
|
||||||
|
nsresult rv = Init(aEvent);
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
nsIFrame* frame = mPresShell->GetPrimaryFrameFor(mRootContent);
|
||||||
|
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
|
// get rect for first frame
|
||||||
|
nsRect resultRect(nsPoint(0, 0), frame->GetRect().Size());
|
||||||
|
rv = ConvertToRootViewRelativeOffset(frame, resultRect);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// account for any additional frames
|
||||||
|
while ((frame = frame->GetNextContinuation()) != nsnull) {
|
||||||
|
nsRect frameRect(nsPoint(0, 0), frame->GetRect().Size());
|
||||||
|
rv = ConvertToRootViewRelativeOffset(frame, frameRect);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
resultRect.UnionRect(resultRect, frameRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
aEvent->mReply.mRect =
|
||||||
|
nsRect::ToOutsidePixels(resultRect, mPresContext->AppUnitsPerDevPixel());
|
||||||
|
aEvent->mSucceeded = PR_TRUE;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsContentEventHandler::OnQueryCaretRect(nsQueryContentEvent* aEvent)
|
||||||
{
|
{
|
||||||
nsresult rv = Init(aEvent);
|
nsresult rv = Init(aEvent);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
|
@ -502,7 +638,7 @@ nsQueryContentEventHandler::OnQueryCaretRect(nsQueryContentEvent* aEvent)
|
||||||
|
|
||||||
if (selectionIsCollapsed) {
|
if (selectionIsCollapsed) {
|
||||||
PRUint32 offset;
|
PRUint32 offset;
|
||||||
rv = GetFlatTextOffsetOfRange(mFirstSelectedRange, &offset);
|
rv = GetFlatTextOffsetOfRange(mRootContent, mFirstSelectedRange, &offset);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
if (offset == aEvent->mInput.mOffset) {
|
if (offset == aEvent->mInput.mOffset) {
|
||||||
PRBool isCollapsed;
|
PRBool isCollapsed;
|
||||||
|
@ -510,7 +646,8 @@ nsQueryContentEventHandler::OnQueryCaretRect(nsQueryContentEvent* aEvent)
|
||||||
rv = caret->GetCaretCoordinates(nsCaret::eTopLevelWindowCoordinates,
|
rv = caret->GetCaretCoordinates(nsCaret::eTopLevelWindowCoordinates,
|
||||||
mSelection, &rect,
|
mSelection, &rect,
|
||||||
&isCollapsed, nsnull);
|
&isCollapsed, nsnull);
|
||||||
aEvent->mReply.mRect = nsRect::ToOutsidePixels(rect, mPresContext->AppUnitsPerDevPixel());
|
aEvent->mReply.mRect =
|
||||||
|
nsRect::ToOutsidePixels(rect, mPresContext->AppUnitsPerDevPixel());
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
aEvent->mSucceeded = PR_TRUE;
|
aEvent->mSucceeded = PR_TRUE;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -523,12 +660,35 @@ nsQueryContentEventHandler::OnQueryCaretRect(nsQueryContentEvent* aEvent)
|
||||||
rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset, 0, PR_TRUE);
|
rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset, 0, PR_TRUE);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
return QueryRectFor(aEvent, range, caret);
|
PRInt32 offsetInFrame;
|
||||||
|
nsIFrame* frame;
|
||||||
|
rv = GetStartFrameAndOffset(range, &frame, &offsetInFrame);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsPoint posInFrame;
|
||||||
|
rv = frame->GetPointFromOffset(range->StartOffset(), &posInFrame);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsRect rect;
|
||||||
|
rect.x = posInFrame.x;
|
||||||
|
rect.y = posInFrame.y;
|
||||||
|
rect.width = caret->GetCaretRect().width;
|
||||||
|
rect.height = frame->GetSize().height;
|
||||||
|
|
||||||
|
rv = ConvertToRootViewRelativeOffset(frame, rect);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
aEvent->mReply.mRect =
|
||||||
|
nsRect::ToOutsidePixels(rect, mPresContext->AppUnitsPerDevPixel());
|
||||||
|
aEvent->mSucceeded = PR_TRUE;
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsQueryContentEventHandler::GetFlatTextOffsetOfRange(nsIRange* aRange,
|
nsContentEventHandler::GetFlatTextOffsetOfRange(nsIContent* aRootContent,
|
||||||
PRUint32* aNativeOffset)
|
nsINode* aNode,
|
||||||
|
PRInt32 aNodeOffset,
|
||||||
|
PRUint32* aNativeOffset)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(aNativeOffset, "param is invalid");
|
NS_ASSERTION(aNativeOffset, "param is invalid");
|
||||||
|
|
||||||
|
@ -536,16 +696,12 @@ nsQueryContentEventHandler::GetFlatTextOffsetOfRange(nsIRange* aRange,
|
||||||
NS_ENSURE_TRUE(prev, NS_ERROR_OUT_OF_MEMORY);
|
NS_ENSURE_TRUE(prev, NS_ERROR_OUT_OF_MEMORY);
|
||||||
nsCOMPtr<nsIDOMRange> domPrev(do_QueryInterface(prev));
|
nsCOMPtr<nsIDOMRange> domPrev(do_QueryInterface(prev));
|
||||||
NS_ASSERTION(domPrev, "nsRange doesn't have nsIDOMRange??");
|
NS_ASSERTION(domPrev, "nsRange doesn't have nsIDOMRange??");
|
||||||
nsCOMPtr<nsIDOMNode> rootDOMNode(do_QueryInterface(mRootContent));
|
nsCOMPtr<nsIDOMNode> rootDOMNode(do_QueryInterface(aRootContent));
|
||||||
domPrev->SetStart(rootDOMNode, 0);
|
domPrev->SetStart(rootDOMNode, 0);
|
||||||
|
|
||||||
nsINode* startNode = aRange->GetStartParent();
|
nsCOMPtr<nsIDOMNode> startDOMNode(do_QueryInterface(aNode));
|
||||||
NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
|
|
||||||
|
|
||||||
PRInt32 startOffset = aRange->StartOffset();
|
|
||||||
nsCOMPtr<nsIDOMNode> startDOMNode(do_QueryInterface(startNode));
|
|
||||||
NS_ASSERTION(startDOMNode, "startNode doesn't have nsIDOMNode");
|
NS_ASSERTION(startDOMNode, "startNode doesn't have nsIDOMNode");
|
||||||
domPrev->SetEnd(startDOMNode, startOffset);
|
domPrev->SetEnd(startDOMNode, aNodeOffset);
|
||||||
|
|
||||||
nsAutoString prevStr;
|
nsAutoString prevStr;
|
||||||
nsresult rv = GenerateFlatTextContent(prev, prevStr);
|
nsresult rv = GenerateFlatTextContent(prev, prevStr);
|
||||||
|
@ -555,9 +711,21 @@ nsQueryContentEventHandler::GetFlatTextOffsetOfRange(nsIRange* aRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsQueryContentEventHandler::GetStartFrameAndOffset(nsIRange* aRange,
|
nsContentEventHandler::GetFlatTextOffsetOfRange(nsIContent* aRootContent,
|
||||||
nsIFrame** aFrame,
|
nsIRange* aRange,
|
||||||
PRInt32* aOffsetInFrame)
|
PRUint32* aNativeOffset)
|
||||||
|
{
|
||||||
|
nsINode* startNode = aRange->GetStartParent();
|
||||||
|
NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
|
||||||
|
PRInt32 startOffset = aRange->StartOffset();
|
||||||
|
return GetFlatTextOffsetOfRange(aRootContent, startNode, startOffset,
|
||||||
|
aNativeOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsContentEventHandler::GetStartFrameAndOffset(nsIRange* aRange,
|
||||||
|
nsIFrame** aFrame,
|
||||||
|
PRInt32* aOffsetInFrame)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(aRange && aFrame && aOffsetInFrame, "params are invalid");
|
NS_ASSERTION(aRange && aFrame && aOffsetInFrame, "params are invalid");
|
||||||
|
|
||||||
|
@ -577,8 +745,8 @@ nsQueryContentEventHandler::GetStartFrameAndOffset(nsIRange* aRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsQueryContentEventHandler::ConvertToRootViewRelativeOffset(nsIFrame* aFrame,
|
nsContentEventHandler::ConvertToRootViewRelativeOffset(nsIFrame* aFrame,
|
||||||
nsRect& aRect)
|
nsRect& aRect)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(aFrame, "aFrame must not be null");
|
NS_ASSERTION(aFrame, "aFrame must not be null");
|
||||||
|
|
||||||
|
@ -590,3 +758,86 @@ nsQueryContentEventHandler::ConvertToRootViewRelativeOffset(nsIFrame* aFrame,
|
||||||
aRect += posInView + view->GetOffsetTo(nsnull);
|
aRect += posInView + view->GetOffsetTo(nsnull);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void AdjustRangeForSelection(nsIContent* aRoot,
|
||||||
|
nsINode** aNode,
|
||||||
|
PRInt32* aOffset)
|
||||||
|
{
|
||||||
|
nsINode* node = *aNode;
|
||||||
|
PRInt32 offset = *aOffset;
|
||||||
|
if (aRoot != node && node->GetParent() &&
|
||||||
|
!node->IsNodeOfType(nsINode::eTEXT)) {
|
||||||
|
node = node->GetParent();
|
||||||
|
offset = node->IndexOf(*aNode) + (offset ? 1 : 0);
|
||||||
|
}
|
||||||
|
nsINode* brNode = node->GetChildAt(offset - 1);
|
||||||
|
while (brNode && brNode->IsNodeOfType(nsINode::eHTML)) {
|
||||||
|
nsIContent* brContent = static_cast<nsIContent*>(brNode);
|
||||||
|
if (brContent->Tag() != nsGkAtoms::br || IsContentBR(brContent))
|
||||||
|
break;
|
||||||
|
brNode = node->GetChildAt(--offset - 1);
|
||||||
|
}
|
||||||
|
*aNode = node;
|
||||||
|
*aOffset = PR_MAX(offset, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsContentEventHandler::OnSelectionEvent(nsSelectionEvent* aEvent)
|
||||||
|
{
|
||||||
|
aEvent->mSucceeded = PR_FALSE;
|
||||||
|
|
||||||
|
// Get selection to manipulate
|
||||||
|
nsCOMPtr<nsISelection> sel;
|
||||||
|
nsresult rv = nsIMEStateManager::
|
||||||
|
GetFocusSelectionAndRoot(getter_AddRefs(sel),
|
||||||
|
getter_AddRefs(mRootContent));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// Get range from offset and length
|
||||||
|
nsRefPtr<nsRange> range = new nsRange();
|
||||||
|
NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
rv = SetRangeFromFlatTextOffset(range, aEvent->mOffset,
|
||||||
|
aEvent->mLength, PR_TRUE);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsINode* startNode = range->GetStartParent();
|
||||||
|
nsINode* endNode = range->GetEndParent();
|
||||||
|
PRInt32 startOffset = range->StartOffset();
|
||||||
|
PRInt32 endOffset = range->EndOffset();
|
||||||
|
AdjustRangeForSelection(mRootContent, &startNode, &startOffset);
|
||||||
|
AdjustRangeForSelection(mRootContent, &endNode, &endOffset);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMNode> startDomNode(do_QueryInterface(startNode));
|
||||||
|
nsCOMPtr<nsIDOMNode> endDomNode(do_QueryInterface(endNode));
|
||||||
|
NS_ENSURE_TRUE(startDomNode && endDomNode, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(sel);
|
||||||
|
NS_ENSURE_TRUE(selPrivate, NS_ERROR_UNEXPECTED);
|
||||||
|
selPrivate->StartBatchChanges();
|
||||||
|
|
||||||
|
// Clear selection first before setting
|
||||||
|
rv = sel->RemoveAllRanges();
|
||||||
|
// Need to call EndBatchChanges at the end even if call failed
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
if (aEvent->mReversed) {
|
||||||
|
rv = sel->Collapse(endDomNode, endOffset);
|
||||||
|
} else {
|
||||||
|
rv = sel->Collapse(startDomNode, startOffset);
|
||||||
|
}
|
||||||
|
if (NS_SUCCEEDED(rv) &&
|
||||||
|
(startDomNode != endDomNode || startOffset != endOffset)) {
|
||||||
|
if (aEvent->mReversed) {
|
||||||
|
rv = sel->Extend(startDomNode, startOffset);
|
||||||
|
} else {
|
||||||
|
rv = sel->Extend(endDomNode, endOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selPrivate->EndBatchChanges();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsCOMPtr<nsISelection2>(do_QueryInterface(sel))->ScrollIntoView(
|
||||||
|
nsISelectionController::SELECTION_FOCUS_REGION, PR_FALSE, -1, -1);
|
||||||
|
aEvent->mSucceeded = PR_TRUE;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
|
@ -21,6 +21,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Masayuki Nakano <masayuki@d-toybox.com>
|
* Masayuki Nakano <masayuki@d-toybox.com>
|
||||||
|
* Ningjie Chen <chenn@email.uc.edu>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* 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"),
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
@ -36,8 +37,8 @@
|
||||||
*
|
*
|
||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
#ifndef nsQueryContentEventHandler_h__
|
#ifndef nsContentEventHandler_h__
|
||||||
#define nsQueryContentEventHandler_h__
|
#define nsContentEventHandler_h__
|
||||||
|
|
||||||
#include "nscore.h"
|
#include "nscore.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
|
@ -50,29 +51,36 @@
|
||||||
class nsPresContext;
|
class nsPresContext;
|
||||||
class nsIPresShell;
|
class nsIPresShell;
|
||||||
class nsQueryContentEvent;
|
class nsQueryContentEvent;
|
||||||
|
class nsSelectionEvent;
|
||||||
class nsCaret;
|
class nsCaret;
|
||||||
struct nsRect;
|
struct nsRect;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Query Content Event Handler
|
* Query Content Event Handler
|
||||||
* nsQueryContentEventHandler is a helper class for nsEventStateManager.
|
* nsContentEventHandler is a helper class for nsEventStateManager.
|
||||||
* The platforms request some content informations, e.g., the selected text,
|
* The platforms request some content informations, e.g., the selected text,
|
||||||
* the offset of the selected text and the text for specified range.
|
* the offset of the selected text and the text for specified range.
|
||||||
* This class answers to NS_QUERY_* events from actual contents.
|
* This class answers to NS_QUERY_* events from actual contents.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class NS_STACK_CLASS nsQueryContentEventHandler {
|
class NS_STACK_CLASS nsContentEventHandler {
|
||||||
public:
|
public:
|
||||||
nsQueryContentEventHandler(nsPresContext *aPresContext);
|
nsContentEventHandler(nsPresContext *aPresContext);
|
||||||
|
|
||||||
// NS_QUERY_SELECTED_TEXT event handler
|
// NS_QUERY_SELECTED_TEXT event handler
|
||||||
nsresult OnQuerySelectedText(nsQueryContentEvent* aEvent);
|
nsresult OnQuerySelectedText(nsQueryContentEvent* aEvent);
|
||||||
// NS_QUERY_TEXT_CONTENT event handler
|
// NS_QUERY_TEXT_CONTENT event handler
|
||||||
nsresult OnQueryTextContent(nsQueryContentEvent* aEvent);
|
nsresult OnQueryTextContent(nsQueryContentEvent* aEvent);
|
||||||
// NS_QUERY_CHARACTER_RECT event handler
|
|
||||||
nsresult OnQueryCharacterRect(nsQueryContentEvent* aEvent);
|
|
||||||
// NS_QUERY_CARET_RECT event handler
|
// NS_QUERY_CARET_RECT event handler
|
||||||
nsresult OnQueryCaretRect(nsQueryContentEvent* aEvent);
|
nsresult OnQueryCaretRect(nsQueryContentEvent* aEvent);
|
||||||
|
// NS_QUERY_TEXT_RECT event handler
|
||||||
|
nsresult OnQueryTextRect(nsQueryContentEvent* aEvent);
|
||||||
|
// NS_QUERY_EDITOR_RECT event handler
|
||||||
|
nsresult OnQueryEditorRect(nsQueryContentEvent* aEvent);
|
||||||
|
|
||||||
|
// NS_SELECTION_* event
|
||||||
|
nsresult OnSelectionEvent(nsSelectionEvent* aEvent);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsPresContext* mPresContext;
|
nsPresContext* mPresContext;
|
||||||
nsIPresShell* mPresShell;
|
nsIPresShell* mPresShell;
|
||||||
|
@ -82,11 +90,19 @@ protected:
|
||||||
|
|
||||||
nsresult Init(nsQueryContentEvent* aEvent);
|
nsresult Init(nsQueryContentEvent* aEvent);
|
||||||
|
|
||||||
|
public:
|
||||||
// FlatText means the text that is generated from DOM tree. The BR elements
|
// FlatText means the text that is generated from DOM tree. The BR elements
|
||||||
// are replaced to native linefeeds. Other elements are ignored.
|
// are replaced to native linefeeds. Other elements are ignored.
|
||||||
|
|
||||||
// Generate the FlatText from DOM range.
|
// Get the offset in FlatText of the range. (also used by nsIMEStateManager)
|
||||||
nsresult GenerateFlatTextContent(nsIRange* aRange, nsAFlatString& aString);
|
static nsresult GetFlatTextOffsetOfRange(nsIContent* aRootContent,
|
||||||
|
nsINode* aNode,
|
||||||
|
PRInt32 aNodeOffset,
|
||||||
|
PRUint32* aOffset);
|
||||||
|
static nsresult GetFlatTextOffsetOfRange(nsIContent* aRootContent,
|
||||||
|
nsIRange* aRange,
|
||||||
|
PRUint32* aOffset);
|
||||||
|
protected:
|
||||||
// Make the DOM range from the offset of FlatText and the text length.
|
// Make the DOM range from the offset of FlatText and the text length.
|
||||||
// If aExpandToClusterBoundaries is true, the start offset and the end one are
|
// If aExpandToClusterBoundaries is true, the start offset and the end one are
|
||||||
// expanded to nearest cluster boundaries.
|
// expanded to nearest cluster boundaries.
|
||||||
|
@ -94,22 +110,18 @@ protected:
|
||||||
PRUint32 aNativeOffset,
|
PRUint32 aNativeOffset,
|
||||||
PRUint32 aNativeLength,
|
PRUint32 aNativeLength,
|
||||||
PRBool aExpandToClusterBoundaries);
|
PRBool aExpandToClusterBoundaries);
|
||||||
// Get the offset in FlatText of the range.
|
|
||||||
nsresult GetFlatTextOffsetOfRange(nsIRange* aRange, PRUint32* aOffset);
|
|
||||||
// Find the first textframe for the range, and get the start offset in
|
// Find the first textframe for the range, and get the start offset in
|
||||||
// the frame.
|
// the frame.
|
||||||
nsresult GetStartFrameAndOffset(nsIRange* aRange,
|
nsresult GetStartFrameAndOffset(nsIRange* aRange,
|
||||||
nsIFrame** aFrame, PRInt32* aOffsetInFrame);
|
nsIFrame** aFrame,
|
||||||
|
PRInt32* aOffsetInFrame);
|
||||||
// Convert the frame relative offset to the root view relative offset.
|
// Convert the frame relative offset to the root view relative offset.
|
||||||
nsresult ConvertToRootViewRelativeOffset(nsIFrame* aFrame, nsRect& aRect);
|
nsresult ConvertToRootViewRelativeOffset(nsIFrame* aFrame,
|
||||||
// The helper for OnQueryCharacterRect/OnQueryCaretRect.
|
nsRect& aRect);
|
||||||
// Don't call for another event.
|
|
||||||
nsresult QueryRectFor(nsQueryContentEvent* aEvent, nsIRange* aRange,
|
|
||||||
nsCaret* aCaret);
|
|
||||||
// Expand aXPOffset to the nearest offset in cluster boundary. aForward is
|
// Expand aXPOffset to the nearest offset in cluster boundary. aForward is
|
||||||
// true, it is expanded to forward.
|
// true, it is expanded to forward.
|
||||||
nsresult ExpandToClusterBoundary(nsIContent* aContent, PRBool aForward,
|
nsresult ExpandToClusterBoundary(nsIContent* aContent, PRBool aForward,
|
||||||
PRUint32* aXPOffset);
|
PRUint32* aXPOffset);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // nsQueryContentEventHandler_h__
|
#endif // nsContentEventHandler_h__
|
|
@ -28,6 +28,7 @@
|
||||||
* Ginn Chen <ginn.chen@sun.com>
|
* Ginn Chen <ginn.chen@sun.com>
|
||||||
* Simon Bünzli <zeniko@gmail.com>
|
* Simon Bünzli <zeniko@gmail.com>
|
||||||
* Ehsan Akhgari <ehsan.akhgari@gmail.com>
|
* Ehsan Akhgari <ehsan.akhgari@gmail.com>
|
||||||
|
* Ningjie Chen <chenn@email.uc.edu>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* 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"),
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
@ -47,7 +48,7 @@
|
||||||
#include "nsEventStateManager.h"
|
#include "nsEventStateManager.h"
|
||||||
#include "nsEventListenerManager.h"
|
#include "nsEventListenerManager.h"
|
||||||
#include "nsIMEStateManager.h"
|
#include "nsIMEStateManager.h"
|
||||||
#include "nsQueryContentEventHandler.h"
|
#include "nsContentEventHandler.h"
|
||||||
#include "nsIContent.h"
|
#include "nsIContent.h"
|
||||||
#include "nsINodeInfo.h"
|
#include "nsINodeInfo.h"
|
||||||
#include "nsIDocument.h"
|
#include "nsIDocument.h"
|
||||||
|
@ -959,6 +960,8 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (mDocument) {
|
if (mDocument) {
|
||||||
|
nsIMEStateManager::OnTextStateBlur(mPresContext, mCurrentFocus);
|
||||||
|
|
||||||
if (gLastFocusedDocument && gLastFocusedPresContextWeak) {
|
if (gLastFocusedDocument && gLastFocusedPresContextWeak) {
|
||||||
nsCOMPtr<nsPIDOMWindow> ourWindow =
|
nsCOMPtr<nsPIDOMWindow> ourWindow =
|
||||||
gLastFocusedDocument->GetWindow();
|
gLastFocusedDocument->GetWindow();
|
||||||
|
@ -1076,6 +1079,8 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||||
NS_IF_RELEASE(gLastFocusedContent);
|
NS_IF_RELEASE(gLastFocusedContent);
|
||||||
gLastFocusedContent = mCurrentFocus;
|
gLastFocusedContent = mCurrentFocus;
|
||||||
NS_IF_ADDREF(gLastFocusedContent);
|
NS_IF_ADDREF(gLastFocusedContent);
|
||||||
|
|
||||||
|
nsIMEStateManager::OnTextStateFocus(mPresContext, mCurrentFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to keep the focus controllers and the globals in synch
|
// Try to keep the focus controllers and the globals in synch
|
||||||
|
@ -1147,6 +1152,8 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||||
NS_RELEASE(gLastFocusedContent);
|
NS_RELEASE(gLastFocusedContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsIMEStateManager::OnTextStateBlur(nsnull, nsnull);
|
||||||
|
|
||||||
// Now fire blurs. We fire a blur on the focused document, element,
|
// Now fire blurs. We fire a blur on the focused document, element,
|
||||||
// and window.
|
// and window.
|
||||||
|
|
||||||
|
@ -1320,6 +1327,8 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||||
if (focusController)
|
if (focusController)
|
||||||
focusController->SetSuppressFocus(PR_TRUE, "Deactivate Suppression");
|
focusController->SetSuppressFocus(PR_TRUE, "Deactivate Suppression");
|
||||||
|
|
||||||
|
nsIMEStateManager::OnTextStateBlur(nsnull, nsnull);
|
||||||
|
|
||||||
// Now fire blurs. Blur the content, then the document, then the window.
|
// Now fire blurs. Blur the content, then the document, then the window.
|
||||||
|
|
||||||
if (gLastFocusedDocument && gLastFocusedDocument == mDocument &&
|
if (gLastFocusedDocument && gLastFocusedDocument == mDocument &&
|
||||||
|
@ -1494,28 +1503,40 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||||
break;
|
break;
|
||||||
case NS_QUERY_SELECTED_TEXT:
|
case NS_QUERY_SELECTED_TEXT:
|
||||||
{
|
{
|
||||||
nsQueryContentEventHandler handler(mPresContext);
|
nsContentEventHandler handler(mPresContext);
|
||||||
handler.OnQuerySelectedText((nsQueryContentEvent*)aEvent);
|
handler.OnQuerySelectedText((nsQueryContentEvent*)aEvent);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NS_QUERY_TEXT_CONTENT:
|
case NS_QUERY_TEXT_CONTENT:
|
||||||
{
|
{
|
||||||
nsQueryContentEventHandler handler(mPresContext);
|
nsContentEventHandler handler(mPresContext);
|
||||||
handler.OnQueryTextContent((nsQueryContentEvent*)aEvent);
|
handler.OnQueryTextContent((nsQueryContentEvent*)aEvent);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NS_QUERY_CHARACTER_RECT:
|
|
||||||
{
|
|
||||||
nsQueryContentEventHandler handler(mPresContext);
|
|
||||||
handler.OnQueryCharacterRect((nsQueryContentEvent*)aEvent);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NS_QUERY_CARET_RECT:
|
case NS_QUERY_CARET_RECT:
|
||||||
{
|
{
|
||||||
nsQueryContentEventHandler handler(mPresContext);
|
nsContentEventHandler handler(mPresContext);
|
||||||
handler.OnQueryCaretRect((nsQueryContentEvent*)aEvent);
|
handler.OnQueryCaretRect((nsQueryContentEvent*)aEvent);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NS_QUERY_TEXT_RECT:
|
||||||
|
{
|
||||||
|
nsContentEventHandler handler(mPresContext);
|
||||||
|
handler.OnQueryTextRect((nsQueryContentEvent*)aEvent);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NS_QUERY_EDITOR_RECT:
|
||||||
|
{
|
||||||
|
nsContentEventHandler handler(mPresContext);
|
||||||
|
handler.OnQueryEditorRect((nsQueryContentEvent*)aEvent);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NS_SELECTION_SET:
|
||||||
|
{
|
||||||
|
nsContentEventHandler handler(mPresContext);
|
||||||
|
handler.OnSelectionEvent((nsSelectionEvent*)aEvent);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -5031,6 +5052,8 @@ nsEventStateManager::SendFocusBlur(nsPresContext* aPresContext,
|
||||||
// Track the old focus controller if any focus suppressions is used on it.
|
// Track the old focus controller if any focus suppressions is used on it.
|
||||||
nsFocusSuppressor oldFocusSuppressor;
|
nsFocusSuppressor oldFocusSuppressor;
|
||||||
|
|
||||||
|
nsIMEStateManager::OnTextStateBlur(aPresContext, aContent);
|
||||||
|
|
||||||
if (nsnull != gLastFocusedPresContextWeak) {
|
if (nsnull != gLastFocusedPresContextWeak) {
|
||||||
|
|
||||||
nsCOMPtr<nsIContent> focusAfterBlur;
|
nsCOMPtr<nsIContent> focusAfterBlur;
|
||||||
|
@ -5261,6 +5284,8 @@ nsEventStateManager::SendFocusBlur(nsPresContext* aPresContext,
|
||||||
if (clearFirstFocusEvent) {
|
if (clearFirstFocusEvent) {
|
||||||
mFirstFocusEvent = nsnull;
|
mFirstFocusEvent = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsIMEStateManager::OnTextStateFocus(mPresContext, mCurrentFocus);
|
||||||
} else if (!aContent) {
|
} else if (!aContent) {
|
||||||
//fire focus on document even if the content isn't focusable (ie. text)
|
//fire focus on document even if the content isn't focusable (ie. text)
|
||||||
//see bugzilla bug 93521
|
//see bugzilla bug 93521
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Masayuki Nakano <masayuki@d-toybox.com>
|
* Masayuki Nakano <masayuki@d-toybox.com>
|
||||||
|
* Ningjie Chen <chenn@email.uc.edu>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* 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"),
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
@ -53,6 +54,16 @@
|
||||||
#include "nsIFocusController.h"
|
#include "nsIFocusController.h"
|
||||||
#include "nsIDOMWindow.h"
|
#include "nsIDOMWindow.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
|
#include "nsINode.h"
|
||||||
|
#include "nsIFrame.h"
|
||||||
|
#include "nsRange.h"
|
||||||
|
#include "nsIDOMRange.h"
|
||||||
|
#include "nsISelection.h"
|
||||||
|
#include "nsISelectionPrivate.h"
|
||||||
|
#include "nsISelectionListener.h"
|
||||||
|
#include "nsISelectionController.h"
|
||||||
|
#include "nsIMutationObserver.h"
|
||||||
|
#include "nsContentEventHandler.h"
|
||||||
|
|
||||||
/******************************************************************/
|
/******************************************************************/
|
||||||
/* nsIMEStateManager */
|
/* nsIMEStateManager */
|
||||||
|
@ -63,6 +74,8 @@ nsPresContext* nsIMEStateManager::sPresContext = nsnull;
|
||||||
nsPIDOMWindow* nsIMEStateManager::sActiveWindow = nsnull;
|
nsPIDOMWindow* nsIMEStateManager::sActiveWindow = nsnull;
|
||||||
PRBool nsIMEStateManager::sInstalledMenuKeyboardListener = PR_FALSE;
|
PRBool nsIMEStateManager::sInstalledMenuKeyboardListener = PR_FALSE;
|
||||||
|
|
||||||
|
nsTextStateManager* nsIMEStateManager::sTextStateObserver = nsnull;
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsIMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
nsIMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
||||||
{
|
{
|
||||||
|
@ -71,6 +84,7 @@ nsIMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
sContent = nsnull;
|
sContent = nsnull;
|
||||||
sPresContext = nsnull;
|
sPresContext = nsnull;
|
||||||
|
OnTextStateBlur(nsnull, nsnull);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,3 +283,301 @@ nsIMEStateManager::GetWidget(nsPresContext* aPresContext)
|
||||||
return widget;
|
return widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// nsTextStateManager notifies widget of any text and selection changes
|
||||||
|
// in the currently focused editor
|
||||||
|
// sTextStateObserver points to the currently active nsTextStateManager
|
||||||
|
// sTextStateObserver is null if there is no focused editor
|
||||||
|
|
||||||
|
class nsTextStateManager : public nsISelectionListener,
|
||||||
|
public nsStubMutationObserver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
nsTextStateManager();
|
||||||
|
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_DECL_NSISELECTIONLISTENER
|
||||||
|
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
|
||||||
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||||
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||||
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||||
|
|
||||||
|
nsresult Init(nsIWidget* aWidget,
|
||||||
|
nsPresContext* aPresContext,
|
||||||
|
nsINode* aNode);
|
||||||
|
void Destroy(void);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIWidget> mWidget;
|
||||||
|
nsCOMPtr<nsISelection> mSel;
|
||||||
|
nsCOMPtr<nsIContent> mRootContent;
|
||||||
|
nsCOMPtr<nsINode> mEditableNode;
|
||||||
|
PRBool mDestroying;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void NotifyContentAdded(nsINode* aContainer, PRInt32 aStart, PRInt32 aEnd);
|
||||||
|
};
|
||||||
|
|
||||||
|
nsTextStateManager::nsTextStateManager()
|
||||||
|
{
|
||||||
|
mDestroying = PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsTextStateManager::Init(nsIWidget* aWidget,
|
||||||
|
nsPresContext* aPresContext,
|
||||||
|
nsINode* aNode)
|
||||||
|
{
|
||||||
|
mWidget = aWidget;
|
||||||
|
|
||||||
|
nsIPresShell* presShell = aPresContext->PresShell();
|
||||||
|
|
||||||
|
// get selection and root content
|
||||||
|
nsCOMPtr<nsISelectionController> selCon;
|
||||||
|
if (aNode->IsNodeOfType(nsINode::eCONTENT)) {
|
||||||
|
nsIFrame* frame = presShell->GetPrimaryFrameFor(
|
||||||
|
static_cast<nsIContent*>(aNode));
|
||||||
|
NS_ENSURE_TRUE(frame, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
frame->GetSelectionController(aPresContext,
|
||||||
|
getter_AddRefs(selCon));
|
||||||
|
} else {
|
||||||
|
// aNode is a document
|
||||||
|
selCon = do_QueryInterface(presShell);
|
||||||
|
}
|
||||||
|
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
|
nsCOMPtr<nsISelection> sel;
|
||||||
|
nsresult rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
|
||||||
|
getter_AddRefs(sel));
|
||||||
|
NS_ENSURE_TRUE(sel, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMRange> selDomRange;
|
||||||
|
rv = sel->GetRangeAt(0, getter_AddRefs(selDomRange));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
nsCOMPtr<nsIRange> selRange(do_QueryInterface(selDomRange));
|
||||||
|
NS_ENSURE_TRUE(selRange && selRange->GetStartParent(), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
mRootContent = selRange->GetStartParent()->
|
||||||
|
GetSelectionRootContent(presShell);
|
||||||
|
|
||||||
|
// add text change observer
|
||||||
|
mRootContent->AddMutationObserver(this);
|
||||||
|
|
||||||
|
// add selection change listener
|
||||||
|
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(sel));
|
||||||
|
NS_ENSURE_TRUE(selPrivate, NS_ERROR_UNEXPECTED);
|
||||||
|
rv = selPrivate->AddSelectionListener(this);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
mSel = sel;
|
||||||
|
|
||||||
|
mEditableNode = aNode;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsTextStateManager::Destroy(void)
|
||||||
|
{
|
||||||
|
if (mSel) {
|
||||||
|
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSel));
|
||||||
|
if (selPrivate)
|
||||||
|
selPrivate->RemoveSelectionListener(this);
|
||||||
|
mSel = nsnull;
|
||||||
|
}
|
||||||
|
if (mRootContent) {
|
||||||
|
mRootContent->RemoveMutationObserver(this);
|
||||||
|
mRootContent = nsnull;
|
||||||
|
}
|
||||||
|
mEditableNode = nsnull;
|
||||||
|
mWidget = nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS2(nsTextStateManager,
|
||||||
|
nsIMutationObserver,
|
||||||
|
nsISelectionListener)
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsTextStateManager::NotifySelectionChanged(nsIDOMDocument* aDoc,
|
||||||
|
nsISelection* aSel,
|
||||||
|
PRInt16 aReason)
|
||||||
|
{
|
||||||
|
PRInt32 count = 0;
|
||||||
|
nsresult rv = aSel->GetRangeCount(&count);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
if (count > 0) {
|
||||||
|
mWidget->OnIMESelectionChange();
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsTextStateManager::CharacterDataChanged(nsIDocument* aDocument,
|
||||||
|
nsIContent* aContent,
|
||||||
|
CharacterDataChangeInfo* aInfo)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
|
||||||
|
"character data changed for non-text node");
|
||||||
|
|
||||||
|
PRUint32 offset = 0;
|
||||||
|
// get offsets of change and fire notification
|
||||||
|
if (NS_FAILED(nsContentEventHandler::GetFlatTextOffsetOfRange(
|
||||||
|
mRootContent, aContent, aInfo->mChangeStart, &offset)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
PRUint32 oldEnd = offset + aInfo->mChangeEnd - aInfo->mChangeStart;
|
||||||
|
PRUint32 newEnd = offset + aInfo->mReplaceLength;
|
||||||
|
mWidget->OnIMETextChange(offset, oldEnd, newEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsTextStateManager::NotifyContentAdded(nsINode* aContainer,
|
||||||
|
PRInt32 aStartIndex,
|
||||||
|
PRInt32 aEndIndex)
|
||||||
|
{
|
||||||
|
PRUint32 offset = 0, newOffset = 0;
|
||||||
|
if (NS_FAILED(nsContentEventHandler::GetFlatTextOffsetOfRange(
|
||||||
|
mRootContent, aContainer, aStartIndex, &offset)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// get offset at the end of the last added node
|
||||||
|
if (NS_FAILED(nsContentEventHandler::GetFlatTextOffsetOfRange(
|
||||||
|
aContainer->GetChildAt(aStartIndex),
|
||||||
|
aContainer, aEndIndex, &newOffset)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// fire notification
|
||||||
|
if (newOffset)
|
||||||
|
mWidget->OnIMETextChange(offset, offset, offset + newOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsTextStateManager::ContentAppended(nsIDocument* aDocument,
|
||||||
|
nsIContent* aContainer,
|
||||||
|
PRInt32 aNewIndexInContainer)
|
||||||
|
{
|
||||||
|
NotifyContentAdded(aContainer, aNewIndexInContainer,
|
||||||
|
aContainer->GetChildCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsTextStateManager::ContentInserted(nsIDocument* aDocument,
|
||||||
|
nsIContent* aContainer,
|
||||||
|
nsIContent* aChild,
|
||||||
|
PRInt32 aIndexInContainer)
|
||||||
|
{
|
||||||
|
NotifyContentAdded(NODE_FROM(aContainer, aDocument),
|
||||||
|
aIndexInContainer, aIndexInContainer + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsTextStateManager::ContentRemoved(nsIDocument* aDocument,
|
||||||
|
nsIContent* aContainer,
|
||||||
|
nsIContent* aChild,
|
||||||
|
PRInt32 aIndexInContainer)
|
||||||
|
{
|
||||||
|
PRUint32 offset = 0, childOffset = 1;
|
||||||
|
if (NS_FAILED(nsContentEventHandler::GetFlatTextOffsetOfRange(
|
||||||
|
mRootContent, NODE_FROM(aContainer, aDocument),
|
||||||
|
aIndexInContainer, &offset)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// get offset at the end of the deleted node
|
||||||
|
if (aChild->IsNodeOfType(nsINode::eTEXT))
|
||||||
|
childOffset = aChild->TextLength();
|
||||||
|
else if (0 < aChild->GetChildCount())
|
||||||
|
childOffset = aChild->GetChildCount();
|
||||||
|
|
||||||
|
if (NS_FAILED(nsContentEventHandler::GetFlatTextOffsetOfRange(
|
||||||
|
aChild, aChild, childOffset, &childOffset)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// fire notification
|
||||||
|
if (childOffset)
|
||||||
|
mWidget->OnIMETextChange(offset, offset + childOffset, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static nsINode* GetRootEditableNode(nsPresContext* aPresContext,
|
||||||
|
nsIContent* aContent)
|
||||||
|
{
|
||||||
|
if (aContent) {
|
||||||
|
nsINode* root = nsnull;
|
||||||
|
nsINode* node = aContent;
|
||||||
|
while (node && node->IsEditable()) {
|
||||||
|
root = node;
|
||||||
|
node = node->GetParent();
|
||||||
|
}
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
if (aPresContext) {
|
||||||
|
nsIDocument* document = aPresContext->Document();
|
||||||
|
if (document && document->IsEditable())
|
||||||
|
return document;
|
||||||
|
}
|
||||||
|
return nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsIMEStateManager::OnTextStateBlur(nsPresContext* aPresContext,
|
||||||
|
nsIContent* aContent)
|
||||||
|
{
|
||||||
|
if (!sTextStateObserver || sTextStateObserver->mDestroying ||
|
||||||
|
sTextStateObserver->mEditableNode ==
|
||||||
|
GetRootEditableNode(aPresContext, aContent))
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
sTextStateObserver->mDestroying = PR_TRUE;
|
||||||
|
sTextStateObserver->mWidget->OnIMEFocusChange(PR_FALSE);
|
||||||
|
sTextStateObserver->Destroy();
|
||||||
|
NS_RELEASE(sTextStateObserver);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsIMEStateManager::OnTextStateFocus(nsPresContext* aPresContext,
|
||||||
|
nsIContent* aContent)
|
||||||
|
{
|
||||||
|
if (sTextStateObserver) return NS_OK;
|
||||||
|
|
||||||
|
nsINode *editableNode = GetRootEditableNode(aPresContext, aContent);
|
||||||
|
if (!editableNode) return NS_OK;
|
||||||
|
|
||||||
|
nsIViewManager* vm = aPresContext->GetViewManager();
|
||||||
|
NS_ENSURE_TRUE(vm, NS_ERROR_NOT_AVAILABLE);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIWidget> widget;
|
||||||
|
nsresult rv = vm->GetWidget(getter_AddRefs(widget));
|
||||||
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_NOT_AVAILABLE);
|
||||||
|
|
||||||
|
rv = widget->OnIMEFocusChange(PR_TRUE);
|
||||||
|
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||||
|
|
||||||
|
// OnIMEFocusChange may cause focus and sTextStateObserver to change
|
||||||
|
// In that case return and keep the current sTextStateObserver
|
||||||
|
NS_ENSURE_TRUE(!sTextStateObserver, NS_OK);
|
||||||
|
|
||||||
|
sTextStateObserver = new nsTextStateManager();
|
||||||
|
NS_ENSURE_TRUE(sTextStateObserver, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
NS_ADDREF(sTextStateObserver);
|
||||||
|
rv = sTextStateObserver->Init(widget, aPresContext, editableNode);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
sTextStateObserver->mDestroying = PR_TRUE;
|
||||||
|
sTextStateObserver->Destroy();
|
||||||
|
NS_RELEASE(sTextStateObserver);
|
||||||
|
widget->OnIMEFocusChange(PR_FALSE);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsIMEStateManager::GetFocusSelectionAndRoot(nsISelection** aSel,
|
||||||
|
nsIContent** aRoot)
|
||||||
|
{
|
||||||
|
if (!sTextStateObserver || !sTextStateObserver->mEditableNode)
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
||||||
|
NS_ASSERTION(sTextStateObserver->mSel && sTextStateObserver->mRootContent,
|
||||||
|
"uninitialized text state observer");
|
||||||
|
NS_ADDREF(*aSel = sTextStateObserver->mSel);
|
||||||
|
NS_ADDREF(*aRoot = sTextStateObserver->mRootContent);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
|
@ -40,12 +40,15 @@
|
||||||
#define nsIMEStateManager_h__
|
#define nsIMEStateManager_h__
|
||||||
|
|
||||||
#include "nscore.h"
|
#include "nscore.h"
|
||||||
|
#include "nsGUIEvent.h"
|
||||||
|
|
||||||
class nsIContent;
|
class nsIContent;
|
||||||
class nsPIDOMWindow;
|
class nsPIDOMWindow;
|
||||||
class nsPresContext;
|
class nsPresContext;
|
||||||
class nsIWidget;
|
class nsIWidget;
|
||||||
class nsIFocusController;
|
class nsIFocusController;
|
||||||
|
class nsTextStateManager;
|
||||||
|
class nsISelection;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IME state manager
|
* IME state manager
|
||||||
|
@ -62,6 +65,25 @@ public:
|
||||||
static nsresult OnActivate(nsPresContext* aPresContext);
|
static nsresult OnActivate(nsPresContext* aPresContext);
|
||||||
static nsresult OnDeactivate(nsPresContext* aPresContext);
|
static nsresult OnDeactivate(nsPresContext* aPresContext);
|
||||||
static void OnInstalledMenuKeyboardListener(PRBool aInstalling);
|
static void OnInstalledMenuKeyboardListener(PRBool aInstalling);
|
||||||
|
|
||||||
|
// These two methods manage focus and selection/text observers.
|
||||||
|
// They are separate from OnChangeFocus above because this offers finer
|
||||||
|
// control compared to having the two methods incorporated into OnChangeFocus
|
||||||
|
|
||||||
|
// OnTextStateBlur should be called *before* NS_BLUR_CONTENT fires
|
||||||
|
// aPresContext is the nsPresContext receiving focus (not lost focus)
|
||||||
|
// aContent is the nsIContent receiving focus (not lost focus)
|
||||||
|
// aPresContext and/or aContent may be null
|
||||||
|
static nsresult OnTextStateBlur(nsPresContext* aPresContext,
|
||||||
|
nsIContent* aContent);
|
||||||
|
// OnTextStateFocus should be called *after* NS_FOCUS_CONTENT fires
|
||||||
|
// aPresContext is the nsPresContext receiving focus
|
||||||
|
// aContent is the nsIContent receiving focus
|
||||||
|
static nsresult OnTextStateFocus(nsPresContext* aPresContext,
|
||||||
|
nsIContent* aContent);
|
||||||
|
// Get the focused editor's selection and root
|
||||||
|
static nsresult GetFocusSelectionAndRoot(nsISelection** aSel,
|
||||||
|
nsIContent** aRoot);
|
||||||
protected:
|
protected:
|
||||||
static void SetIMEState(nsPresContext* aPresContext,
|
static void SetIMEState(nsPresContext* aPresContext,
|
||||||
PRUint32 aState,
|
PRUint32 aState,
|
||||||
|
@ -78,6 +100,8 @@ protected:
|
||||||
static nsPresContext* sPresContext;
|
static nsPresContext* sPresContext;
|
||||||
static nsPIDOMWindow* sActiveWindow;
|
static nsPIDOMWindow* sActiveWindow;
|
||||||
static PRBool sInstalledMenuKeyboardListener;
|
static PRBool sInstalledMenuKeyboardListener;
|
||||||
|
|
||||||
|
static nsTextStateManager* sTextStateObserver;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // nsIMEStateManager_h__
|
#endif // nsIMEStateManager_h__
|
||||||
|
|
|
@ -569,6 +569,13 @@ public:
|
||||||
|
|
||||||
static nsresult GetHashFromHrefString(const nsAString &aHref,
|
static nsresult GetHashFromHrefString(const nsAString &aHref,
|
||||||
nsAString& aHash);
|
nsAString& aHash);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locate an nsIEditor rooted at this content node, if there is one.
|
||||||
|
*/
|
||||||
|
NS_HIDDEN_(nsresult) GetEditor(nsIEditor** aEditor);
|
||||||
|
NS_HIDDEN_(nsresult) GetEditorInternal(nsIEditor** aEditor);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* Focus or blur the element. This is what you should call if you want to
|
* Focus or blur the element. This is what you should call if you want to
|
||||||
|
@ -728,12 +735,6 @@ protected:
|
||||||
*/
|
*/
|
||||||
NS_HIDDEN_(nsresult) GetURIListAttr(nsIAtom* aAttr, nsAString& aResult);
|
NS_HIDDEN_(nsresult) GetURIListAttr(nsIAtom* aAttr, nsAString& aResult);
|
||||||
|
|
||||||
/**
|
|
||||||
* Locate an nsIEditor rooted at this content node, if there is one.
|
|
||||||
*/
|
|
||||||
NS_HIDDEN_(nsresult) GetEditor(nsIEditor** aEditor);
|
|
||||||
NS_HIDDEN_(nsresult) GetEditorInternal(nsIEditor** aEditor);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locates the nsIEditor associated with this node. In general this is
|
* Locates the nsIEditor associated with this node. In general this is
|
||||||
* equivalent to GetEditorInternal(), but for designmode or contenteditable,
|
* equivalent to GetEditorInternal(), but for designmode or contenteditable,
|
||||||
|
|
|
@ -1542,6 +1542,9 @@ pref("intl.jis0208.map", "CP932");
|
||||||
// Switch the keyboard layout per window
|
// Switch the keyboard layout per window
|
||||||
pref("intl.keyboard.per_window_layout", false);
|
pref("intl.keyboard.per_window_layout", false);
|
||||||
|
|
||||||
|
// Enable/Disable TSF support
|
||||||
|
pref("intl.enable_tsf_support", false);
|
||||||
|
|
||||||
// See bug 448927, on topmost panel, some IMEs are not usable on Windows.
|
// See bug 448927, on topmost panel, some IMEs are not usable on Windows.
|
||||||
pref("ui.panel.default_level_parent", false);
|
pref("ui.panel.default_level_parent", false);
|
||||||
|
|
||||||
|
|
|
@ -1249,6 +1249,7 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS
|
||||||
if (!NS_IS_KEY_EVENT(aEvent) && !NS_IS_IME_EVENT(aEvent) &&
|
if (!NS_IS_KEY_EVENT(aEvent) && !NS_IS_IME_EVENT(aEvent) &&
|
||||||
!NS_IS_CONTEXT_MENU_KEY(aEvent) && !NS_IS_FOCUS_EVENT(aEvent) &&
|
!NS_IS_CONTEXT_MENU_KEY(aEvent) && !NS_IS_FOCUS_EVENT(aEvent) &&
|
||||||
!NS_IS_QUERY_CONTENT_EVENT(aEvent) && !NS_IS_PLUGIN_EVENT(aEvent) &&
|
!NS_IS_QUERY_CONTENT_EVENT(aEvent) && !NS_IS_PLUGIN_EVENT(aEvent) &&
|
||||||
|
!NS_IS_SELECTION_EVENT(aEvent) &&
|
||||||
aEvent->eventStructType != NS_ACCESSIBLE_EVENT) {
|
aEvent->eventStructType != NS_ACCESSIBLE_EVENT) {
|
||||||
// will dispatch using coordinates. Pretty bogus but it's consistent
|
// will dispatch using coordinates. Pretty bogus but it's consistent
|
||||||
// with what presshell does.
|
// with what presshell does.
|
||||||
|
|
|
@ -45,7 +45,7 @@ include $(DEPTH)/config/autoconf.mk
|
||||||
DIRS = public src
|
DIRS = public src
|
||||||
|
|
||||||
ifdef ENABLE_TESTS
|
ifdef ENABLE_TESTS
|
||||||
DIRS += tests
|
TOOL_DIRS += tests
|
||||||
endif
|
endif
|
||||||
|
|
||||||
include $(topsrcdir)/config/rules.mk
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
|
|
@ -105,6 +105,7 @@ class nsHashKey;
|
||||||
#define NS_DRAG_EVENT 35
|
#define NS_DRAG_EVENT 35
|
||||||
#define NS_NOTIFYPAINT_EVENT 36
|
#define NS_NOTIFYPAINT_EVENT 36
|
||||||
#define NS_SIMPLE_GESTURE_EVENT 37
|
#define NS_SIMPLE_GESTURE_EVENT 37
|
||||||
|
#define NS_SELECTION_EVENT 38
|
||||||
|
|
||||||
// These flags are sort of a mess. They're sort of shared between event
|
// These flags are sort of a mess. They're sort of shared between event
|
||||||
// listener flags and event flags, but only some of them. You've been
|
// listener flags and event flags, but only some of them. You've been
|
||||||
|
@ -344,14 +345,18 @@ class nsHashKey;
|
||||||
#define NS_QUERY_SELECTED_TEXT (NS_QUERY_CONTENT_EVENT_START)
|
#define NS_QUERY_SELECTED_TEXT (NS_QUERY_CONTENT_EVENT_START)
|
||||||
// Query for the text content of specified range, it returns actual lengh (if
|
// Query for the text content of specified range, it returns actual lengh (if
|
||||||
// the specified range is too long) and the text of the specified range.
|
// the specified range is too long) and the text of the specified range.
|
||||||
|
// Returns the entire text if requested length > actual length.
|
||||||
#define NS_QUERY_TEXT_CONTENT (NS_QUERY_CONTENT_EVENT_START + 1)
|
#define NS_QUERY_TEXT_CONTENT (NS_QUERY_CONTENT_EVENT_START + 1)
|
||||||
// Query for the character rect of nth character. If there is no character at
|
|
||||||
// the offset, the query will be failed. The offset of the result is relative
|
|
||||||
// position from the top level widget.
|
|
||||||
#define NS_QUERY_CHARACTER_RECT (NS_QUERY_CONTENT_EVENT_START + 2)
|
|
||||||
// Query for the caret rect of nth insertion point. The offset of the result is
|
// Query for the caret rect of nth insertion point. The offset of the result is
|
||||||
// relative position from the top level widget.
|
// relative position from the top level widget.
|
||||||
#define NS_QUERY_CARET_RECT (NS_QUERY_CONTENT_EVENT_START + 3)
|
#define NS_QUERY_CARET_RECT (NS_QUERY_CONTENT_EVENT_START + 3)
|
||||||
|
// Query for the bounding rect of a range of characters. This works on any
|
||||||
|
// valid character range given offset and length. Result is relative to top
|
||||||
|
// level widget coordinates
|
||||||
|
#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)
|
||||||
|
|
||||||
// Video events
|
// Video events
|
||||||
#ifdef MOZ_MEDIA
|
#ifdef MOZ_MEDIA
|
||||||
|
@ -397,6 +402,11 @@ class nsHashKey;
|
||||||
#define NS_PLUGIN_EVENT_START 3600
|
#define NS_PLUGIN_EVENT_START 3600
|
||||||
#define NS_PLUGIN_EVENT (NS_PLUGIN_EVENT_START)
|
#define NS_PLUGIN_EVENT (NS_PLUGIN_EVENT_START)
|
||||||
|
|
||||||
|
// Events to manipulate selection (nsSelectionEvent)
|
||||||
|
#define NS_SELECTION_EVENT_START 3700
|
||||||
|
// Clear any previous selection and set the given range as the selection
|
||||||
|
#define NS_SELECTION_SET (NS_SELECTION_EVENT_START)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return status for event processors, nsEventStatus, is defined in
|
* Return status for event processors, nsEventStatus, is defined in
|
||||||
* nsEvent.h.
|
* nsEvent.h.
|
||||||
|
@ -858,11 +868,11 @@ class nsTextEvent : public nsInputEvent
|
||||||
public:
|
public:
|
||||||
nsTextEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w)
|
nsTextEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w)
|
||||||
: nsInputEvent(isTrusted, msg, w, NS_TEXT_EVENT),
|
: nsInputEvent(isTrusted, msg, w, NS_TEXT_EVENT),
|
||||||
theText(nsnull), rangeCount(0), rangeArray(nsnull), isChar(PR_FALSE)
|
rangeCount(0), rangeArray(nsnull), isChar(PR_FALSE)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const PRUnichar* theText;
|
nsString theText;
|
||||||
nsTextEventReply theReply;
|
nsTextEventReply theReply;
|
||||||
PRUint32 rangeCount;
|
PRUint32 rangeCount;
|
||||||
// Note that the range array may not specify a caret position; in that
|
// Note that the range array may not specify a caret position; in that
|
||||||
|
@ -965,13 +975,6 @@ public:
|
||||||
mInput.mLength = aLength;
|
mInput.mLength = aLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitForQueryCharacterRect(PRUint32 aOffset)
|
|
||||||
{
|
|
||||||
NS_ASSERTION(message == NS_QUERY_CHARACTER_RECT,
|
|
||||||
"wrong initializer is called");
|
|
||||||
mInput.mOffset = aOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitForQueryCaretRect(PRUint32 aOffset)
|
void InitForQueryCaretRect(PRUint32 aOffset)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(message == NS_QUERY_CARET_RECT,
|
NS_ASSERTION(message == NS_QUERY_CARET_RECT,
|
||||||
|
@ -979,6 +982,14 @@ public:
|
||||||
mInput.mOffset = aOffset;
|
mInput.mOffset = aOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InitForQueryTextRect(PRUint32 aOffset, PRUint32 aLength)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(message == NS_QUERY_TEXT_RECT,
|
||||||
|
"wrong initializer is called");
|
||||||
|
mInput.mOffset = aOffset;
|
||||||
|
mInput.mLength = aLength;
|
||||||
|
}
|
||||||
|
|
||||||
PRBool mSucceeded;
|
PRBool mSucceeded;
|
||||||
struct {
|
struct {
|
||||||
PRUint32 mOffset;
|
PRUint32 mOffset;
|
||||||
|
@ -991,9 +1002,25 @@ public:
|
||||||
nsIntRect mRect; // Finally, the coordinates is system coordinates.
|
nsIntRect mRect; // Finally, the coordinates is system coordinates.
|
||||||
// The return widget has the caret. This is set at all query events.
|
// The return widget has the caret. This is set at all query events.
|
||||||
nsIWidget* mFocusedWidget;
|
nsIWidget* mFocusedWidget;
|
||||||
|
PRPackedBool mReversed; // true if selection is reversed (end < start)
|
||||||
} mReply;
|
} mReply;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class nsSelectionEvent : public nsGUIEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
nsSelectionEvent(PRBool aIsTrusted, PRUint32 aMsg, nsIWidget *aWidget) :
|
||||||
|
nsGUIEvent(aIsTrusted, aMsg, aWidget, NS_SELECTION_EVENT),
|
||||||
|
mSucceeded(PR_FALSE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PRUint32 mOffset; // start offset of selection
|
||||||
|
PRUint32 mLength; // length of selection
|
||||||
|
PRPackedBool mReversed; // selection "anchor" should be in front
|
||||||
|
PRPackedBool mSucceeded;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MenuItem event
|
* MenuItem event
|
||||||
*
|
*
|
||||||
|
@ -1232,8 +1259,12 @@ enum nsDragDropEventStatus {
|
||||||
#define NS_IS_QUERY_CONTENT_EVENT(evnt) \
|
#define NS_IS_QUERY_CONTENT_EVENT(evnt) \
|
||||||
(((evnt)->message == NS_QUERY_SELECTED_TEXT) || \
|
(((evnt)->message == NS_QUERY_SELECTED_TEXT) || \
|
||||||
((evnt)->message == NS_QUERY_TEXT_CONTENT) || \
|
((evnt)->message == NS_QUERY_TEXT_CONTENT) || \
|
||||||
((evnt)->message == NS_QUERY_CHARACTER_RECT) || \
|
((evnt)->message == NS_QUERY_CARET_RECT) || \
|
||||||
((evnt)->message == NS_QUERY_CARET_RECT))
|
((evnt)->message == NS_QUERY_TEXT_RECT) || \
|
||||||
|
((evnt)->message == NS_QUERY_EDITOR_RECT))
|
||||||
|
|
||||||
|
#define NS_IS_SELECTION_EVENT(evnt) \
|
||||||
|
(((evnt)->message == NS_SELECTION_SET))
|
||||||
|
|
||||||
#define NS_IS_PLUGIN_EVENT(evnt) \
|
#define NS_IS_PLUGIN_EVENT(evnt) \
|
||||||
(((evnt)->message == NS_PLUGIN_EVENT))
|
(((evnt)->message == NS_PLUGIN_EVENT))
|
||||||
|
|
|
@ -93,11 +93,14 @@ typedef nsEventStatus (* EVENT_CALLBACK)(nsGUIEvent *event);
|
||||||
#define NS_NATIVE_PLUGIN_PORT_QD 100
|
#define NS_NATIVE_PLUGIN_PORT_QD 100
|
||||||
#define NS_NATIVE_PLUGIN_PORT_CG 101
|
#define NS_NATIVE_PLUGIN_PORT_CG 101
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef XP_WIN
|
||||||
|
#define NS_NATIVE_TSF_POINTER 100
|
||||||
|
#endif
|
||||||
|
|
||||||
// a85944af-7fce-4e45-bf04-ac12c823394b
|
// 075a7792-6ba9-454e-b431-25a43fdbd3f6
|
||||||
#define NS_IWIDGET_IID \
|
#define NS_IWIDGET_IID \
|
||||||
{ 0xa85944af, 0x7fce, 0x4e45, \
|
{ 0x075a7792, 0x6ba9, 0x454e, \
|
||||||
{ 0xbf, 0x04, 0xac, 0x12, 0xc8, 0x23, 0x39, 0x4b } }
|
{ 0xb4, 0x31, 0x25, 0xa4, 0x3f, 0xdb, 0xd3, 0xf6 } }
|
||||||
|
|
||||||
// Hide the native window systems real window type so as to avoid
|
// Hide the native window systems real window type so as to avoid
|
||||||
// including native window system types and APIs. This is necessary
|
// including native window system types and APIs. This is necessary
|
||||||
|
@ -1242,6 +1245,29 @@ class nsIWidget : public nsISupports {
|
||||||
*/
|
*/
|
||||||
NS_IMETHOD GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState) = 0;
|
NS_IMETHOD GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState) = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An editable node (i.e. input/textarea/design mode document)
|
||||||
|
* is receiving or giving up focus
|
||||||
|
* aFocus is true if node is receiving focus
|
||||||
|
* aFocus is false if node is giving up focus (blur)
|
||||||
|
*/
|
||||||
|
NS_IMETHOD OnIMEFocusChange(PRBool aFocus) = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Text content of the focused node has changed
|
||||||
|
* aStart is the starting offset of the change
|
||||||
|
* aOldEnd is the ending offset of the change
|
||||||
|
* aNewEnd is the caret offset after the change
|
||||||
|
*/
|
||||||
|
NS_IMETHOD OnIMETextChange(PRUint32 aStart,
|
||||||
|
PRUint32 aOldEnd,
|
||||||
|
PRUint32 aNewEnd) = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Selection has changed in the focused node
|
||||||
|
*/
|
||||||
|
NS_IMETHOD OnIMESelectionChange(void) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// keep the list of children. We also keep track of our siblings.
|
// keep the list of children. We also keep track of our siblings.
|
||||||
// The ownership model is as follows: parent holds a strong ref to
|
// The ownership model is as follows: parent holds a strong ref to
|
||||||
|
|
|
@ -5490,8 +5490,8 @@ GetUSLayoutCharFromKeyTranslate(UInt32 aKeyCode, UInt32 aModifiers)
|
||||||
nsIntRect r;
|
nsIntRect r;
|
||||||
PRBool useCaretRect = theRange.length == 0;
|
PRBool useCaretRect = theRange.length == 0;
|
||||||
if (!useCaretRect) {
|
if (!useCaretRect) {
|
||||||
nsQueryContentEvent charRect(PR_TRUE, NS_QUERY_CHARACTER_RECT, mGeckoChild);
|
nsQueryContentEvent charRect(PR_TRUE, NS_QUERY_TEXT_RECT, mGeckoChild);
|
||||||
charRect.InitForQueryCharacterRect(theRange.location);
|
charRect.InitForQueryTextRect(theRange.location, 1);
|
||||||
mGeckoChild->DispatchWindowEvent(charRect);
|
mGeckoChild->DispatchWindowEvent(charRect);
|
||||||
if (charRect.mSucceeded)
|
if (charRect.mSucceeded)
|
||||||
r = charRect.mReply.mRect;
|
r = charRect.mReply.mRect;
|
||||||
|
|
|
@ -107,6 +107,7 @@ CPPSRCS += \
|
||||||
nsBidiKeyboard.cpp \
|
nsBidiKeyboard.cpp \
|
||||||
nsSound.cpp \
|
nsSound.cpp \
|
||||||
nsIdleServiceWin.cpp \
|
nsIdleServiceWin.cpp \
|
||||||
|
nsTextStore.cpp \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,233 @@
|
||||||
|
/* -*- 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
|
||||||
|
* Netscape Communications Corporation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Ningjie Chen <chenn@email.uc.edu>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either 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 ***** */
|
||||||
|
|
||||||
|
#ifndef NSTEXTSTORE_H_
|
||||||
|
#define NSTEXTSTORE_H_
|
||||||
|
|
||||||
|
#include "nsAutoPtr.h"
|
||||||
|
#include "nsString.h"
|
||||||
|
|
||||||
|
#include <msctf.h>
|
||||||
|
#include <textstor.h>
|
||||||
|
|
||||||
|
struct ITfThreadMgr;
|
||||||
|
struct ITfDocumentMgr;
|
||||||
|
class nsWindow;
|
||||||
|
|
||||||
|
// It doesn't work well when we notify TSF of text change
|
||||||
|
// during a mutation observer call because things get broken.
|
||||||
|
// So we post a message and notify TSF when we get it later.
|
||||||
|
#define WM_USER_TSF_TEXTCHANGE (WM_USER + 0x100)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Text Services Framework text store
|
||||||
|
*/
|
||||||
|
|
||||||
|
class nsTextStore : public ITextStoreACP,
|
||||||
|
public ITfContextOwnerCompositionSink
|
||||||
|
{
|
||||||
|
public: /*IUnknown*/
|
||||||
|
STDMETHODIMP_(ULONG) AddRef(void);
|
||||||
|
STDMETHODIMP QueryInterface(REFIID, void**);
|
||||||
|
STDMETHODIMP_(ULONG) Release(void);
|
||||||
|
|
||||||
|
public: /*ITextStoreACP*/
|
||||||
|
STDMETHODIMP AdviseSink(REFIID, IUnknown*, DWORD);
|
||||||
|
STDMETHODIMP UnadviseSink(IUnknown*);
|
||||||
|
STDMETHODIMP RequestLock(DWORD, HRESULT*);
|
||||||
|
STDMETHODIMP GetStatus(TS_STATUS*);
|
||||||
|
STDMETHODIMP QueryInsert(LONG, LONG, ULONG, LONG*, LONG*);
|
||||||
|
STDMETHODIMP GetSelection(ULONG, ULONG, TS_SELECTION_ACP*, ULONG*);
|
||||||
|
STDMETHODIMP SetSelection(ULONG, const TS_SELECTION_ACP*);
|
||||||
|
STDMETHODIMP GetText(LONG, LONG, WCHAR*, ULONG, ULONG*, TS_RUNINFO*, ULONG,
|
||||||
|
ULONG*, LONG*);
|
||||||
|
STDMETHODIMP SetText(DWORD, LONG, LONG, const WCHAR*, ULONG, TS_TEXTCHANGE*);
|
||||||
|
STDMETHODIMP GetFormattedText(LONG, LONG, IDataObject**);
|
||||||
|
STDMETHODIMP GetEmbedded(LONG, REFGUID, REFIID, IUnknown**);
|
||||||
|
STDMETHODIMP QueryInsertEmbedded(const GUID*, const FORMATETC*, BOOL*);
|
||||||
|
STDMETHODIMP InsertEmbedded(DWORD, LONG, LONG, IDataObject*, TS_TEXTCHANGE*);
|
||||||
|
STDMETHODIMP RequestSupportedAttrs(DWORD, ULONG, const TS_ATTRID*);
|
||||||
|
STDMETHODIMP RequestAttrsAtPosition(LONG, ULONG, const TS_ATTRID*, DWORD);
|
||||||
|
STDMETHODIMP RequestAttrsTransitioningAtPosition(LONG, ULONG,
|
||||||
|
const TS_ATTRID*, DWORD);
|
||||||
|
STDMETHODIMP FindNextAttrTransition(LONG, LONG, ULONG, const TS_ATTRID*,
|
||||||
|
DWORD, LONG*, BOOL*, LONG*);
|
||||||
|
STDMETHODIMP RetrieveRequestedAttrs(ULONG, TS_ATTRVAL*, ULONG*);
|
||||||
|
STDMETHODIMP GetEndACP(LONG*);
|
||||||
|
STDMETHODIMP GetActiveView(TsViewCookie*);
|
||||||
|
STDMETHODIMP GetACPFromPoint(TsViewCookie, const POINT*, DWORD, LONG*);
|
||||||
|
STDMETHODIMP GetTextExt(TsViewCookie, LONG, LONG, RECT*, BOOL*);
|
||||||
|
STDMETHODIMP GetScreenExt(TsViewCookie, RECT*);
|
||||||
|
STDMETHODIMP GetWnd(TsViewCookie, HWND*);
|
||||||
|
STDMETHODIMP InsertTextAtSelection(DWORD, const WCHAR*, ULONG, LONG*, LONG*,
|
||||||
|
TS_TEXTCHANGE*);
|
||||||
|
STDMETHODIMP InsertEmbeddedAtSelection(DWORD, IDataObject*, LONG*, LONG*,
|
||||||
|
TS_TEXTCHANGE*);
|
||||||
|
|
||||||
|
public: /*ITfContextOwnerCompositionSink*/
|
||||||
|
STDMETHODIMP OnStartComposition(ITfCompositionView*, BOOL*);
|
||||||
|
STDMETHODIMP OnUpdateComposition(ITfCompositionView*, ITfRange*);
|
||||||
|
STDMETHODIMP OnEndComposition(ITfCompositionView*);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void Initialize(void);
|
||||||
|
static void Terminate(void);
|
||||||
|
static void SetIMEOpenState(PRBool);
|
||||||
|
static PRBool GetIMEOpenState(void);
|
||||||
|
|
||||||
|
static void CommitComposition(PRBool aDiscard)
|
||||||
|
{
|
||||||
|
if (!sTsfTextStore) return;
|
||||||
|
sTsfTextStore->CommitCompositionInternal(aDiscard);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetIMEEnabled(PRUint32 aState)
|
||||||
|
{
|
||||||
|
if (!sTsfTextStore) return;
|
||||||
|
sTsfTextStore->SetIMEEnabledInternal(aState);
|
||||||
|
}
|
||||||
|
|
||||||
|
static nsresult OnFocusChange(PRBool, nsWindow*, PRUint32);
|
||||||
|
|
||||||
|
static nsresult OnTextChange(PRUint32 aStart,
|
||||||
|
PRUint32 aOldEnd,
|
||||||
|
PRUint32 aNewEnd)
|
||||||
|
{
|
||||||
|
if (!sTsfTextStore) return NS_OK;
|
||||||
|
return sTsfTextStore->OnTextChangeInternal(aStart, aOldEnd, aNewEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OnTextChangeMsg(void)
|
||||||
|
{
|
||||||
|
if (!sTsfTextStore) return;
|
||||||
|
// Notify TSF text change
|
||||||
|
// (see comments on WM_USER_TSF_TEXTCHANGE in nsTextStore.h)
|
||||||
|
sTsfTextStore->OnTextChangeMsgInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
static nsresult OnSelectionChange(void)
|
||||||
|
{
|
||||||
|
if (!sTsfTextStore) return NS_OK;
|
||||||
|
return sTsfTextStore->OnSelectionChangeInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* GetNativeData(void)
|
||||||
|
{
|
||||||
|
// Returns the address of the pointer so that the TSF automatic test can
|
||||||
|
// replace the system object with a custom implementation for testing.
|
||||||
|
Initialize(); // Apply any previous changes
|
||||||
|
return (void*) & sTsfThreadMgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
nsTextStore();
|
||||||
|
~nsTextStore();
|
||||||
|
|
||||||
|
PRBool Create(nsWindow*, PRUint32);
|
||||||
|
PRBool Destroy(void);
|
||||||
|
PRBool Focus(void);
|
||||||
|
PRBool Blur(void);
|
||||||
|
|
||||||
|
HRESULT LoadManagers(void);
|
||||||
|
HRESULT SetSelectionInternal(const TS_SELECTION_ACP*);
|
||||||
|
HRESULT OnStartCompositionInternal(ITfCompositionView*, ITfRange*, PRBool);
|
||||||
|
void CommitCompositionInternal(PRBool);
|
||||||
|
void SetIMEEnabledInternal(PRUint32 aState);
|
||||||
|
nsresult OnTextChangeInternal(PRUint32, PRUint32, PRUint32);
|
||||||
|
void OnTextChangeMsgInternal(void);
|
||||||
|
nsresult OnSelectionChangeInternal(void);
|
||||||
|
|
||||||
|
// TSF display attribute manager, loaded by LoadManagers
|
||||||
|
nsRefPtr<ITfDisplayAttributeMgr> mDAMgr;
|
||||||
|
// TSF category manager, loaded by LoadManagers
|
||||||
|
nsRefPtr<ITfCategoryMgr> mCatMgr;
|
||||||
|
|
||||||
|
// Document manager for the currently focused editor
|
||||||
|
nsRefPtr<ITfDocumentMgr> mDocumentMgr;
|
||||||
|
// Edit cookie associated with the current editing context
|
||||||
|
DWORD mEditCookie;
|
||||||
|
// Editing context at the bottom of mDocumentMgr's context stack
|
||||||
|
nsRefPtr<ITfContext> mContext;
|
||||||
|
// Currently installed notification sink
|
||||||
|
nsRefPtr<ITextStoreACPSink> mSink;
|
||||||
|
// TS_AS_* mask of what events to notify
|
||||||
|
DWORD mSinkMask;
|
||||||
|
// Window containing the focused editor
|
||||||
|
nsWindow* mWindow;
|
||||||
|
// 0 if not locked, otherwise TS_LF_* indicating the current lock
|
||||||
|
DWORD mLock;
|
||||||
|
// 0 if no lock is queued, otherwise TS_LF_* indicating the queue lock
|
||||||
|
DWORD mLockQueued;
|
||||||
|
// Cumulative text change offsets since the last notification
|
||||||
|
TS_TEXTCHANGE mTextChange;
|
||||||
|
// NULL if no composition is active, otherwise the current composition
|
||||||
|
nsRefPtr<ITfCompositionView> mCompositionView;
|
||||||
|
// Current copy of the active composition string. Only mCompositionString is
|
||||||
|
// changed during a InsertTextAtSelection call if we have a composition.
|
||||||
|
// mCompositionString acts as a buffer until OnUpdateComposition is called
|
||||||
|
// and mCompositionString is flushed to editor through NS_TEXT_TEXT. This
|
||||||
|
// way all changes are updated in batches to avoid inconsistencies/artifacts.
|
||||||
|
nsString mCompositionString;
|
||||||
|
// "Current selection" during a composition, in ACP offsets.
|
||||||
|
// We use a fake selection during a composition because editor code doesn't
|
||||||
|
// like us accessing the actual selection during a composition. So we leave
|
||||||
|
// the actual selection alone and get/set mCompositionSelection instead
|
||||||
|
// during GetSelection/SetSelection calls.
|
||||||
|
TS_SELECTION_ACP mCompositionSelection;
|
||||||
|
// The start and length of the current active composition, in ACP offsets
|
||||||
|
LONG mCompositionStart;
|
||||||
|
LONG mCompositionLength;
|
||||||
|
|
||||||
|
// TSF thread manager object for the current application
|
||||||
|
static ITfThreadMgr* sTsfThreadMgr;
|
||||||
|
// TSF client ID for the current application
|
||||||
|
static DWORD sTsfClientId;
|
||||||
|
// Current text store. Currently only ONE nsTextStore instance is ever used,
|
||||||
|
// although Create is called when an editor is focused and Destroy called
|
||||||
|
// when the focused editor is blurred.
|
||||||
|
static nsTextStore* sTsfTextStore;
|
||||||
|
|
||||||
|
// Message the Tablet Input Panel uses to flush text during blurring.
|
||||||
|
// See comments in Destroy
|
||||||
|
static UINT sFlushTIPInputMessage;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ULONG mRefCnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /*NSTEXTSTORE_H_*/
|
|
@ -34,6 +34,7 @@
|
||||||
* Dainis Jonitis <Dainis_Jonitis@swh-t.lv>
|
* Dainis Jonitis <Dainis_Jonitis@swh-t.lv>
|
||||||
* Christian Biesinger <cbiesinger@web.de>
|
* Christian Biesinger <cbiesinger@web.de>
|
||||||
* Mats Palmgren <mats.palmgren@bredband.net>
|
* Mats Palmgren <mats.palmgren@bredband.net>
|
||||||
|
* Ningjie Chen <chenn@email.uc.edu>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -150,6 +151,9 @@
|
||||||
#include "prmem.h"
|
#include "prmem.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef NS_ENABLE_TSF
|
||||||
|
#include "nsTextStore.h"
|
||||||
|
#endif //NS_ENABLE_TSF
|
||||||
|
|
||||||
#ifdef WINCE
|
#ifdef WINCE
|
||||||
|
|
||||||
|
@ -746,14 +750,19 @@ nsWindow::nsWindow() : nsBaseWidget()
|
||||||
mIsTopWidgetWindow = PR_FALSE;
|
mIsTopWidgetWindow = PR_FALSE;
|
||||||
mLastKeyboardLayout = 0;
|
mLastKeyboardLayout = 0;
|
||||||
|
|
||||||
|
#ifdef NS_ENABLE_TSF
|
||||||
|
if (!sInstanceCount)
|
||||||
|
nsTextStore::Initialize();
|
||||||
|
#endif //NS_ENABLE_TSF
|
||||||
|
|
||||||
#ifndef WINCE
|
#ifndef WINCE
|
||||||
if (!sInstanceCount && SUCCEEDED(::OleInitialize(NULL))) {
|
if (!sInstanceCount && SUCCEEDED(::OleInitialize(NULL))) {
|
||||||
sIsOleInitialized = TRUE;
|
sIsOleInitialized = TRUE;
|
||||||
}
|
}
|
||||||
NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n");
|
NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
sInstanceCount++;
|
sInstanceCount++;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
@ -788,11 +797,17 @@ nsWindow::~nsWindow()
|
||||||
SetCursor(eCursor_standard);
|
SetCursor(eCursor_standard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sInstanceCount--;
|
||||||
|
|
||||||
|
#ifdef NS_ENABLE_TSF
|
||||||
|
if (!sInstanceCount)
|
||||||
|
nsTextStore::Terminate();
|
||||||
|
#endif //NS_ENABLE_TSF
|
||||||
|
|
||||||
#ifndef WINCE
|
#ifndef WINCE
|
||||||
//
|
//
|
||||||
// delete any of the IME structures that we allocated
|
// delete any of the IME structures that we allocated
|
||||||
//
|
//
|
||||||
sInstanceCount--;
|
|
||||||
if (sInstanceCount == 0) {
|
if (sInstanceCount == 0) {
|
||||||
if (sIMECompUnicode)
|
if (sIMECompUnicode)
|
||||||
delete sIMECompUnicode;
|
delete sIMECompUnicode;
|
||||||
|
@ -2826,6 +2841,12 @@ void* nsWindow::GetNativeData(PRUint32 aDataType)
|
||||||
#else
|
#else
|
||||||
return (void*)::GetDC(mWnd);
|
return (void*)::GetDC(mWnd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef NS_ENABLE_TSF
|
||||||
|
case NS_NATIVE_TSF_POINTER:
|
||||||
|
return nsTextStore::GetNativeData();
|
||||||
|
#endif //NS_ENABLE_TSF
|
||||||
|
|
||||||
case NS_NATIVE_COLORMAP:
|
case NS_NATIVE_COLORMAP:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -5303,6 +5324,12 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT
|
||||||
}
|
}
|
||||||
#endif // WINCE
|
#endif // WINCE
|
||||||
|
|
||||||
|
#ifdef NS_ENABLE_TSF
|
||||||
|
else if (msg == WM_USER_TSF_TEXTCHANGE) {
|
||||||
|
nsTextStore::OnTextChangeMsg();
|
||||||
|
}
|
||||||
|
#endif //NS_ENABLE_TSF
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#ifndef WINCE
|
#ifndef WINCE
|
||||||
|
@ -7427,8 +7454,8 @@ PRBool nsWindow::OnIMEQueryCharPosition(LPARAM aData, LRESULT *oResult)
|
||||||
|
|
||||||
nsIntRect r;
|
nsIntRect r;
|
||||||
if (!useCaretRect) {
|
if (!useCaretRect) {
|
||||||
nsQueryContentEvent charRect(PR_TRUE, NS_QUERY_CHARACTER_RECT, this);
|
nsQueryContentEvent charRect(PR_TRUE, NS_QUERY_TEXT_RECT, this);
|
||||||
charRect.InitForQueryCharacterRect(offset);
|
charRect.InitForQueryTextRect(offset, 1);
|
||||||
InitEvent(charRect, &point);
|
InitEvent(charRect, &point);
|
||||||
DispatchWindowEvent(&charRect);
|
DispatchWindowEvent(&charRect);
|
||||||
if (charRect.mSucceeded)
|
if (charRect.mSucceeded)
|
||||||
|
@ -7536,6 +7563,11 @@ NS_IMETHODIMP nsWindow::ResetInputState()
|
||||||
#ifdef DEBUG_KBSTATE
|
#ifdef DEBUG_KBSTATE
|
||||||
printf("ResetInputState\n");
|
printf("ResetInputState\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef NS_ENABLE_TSF
|
||||||
|
nsTextStore::CommitComposition(PR_FALSE);
|
||||||
|
#endif //NS_ENABLE_TSF
|
||||||
|
|
||||||
HIMC hIMC = ::ImmGetContext(mWnd);
|
HIMC hIMC = ::ImmGetContext(mWnd);
|
||||||
if (hIMC) {
|
if (hIMC) {
|
||||||
BOOL ret = FALSE;
|
BOOL ret = FALSE;
|
||||||
|
@ -7553,6 +7585,11 @@ NS_IMETHODIMP nsWindow::SetIMEOpenState(PRBool aState)
|
||||||
#ifdef DEBUG_KBSTATE
|
#ifdef DEBUG_KBSTATE
|
||||||
printf("SetIMEOpenState %s\n", (aState ? "Open" : "Close"));
|
printf("SetIMEOpenState %s\n", (aState ? "Open" : "Close"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef NS_ENABLE_TSF
|
||||||
|
nsTextStore::SetIMEOpenState(aState);
|
||||||
|
#endif //NS_ENABLE_TSF
|
||||||
|
|
||||||
HIMC hIMC = ::ImmGetContext(mWnd);
|
HIMC hIMC = ::ImmGetContext(mWnd);
|
||||||
if (hIMC) {
|
if (hIMC) {
|
||||||
::ImmSetOpenStatus(hIMC, aState ? TRUE : FALSE);
|
::ImmSetOpenStatus(hIMC, aState ? TRUE : FALSE);
|
||||||
|
@ -7571,12 +7608,21 @@ NS_IMETHODIMP nsWindow::GetIMEOpenState(PRBool* aState)
|
||||||
::ImmReleaseContext(mWnd, hIMC);
|
::ImmReleaseContext(mWnd, hIMC);
|
||||||
} else
|
} else
|
||||||
*aState = PR_FALSE;
|
*aState = PR_FALSE;
|
||||||
|
|
||||||
|
#ifdef NS_ENABLE_TSF
|
||||||
|
*aState |= nsTextStore::GetIMEOpenState();
|
||||||
|
#endif //NS_ENABLE_TSF
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
NS_IMETHODIMP nsWindow::SetIMEEnabled(PRUint32 aState)
|
NS_IMETHODIMP nsWindow::SetIMEEnabled(PRUint32 aState)
|
||||||
{
|
{
|
||||||
|
#ifdef NS_ENABLE_TSF
|
||||||
|
nsTextStore::SetIMEEnabled(aState);
|
||||||
|
#endif //NS_ENABLE_TSF
|
||||||
|
|
||||||
if (sIMEIsComposing)
|
if (sIMEIsComposing)
|
||||||
ResetInputState();
|
ResetInputState();
|
||||||
mIMEEnabled = aState;
|
mIMEEnabled = aState;
|
||||||
|
@ -7603,6 +7649,11 @@ NS_IMETHODIMP nsWindow::CancelIMEComposition()
|
||||||
#ifdef DEBUG_KBSTATE
|
#ifdef DEBUG_KBSTATE
|
||||||
printf("CancelIMEComposition\n");
|
printf("CancelIMEComposition\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef NS_ENABLE_TSF
|
||||||
|
nsTextStore::CommitComposition(PR_TRUE);
|
||||||
|
#endif //NS_ENABLE_TSF
|
||||||
|
|
||||||
HIMC hIMC = ::ImmGetContext(mWnd);
|
HIMC hIMC = ::ImmGetContext(mWnd);
|
||||||
if (hIMC) {
|
if (hIMC) {
|
||||||
BOOL ret = FALSE;
|
BOOL ret = FALSE;
|
||||||
|
@ -7808,6 +7859,30 @@ static VOID CALLBACK nsGetAttentionTimerFunc(HWND hwnd, UINT uMsg, UINT idEvent,
|
||||||
gAttentionTimerMonitor->KillTimer(hwnd);
|
gAttentionTimerMonitor->KillTimer(hwnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef NS_ENABLE_TSF
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsWindow::OnIMEFocusChange(PRBool aFocus)
|
||||||
|
{
|
||||||
|
return nsTextStore::OnFocusChange(aFocus, this, mIMEEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsWindow::OnIMETextChange(PRUint32 aStart,
|
||||||
|
PRUint32 aOldEnd,
|
||||||
|
PRUint32 aNewEnd)
|
||||||
|
{
|
||||||
|
return nsTextStore::OnTextChange(aStart, aOldEnd, aNewEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsWindow::OnIMESelectionChange(void)
|
||||||
|
{
|
||||||
|
return nsTextStore::OnSelectionChange();
|
||||||
|
}
|
||||||
|
#endif //NS_ENABLE_TSF
|
||||||
|
|
||||||
|
|
||||||
// Draw user's attention to this window until it comes to foreground.
|
// Draw user's attention to this window until it comes to foreground.
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsWindow::GetAttention(PRInt32 aCycleCount)
|
nsWindow::GetAttention(PRInt32 aCycleCount)
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
* Makoto Kato <m_kato@ga2.so-net.ne.jp>
|
* Makoto Kato <m_kato@ga2.so-net.ne.jp>
|
||||||
* Dainis Jonitis <Dainis_Jonitis@swh-t.lv>
|
* Dainis Jonitis <Dainis_Jonitis@swh-t.lv>
|
||||||
* Masayuki Nakano <masayuki@d-toybox.com>
|
* Masayuki Nakano <masayuki@d-toybox.com>
|
||||||
|
* Ningjie Chen <chenn@email.uc.edu>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -73,6 +74,11 @@ struct nsFakeCharMessage;
|
||||||
|
|
||||||
#include "gfxWindowsSurface.h"
|
#include "gfxWindowsSurface.h"
|
||||||
|
|
||||||
|
// Text Services Framework support
|
||||||
|
#ifndef WINCE
|
||||||
|
#define NS_ENABLE_TSF
|
||||||
|
#endif //WINCE
|
||||||
|
|
||||||
#define IME_MAX_CHAR_POS 64
|
#define IME_MAX_CHAR_POS 64
|
||||||
|
|
||||||
#define NSRGB_2_COLOREF(color) \
|
#define NSRGB_2_COLOREF(color) \
|
||||||
|
@ -235,6 +241,12 @@ public:
|
||||||
NS_IMETHOD CancelIMEComposition();
|
NS_IMETHOD CancelIMEComposition();
|
||||||
NS_IMETHOD GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState);
|
NS_IMETHOD GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState);
|
||||||
|
|
||||||
|
#ifdef NS_ENABLE_TSF
|
||||||
|
NS_IMETHOD OnIMEFocusChange(PRBool aFocus);
|
||||||
|
NS_IMETHOD OnIMETextChange(PRUint32 aStart, PRUint32 aOldEnd, PRUint32 aNewEnd);
|
||||||
|
NS_IMETHOD OnIMESelectionChange(void);
|
||||||
|
#endif //NS_ENABLE_TSF
|
||||||
|
|
||||||
PRBool IMEMouseHandling(PRInt32 aAction, LPARAM lParam);
|
PRBool IMEMouseHandling(PRInt32 aAction, LPARAM lParam);
|
||||||
PRBool IMECompositionHitTest(POINT * ptPos);
|
PRBool IMECompositionHitTest(POINT * ptPos);
|
||||||
PRBool HandleMouseActionOfIME(PRInt32 aAction, POINT* ptPos);
|
PRBool HandleMouseActionOfIME(PRInt32 aAction, POINT* ptPos);
|
||||||
|
@ -250,6 +262,8 @@ public:
|
||||||
LPARAM lParam,
|
LPARAM lParam,
|
||||||
PRBool aIsContextMenuKey = PR_FALSE,
|
PRBool aIsContextMenuKey = PR_FALSE,
|
||||||
PRInt16 aButton = nsMouseEvent::eLeftButton);
|
PRInt16 aButton = nsMouseEvent::eLeftButton);
|
||||||
|
virtual PRBool DispatchWindowEvent(nsGUIEvent* event);
|
||||||
|
virtual PRBool DispatchWindowEvent(nsGUIEvent*event, nsEventStatus &aStatus);
|
||||||
#ifdef ACCESSIBILITY
|
#ifdef ACCESSIBILITY
|
||||||
virtual PRBool DispatchAccessibleEvent(PRUint32 aEventType, nsIAccessible** aAccessible, nsIntPoint* aPoint = nsnull);
|
virtual PRBool DispatchAccessibleEvent(PRUint32 aEventType, nsIAccessible** aAccessible, nsIntPoint* aPoint = nsnull);
|
||||||
already_AddRefed<nsIAccessible> GetRootAccessible();
|
already_AddRefed<nsIAccessible> GetRootAccessible();
|
||||||
|
@ -303,8 +317,6 @@ protected:
|
||||||
LRESULT ProcessKeyDownMessage(const MSG &aMsg,
|
LRESULT ProcessKeyDownMessage(const MSG &aMsg,
|
||||||
PRBool *aEventDispatched);
|
PRBool *aEventDispatched);
|
||||||
|
|
||||||
virtual PRBool DispatchWindowEvent(nsGUIEvent* event);
|
|
||||||
virtual PRBool DispatchWindowEvent(nsGUIEvent*event, nsEventStatus &aStatus);
|
|
||||||
|
|
||||||
// Allow Derived classes to modify the height that is passed
|
// Allow Derived classes to modify the height that is passed
|
||||||
// when the window is created or resized.
|
// when the window is created or resized.
|
||||||
|
|
|
@ -139,13 +139,16 @@ public:
|
||||||
NS_IMETHOD BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical);
|
NS_IMETHOD BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical);
|
||||||
virtual nsresult ActivateNativeMenuItemAt(const nsAString& indexString) { return NS_ERROR_NOT_IMPLEMENTED; }
|
virtual nsresult ActivateNativeMenuItemAt(const nsAString& indexString) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||||
virtual nsresult ForceUpdateNativeMenuAt(const nsAString& indexString) { return NS_ERROR_NOT_IMPLEMENTED; }
|
virtual nsresult ForceUpdateNativeMenuAt(const nsAString& indexString) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||||
NS_IMETHOD ResetInputState() { return NS_ERROR_NOT_IMPLEMENTED; }
|
NS_IMETHOD ResetInputState() { return NS_OK; }
|
||||||
NS_IMETHOD SetIMEOpenState(PRBool aState) { return NS_ERROR_NOT_IMPLEMENTED; }
|
NS_IMETHOD SetIMEOpenState(PRBool aState) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||||
NS_IMETHOD GetIMEOpenState(PRBool* aState) { return NS_ERROR_NOT_IMPLEMENTED; }
|
NS_IMETHOD GetIMEOpenState(PRBool* aState) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||||
NS_IMETHOD SetIMEEnabled(PRUint32 aState) { return NS_ERROR_NOT_IMPLEMENTED; }
|
NS_IMETHOD SetIMEEnabled(PRUint32 aState) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||||
NS_IMETHOD GetIMEEnabled(PRUint32* aState) { return NS_ERROR_NOT_IMPLEMENTED; }
|
NS_IMETHOD GetIMEEnabled(PRUint32* aState) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||||
NS_IMETHOD CancelIMEComposition() { return NS_ERROR_NOT_IMPLEMENTED; }
|
NS_IMETHOD CancelIMEComposition() { return NS_OK; }
|
||||||
NS_IMETHOD GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState) { return NS_ERROR_NOT_IMPLEMENTED; }
|
NS_IMETHOD GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||||
|
NS_IMETHOD OnIMEFocusChange(PRBool aFocus) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||||
|
NS_IMETHOD OnIMETextChange(PRUint32 aStart, PRUint32 aOldEnd, PRUint32 aNewEnd) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||||
|
NS_IMETHOD OnIMESelectionChange(void) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
|
@ -39,9 +39,22 @@ DEPTH = ../..
|
||||||
topsrcdir = @top_srcdir@
|
topsrcdir = @top_srcdir@
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@
|
||||||
relativesrcdir = widget/test
|
relativesrcdir = widget/tests
|
||||||
|
|
||||||
include $(DEPTH)/config/autoconf.mk
|
include $(DEPTH)/config/autoconf.mk
|
||||||
|
|
||||||
|
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
|
||||||
|
ifneq ($(OS_ARCH), WINCE)
|
||||||
|
CPP_UNIT_TESTS += TestWinTSF.cpp \
|
||||||
|
$(NULL)
|
||||||
|
REQUIRES += appshell content docshell \
|
||||||
|
dom embed_base gfx layout locale \
|
||||||
|
necko string thebes uriloader view \
|
||||||
|
webbrwsr widget xpcom \
|
||||||
|
$(NULL)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
include $(topsrcdir)/config/rules.mk
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
|
||||||
_TEST_FILES = test_bug343416.xul \
|
_TEST_FILES = test_bug343416.xul \
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче