зеркало из https://github.com/mozilla/pjs.git
Bug 348341 "Reverse conversion" doesn't work by Kotoeri(Japanese input). r=josh+peterv+roc, sr=roc, b1.9=pavlov
This commit is contained in:
Родитель
3f5111351b
Коммит
b19b3109f2
|
@ -48,6 +48,7 @@
|
|||
class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsIDOMEvent;
|
||||
class nsIPresShell;
|
||||
class nsPresContext;
|
||||
class nsEventChainVisitor;
|
||||
class nsEventChainPreVisitor;
|
||||
|
@ -59,6 +60,7 @@ class nsIMutationObserver;
|
|||
class nsChildContentList;
|
||||
class nsNodeWeakReference;
|
||||
class nsNodeSupportsWeakRefTearoff;
|
||||
class nsIEditor;
|
||||
|
||||
enum {
|
||||
// This bit will be set if the node doesn't have nsSlots
|
||||
|
@ -144,8 +146,8 @@ inline nsINode* NODE_FROM(C& aContent, D& aDocument)
|
|||
|
||||
// IID for the nsINode interface
|
||||
#define NS_INODE_IID \
|
||||
{ 0xd1c2e967, 0x854a, 0x436b, \
|
||||
{ 0xbf, 0xa5, 0xf6, 0xa4, 0x9a, 0x97, 0x46, 0x74 } }
|
||||
{ 0x6f69dd90, 0x318d, 0x40ac, \
|
||||
{ 0xb8, 0xb8, 0x99, 0xb8, 0xa7, 0xbb, 0x9a, 0x58 } }
|
||||
|
||||
/**
|
||||
* An internal interface that abstracts some DOMNode-related parts that both
|
||||
|
@ -652,6 +654,22 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root content of an editor. So, this node must be a descendant of
|
||||
* an editor. Note that this should be only used for getting input or textarea
|
||||
* editor's root content. This method doesn't support HTML editors.
|
||||
*/
|
||||
nsIContent* GetTextEditorRootContent(nsIEditor** aEditor = nsnull);
|
||||
|
||||
/**
|
||||
* Get the nearest selection root, ie. the node that will be selected if the
|
||||
* user does "Select All" while the focus is in this node. Note that if this
|
||||
* node is not in an editor, the result comes from the nsFrameSelection that
|
||||
* is related to aPresShell, so the result might not be the ancestor of this
|
||||
* node.
|
||||
*/
|
||||
nsIContent* GetSelectionRootContent(nsIPresShell* aPresShell);
|
||||
|
||||
protected:
|
||||
|
||||
// Override this function to create a custom slots class.
|
||||
|
|
|
@ -81,6 +81,7 @@ REQUIRES = xpcom \
|
|||
util \
|
||||
appshell \
|
||||
shistory \
|
||||
editor \
|
||||
$(NULL)
|
||||
|
||||
ifdef ACCESSIBILITY
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
%import-idl "nsIDOMXPathEvaluator.idl"
|
||||
|
||||
%pseudo-iid nsIContent fba9aa39-016e-4d5d-ab62-22a1b84a3c7b
|
||||
%pseudo-iid nsINode d1c2e967-854a-436b-bfa5-f6a49a974674
|
||||
%pseudo-iid nsINode 6f69dd90-318d-40ac-b8b8-99b8a7bb9a58
|
||||
%pseudo-iid nsPIDOMEventTarget 44a6597b-9fc3-4a8d-b7a4-d9009abf9d15
|
||||
%pseudo-iid nsIDocument 626d86d2-615f-4a12-94d8-e3db3a298372
|
||||
%pseudo-iid nsIScriptObjectPrincipal 3eedba38-8d22-41e1-817a-0e43e165b664
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
#include "nsXULElement.h"
|
||||
#endif /* MOZ_XUL */
|
||||
#include "nsFrameManager.h"
|
||||
#include "nsFrameSelection.h"
|
||||
|
||||
#include "nsBindingManager.h"
|
||||
#include "nsXBLBinding.h"
|
||||
|
@ -117,6 +118,9 @@
|
|||
#include "nsIDOMNSFeatureFactory.h"
|
||||
#include "nsIDOMDocumentType.h"
|
||||
#include "nsIDOMUserDataHandler.h"
|
||||
#include "nsIDOMNSEditableElement.h"
|
||||
#include "nsIEditor.h"
|
||||
#include "nsIEditorDocShell.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
#include "nsIFocusController.h"
|
||||
|
@ -311,6 +315,101 @@ nsINode::IsEditableInternal() const
|
|||
return doc && doc->HasFlag(NODE_IS_EDITABLE);
|
||||
}
|
||||
|
||||
static nsIContent* GetEditorRootContent(nsIEditor* aEditor)
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement> rootElement;
|
||||
aEditor->GetRootElement(getter_AddRefs(rootElement));
|
||||
nsCOMPtr<nsIContent> rootContent(do_QueryInterface(rootElement));
|
||||
return rootContent;
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
nsINode::GetTextEditorRootContent(nsIEditor** aEditor)
|
||||
{
|
||||
if (aEditor)
|
||||
*aEditor = nsnull;
|
||||
for (nsINode* node = this; node; node = node->GetNodeParent()) {
|
||||
nsCOMPtr<nsIDOMNSEditableElement> editableElement(do_QueryInterface(node));
|
||||
if (!editableElement)
|
||||
continue;
|
||||
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
nsresult rv = editableElement->GetEditor(getter_AddRefs(editor));
|
||||
NS_ENSURE_TRUE(editor, nsnull);
|
||||
nsIContent* rootContent = GetEditorRootContent(editor);
|
||||
if (aEditor)
|
||||
editor.swap(*aEditor);
|
||||
return rootContent;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
static nsIEditor* GetHTMLEditor(nsPresContext* aPresContext)
|
||||
{
|
||||
nsCOMPtr<nsISupports> container = aPresContext->GetContainer();
|
||||
nsCOMPtr<nsIEditorDocShell> editorDocShell(do_QueryInterface(container));
|
||||
PRBool isEditable;
|
||||
if (!editorDocShell ||
|
||||
NS_FAILED(editorDocShell->GetEditable(&isEditable)) || !isEditable)
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
editorDocShell->GetEditor(getter_AddRefs(editor));
|
||||
return editor;
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
nsINode::GetSelectionRootContent(nsIPresShell* aPresShell)
|
||||
{
|
||||
NS_ENSURE_TRUE(aPresShell, nsnull);
|
||||
|
||||
if (IsNodeOfType(eDOCUMENT))
|
||||
return static_cast<nsIDocument*>(this)->GetRootContent();
|
||||
if (!IsNodeOfType(eCONTENT))
|
||||
return nsnull;
|
||||
|
||||
nsIFrame* frame =
|
||||
aPresShell->GetPrimaryFrameFor(static_cast<nsIContent*>(this));
|
||||
if (frame && frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) {
|
||||
// This node should be a descendant of input/textarea editor.
|
||||
nsIContent* content = GetTextEditorRootContent();
|
||||
if (content)
|
||||
return content;
|
||||
NS_ERROR("Editor is not found!");
|
||||
}
|
||||
|
||||
nsPresContext* presContext = aPresShell->GetPresContext();
|
||||
if (presContext) {
|
||||
nsIEditor* editor = GetHTMLEditor(presContext);
|
||||
if (editor) {
|
||||
// This node is in HTML editor.
|
||||
nsIDocument* doc = GetCurrentDoc();
|
||||
if (!doc || doc->HasFlag(NODE_IS_EDITABLE) || !HasFlag(NODE_IS_EDITABLE))
|
||||
return GetEditorRootContent(editor);
|
||||
// If the current document is not editable, but current content is
|
||||
// editable, we should assume that the child of the nearest non-editable
|
||||
// ancestor is selection root.
|
||||
nsIContent* content = static_cast<nsIContent*>(this);
|
||||
for (nsIContent* parent = GetParent();
|
||||
parent && parent->HasFlag(NODE_IS_EDITABLE);
|
||||
parent = content->GetParent())
|
||||
content = parent;
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsFrameSelection> fs = aPresShell->FrameSelection();
|
||||
nsIContent* content = fs->GetLimiter();
|
||||
if (content)
|
||||
return content;
|
||||
content = fs->GetAncestorLimiter();
|
||||
if (content)
|
||||
return content;
|
||||
nsIDocument* doc = aPresShell->GetDocument();
|
||||
NS_ENSURE_TRUE(doc, nsnull);
|
||||
return doc->GetRootContent();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
PRInt32
|
||||
|
|
|
@ -63,6 +63,7 @@ REQUIRES = xpcom \
|
|||
necko \
|
||||
unicharutil \
|
||||
imglib2 \
|
||||
editor \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
|
@ -88,6 +89,7 @@ CPPSRCS = \
|
|||
nsPLDOMEvent.cpp \
|
||||
nsEventDispatcher.cpp \
|
||||
nsIMEStateManager.cpp \
|
||||
nsQueryContentEventHandler.cpp \
|
||||
$(NULL)
|
||||
|
||||
# we don't want the shared lib, but we want to force the creation of a static lib.
|
||||
|
@ -101,6 +103,8 @@ LOCAL_INCLUDES = \
|
|||
-I$(srcdir)/../../xul/content/src \
|
||||
-I$(srcdir)/../../xml/content/src \
|
||||
-I$(srcdir)/../../../dom/src/base \
|
||||
-I$(srcdir)/../../../layout/generic \
|
||||
-I$(srcdir)/../../../layout/xul/base/src \
|
||||
$(NULL)
|
||||
|
||||
DEFINES += -D_IMPL_NS_LAYOUT
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "nsEventStateManager.h"
|
||||
#include "nsEventListenerManager.h"
|
||||
#include "nsIMEStateManager.h"
|
||||
#include "nsQueryContentEventHandler.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsINodeInfo.h"
|
||||
#include "nsIDocument.h"
|
||||
|
@ -1375,6 +1376,30 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
|||
}
|
||||
}
|
||||
break;
|
||||
case NS_QUERY_SELECTED_TEXT:
|
||||
{
|
||||
nsQueryContentEventHandler handler(mPresContext);
|
||||
handler.OnQuerySelectedText((nsQueryContentEvent*)aEvent);
|
||||
}
|
||||
break;
|
||||
case NS_QUERY_TEXT_CONTENT:
|
||||
{
|
||||
nsQueryContentEventHandler handler(mPresContext);
|
||||
handler.OnQueryTextContent((nsQueryContentEvent*)aEvent);
|
||||
}
|
||||
break;
|
||||
case NS_QUERY_CHARACTER_RECT:
|
||||
{
|
||||
nsQueryContentEventHandler handler(mPresContext);
|
||||
handler.OnQueryCharacterRect((nsQueryContentEvent*)aEvent);
|
||||
}
|
||||
break;
|
||||
case NS_QUERY_CARET_RECT:
|
||||
{
|
||||
nsQueryContentEventHandler handler(mPresContext);
|
||||
handler.OnQueryCaretRect((nsQueryContentEvent*)aEvent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,575 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Japan.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Masayuki Nakano <masayuki@d-toybox.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsQueryContentEventHandler.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsISelection.h"
|
||||
#include "nsIDOMText.h"
|
||||
#include "nsIDOMRange.h"
|
||||
#include "nsRange.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsICaret.h"
|
||||
#include "nsFrameSelection.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIView.h"
|
||||
#include "nsIContentIterator.h"
|
||||
#include "nsTextFragment.h"
|
||||
#include "nsTextFrame.h"
|
||||
|
||||
nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult);
|
||||
|
||||
/******************************************************************/
|
||||
/* nsQueryContentEventHandler */
|
||||
/******************************************************************/
|
||||
|
||||
nsQueryContentEventHandler::nsQueryContentEventHandler(
|
||||
nsPresContext* aPresContext) :
|
||||
mPresContext(aPresContext),
|
||||
mPresShell(aPresContext->GetPresShell()), mSelection(nsnull),
|
||||
mFirstSelectedRange(nsnull), mRootContent(nsnull)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsQueryContentEventHandler::Init(nsQueryContentEvent* aEvent)
|
||||
{
|
||||
NS_ASSERTION(aEvent, "aEvent must not be null");
|
||||
|
||||
if (mSelection)
|
||||
return NS_OK;
|
||||
|
||||
aEvent->mSucceeded = PR_FALSE;
|
||||
|
||||
if (!mPresShell)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsresult rv = mPresShell->GetSelectionForCopy(getter_AddRefs(mSelection));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ASSERTION(mSelection,
|
||||
"GetSelectionForCopy succeeded, but the result is null");
|
||||
|
||||
nsCOMPtr<nsIDOMRange> firstRange;
|
||||
rv = mSelection->GetRangeAt(0, getter_AddRefs(firstRange));
|
||||
// This shell doesn't support selection.
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
mFirstSelectedRange = do_QueryInterface(firstRange);
|
||||
NS_ENSURE_TRUE(mFirstSelectedRange, NS_ERROR_FAILURE);
|
||||
|
||||
nsINode* startNode = mFirstSelectedRange->GetStartParent();
|
||||
NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
|
||||
mRootContent = startNode->GetSelectionRootContent(mPresShell);
|
||||
NS_ENSURE_TRUE(mRootContent, NS_ERROR_FAILURE);
|
||||
|
||||
aEvent->mReply.mContentsRoot = mRootContent.get();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static void ConvertToNativeNewlines(nsAFlatString& aString)
|
||||
{
|
||||
#if defined(XP_MACOSX)
|
||||
aString.ReplaceSubstring(NS_LITERAL_STRING("\n"), NS_LITERAL_STRING("\r"));
|
||||
#elif defined(XP_WIN)
|
||||
aString.ReplaceSubstring(NS_LITERAL_STRING("\n"), NS_LITERAL_STRING("\r\n"));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ConvertToXPNewlines(nsAFlatString& aString)
|
||||
{
|
||||
#if defined(XP_MACOSX)
|
||||
aString.ReplaceSubstring(NS_LITERAL_STRING("\r"), NS_LITERAL_STRING("\n"));
|
||||
#elif defined(XP_WIN)
|
||||
aString.ReplaceSubstring(NS_LITERAL_STRING("\r\n"), NS_LITERAL_STRING("\n"));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void AppendString(nsAString& aString, nsIContent* aContent)
|
||||
{
|
||||
NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
|
||||
"aContent is not a text node!");
|
||||
const nsTextFragment* text = aContent->GetText();
|
||||
if (!text)
|
||||
return;
|
||||
text->AppendTo(aString);
|
||||
}
|
||||
|
||||
static void AppendSubString(nsAString& aString, nsIContent* aContent,
|
||||
PRUint32 aXPOffset, PRUint32 aXPLength)
|
||||
{
|
||||
NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
|
||||
"aContent is not a text node!");
|
||||
const nsTextFragment* text = aContent->GetText();
|
||||
if (!text)
|
||||
return;
|
||||
text->AppendTo(aString, PRInt32(aXPOffset), PRInt32(aXPLength));
|
||||
}
|
||||
|
||||
static PRUint32 GetNativeTextLength(nsIContent* aContent)
|
||||
{
|
||||
nsAutoString str;
|
||||
if (aContent->IsNodeOfType(nsINode::eTEXT))
|
||||
AppendString(str, aContent);
|
||||
else if (aContent->IsNodeOfType(nsINode::eHTML) &&
|
||||
aContent->Tag() == nsGkAtoms::br)
|
||||
str.Assign(PRUnichar('\n'));
|
||||
ConvertToNativeNewlines(str);
|
||||
return str.Length();
|
||||
}
|
||||
|
||||
static PRUint32 ConvertToXPOffset(nsIContent* aContent, PRUint32 aNativeOffset)
|
||||
{
|
||||
|
||||
nsAutoString str;
|
||||
AppendString(str, aContent);
|
||||
ConvertToNativeNewlines(str);
|
||||
NS_ASSERTION(aNativeOffset <= str.Length(),
|
||||
"aOffsetForNativeLF is too large!");
|
||||
str.Truncate(aNativeOffset);
|
||||
ConvertToXPNewlines(str);
|
||||
return str.Length();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsQueryContentEventHandler::GenerateFlatTextContent(nsIRange* aRange,
|
||||
nsAFlatString& aString)
|
||||
{
|
||||
nsCOMPtr<nsIContentIterator> iter;
|
||||
nsresult rv = NS_NewContentIterator(getter_AddRefs(iter));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ASSERTION(iter, "NS_NewContentIterator succeeded, but the result is null");
|
||||
nsCOMPtr<nsIDOMRange> domRange(do_QueryInterface(aRange));
|
||||
NS_ASSERTION(domRange, "aRange doesn't have nsIDOMRange!");
|
||||
iter->Init(domRange);
|
||||
|
||||
NS_ASSERTION(aString.IsEmpty(), "aString must be empty string");
|
||||
|
||||
nsINode* startNode = aRange->GetStartParent();
|
||||
nsINode* endNode = aRange->GetEndParent();
|
||||
|
||||
if (startNode == endNode && startNode->IsNodeOfType(nsINode::eTEXT)) {
|
||||
nsIContent* content = static_cast<nsIContent*>(startNode);
|
||||
AppendSubString(aString, content, aRange->StartOffset(),
|
||||
aRange->EndOffset() - aRange->StartOffset());
|
||||
ConvertToNativeNewlines(aString);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString tmpStr;
|
||||
for (; !iter->IsDone(); iter->Next()) {
|
||||
nsIContent* content = iter->GetCurrentNode();
|
||||
if (!content)
|
||||
continue;
|
||||
|
||||
if (content->IsNodeOfType(nsINode::eTEXT)) {
|
||||
if (content == startNode)
|
||||
AppendSubString(aString, content, aRange->StartOffset(),
|
||||
content->TextLength() - aRange->StartOffset());
|
||||
else if (content == endNode)
|
||||
AppendSubString(aString, content, 0, aRange->EndOffset());
|
||||
else
|
||||
AppendString(aString, content);
|
||||
} else if (content->IsNodeOfType(nsINode::eHTML) &&
|
||||
content->Tag() == nsGkAtoms::br)
|
||||
aString.Append(PRUnichar('\n'));
|
||||
}
|
||||
ConvertToNativeNewlines(aString);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsQueryContentEventHandler::ExpandToClusterBoundary(nsIContent* aContent,
|
||||
PRBool aForward,
|
||||
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
|
||||
// boundaries. It's false, but no problem now, maybe.
|
||||
if (!aContent->IsNodeOfType(nsINode::eTEXT) ||
|
||||
*aXPOffset == 0 || *aXPOffset == aContent->TextLength())
|
||||
return NS_OK;
|
||||
nsCOMPtr<nsFrameSelection> fs = mPresShell->FrameSelection();
|
||||
PRInt32 offsetInFrame;
|
||||
nsFrameSelection::HINT hint =
|
||||
aForward ? nsFrameSelection::HINTLEFT : nsFrameSelection::HINTRIGHT;
|
||||
nsIFrame* frame = fs->GetFrameForNodeOffset(aContent, PRInt32(*aXPOffset),
|
||||
hint, &offsetInFrame);
|
||||
if (!frame) {
|
||||
// This content doesn't have any frames, we only can check surrogate pair...
|
||||
const nsTextFragment* text = aContent->GetText();
|
||||
NS_ENSURE_TRUE(text, NS_ERROR_FAILURE);
|
||||
if (NS_IS_LOW_SURROGATE(text->CharAt(*aXPOffset)) &&
|
||||
NS_IS_HIGH_SURROGATE(text->CharAt(*aXPOffset - 1)))
|
||||
*aXPOffset += aForward ? 1 : -1;
|
||||
return NS_OK;
|
||||
}
|
||||
PRInt32 startOffset, endOffset;
|
||||
nsresult rv = frame->GetOffsets(startOffset, endOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (*aXPOffset == PRUint32(startOffset) || *aXPOffset == PRUint32(endOffset))
|
||||
return NS_OK;
|
||||
if (frame->GetType() != nsGkAtoms::textFrame)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
|
||||
PRInt32 newOffsetInFrame = offsetInFrame;
|
||||
newOffsetInFrame += aForward ? -1 : 1;
|
||||
textFrame->PeekOffsetCharacter(aForward, &newOffsetInFrame);
|
||||
*aXPOffset = startOffset + newOffsetInFrame;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsQueryContentEventHandler::SetRangeFromFlatTextOffset(
|
||||
nsIRange* aRange,
|
||||
PRUint32 aNativeOffset,
|
||||
PRUint32 aNativeLength,
|
||||
PRBool aExpandToClusterBoundaries)
|
||||
{
|
||||
nsCOMPtr<nsIContentIterator> iter;
|
||||
nsresult rv = NS_NewContentIterator(getter_AddRefs(iter));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ASSERTION(iter, "NS_NewContentIterator succeeded, but the result is null");
|
||||
rv = iter->Init(mRootContent);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIDOMRange> domRange(do_QueryInterface(aRange));
|
||||
NS_ASSERTION(domRange, "aRange doesn't have nsIDOMRange!");
|
||||
|
||||
PRUint32 nativeOffset = 0;
|
||||
PRUint32 nativeEndOffset = aNativeOffset + aNativeLength;
|
||||
nsIContent* content = nsnull;
|
||||
for (; !iter->IsDone(); iter->Next()) {
|
||||
content = iter->GetCurrentNode();
|
||||
if (!content)
|
||||
continue;
|
||||
|
||||
PRUint32 nativeTextLength;
|
||||
nativeTextLength = GetNativeTextLength(content);
|
||||
if (nativeTextLength == 0)
|
||||
continue;
|
||||
|
||||
if (nativeOffset <= aNativeOffset &&
|
||||
aNativeOffset < nativeOffset + nativeTextLength) {
|
||||
nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(content));
|
||||
NS_ASSERTION(domNode, "aContent doesn't have nsIDOMNode!");
|
||||
|
||||
PRUint32 xpOffset =
|
||||
content->IsNodeOfType(nsINode::eTEXT) ?
|
||||
ConvertToXPOffset(content, aNativeOffset - nativeOffset) : 0;
|
||||
|
||||
if (aExpandToClusterBoundaries) {
|
||||
rv = ExpandToClusterBoundary(content, PR_FALSE, &xpOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = domRange->SetStart(domNode, PRInt32(xpOffset));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (aNativeLength == 0) {
|
||||
// Ensure that the end offset and the start offset are same.
|
||||
rv = domRange->SetEnd(domNode, PRInt32(xpOffset));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
if (nativeEndOffset <= nativeOffset + nativeTextLength) {
|
||||
nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(content));
|
||||
NS_ASSERTION(domNode, "aContent doesn't have nsIDOMNode!");
|
||||
|
||||
PRUint32 xpOffset;
|
||||
if (content->IsNodeOfType(nsINode::eTEXT)) {
|
||||
xpOffset = ConvertToXPOffset(content, nativeEndOffset - nativeOffset);
|
||||
if (aExpandToClusterBoundaries) {
|
||||
rv = ExpandToClusterBoundary(content, PR_TRUE, &xpOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
} else {
|
||||
// Use first position of next node, because the end node is ignored
|
||||
// by ContentIterator when the offset is zero.
|
||||
xpOffset = 0;
|
||||
iter->Next();
|
||||
if (iter->IsDone())
|
||||
break;
|
||||
domNode = do_QueryInterface(iter->GetCurrentNode());
|
||||
}
|
||||
|
||||
rv = domRange->SetEnd(domNode, PRInt32(xpOffset));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nativeOffset += nativeTextLength;
|
||||
}
|
||||
|
||||
if (nativeOffset < aNativeOffset)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mRootContent));
|
||||
NS_ASSERTION(domNode, "lastContent doesn't have nsIDOMNode!");
|
||||
if (!content) {
|
||||
rv = domRange->SetStart(domNode, 0);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
rv = domRange->SetEnd(domNode, PRInt32(mRootContent->GetChildCount()));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "nsIDOMRange::SetEnd failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsQueryContentEventHandler::OnQuerySelectedText(nsQueryContentEvent* aEvent)
|
||||
{
|
||||
nsresult rv = Init(aEvent);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
NS_ASSERTION(aEvent->mReply.mString.IsEmpty(),
|
||||
"The reply string must be empty");
|
||||
|
||||
rv = GetFlatTextOffsetOfRange(mFirstSelectedRange, &aEvent->mReply.mOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRBool isCollapsed;
|
||||
rv = mSelection->GetIsCollapsed(&isCollapsed);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!isCollapsed) {
|
||||
nsCOMPtr<nsIDOMRange> domRange;
|
||||
rv = mSelection->GetRangeAt(0, getter_AddRefs(domRange));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ASSERTION(domRange, "GetRangeAt succeeded, but the result is null");
|
||||
|
||||
nsCOMPtr<nsIRange> range(do_QueryInterface(domRange));
|
||||
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
|
||||
rv = GenerateFlatTextContent(range, aEvent->mReply.mString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
aEvent->mSucceeded = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsQueryContentEventHandler::OnQueryTextContent(nsQueryContentEvent* aEvent)
|
||||
{
|
||||
nsresult rv = Init(aEvent);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
NS_ASSERTION(aEvent->mReply.mString.IsEmpty(),
|
||||
"The reply string must be empty");
|
||||
|
||||
nsCOMPtr<nsIRange> range = new nsRange();
|
||||
NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY);
|
||||
rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset,
|
||||
aEvent->mInput.mLength, PR_FALSE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = GenerateFlatTextContent(range, aEvent->mReply.mString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aEvent->mSucceeded = PR_TRUE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsQueryContentEventHandler::QueryRectFor(nsQueryContentEvent* aEvent,
|
||||
nsIRange* aRange,
|
||||
nsICaret* aCaret)
|
||||
{
|
||||
PRInt32 offsetInFrame;
|
||||
nsIFrame* frame;
|
||||
nsresult rv = GetStartFrameAndOffset(aRange, &frame, &offsetInFrame);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsPoint posInFrame;
|
||||
rv = frame->GetPointFromOffset(aRange->StartOffset(), &posInFrame);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aEvent->mReply.mRect.y = posInFrame.y;
|
||||
aEvent->mReply.mRect.height = frame->GetSize().height;
|
||||
|
||||
if (aEvent->message == NS_QUERY_CHARACTER_RECT) {
|
||||
nsPoint nextPos;
|
||||
rv = frame->GetPointFromOffset(aRange->EndOffset(), &nextPos);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
aEvent->mReply.mRect.x = PR_MIN(posInFrame.x, nextPos.x);
|
||||
aEvent->mReply.mRect.width = PR_ABS(posInFrame.x - nextPos.x);
|
||||
} else {
|
||||
aEvent->mReply.mRect.x = posInFrame.x;
|
||||
aEvent->mReply.mRect.width = aCaret->GetCaretRect().width;
|
||||
}
|
||||
|
||||
// The coordinates are app units here, they will be converted to system
|
||||
// coordinates by view manager.
|
||||
rv = ConvertToRootViewRelativeOffset(frame, aEvent->mReply.mRect);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aEvent->mSucceeded = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsQueryContentEventHandler::OnQueryCharacterRect(nsQueryContentEvent* aEvent)
|
||||
{
|
||||
nsresult rv = Init(aEvent);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsCOMPtr<nsIRange> range = new nsRange();
|
||||
NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY);
|
||||
rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset, 1, PR_TRUE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (range->Collapsed()) {
|
||||
// There is no character at the offset.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return QueryRectFor(aEvent, range, nsnull);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsQueryContentEventHandler::OnQueryCaretRect(nsQueryContentEvent* aEvent)
|
||||
{
|
||||
nsresult rv = Init(aEvent);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsCOMPtr<nsICaret> caret;
|
||||
rv = mPresShell->GetCaret(getter_AddRefs(caret));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ASSERTION(caret, "GetCaret succeeded, but the result is null");
|
||||
|
||||
// When the selection is collapsed and the queried offset is current caret
|
||||
// position, we should return the "real" caret rect.
|
||||
PRBool selectionIsCollapsed;
|
||||
rv = mSelection->GetIsCollapsed(&selectionIsCollapsed);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (selectionIsCollapsed) {
|
||||
PRUint32 offset;
|
||||
rv = GetFlatTextOffsetOfRange(mFirstSelectedRange, &offset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (offset == aEvent->mInput.mOffset) {
|
||||
PRBool isCollapsed;
|
||||
rv = caret->GetCaretCoordinates(nsICaret::eTopLevelWindowCoordinates,
|
||||
mSelection, &aEvent->mReply.mRect,
|
||||
&isCollapsed, nsnull);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
aEvent->mSucceeded = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, we should set the guessed caret rect.
|
||||
nsCOMPtr<nsIRange> range = new nsRange();
|
||||
NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY);
|
||||
rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset, 0, PR_TRUE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return QueryRectFor(aEvent, range, caret);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsQueryContentEventHandler::GetFlatTextOffsetOfRange(nsIRange* aRange,
|
||||
PRUint32* aNativeOffset)
|
||||
{
|
||||
NS_ASSERTION(aNativeOffset, "param is invalid");
|
||||
|
||||
nsCOMPtr<nsIRange> prev = new nsRange();
|
||||
NS_ENSURE_TRUE(prev, NS_ERROR_OUT_OF_MEMORY);
|
||||
nsCOMPtr<nsIDOMRange> domPrev(do_QueryInterface(prev));
|
||||
NS_ASSERTION(domPrev, "nsRange doesn't have nsIDOMRange??");
|
||||
nsCOMPtr<nsIDOMNode> rootDOMNode(do_QueryInterface(mRootContent));
|
||||
domPrev->SetStart(rootDOMNode, 0);
|
||||
|
||||
nsINode* startNode = aRange->GetStartParent();
|
||||
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");
|
||||
domPrev->SetEnd(startDOMNode, startOffset);
|
||||
|
||||
nsAutoString prevStr;
|
||||
nsresult rv = GenerateFlatTextContent(prev, prevStr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
*aNativeOffset = prevStr.Length();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsQueryContentEventHandler::GetStartFrameAndOffset(nsIRange* aRange,
|
||||
nsIFrame** aFrame,
|
||||
PRInt32* aOffsetInFrame)
|
||||
{
|
||||
NS_ASSERTION(aRange && aFrame && aOffsetInFrame, "params are invalid");
|
||||
|
||||
nsIContent* content = nsnull;
|
||||
nsINode* node = aRange->GetStartParent();
|
||||
if (node && node->IsNodeOfType(nsINode::eCONTENT))
|
||||
content = static_cast<nsIContent*>(node);
|
||||
NS_ASSERTION(content, "the start node doesn't have nsIContent!");
|
||||
|
||||
nsCOMPtr<nsFrameSelection> fs = mPresShell->FrameSelection();
|
||||
*aFrame = fs->GetFrameForNodeOffset(content, aRange->StartOffset(),
|
||||
fs->GetHint(), aOffsetInFrame);
|
||||
NS_ENSURE_TRUE((*aFrame), NS_ERROR_FAILURE);
|
||||
NS_ASSERTION((*aFrame)->GetType() == nsGkAtoms::textFrame,
|
||||
"The frame is not textframe");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsQueryContentEventHandler::ConvertToRootViewRelativeOffset(nsIFrame* aFrame,
|
||||
nsRect& aRect)
|
||||
{
|
||||
NS_ASSERTION(aFrame, "aFrame must not be null");
|
||||
|
||||
nsIView* view = nsnull;
|
||||
nsPoint posInView;
|
||||
aFrame->GetOffsetFromView(posInView, &view);
|
||||
if (!view)
|
||||
return NS_ERROR_FAILURE;
|
||||
aRect += posInView + view->GetOffsetTo(nsnull);
|
||||
return NS_OK;
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Japan.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Masayuki Nakano <masayuki@d-toybox.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsQueryContentEventHandler_h__
|
||||
#define nsQueryContentEventHandler_h__
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "nsISelection.h"
|
||||
#include "nsIRange.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDOMTreeWalker.h"
|
||||
|
||||
class nsPresContext;
|
||||
class nsIPresShell;
|
||||
class nsQueryContentEvent;
|
||||
class nsICaret;
|
||||
struct nsRect;
|
||||
|
||||
/*
|
||||
* Query Content Event Handler
|
||||
* nsQueryContentEventHandler is a helper class for nsEventStateManager.
|
||||
* The platforms request some content informations, e.g., the selected text,
|
||||
* the offset of the selected text and the text for specified range.
|
||||
* This class answers to NS_QUERY_* events from actual contents.
|
||||
*/
|
||||
|
||||
class nsQueryContentEventHandler {
|
||||
public:
|
||||
nsQueryContentEventHandler(nsPresContext *aPresContext);
|
||||
|
||||
// NS_QUERY_SELECTED_TEXT event handler
|
||||
nsresult OnQuerySelectedText(nsQueryContentEvent* aEvent);
|
||||
// NS_QUERY_TEXT_CONTENT event handler
|
||||
nsresult OnQueryTextContent(nsQueryContentEvent* aEvent);
|
||||
// NS_QUERY_CHARACTER_RECT event handler
|
||||
nsresult OnQueryCharacterRect(nsQueryContentEvent* aEvent);
|
||||
// NS_QUERY_CARET_RECT event handler
|
||||
nsresult OnQueryCaretRect(nsQueryContentEvent* aEvent);
|
||||
protected:
|
||||
nsPresContext* mPresContext;
|
||||
nsIPresShell* mPresShell;
|
||||
nsCOMPtr<nsISelection> mSelection;
|
||||
nsCOMPtr<nsIRange> mFirstSelectedRange;
|
||||
nsCOMPtr<nsIContent> mRootContent;
|
||||
|
||||
nsresult Init(nsQueryContentEvent* aEvent);
|
||||
|
||||
// FlatText means the text that is generated from DOM tree. The BR elements
|
||||
// are replaced to native linefeeds. Other elements are ignored.
|
||||
|
||||
// Generate the FlatText from DOM range.
|
||||
nsresult GenerateFlatTextContent(nsIRange* aRange, nsAFlatString& aString);
|
||||
// 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
|
||||
// expanded to nearest cluster boundaries.
|
||||
nsresult SetRangeFromFlatTextOffset(nsIRange* aRange,
|
||||
PRUint32 aNativeOffset,
|
||||
PRUint32 aNativeLength,
|
||||
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
|
||||
// the frame.
|
||||
nsresult GetStartFrameAndOffset(nsIRange* aRange,
|
||||
nsIFrame** aFrame, PRInt32* aOffsetInFrame);
|
||||
// Convert the frame relative offset to the root view relative offset.
|
||||
nsresult ConvertToRootViewRelativeOffset(nsIFrame* aFrame, nsRect& aRect);
|
||||
// The helper for OnQueryCharacterRect/OnQueryCaretRect.
|
||||
// Don't call for another event.
|
||||
nsresult QueryRectFor(nsQueryContentEvent* aEvent, nsIRange* aRange,
|
||||
nsICaret* aCaret);
|
||||
// Expand aXPOffset to the nearest offset in cluster boundary. aForward is
|
||||
// true, it is expanded to forward.
|
||||
nsresult ExpandToClusterBoundary(nsIContent* aContent, PRBool aForward,
|
||||
PRUint32* aXPOffset);
|
||||
};
|
||||
|
||||
#endif // nsQueryContentEventHandler_h__
|
|
@ -4232,23 +4232,6 @@ nsHTMLEditor::SelectEntireDocument(nsISelection *aSelection)
|
|||
return nsEditor::SelectEntireDocument(aSelection);
|
||||
}
|
||||
|
||||
static nsIContent*
|
||||
FindEditableRoot(nsIContent *aContent)
|
||||
{
|
||||
nsIDocument *document = aContent->GetCurrentDoc();
|
||||
if (!document || document->HasFlag(NODE_IS_EDITABLE) ||
|
||||
!aContent->HasFlag(NODE_IS_EDITABLE)) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsIContent *parent, *content = aContent;
|
||||
while ((parent = content->GetParent()) && parent->HasFlag(NODE_IS_EDITABLE)) {
|
||||
content = parent;
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::SelectAll()
|
||||
{
|
||||
|
@ -4270,10 +4253,9 @@ nsHTMLEditor::SelectAll()
|
|||
nsCOMPtr<nsIContent> anchorContent = do_QueryInterface(anchorNode, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsIContent *rootContent = FindEditableRoot(anchorContent);
|
||||
if (!rootContent) {
|
||||
return SelectEntireDocument(selection);
|
||||
}
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
nsIContent *rootContent = anchorContent->GetSelectionRootContent(ps);
|
||||
NS_ASSERTION(rootContent, "GetSelectionRootContent failed");
|
||||
|
||||
nsCOMPtr<nsIDOMNode> rootElement = do_QueryInterface(rootContent, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
|
|
@ -994,6 +994,14 @@ void nsViewManager::UnsuppressFocusEvents()
|
|||
|
||||
}
|
||||
|
||||
static void ConvertRectAppUnitsToIntPixels(nsRect& aRect, PRInt32 p2a)
|
||||
{
|
||||
aRect.x = NSAppUnitsToIntPixels(aRect.x, p2a);
|
||||
aRect.y = NSAppUnitsToIntPixels(aRect.y, p2a);
|
||||
aRect.width = NSAppUnitsToIntPixels(aRect.width, p2a);
|
||||
aRect.height = NSAppUnitsToIntPixels(aRect.height, p2a);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aStatus)
|
||||
{
|
||||
*aStatus = nsEventStatus_eIgnore;
|
||||
|
@ -1240,6 +1248,7 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS
|
|||
|
||||
if (!NS_IS_KEY_EVENT(aEvent) && !NS_IS_IME_EVENT(aEvent) &&
|
||||
!NS_IS_CONTEXT_MENU_KEY(aEvent) && !NS_IS_FOCUS_EVENT(aEvent) &&
|
||||
!NS_IS_QUERY_CONTENT_EVENT(aEvent) &&
|
||||
aEvent->eventStructType != NS_ACCESSIBLE_EVENT) {
|
||||
// will dispatch using coordinates. Pretty bogus but it's consistent
|
||||
// with what presshell does.
|
||||
|
@ -1326,26 +1335,27 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS
|
|||
*aStatus = HandleEvent(view, pt, aEvent, capturedEvent);
|
||||
|
||||
//
|
||||
// if the event is an nsTextEvent, we need to map the reply back into platform coordinates
|
||||
// need to map the reply back into platform coordinates
|
||||
//
|
||||
if (aEvent->message==NS_TEXT_TEXT) {
|
||||
((nsTextEvent*)aEvent)->theReply.mCursorPosition.x=NSAppUnitsToIntPixels(((nsTextEvent*)aEvent)->theReply.mCursorPosition.x, p2a);
|
||||
((nsTextEvent*)aEvent)->theReply.mCursorPosition.y=NSAppUnitsToIntPixels(((nsTextEvent*)aEvent)->theReply.mCursorPosition.y, p2a);
|
||||
((nsTextEvent*)aEvent)->theReply.mCursorPosition.width=NSAppUnitsToIntPixels(((nsTextEvent*)aEvent)->theReply.mCursorPosition.width, p2a);
|
||||
((nsTextEvent*)aEvent)->theReply.mCursorPosition.height=NSAppUnitsToIntPixels(((nsTextEvent*)aEvent)->theReply.mCursorPosition.height, p2a);
|
||||
}
|
||||
if((aEvent->message==NS_COMPOSITION_START) ||
|
||||
(aEvent->message==NS_COMPOSITION_QUERY)) {
|
||||
((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.x=NSAppUnitsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.x, p2a);
|
||||
((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.y=NSAppUnitsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.y, p2a);
|
||||
((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.width=NSAppUnitsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.width, p2a);
|
||||
((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.height=NSAppUnitsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.height, p2a);
|
||||
}
|
||||
if(aEvent->message==NS_QUERYCARETRECT) {
|
||||
((nsQueryCaretRectEvent*)aEvent)->theReply.mCaretRect.x=NSAppUnitsToIntPixels(((nsQueryCaretRectEvent*)aEvent)->theReply.mCaretRect.x, p2a);
|
||||
((nsQueryCaretRectEvent*)aEvent)->theReply.mCaretRect.y=NSAppUnitsToIntPixels(((nsQueryCaretRectEvent*)aEvent)->theReply.mCaretRect.y, p2a);
|
||||
((nsQueryCaretRectEvent*)aEvent)->theReply.mCaretRect.width=NSAppUnitsToIntPixels(((nsQueryCaretRectEvent*)aEvent)->theReply.mCaretRect.width, p2a);
|
||||
((nsQueryCaretRectEvent*)aEvent)->theReply.mCaretRect.height=NSAppUnitsToIntPixels(((nsQueryCaretRectEvent*)aEvent)->theReply.mCaretRect.height, p2a);
|
||||
switch (aEvent->message) {
|
||||
case NS_TEXT_TEXT:
|
||||
ConvertRectAppUnitsToIntPixels(
|
||||
((nsTextEvent*)aEvent)->theReply.mCursorPosition, p2a);
|
||||
break;
|
||||
case NS_COMPOSITION_START:
|
||||
case NS_COMPOSITION_QUERY:
|
||||
ConvertRectAppUnitsToIntPixels(
|
||||
((nsCompositionEvent*)aEvent)->theReply.mCursorPosition, p2a);
|
||||
break;
|
||||
case NS_QUERYCARETRECT:
|
||||
ConvertRectAppUnitsToIntPixels(
|
||||
((nsQueryCaretRectEvent*)aEvent)->theReply.mCaretRect, p2a);
|
||||
break;
|
||||
case NS_QUERY_CHARACTER_RECT:
|
||||
case NS_QUERY_CARET_RECT:
|
||||
ConvertRectAppUnitsToIntPixels(
|
||||
((nsQueryContentEvent*)aEvent)->mReply.mRect, p2a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -102,6 +102,7 @@ class nsHashKey;
|
|||
#define NS_SVGZOOM_EVENT 31
|
||||
#endif // MOZ_SVG
|
||||
#define NS_XUL_COMMAND_EVENT 32
|
||||
#define NS_QUERY_CONTENT_EVENT 33
|
||||
|
||||
// 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
|
||||
|
@ -344,6 +345,22 @@ class nsHashKey;
|
|||
#define NS_BEFORECUT (NS_CUTCOPYPASTE_EVENT_START + 4)
|
||||
#define NS_BEFOREPASTE (NS_CUTCOPYPASTE_EVENT_START + 5)
|
||||
|
||||
// Query the content information
|
||||
#define NS_QUERY_CONTENT_EVENT_START 3200
|
||||
// Query for the selected text information, it return the selection offset,
|
||||
// selection length and selected text.
|
||||
#define NS_QUERY_SELECTED_TEXT (NS_QUERY_CONTENT_EVENT_START)
|
||||
// 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.
|
||||
#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
|
||||
// relative position from the top level widget.
|
||||
#define NS_QUERY_CARET_RECT (NS_QUERY_CONTENT_EVENT_START + 3)
|
||||
|
||||
/**
|
||||
* Return status for event processors, nsEventStatus, is defined in
|
||||
* nsEvent.h.
|
||||
|
@ -823,6 +840,50 @@ public:
|
|||
nsQueryCaretRectEventReply theReply;
|
||||
};
|
||||
|
||||
class nsQueryContentEvent : public nsGUIEvent
|
||||
{
|
||||
public:
|
||||
nsQueryContentEvent(PRBool aIsTrusted, PRUint32 aMsg, nsIWidget *aWidget) :
|
||||
nsGUIEvent(aIsTrusted, aMsg, aWidget, NS_QUERY_CONTENT_EVENT),
|
||||
mSucceeded(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
void InitForQueryTextContent(PRUint32 aOffset, PRUint32 aLength)
|
||||
{
|
||||
NS_ASSERTION(message == NS_QUERY_TEXT_CONTENT,
|
||||
"wrong initializer is called");
|
||||
mInput.mOffset = aOffset;
|
||||
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)
|
||||
{
|
||||
NS_ASSERTION(message == NS_QUERY_CARET_RECT,
|
||||
"wrong initializer is called");
|
||||
mInput.mOffset = aOffset;
|
||||
}
|
||||
|
||||
PRBool mSucceeded;
|
||||
struct {
|
||||
PRUint32 mOffset;
|
||||
PRUint32 mLength;
|
||||
} mInput;
|
||||
struct {
|
||||
void* mContentsRoot;
|
||||
PRUint32 mOffset;
|
||||
nsString mString;
|
||||
nsRect mRect; // Finally, the coordinates is system coordinates.
|
||||
} mReply;
|
||||
};
|
||||
|
||||
/**
|
||||
* MenuItem event
|
||||
*
|
||||
|
@ -1023,6 +1084,12 @@ enum nsDragDropEventStatus {
|
|||
((evnt)->message == NS_DEACTIVATE) || \
|
||||
((evnt)->message == NS_PLUGIN_ACTIVATE))
|
||||
|
||||
#define NS_IS_QUERY_CONTENT_EVENT(evnt) \
|
||||
(((evnt)->message == NS_QUERY_SELECTED_TEXT) || \
|
||||
((evnt)->message == NS_QUERY_TEXT_CONTENT) || \
|
||||
((evnt)->message == NS_QUERY_CHARACTER_RECT) || \
|
||||
((evnt)->message == NS_QUERY_CARET_RECT))
|
||||
|
||||
#define NS_IS_TRUSTED_EVENT(event) \
|
||||
(((event)->flags & NS_EVENT_FLAG_TRUSTED) != 0)
|
||||
|
||||
|
|
|
@ -96,7 +96,6 @@ union nsPluginPort;
|
|||
|
||||
// needed for NSTextInput implementation
|
||||
NSRange mMarkedRange;
|
||||
NSRange mSelectedRange;
|
||||
BOOL mIgnoreDoCommand;
|
||||
|
||||
BOOL mInHandScroll; // true for as long as we are hand scrolling
|
||||
|
@ -240,6 +239,7 @@ public:
|
|||
NS_IMETHOD IsVisible(PRBool& outState);
|
||||
|
||||
virtual nsIWidget* GetParent(void);
|
||||
nsIWidget* GetTopLevelWidget();
|
||||
|
||||
NS_IMETHOD ModalEventFilter(PRBool aRealEvent, void *aEvent,
|
||||
PRBool *aForWindow);
|
||||
|
|
|
@ -734,6 +734,14 @@ nsChildView::GetParent(void)
|
|||
return mParentWidget;
|
||||
}
|
||||
|
||||
nsIWidget*
|
||||
nsChildView::GetTopLevelWidget()
|
||||
{
|
||||
nsIWidget* current = this;
|
||||
for (nsIWidget* parent = GetParent(); parent ; parent = parent->GetParent())
|
||||
current = parent;
|
||||
return current;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsChildView::ModalEventFilter(PRBool aRealEvent, void *aEvent,
|
||||
PRBool *aForWindow)
|
||||
|
@ -1853,8 +1861,6 @@ NSEvent* gLastDragEvent = nil;
|
|||
// initialization for NSTextInput
|
||||
mMarkedRange.location = NSNotFound;
|
||||
mMarkedRange.length = 0;
|
||||
mSelectedRange.location = NSNotFound;
|
||||
mSelectedRange.length = 0;
|
||||
mIgnoreDoCommand = NO;
|
||||
mLastMenuForEventEvent = nil;
|
||||
mDragService = nsnull;
|
||||
|
@ -3590,7 +3596,7 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
|
|||
{
|
||||
#if DEBUG_IME
|
||||
NSLog(@"****in insertText: '%@'", insertString);
|
||||
NSLog(@" markRange = %d, %d; selRange = %d, %d", mMarkedRange.location, mMarkedRange.length, mSelectedRange.location, mSelectedRange.length);
|
||||
NSLog(@" markRange = %d, %d", mMarkedRange.location, mMarkedRange.length);
|
||||
#endif
|
||||
if (!mGeckoChild)
|
||||
return;
|
||||
|
@ -3671,7 +3677,7 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
|
|||
[self sendCompositionEvent:NS_COMPOSITION_END];
|
||||
// Note: mGeckoChild might have become null here. Don't count on it from here on.
|
||||
nsTSMManager::EndComposing();
|
||||
mSelectedRange = mMarkedRange = NSMakeRange(NSNotFound, 0);
|
||||
mMarkedRange = NSMakeRange(NSNotFound, 0);
|
||||
}
|
||||
|
||||
if (bufPtr != buffer)
|
||||
|
@ -3708,7 +3714,7 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
|
|||
{
|
||||
#if DEBUG_IME
|
||||
NSLog(@"****in setMarkedText location: %d, length: %d", selRange.location, selRange.length);
|
||||
NSLog(@" markRange = %d, %d; selRange = %d, %d", mMarkedRange.location, mMarkedRange.length, mSelectedRange.location, mSelectedRange.length);
|
||||
NSLog(@" markRange = %d, %d", mMarkedRange.location, mMarkedRange.length);
|
||||
NSLog(@" aString = '%@'", aString);
|
||||
#endif
|
||||
|
||||
|
@ -3718,8 +3724,6 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
|
|||
if (![aString isKindOfClass:[NSAttributedString class]])
|
||||
aString = [[[NSAttributedString alloc] initWithString:aString] autorelease];
|
||||
|
||||
mSelectedRange = selRange;
|
||||
|
||||
NSMutableAttributedString *mutableAttribStr = aString;
|
||||
NSString *tmpStr = [mutableAttribStr string];
|
||||
unsigned int len = [tmpStr length];
|
||||
|
@ -3732,14 +3736,17 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
|
|||
printf("****in setMarkedText, len = %d, text = ", len);
|
||||
PRUint32 n = 0;
|
||||
PRUint32 maxlen = len > 12 ? 12 : len;
|
||||
for (PRUnichar *a = bufPtr; (*a != PRUnichar('\0')) && n<maxlen; a++, n++) printf((*a&0xff80) ? "\\u%4X" : "%c", *a);
|
||||
for (PRUnichar *a = bufPtr; (*a != PRUnichar('\0')) && n<maxlen; a++, n++)
|
||||
printf((*a&0xff80) ? "\\u%4X" : "%c", *a);
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
mMarkedRange.location = 0;
|
||||
mMarkedRange.length = len;
|
||||
|
||||
if (!nsTSMManager::IsComposing()) {
|
||||
nsQueryContentEvent selection(PR_TRUE, NS_QUERY_SELECTED_TEXT, mGeckoChild);
|
||||
mGeckoChild->DispatchWindowEvent(selection);
|
||||
mMarkedRange.location = selection.mSucceeded ? selection.mReply.mOffset : 0;
|
||||
[self sendCompositionEvent:NS_COMPOSITION_START];
|
||||
// Note: mGeckoChild might have become null here. Don't count on it from here on.
|
||||
nsTSMManager::StartComposing(self);
|
||||
|
@ -3771,7 +3778,6 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
|
|||
#if DEBUG_IME
|
||||
NSLog(@"****in unmarkText");
|
||||
NSLog(@" markedRange = %d, %d", mMarkedRange.location, mMarkedRange.length);
|
||||
NSLog(@" selectedRange = %d, %d", mSelectedRange.location, mSelectedRange.length);
|
||||
#endif
|
||||
nsTSMManager::CommitIME();
|
||||
}
|
||||
|
@ -3779,13 +3785,30 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
|
|||
|
||||
- (BOOL) hasMarkedText
|
||||
{
|
||||
#if DEBUG_IME
|
||||
NSLog(@"****in hasMarkText");
|
||||
NSLog(@" markedRange = %d, %d", mMarkedRange.location, mMarkedRange.length);
|
||||
#endif
|
||||
return (mMarkedRange.location != NSNotFound) && (mMarkedRange.length != 0);
|
||||
}
|
||||
|
||||
|
||||
- (long) conversationIdentifier
|
||||
{
|
||||
return (long)self;
|
||||
#if DEBUG_IME
|
||||
NSLog(@"****in conversationIdentifier");
|
||||
#endif
|
||||
if (!mGeckoChild)
|
||||
return (long)self;
|
||||
nsQueryContentEvent textContent(PR_TRUE, NS_QUERY_TEXT_CONTENT, mGeckoChild);
|
||||
textContent.InitForQueryTextContent(0, 0);
|
||||
mGeckoChild->DispatchWindowEvent(textContent);
|
||||
if (!textContent.mSucceeded)
|
||||
return (long)self;
|
||||
#if DEBUG_IME
|
||||
NSLog(@" the ID = %ld", (long)textContent.mReply.mContentsRoot);
|
||||
#endif
|
||||
return (long)textContent.mReply.mContentsRoot;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3795,24 +3818,25 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
|
|||
NSLog(@"****in attributedSubstringFromRange");
|
||||
NSLog(@" theRange = %d, %d", theRange.location, theRange.length);
|
||||
NSLog(@" markedRange = %d, %d", mMarkedRange.location, mMarkedRange.length);
|
||||
NSLog(@" selectedRange = %d, %d", mSelectedRange.location, mSelectedRange.length);
|
||||
#endif
|
||||
if (!mGeckoChild)
|
||||
if (!mGeckoChild || theRange.length == 0)
|
||||
return nil;
|
||||
|
||||
nsReconversionEvent reconversionEvent(PR_TRUE, NS_RECONVERSION_QUERY, mGeckoChild);
|
||||
reconversionEvent.time = PR_IntervalNow();
|
||||
nsAutoString str;
|
||||
nsQueryContentEvent textContent(PR_TRUE, NS_QUERY_TEXT_CONTENT, mGeckoChild);
|
||||
textContent.InitForQueryTextContent(theRange.location, theRange.length);
|
||||
mGeckoChild->DispatchWindowEvent(textContent);
|
||||
|
||||
nsresult rv = mGeckoChild->DispatchWindowEvent(reconversionEvent);
|
||||
PRUnichar* reconvstr;
|
||||
if (NS_SUCCEEDED(rv) && (reconvstr = reconversionEvent.theReply.mReconversionString)) {
|
||||
NSAttributedString* result = [[[NSAttributedString alloc] initWithString:[NSString stringWithCharacters:reconvstr length:nsCRT::strlen(reconvstr)]
|
||||
attributes:nil] autorelease];
|
||||
nsMemory::Free(reconvstr);
|
||||
return result;
|
||||
}
|
||||
if (!textContent.mSucceeded || textContent.mReply.mString.IsEmpty())
|
||||
return nil;
|
||||
|
||||
return nil;
|
||||
NSString* nsstr =
|
||||
[NSString stringWithCharacters:textContent.mReply.mString.get()
|
||||
length:textContent.mReply.mString.Length()];
|
||||
NSAttributedString* result =
|
||||
[[[NSAttributedString alloc] initWithString:nsstr
|
||||
attributes:nil] autorelease];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3821,7 +3845,6 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
|
|||
#if DEBUG_IME
|
||||
NSLog(@"****in markedRange");
|
||||
NSLog(@" markedRange = %d, %d", mMarkedRange.location, mMarkedRange.length);
|
||||
NSLog(@" selectedRange = %d, %d", mSelectedRange.location, mSelectedRange.length);
|
||||
#endif
|
||||
|
||||
if (![self hasMarkedText]) {
|
||||
|
@ -3837,10 +3860,20 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
|
|||
#if DEBUG_IME
|
||||
NSLog(@"****in selectedRange");
|
||||
NSLog(@" markedRange = %d, %d", mMarkedRange.location, mMarkedRange.length);
|
||||
NSLog(@" selectedRange = %d, %d", mSelectedRange.location, mSelectedRange.length);
|
||||
#endif
|
||||
if (!mGeckoChild)
|
||||
return NSMakeRange(NSNotFound, 0);
|
||||
nsQueryContentEvent selection(PR_TRUE, NS_QUERY_SELECTED_TEXT, mGeckoChild);
|
||||
mGeckoChild->DispatchWindowEvent(selection);
|
||||
if (!selection.mSucceeded)
|
||||
return NSMakeRange(NSNotFound, 0);
|
||||
|
||||
return mSelectedRange;
|
||||
#if DEBUG_IME
|
||||
NSLog(@" result of selectedRange = %d, %d",
|
||||
selection.mReply.mOffset, selection.mReply.mString.Length());
|
||||
#endif
|
||||
return NSMakeRange(selection.mReply.mOffset,
|
||||
selection.mReply.mString.Length());
|
||||
}
|
||||
|
||||
|
||||
|
@ -3850,20 +3883,52 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
|
|||
NSLog(@"****in firstRectForCharacterRange");
|
||||
NSLog(@" theRange = %d, %d", theRange.location, theRange.length);
|
||||
NSLog(@" markedRange = %d, %d", mMarkedRange.location, mMarkedRange.length);
|
||||
NSLog(@" selectedRange = %d, %d", mSelectedRange.location, mSelectedRange.length);
|
||||
#endif
|
||||
// XXX this returns first character rect or caret rect, it is limitation of
|
||||
// now. We need more work for returns first line rect. But current
|
||||
// implementation is enough for IMEs.
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsRect compositionRect = [self sendCompositionEvent:NS_COMPOSITION_QUERY];
|
||||
NSRect rect;
|
||||
if (!mGeckoChild || theRange.location == NSNotFound)
|
||||
return rect;
|
||||
|
||||
NSRect rangeRect;
|
||||
GeckoRectToNSRect(compositionRect, rangeRect);
|
||||
nsRect r;
|
||||
PRBool useCaretRect = theRange.length == 0;
|
||||
if (!useCaretRect) {
|
||||
nsQueryContentEvent charRect(PR_TRUE, NS_QUERY_CHARACTER_RECT, mGeckoChild);
|
||||
charRect.InitForQueryCharacterRect(theRange.location);
|
||||
mGeckoChild->DispatchWindowEvent(charRect);
|
||||
if (charRect.mSucceeded)
|
||||
r = charRect.mReply.mRect;
|
||||
else
|
||||
useCaretRect = PR_TRUE;
|
||||
}
|
||||
|
||||
// convert to window coords
|
||||
rangeRect = [self convertRect:rangeRect toView:nil];
|
||||
// convert to cocoa screen coords
|
||||
rangeRect.origin = [[self nativeWindow] convertBaseToScreen:rangeRect.origin];
|
||||
return rangeRect;
|
||||
if (useCaretRect) {
|
||||
nsQueryContentEvent caretRect(PR_TRUE, NS_QUERY_CARET_RECT, mGeckoChild);
|
||||
caretRect.InitForQueryCaretRect(theRange.location);
|
||||
mGeckoChild->DispatchWindowEvent(caretRect);
|
||||
if (!caretRect.mSucceeded)
|
||||
return rect;
|
||||
r = caretRect.mReply.mRect;
|
||||
r.width = 0;
|
||||
}
|
||||
|
||||
nsIWidget* rootWidget = mGeckoChild->GetTopLevelWidget();
|
||||
NSWindow* rootWindow =
|
||||
static_cast<NSWindow*>(rootWidget->GetNativeData(NS_NATIVE_WINDOW));
|
||||
NSView* rootView =
|
||||
static_cast<NSView*>(rootWidget->GetNativeData(NS_NATIVE_WIDGET));
|
||||
if (!rootWindow || !rootView)
|
||||
return rect;
|
||||
GeckoRectToNSRect(r, rect);
|
||||
rect = [rootView convertRect:rect toView:nil];
|
||||
rect.origin = [rootWindow convertBaseToScreen:rect.origin];
|
||||
#if DEBUG_IME
|
||||
NSLog(@" result rect (x,y,w,h) = %f, %f, %f, %f",
|
||||
rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
|
||||
#endif
|
||||
return rect;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3871,7 +3936,7 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
|
|||
{
|
||||
#if DEBUG_IME
|
||||
NSLog(@"****in characterIndexForPoint");
|
||||
NSLog(@" markRange = %d, %d; selectRange = %d, %d", mMarkedRange.location, mMarkedRange.length, mSelectedRange.location, mSelectedRange.length);
|
||||
NSLog(@" markRange = %d, %d", mMarkedRange.location, mMarkedRange.length);
|
||||
#endif
|
||||
|
||||
// To implement this, we'd have to grovel in text frames looking at text offsets.
|
||||
|
@ -3883,7 +3948,7 @@ static PRBool IsSpecialGeckoKey(UInt32 macKeyCode)
|
|||
{
|
||||
#if DEBUG_IME
|
||||
NSLog(@"****in validAttributesForMarkedText");
|
||||
NSLog(@" markRange = %d, %d; selectRange = %d, %d", mMarkedRange.location, mMarkedRange.length, mSelectedRange.location, mSelectedRange.length);
|
||||
NSLog(@" markRange = %d, %d", mMarkedRange.location, mMarkedRange.length);
|
||||
#endif
|
||||
|
||||
//return [NSArray arrayWithObjects:NSUnderlineStyleAttributeName, NSMarkedClauseSegmentAttributeName, NSTextInputReplacementRangeAttributeName, nil];
|
||||
|
|
Загрузка…
Ссылка в новой задаче