1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=80: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
20 * Portions created by the Initial Developer are Copyright (C) 2008
21 * the Initial Developer. All Rights Reserved.
24 * Masayuki Nakano <masayuki@d-toybox.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "nsQueryContentEventHandler.h"
42 #include "nsPresContext.h"
43 #include "nsIPresShell.h"
44 #include "nsISelection.h"
45 #include "nsIDOMText.h"
46 #include "nsIDOMRange.h"
48 #include "nsGUIEvent.h"
50 #include "nsFrameSelection.h"
53 #include "nsIContentIterator.h"
54 #include "nsTextFragment.h"
55 #include "nsTextFrame.h"
57 nsresult
NS_NewContentIterator(nsIContentIterator
** aInstancePtrResult
);
59 /******************************************************************/
60 /* nsQueryContentEventHandler */
61 /******************************************************************/
63 nsQueryContentEventHandler::nsQueryContentEventHandler(
64 nsPresContext
* aPresContext
) :
65 mPresContext(aPresContext
),
66 mPresShell(aPresContext
->GetPresShell()), mSelection(nsnull
),
67 mFirstSelectedRange(nsnull
), mRootContent(nsnull
)
72 nsQueryContentEventHandler::Init(nsQueryContentEvent
* aEvent
)
74 NS_ASSERTION(aEvent
, "aEvent must not be null");
79 aEvent
->mSucceeded
= PR_FALSE
;
82 return NS_ERROR_NOT_AVAILABLE
;
84 nsresult rv
= mPresShell
->GetSelectionForCopy(getter_AddRefs(mSelection
));
85 NS_ENSURE_SUCCESS(rv
, rv
);
86 NS_ASSERTION(mSelection
,
87 "GetSelectionForCopy succeeded, but the result is null");
89 nsCOMPtr
<nsIDOMRange
> firstRange
;
90 rv
= mSelection
->GetRangeAt(0, getter_AddRefs(firstRange
));
91 // This shell doesn't support selection.
93 return NS_ERROR_NOT_AVAILABLE
;
94 mFirstSelectedRange
= do_QueryInterface(firstRange
);
95 NS_ENSURE_TRUE(mFirstSelectedRange
, NS_ERROR_FAILURE
);
97 nsINode
* startNode
= mFirstSelectedRange
->GetStartParent();
98 NS_ENSURE_TRUE(startNode
, NS_ERROR_FAILURE
);
99 mRootContent
= startNode
->GetSelectionRootContent(mPresShell
);
100 NS_ENSURE_TRUE(mRootContent
, NS_ERROR_FAILURE
);
102 aEvent
->mReply
.mContentsRoot
= mRootContent
.get();
104 nsRefPtr
<nsCaret
> caret
;
105 rv
= mPresShell
->GetCaret(getter_AddRefs(caret
));
106 NS_ENSURE_SUCCESS(rv
, rv
);
107 NS_ASSERTION(caret
, "GetCaret succeeded, but the result is null");
110 nsIView
* view
= nsnull
;
111 rv
= caret
->GetCaretCoordinates(nsCaret::eRenderingViewCoordinates
,
112 mSelection
, &r
, &isCollapsed
, &view
);
113 NS_ENSURE_SUCCESS(rv
, rv
);
114 NS_ENSURE_TRUE(view
, NS_ERROR_FAILURE
);
115 aEvent
->mReply
.mFocusedWidget
= view
->GetWidget();
120 static void ConvertToNativeNewlines(nsAFlatString
& aString
)
122 #if defined(XP_MACOSX)
123 aString
.ReplaceSubstring(NS_LITERAL_STRING("\n"), NS_LITERAL_STRING("\r"));
124 #elif defined(XP_WIN)
125 aString
.ReplaceSubstring(NS_LITERAL_STRING("\n"), NS_LITERAL_STRING("\r\n"));
129 static void ConvertToXPNewlines(nsAFlatString
& aString
)
131 #if defined(XP_MACOSX)
132 aString
.ReplaceSubstring(NS_LITERAL_STRING("\r"), NS_LITERAL_STRING("\n"));
133 #elif defined(XP_WIN)
134 aString
.ReplaceSubstring(NS_LITERAL_STRING("\r\n"), NS_LITERAL_STRING("\n"));
138 static void AppendString(nsAString
& aString
, nsIContent
* aContent
)
140 NS_ASSERTION(aContent
->IsNodeOfType(nsINode::eTEXT
),
141 "aContent is not a text node!");
142 const nsTextFragment
* text
= aContent
->GetText();
145 text
->AppendTo(aString
);
148 static void AppendSubString(nsAString
& aString
, nsIContent
* aContent
,
149 PRUint32 aXPOffset
, PRUint32 aXPLength
)
151 NS_ASSERTION(aContent
->IsNodeOfType(nsINode::eTEXT
),
152 "aContent is not a text node!");
153 const nsTextFragment
* text
= aContent
->GetText();
156 text
->AppendTo(aString
, PRInt32(aXPOffset
), PRInt32(aXPLength
));
159 static PRUint32
GetNativeTextLength(nsIContent
* aContent
)
162 if (aContent
->IsNodeOfType(nsINode::eTEXT
))
163 AppendString(str
, aContent
);
164 else if (aContent
->IsNodeOfType(nsINode::eHTML
) &&
165 aContent
->Tag() == nsGkAtoms::br
)
166 str
.Assign(PRUnichar('\n'));
167 ConvertToNativeNewlines(str
);
171 static PRUint32
ConvertToXPOffset(nsIContent
* aContent
, PRUint32 aNativeOffset
)
175 AppendString(str
, aContent
);
176 ConvertToNativeNewlines(str
);
177 NS_ASSERTION(aNativeOffset
<= str
.Length(),
178 "aOffsetForNativeLF is too large!");
179 str
.Truncate(aNativeOffset
);
180 ConvertToXPNewlines(str
);
185 nsQueryContentEventHandler::GenerateFlatTextContent(nsIRange
* aRange
,
186 nsAFlatString
& aString
)
188 nsCOMPtr
<nsIContentIterator
> iter
;
189 nsresult rv
= NS_NewContentIterator(getter_AddRefs(iter
));
190 NS_ENSURE_SUCCESS(rv
, rv
);
191 NS_ASSERTION(iter
, "NS_NewContentIterator succeeded, but the result is null");
192 nsCOMPtr
<nsIDOMRange
> domRange(do_QueryInterface(aRange
));
193 NS_ASSERTION(domRange
, "aRange doesn't have nsIDOMRange!");
194 iter
->Init(domRange
);
196 NS_ASSERTION(aString
.IsEmpty(), "aString must be empty string");
198 nsINode
* startNode
= aRange
->GetStartParent();
199 nsINode
* endNode
= aRange
->GetEndParent();
201 if (startNode
== endNode
&& startNode
->IsNodeOfType(nsINode::eTEXT
)) {
202 nsIContent
* content
= static_cast<nsIContent
*>(startNode
);
203 AppendSubString(aString
, content
, aRange
->StartOffset(),
204 aRange
->EndOffset() - aRange
->StartOffset());
205 ConvertToNativeNewlines(aString
);
210 for (; !iter
->IsDone(); iter
->Next()) {
211 nsINode
* node
= iter
->GetCurrentNode();
212 if (!node
|| !node
->IsNodeOfType(nsINode::eCONTENT
))
214 nsIContent
* content
= static_cast<nsIContent
*>(node
);
216 if (content
->IsNodeOfType(nsINode::eTEXT
)) {
217 if (content
== startNode
)
218 AppendSubString(aString
, content
, aRange
->StartOffset(),
219 content
->TextLength() - aRange
->StartOffset());
220 else if (content
== endNode
)
221 AppendSubString(aString
, content
, 0, aRange
->EndOffset());
223 AppendString(aString
, content
);
224 } else if (content
->IsNodeOfType(nsINode::eHTML
) &&
225 content
->Tag() == nsGkAtoms::br
)
226 aString
.Append(PRUnichar('\n'));
228 ConvertToNativeNewlines(aString
);
233 nsQueryContentEventHandler::ExpandToClusterBoundary(nsIContent
* aContent
,
237 NS_ASSERTION(*aXPOffset
>= 0 && *aXPOffset
<= aContent
->TextLength(),
238 "offset is out of range.");
240 // XXX This method assumes that the frame boundaries must be cluster
241 // boundaries. It's false, but no problem now, maybe.
242 if (!aContent
->IsNodeOfType(nsINode::eTEXT
) ||
243 *aXPOffset
== 0 || *aXPOffset
== aContent
->TextLength())
245 nsCOMPtr
<nsFrameSelection
> fs
= mPresShell
->FrameSelection();
246 PRInt32 offsetInFrame
;
247 nsFrameSelection::HINT hint
=
248 aForward
? nsFrameSelection::HINTLEFT
: nsFrameSelection::HINTRIGHT
;
249 nsIFrame
* frame
= fs
->GetFrameForNodeOffset(aContent
, PRInt32(*aXPOffset
),
250 hint
, &offsetInFrame
);
252 // This content doesn't have any frames, we only can check surrogate pair...
253 const nsTextFragment
* text
= aContent
->GetText();
254 NS_ENSURE_TRUE(text
, NS_ERROR_FAILURE
);
255 if (NS_IS_LOW_SURROGATE(text
->CharAt(*aXPOffset
)) &&
256 NS_IS_HIGH_SURROGATE(text
->CharAt(*aXPOffset
- 1)))
257 *aXPOffset
+= aForward
? 1 : -1;
260 PRInt32 startOffset
, endOffset
;
261 nsresult rv
= frame
->GetOffsets(startOffset
, endOffset
);
262 NS_ENSURE_SUCCESS(rv
, rv
);
263 if (*aXPOffset
== PRUint32(startOffset
) || *aXPOffset
== PRUint32(endOffset
))
265 if (frame
->GetType() != nsGkAtoms::textFrame
)
266 return NS_ERROR_FAILURE
;
267 nsTextFrame
* textFrame
= static_cast<nsTextFrame
*>(frame
);
268 PRInt32 newOffsetInFrame
= offsetInFrame
;
269 newOffsetInFrame
+= aForward
? -1 : 1;
270 textFrame
->PeekOffsetCharacter(aForward
, &newOffsetInFrame
);
271 *aXPOffset
= startOffset
+ newOffsetInFrame
;
276 nsQueryContentEventHandler::SetRangeFromFlatTextOffset(
278 PRUint32 aNativeOffset
,
279 PRUint32 aNativeLength
,
280 PRBool aExpandToClusterBoundaries
)
282 nsCOMPtr
<nsIContentIterator
> iter
;
283 nsresult rv
= NS_NewContentIterator(getter_AddRefs(iter
));
284 NS_ENSURE_SUCCESS(rv
, rv
);
285 NS_ASSERTION(iter
, "NS_NewContentIterator succeeded, but the result is null");
286 rv
= iter
->Init(mRootContent
);
287 NS_ENSURE_SUCCESS(rv
, rv
);
288 nsCOMPtr
<nsIDOMRange
> domRange(do_QueryInterface(aRange
));
289 NS_ASSERTION(domRange
, "aRange doesn't have nsIDOMRange!");
291 PRUint32 nativeOffset
= 0;
292 PRUint32 nativeEndOffset
= aNativeOffset
+ aNativeLength
;
293 nsCOMPtr
<nsIContent
> content
;
294 for (; !iter
->IsDone(); iter
->Next()) {
295 nsINode
* node
= iter
->GetCurrentNode();
296 if (!node
|| !node
->IsNodeOfType(nsINode::eCONTENT
))
298 nsIContent
* content
= static_cast<nsIContent
*>(node
);
300 PRUint32 nativeTextLength
;
301 nativeTextLength
= GetNativeTextLength(content
);
302 if (nativeTextLength
== 0)
305 if (nativeOffset
<= aNativeOffset
&&
306 aNativeOffset
< nativeOffset
+ nativeTextLength
) {
307 nsCOMPtr
<nsIDOMNode
> domNode(do_QueryInterface(content
));
308 NS_ASSERTION(domNode
, "aContent doesn't have nsIDOMNode!");
311 content
->IsNodeOfType(nsINode::eTEXT
) ?
312 ConvertToXPOffset(content
, aNativeOffset
- nativeOffset
) : 0;
314 if (aExpandToClusterBoundaries
) {
315 rv
= ExpandToClusterBoundary(content
, PR_FALSE
, &xpOffset
);
316 NS_ENSURE_SUCCESS(rv
, rv
);
319 rv
= domRange
->SetStart(domNode
, PRInt32(xpOffset
));
320 NS_ENSURE_SUCCESS(rv
, rv
);
321 if (aNativeLength
== 0) {
322 // Ensure that the end offset and the start offset are same.
323 rv
= domRange
->SetEnd(domNode
, PRInt32(xpOffset
));
324 NS_ENSURE_SUCCESS(rv
, rv
);
328 if (nativeEndOffset
<= nativeOffset
+ nativeTextLength
) {
329 nsCOMPtr
<nsIDOMNode
> domNode(do_QueryInterface(content
));
330 NS_ASSERTION(domNode
, "aContent doesn't have nsIDOMNode!");
333 if (content
->IsNodeOfType(nsINode::eTEXT
)) {
334 xpOffset
= ConvertToXPOffset(content
, nativeEndOffset
- nativeOffset
);
335 if (aExpandToClusterBoundaries
) {
336 rv
= ExpandToClusterBoundary(content
, PR_TRUE
, &xpOffset
);
337 NS_ENSURE_SUCCESS(rv
, rv
);
340 // Use first position of next node, because the end node is ignored
341 // by ContentIterator when the offset is zero.
346 domNode
= do_QueryInterface(iter
->GetCurrentNode());
349 rv
= domRange
->SetEnd(domNode
, PRInt32(xpOffset
));
350 NS_ENSURE_SUCCESS(rv
, rv
);
354 nativeOffset
+= nativeTextLength
;
357 if (nativeOffset
< aNativeOffset
)
358 return NS_ERROR_FAILURE
;
360 nsCOMPtr
<nsIDOMNode
> domNode(do_QueryInterface(mRootContent
));
361 NS_ASSERTION(domNode
, "lastContent doesn't have nsIDOMNode!");
363 rv
= domRange
->SetStart(domNode
, 0);
364 NS_ENSURE_SUCCESS(rv
, rv
);
366 rv
= domRange
->SetEnd(domNode
, PRInt32(mRootContent
->GetChildCount()));
367 NS_ASSERTION(NS_SUCCEEDED(rv
), "nsIDOMRange::SetEnd failed");
372 nsQueryContentEventHandler::OnQuerySelectedText(nsQueryContentEvent
* aEvent
)
374 nsresult rv
= Init(aEvent
);
378 NS_ASSERTION(aEvent
->mReply
.mString
.IsEmpty(),
379 "The reply string must be empty");
381 rv
= GetFlatTextOffsetOfRange(mFirstSelectedRange
, &aEvent
->mReply
.mOffset
);
382 NS_ENSURE_SUCCESS(rv
, rv
);
385 rv
= mSelection
->GetIsCollapsed(&isCollapsed
);
386 NS_ENSURE_SUCCESS(rv
, rv
);
389 nsCOMPtr
<nsIDOMRange
> domRange
;
390 rv
= mSelection
->GetRangeAt(0, getter_AddRefs(domRange
));
391 NS_ENSURE_SUCCESS(rv
, rv
);
392 NS_ASSERTION(domRange
, "GetRangeAt succeeded, but the result is null");
394 nsCOMPtr
<nsIRange
> range(do_QueryInterface(domRange
));
395 NS_ENSURE_TRUE(range
, NS_ERROR_FAILURE
);
396 rv
= GenerateFlatTextContent(range
, aEvent
->mReply
.mString
);
397 NS_ENSURE_SUCCESS(rv
, rv
);
400 aEvent
->mSucceeded
= PR_TRUE
;
405 nsQueryContentEventHandler::OnQueryTextContent(nsQueryContentEvent
* aEvent
)
407 nsresult rv
= Init(aEvent
);
411 NS_ASSERTION(aEvent
->mReply
.mString
.IsEmpty(),
412 "The reply string must be empty");
414 nsCOMPtr
<nsIRange
> range
= new nsRange();
415 NS_ENSURE_TRUE(range
, NS_ERROR_OUT_OF_MEMORY
);
416 rv
= SetRangeFromFlatTextOffset(range
, aEvent
->mInput
.mOffset
,
417 aEvent
->mInput
.mLength
, PR_FALSE
);
418 NS_ENSURE_SUCCESS(rv
, rv
);
420 rv
= GenerateFlatTextContent(range
, aEvent
->mReply
.mString
);
421 NS_ENSURE_SUCCESS(rv
, rv
);
423 aEvent
->mSucceeded
= PR_TRUE
;
429 nsQueryContentEventHandler::QueryRectFor(nsQueryContentEvent
* aEvent
,
433 PRInt32 offsetInFrame
;
435 nsresult rv
= GetStartFrameAndOffset(aRange
, &frame
, &offsetInFrame
);
436 NS_ENSURE_SUCCESS(rv
, rv
);
439 rv
= frame
->GetPointFromOffset(aRange
->StartOffset(), &posInFrame
);
440 NS_ENSURE_SUCCESS(rv
, rv
);
442 aEvent
->mReply
.mRect
.y
= posInFrame
.y
;
443 aEvent
->mReply
.mRect
.height
= frame
->GetSize().height
;
445 if (aEvent
->message
== NS_QUERY_CHARACTER_RECT
) {
447 rv
= frame
->GetPointFromOffset(aRange
->EndOffset(), &nextPos
);
448 NS_ENSURE_SUCCESS(rv
, rv
);
449 aEvent
->mReply
.mRect
.x
= PR_MIN(posInFrame
.x
, nextPos
.x
);
450 aEvent
->mReply
.mRect
.width
= PR_ABS(posInFrame
.x
- nextPos
.x
);
452 aEvent
->mReply
.mRect
.x
= posInFrame
.x
;
453 aEvent
->mReply
.mRect
.width
= aCaret
->GetCaretRect().width
;
456 // The coordinates are app units here, they will be converted to system
457 // coordinates by view manager.
458 rv
= ConvertToRootViewRelativeOffset(frame
, aEvent
->mReply
.mRect
);
459 NS_ENSURE_SUCCESS(rv
, rv
);
461 aEvent
->mSucceeded
= PR_TRUE
;
466 nsQueryContentEventHandler::OnQueryCharacterRect(nsQueryContentEvent
* aEvent
)
468 nsresult rv
= Init(aEvent
);
472 nsCOMPtr
<nsIRange
> range
= new nsRange();
473 NS_ENSURE_TRUE(range
, NS_ERROR_OUT_OF_MEMORY
);
474 rv
= SetRangeFromFlatTextOffset(range
, aEvent
->mInput
.mOffset
, 1, PR_TRUE
);
475 NS_ENSURE_SUCCESS(rv
, rv
);
477 if (range
->Collapsed()) {
478 // There is no character at the offset.
482 return QueryRectFor(aEvent
, range
, nsnull
);
486 nsQueryContentEventHandler::OnQueryCaretRect(nsQueryContentEvent
* aEvent
)
488 nsresult rv
= Init(aEvent
);
492 nsRefPtr
<nsCaret
> caret
;
493 rv
= mPresShell
->GetCaret(getter_AddRefs(caret
));
494 NS_ENSURE_SUCCESS(rv
, rv
);
495 NS_ASSERTION(caret
, "GetCaret succeeded, but the result is null");
497 // When the selection is collapsed and the queried offset is current caret
498 // position, we should return the "real" caret rect.
499 PRBool selectionIsCollapsed
;
500 rv
= mSelection
->GetIsCollapsed(&selectionIsCollapsed
);
501 NS_ENSURE_SUCCESS(rv
, rv
);
503 if (selectionIsCollapsed
) {
505 rv
= GetFlatTextOffsetOfRange(mFirstSelectedRange
, &offset
);
506 NS_ENSURE_SUCCESS(rv
, rv
);
507 if (offset
== aEvent
->mInput
.mOffset
) {
509 rv
= caret
->GetCaretCoordinates(nsCaret::eTopLevelWindowCoordinates
,
510 mSelection
, &aEvent
->mReply
.mRect
,
511 &isCollapsed
, nsnull
);
512 NS_ENSURE_SUCCESS(rv
, rv
);
513 aEvent
->mSucceeded
= PR_TRUE
;
518 // Otherwise, we should set the guessed caret rect.
519 nsCOMPtr
<nsIRange
> range
= new nsRange();
520 NS_ENSURE_TRUE(range
, NS_ERROR_OUT_OF_MEMORY
);
521 rv
= SetRangeFromFlatTextOffset(range
, aEvent
->mInput
.mOffset
, 0, PR_TRUE
);
522 NS_ENSURE_SUCCESS(rv
, rv
);
524 return QueryRectFor(aEvent
, range
, caret
);
528 nsQueryContentEventHandler::GetFlatTextOffsetOfRange(nsIRange
* aRange
,
529 PRUint32
* aNativeOffset
)
531 NS_ASSERTION(aNativeOffset
, "param is invalid");
533 nsCOMPtr
<nsIRange
> prev
= new nsRange();
534 NS_ENSURE_TRUE(prev
, NS_ERROR_OUT_OF_MEMORY
);
535 nsCOMPtr
<nsIDOMRange
> domPrev(do_QueryInterface(prev
));
536 NS_ASSERTION(domPrev
, "nsRange doesn't have nsIDOMRange??");
537 nsCOMPtr
<nsIDOMNode
> rootDOMNode(do_QueryInterface(mRootContent
));
538 domPrev
->SetStart(rootDOMNode
, 0);
540 nsINode
* startNode
= aRange
->GetStartParent();
541 NS_ENSURE_TRUE(startNode
, NS_ERROR_FAILURE
);
543 PRInt32 startOffset
= aRange
->StartOffset();
544 nsCOMPtr
<nsIDOMNode
> startDOMNode(do_QueryInterface(startNode
));
545 NS_ASSERTION(startDOMNode
, "startNode doesn't have nsIDOMNode");
546 domPrev
->SetEnd(startDOMNode
, startOffset
);
548 nsAutoString prevStr
;
549 nsresult rv
= GenerateFlatTextContent(prev
, prevStr
);
550 NS_ENSURE_SUCCESS(rv
, rv
);
551 *aNativeOffset
= prevStr
.Length();
556 nsQueryContentEventHandler::GetStartFrameAndOffset(nsIRange
* aRange
,
558 PRInt32
* aOffsetInFrame
)
560 NS_ASSERTION(aRange
&& aFrame
&& aOffsetInFrame
, "params are invalid");
562 nsIContent
* content
= nsnull
;
563 nsINode
* node
= aRange
->GetStartParent();
564 if (node
&& node
->IsNodeOfType(nsINode::eCONTENT
))
565 content
= static_cast<nsIContent
*>(node
);
566 NS_ASSERTION(content
, "the start node doesn't have nsIContent!");
568 nsCOMPtr
<nsFrameSelection
> fs
= mPresShell
->FrameSelection();
569 *aFrame
= fs
->GetFrameForNodeOffset(content
, aRange
->StartOffset(),
570 fs
->GetHint(), aOffsetInFrame
);
571 NS_ENSURE_TRUE((*aFrame
), NS_ERROR_FAILURE
);
572 NS_ASSERTION((*aFrame
)->GetType() == nsGkAtoms::textFrame
,
573 "The frame is not textframe");
578 nsQueryContentEventHandler::ConvertToRootViewRelativeOffset(nsIFrame
* aFrame
,
581 NS_ASSERTION(aFrame
, "aFrame must not be null");
583 nsIView
* view
= nsnull
;
585 aFrame
->GetOffsetFromView(posInView
, &view
);
587 return NS_ERROR_FAILURE
;
588 aRect
+= posInView
+ view
->GetOffsetTo(nsnull
);