Bug 359675 - provide an option to manually fill forms and log in. p=poshannessy@mozil...
[wine-gecko.git] / content / events / src / nsQueryContentEventHandler.cpp
blob33aa4f3b37a93c975549635768464b2b7f932894
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
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Mozilla Japan.
20 * Portions created by the Initial Developer are Copyright (C) 2008
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
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"
41 #include "nsCOMPtr.h"
42 #include "nsPresContext.h"
43 #include "nsIPresShell.h"
44 #include "nsISelection.h"
45 #include "nsIDOMText.h"
46 #include "nsIDOMRange.h"
47 #include "nsRange.h"
48 #include "nsGUIEvent.h"
49 #include "nsICaret.h"
50 #include "nsFrameSelection.h"
51 #include "nsIFrame.h"
52 #include "nsIView.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)
71 nsresult
72 nsQueryContentEventHandler::Init(nsQueryContentEvent* aEvent)
74 NS_ASSERTION(aEvent, "aEvent must not be null");
76 if (mSelection)
77 return NS_OK;
79 aEvent->mSucceeded = PR_FALSE;
81 if (!mPresShell)
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.
92 if (NS_FAILED(rv))
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 return NS_OK;
107 static void ConvertToNativeNewlines(nsAFlatString& aString)
109 #if defined(XP_MACOSX)
110 aString.ReplaceSubstring(NS_LITERAL_STRING("\n"), NS_LITERAL_STRING("\r"));
111 #elif defined(XP_WIN)
112 aString.ReplaceSubstring(NS_LITERAL_STRING("\n"), NS_LITERAL_STRING("\r\n"));
113 #endif
116 static void ConvertToXPNewlines(nsAFlatString& aString)
118 #if defined(XP_MACOSX)
119 aString.ReplaceSubstring(NS_LITERAL_STRING("\r"), NS_LITERAL_STRING("\n"));
120 #elif defined(XP_WIN)
121 aString.ReplaceSubstring(NS_LITERAL_STRING("\r\n"), NS_LITERAL_STRING("\n"));
122 #endif
125 static void AppendString(nsAString& aString, nsIContent* aContent)
127 NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
128 "aContent is not a text node!");
129 const nsTextFragment* text = aContent->GetText();
130 if (!text)
131 return;
132 text->AppendTo(aString);
135 static void AppendSubString(nsAString& aString, nsIContent* aContent,
136 PRUint32 aXPOffset, PRUint32 aXPLength)
138 NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
139 "aContent is not a text node!");
140 const nsTextFragment* text = aContent->GetText();
141 if (!text)
142 return;
143 text->AppendTo(aString, PRInt32(aXPOffset), PRInt32(aXPLength));
146 static PRUint32 GetNativeTextLength(nsIContent* aContent)
148 nsAutoString str;
149 if (aContent->IsNodeOfType(nsINode::eTEXT))
150 AppendString(str, aContent);
151 else if (aContent->IsNodeOfType(nsINode::eHTML) &&
152 aContent->Tag() == nsGkAtoms::br)
153 str.Assign(PRUnichar('\n'));
154 ConvertToNativeNewlines(str);
155 return str.Length();
158 static PRUint32 ConvertToXPOffset(nsIContent* aContent, PRUint32 aNativeOffset)
161 nsAutoString str;
162 AppendString(str, aContent);
163 ConvertToNativeNewlines(str);
164 NS_ASSERTION(aNativeOffset <= str.Length(),
165 "aOffsetForNativeLF is too large!");
166 str.Truncate(aNativeOffset);
167 ConvertToXPNewlines(str);
168 return str.Length();
171 nsresult
172 nsQueryContentEventHandler::GenerateFlatTextContent(nsIRange* aRange,
173 nsAFlatString& aString)
175 nsCOMPtr<nsIContentIterator> iter;
176 nsresult rv = NS_NewContentIterator(getter_AddRefs(iter));
177 NS_ENSURE_SUCCESS(rv, rv);
178 NS_ASSERTION(iter, "NS_NewContentIterator succeeded, but the result is null");
179 nsCOMPtr<nsIDOMRange> domRange(do_QueryInterface(aRange));
180 NS_ASSERTION(domRange, "aRange doesn't have nsIDOMRange!");
181 iter->Init(domRange);
183 NS_ASSERTION(aString.IsEmpty(), "aString must be empty string");
185 nsINode* startNode = aRange->GetStartParent();
186 nsINode* endNode = aRange->GetEndParent();
188 if (startNode == endNode && startNode->IsNodeOfType(nsINode::eTEXT)) {
189 nsIContent* content = static_cast<nsIContent*>(startNode);
190 AppendSubString(aString, content, aRange->StartOffset(),
191 aRange->EndOffset() - aRange->StartOffset());
192 ConvertToNativeNewlines(aString);
193 return NS_OK;
196 nsAutoString tmpStr;
197 for (; !iter->IsDone(); iter->Next()) {
198 nsIContent* content = iter->GetCurrentNode();
199 if (!content)
200 continue;
202 if (content->IsNodeOfType(nsINode::eTEXT)) {
203 if (content == startNode)
204 AppendSubString(aString, content, aRange->StartOffset(),
205 content->TextLength() - aRange->StartOffset());
206 else if (content == endNode)
207 AppendSubString(aString, content, 0, aRange->EndOffset());
208 else
209 AppendString(aString, content);
210 } else if (content->IsNodeOfType(nsINode::eHTML) &&
211 content->Tag() == nsGkAtoms::br)
212 aString.Append(PRUnichar('\n'));
214 ConvertToNativeNewlines(aString);
215 return NS_OK;
218 nsresult
219 nsQueryContentEventHandler::ExpandToClusterBoundary(nsIContent* aContent,
220 PRBool aForward,
221 PRUint32* aXPOffset)
223 NS_ASSERTION(*aXPOffset >= 0 && *aXPOffset <= aContent->TextLength(),
224 "offset is out of range.");
226 // XXX This method assumes that the frame boundaries must be cluster
227 // boundaries. It's false, but no problem now, maybe.
228 if (!aContent->IsNodeOfType(nsINode::eTEXT) ||
229 *aXPOffset == 0 || *aXPOffset == aContent->TextLength())
230 return NS_OK;
231 nsCOMPtr<nsFrameSelection> fs = mPresShell->FrameSelection();
232 PRInt32 offsetInFrame;
233 nsFrameSelection::HINT hint =
234 aForward ? nsFrameSelection::HINTLEFT : nsFrameSelection::HINTRIGHT;
235 nsIFrame* frame = fs->GetFrameForNodeOffset(aContent, PRInt32(*aXPOffset),
236 hint, &offsetInFrame);
237 if (!frame) {
238 // This content doesn't have any frames, we only can check surrogate pair...
239 const nsTextFragment* text = aContent->GetText();
240 NS_ENSURE_TRUE(text, NS_ERROR_FAILURE);
241 if (NS_IS_LOW_SURROGATE(text->CharAt(*aXPOffset)) &&
242 NS_IS_HIGH_SURROGATE(text->CharAt(*aXPOffset - 1)))
243 *aXPOffset += aForward ? 1 : -1;
244 return NS_OK;
246 PRInt32 startOffset, endOffset;
247 nsresult rv = frame->GetOffsets(startOffset, endOffset);
248 NS_ENSURE_SUCCESS(rv, rv);
249 if (*aXPOffset == PRUint32(startOffset) || *aXPOffset == PRUint32(endOffset))
250 return NS_OK;
251 if (frame->GetType() != nsGkAtoms::textFrame)
252 return NS_ERROR_FAILURE;
253 nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
254 PRInt32 newOffsetInFrame = offsetInFrame;
255 newOffsetInFrame += aForward ? -1 : 1;
256 textFrame->PeekOffsetCharacter(aForward, &newOffsetInFrame);
257 *aXPOffset = startOffset + newOffsetInFrame;
258 return NS_OK;
261 nsresult
262 nsQueryContentEventHandler::SetRangeFromFlatTextOffset(
263 nsIRange* aRange,
264 PRUint32 aNativeOffset,
265 PRUint32 aNativeLength,
266 PRBool aExpandToClusterBoundaries)
268 nsCOMPtr<nsIContentIterator> iter;
269 nsresult rv = NS_NewContentIterator(getter_AddRefs(iter));
270 NS_ENSURE_SUCCESS(rv, rv);
271 NS_ASSERTION(iter, "NS_NewContentIterator succeeded, but the result is null");
272 rv = iter->Init(mRootContent);
273 NS_ENSURE_SUCCESS(rv, rv);
274 nsCOMPtr<nsIDOMRange> domRange(do_QueryInterface(aRange));
275 NS_ASSERTION(domRange, "aRange doesn't have nsIDOMRange!");
277 PRUint32 nativeOffset = 0;
278 PRUint32 nativeEndOffset = aNativeOffset + aNativeLength;
279 nsIContent* content = nsnull;
280 for (; !iter->IsDone(); iter->Next()) {
281 content = iter->GetCurrentNode();
282 if (!content)
283 continue;
285 PRUint32 nativeTextLength;
286 nativeTextLength = GetNativeTextLength(content);
287 if (nativeTextLength == 0)
288 continue;
290 if (nativeOffset <= aNativeOffset &&
291 aNativeOffset < nativeOffset + nativeTextLength) {
292 nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(content));
293 NS_ASSERTION(domNode, "aContent doesn't have nsIDOMNode!");
295 PRUint32 xpOffset =
296 content->IsNodeOfType(nsINode::eTEXT) ?
297 ConvertToXPOffset(content, aNativeOffset - nativeOffset) : 0;
299 if (aExpandToClusterBoundaries) {
300 rv = ExpandToClusterBoundary(content, PR_FALSE, &xpOffset);
301 NS_ENSURE_SUCCESS(rv, rv);
304 rv = domRange->SetStart(domNode, PRInt32(xpOffset));
305 NS_ENSURE_SUCCESS(rv, rv);
306 if (aNativeLength == 0) {
307 // Ensure that the end offset and the start offset are same.
308 rv = domRange->SetEnd(domNode, PRInt32(xpOffset));
309 NS_ENSURE_SUCCESS(rv, rv);
310 return NS_OK;
313 if (nativeEndOffset <= nativeOffset + nativeTextLength) {
314 nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(content));
315 NS_ASSERTION(domNode, "aContent doesn't have nsIDOMNode!");
317 PRUint32 xpOffset;
318 if (content->IsNodeOfType(nsINode::eTEXT)) {
319 xpOffset = ConvertToXPOffset(content, nativeEndOffset - nativeOffset);
320 if (aExpandToClusterBoundaries) {
321 rv = ExpandToClusterBoundary(content, PR_TRUE, &xpOffset);
322 NS_ENSURE_SUCCESS(rv, rv);
324 } else {
325 // Use first position of next node, because the end node is ignored
326 // by ContentIterator when the offset is zero.
327 xpOffset = 0;
328 iter->Next();
329 if (iter->IsDone())
330 break;
331 domNode = do_QueryInterface(iter->GetCurrentNode());
334 rv = domRange->SetEnd(domNode, PRInt32(xpOffset));
335 NS_ENSURE_SUCCESS(rv, rv);
336 return NS_OK;
339 nativeOffset += nativeTextLength;
342 if (nativeOffset < aNativeOffset)
343 return NS_ERROR_FAILURE;
345 nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mRootContent));
346 NS_ASSERTION(domNode, "lastContent doesn't have nsIDOMNode!");
347 if (!content) {
348 rv = domRange->SetStart(domNode, 0);
349 NS_ENSURE_SUCCESS(rv, rv);
351 rv = domRange->SetEnd(domNode, PRInt32(mRootContent->GetChildCount()));
352 NS_ASSERTION(NS_SUCCEEDED(rv), "nsIDOMRange::SetEnd failed");
353 return rv;
356 nsresult
357 nsQueryContentEventHandler::OnQuerySelectedText(nsQueryContentEvent* aEvent)
359 nsresult rv = Init(aEvent);
360 if (NS_FAILED(rv))
361 return rv;
363 NS_ASSERTION(aEvent->mReply.mString.IsEmpty(),
364 "The reply string must be empty");
366 rv = GetFlatTextOffsetOfRange(mFirstSelectedRange, &aEvent->mReply.mOffset);
367 NS_ENSURE_SUCCESS(rv, rv);
369 PRBool isCollapsed;
370 rv = mSelection->GetIsCollapsed(&isCollapsed);
371 NS_ENSURE_SUCCESS(rv, rv);
373 if (!isCollapsed) {
374 nsCOMPtr<nsIDOMRange> domRange;
375 rv = mSelection->GetRangeAt(0, getter_AddRefs(domRange));
376 NS_ENSURE_SUCCESS(rv, rv);
377 NS_ASSERTION(domRange, "GetRangeAt succeeded, but the result is null");
379 nsCOMPtr<nsIRange> range(do_QueryInterface(domRange));
380 NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
381 rv = GenerateFlatTextContent(range, aEvent->mReply.mString);
382 NS_ENSURE_SUCCESS(rv, rv);
385 aEvent->mSucceeded = PR_TRUE;
386 return NS_OK;
389 nsresult
390 nsQueryContentEventHandler::OnQueryTextContent(nsQueryContentEvent* aEvent)
392 nsresult rv = Init(aEvent);
393 if (NS_FAILED(rv))
394 return rv;
396 NS_ASSERTION(aEvent->mReply.mString.IsEmpty(),
397 "The reply string must be empty");
399 nsCOMPtr<nsIRange> range = new nsRange();
400 NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY);
401 rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset,
402 aEvent->mInput.mLength, PR_FALSE);
403 NS_ENSURE_SUCCESS(rv, rv);
405 rv = GenerateFlatTextContent(range, aEvent->mReply.mString);
406 NS_ENSURE_SUCCESS(rv, rv);
408 aEvent->mSucceeded = PR_TRUE;
410 return NS_OK;
413 nsresult
414 nsQueryContentEventHandler::QueryRectFor(nsQueryContentEvent* aEvent,
415 nsIRange* aRange,
416 nsICaret* aCaret)
418 PRInt32 offsetInFrame;
419 nsIFrame* frame;
420 nsresult rv = GetStartFrameAndOffset(aRange, &frame, &offsetInFrame);
421 NS_ENSURE_SUCCESS(rv, rv);
423 nsPoint posInFrame;
424 rv = frame->GetPointFromOffset(aRange->StartOffset(), &posInFrame);
425 NS_ENSURE_SUCCESS(rv, rv);
427 aEvent->mReply.mRect.y = posInFrame.y;
428 aEvent->mReply.mRect.height = frame->GetSize().height;
430 if (aEvent->message == NS_QUERY_CHARACTER_RECT) {
431 nsPoint nextPos;
432 rv = frame->GetPointFromOffset(aRange->EndOffset(), &nextPos);
433 NS_ENSURE_SUCCESS(rv, rv);
434 aEvent->mReply.mRect.x = PR_MIN(posInFrame.x, nextPos.x);
435 aEvent->mReply.mRect.width = PR_ABS(posInFrame.x - nextPos.x);
436 } else {
437 aEvent->mReply.mRect.x = posInFrame.x;
438 aEvent->mReply.mRect.width = aCaret->GetCaretRect().width;
441 // The coordinates are app units here, they will be converted to system
442 // coordinates by view manager.
443 rv = ConvertToRootViewRelativeOffset(frame, aEvent->mReply.mRect);
444 NS_ENSURE_SUCCESS(rv, rv);
446 aEvent->mSucceeded = PR_TRUE;
447 return NS_OK;
450 nsresult
451 nsQueryContentEventHandler::OnQueryCharacterRect(nsQueryContentEvent* aEvent)
453 nsresult rv = Init(aEvent);
454 if (NS_FAILED(rv))
455 return rv;
457 nsCOMPtr<nsIRange> range = new nsRange();
458 NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY);
459 rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset, 1, PR_TRUE);
460 NS_ENSURE_SUCCESS(rv, rv);
462 if (range->Collapsed()) {
463 // There is no character at the offset.
464 return NS_OK;
467 return QueryRectFor(aEvent, range, nsnull);
470 nsresult
471 nsQueryContentEventHandler::OnQueryCaretRect(nsQueryContentEvent* aEvent)
473 nsresult rv = Init(aEvent);
474 if (NS_FAILED(rv))
475 return rv;
477 nsCOMPtr<nsICaret> caret;
478 rv = mPresShell->GetCaret(getter_AddRefs(caret));
479 NS_ENSURE_SUCCESS(rv, rv);
480 NS_ASSERTION(caret, "GetCaret succeeded, but the result is null");
482 // When the selection is collapsed and the queried offset is current caret
483 // position, we should return the "real" caret rect.
484 PRBool selectionIsCollapsed;
485 rv = mSelection->GetIsCollapsed(&selectionIsCollapsed);
486 NS_ENSURE_SUCCESS(rv, rv);
488 if (selectionIsCollapsed) {
489 PRUint32 offset;
490 rv = GetFlatTextOffsetOfRange(mFirstSelectedRange, &offset);
491 NS_ENSURE_SUCCESS(rv, rv);
492 if (offset == aEvent->mInput.mOffset) {
493 PRBool isCollapsed;
494 rv = caret->GetCaretCoordinates(nsICaret::eTopLevelWindowCoordinates,
495 mSelection, &aEvent->mReply.mRect,
496 &isCollapsed, nsnull);
497 NS_ENSURE_SUCCESS(rv, rv);
498 aEvent->mSucceeded = PR_TRUE;
499 return NS_OK;
503 // Otherwise, we should set the guessed caret rect.
504 nsCOMPtr<nsIRange> range = new nsRange();
505 NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY);
506 rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset, 0, PR_TRUE);
507 NS_ENSURE_SUCCESS(rv, rv);
509 return QueryRectFor(aEvent, range, caret);
512 nsresult
513 nsQueryContentEventHandler::GetFlatTextOffsetOfRange(nsIRange* aRange,
514 PRUint32* aNativeOffset)
516 NS_ASSERTION(aNativeOffset, "param is invalid");
518 nsCOMPtr<nsIRange> prev = new nsRange();
519 NS_ENSURE_TRUE(prev, NS_ERROR_OUT_OF_MEMORY);
520 nsCOMPtr<nsIDOMRange> domPrev(do_QueryInterface(prev));
521 NS_ASSERTION(domPrev, "nsRange doesn't have nsIDOMRange??");
522 nsCOMPtr<nsIDOMNode> rootDOMNode(do_QueryInterface(mRootContent));
523 domPrev->SetStart(rootDOMNode, 0);
525 nsINode* startNode = aRange->GetStartParent();
526 NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
528 PRInt32 startOffset = aRange->StartOffset();
529 nsCOMPtr<nsIDOMNode> startDOMNode(do_QueryInterface(startNode));
530 NS_ASSERTION(startDOMNode, "startNode doesn't have nsIDOMNode");
531 domPrev->SetEnd(startDOMNode, startOffset);
533 nsAutoString prevStr;
534 nsresult rv = GenerateFlatTextContent(prev, prevStr);
535 NS_ENSURE_SUCCESS(rv, rv);
536 *aNativeOffset = prevStr.Length();
537 return NS_OK;
540 nsresult
541 nsQueryContentEventHandler::GetStartFrameAndOffset(nsIRange* aRange,
542 nsIFrame** aFrame,
543 PRInt32* aOffsetInFrame)
545 NS_ASSERTION(aRange && aFrame && aOffsetInFrame, "params are invalid");
547 nsIContent* content = nsnull;
548 nsINode* node = aRange->GetStartParent();
549 if (node && node->IsNodeOfType(nsINode::eCONTENT))
550 content = static_cast<nsIContent*>(node);
551 NS_ASSERTION(content, "the start node doesn't have nsIContent!");
553 nsCOMPtr<nsFrameSelection> fs = mPresShell->FrameSelection();
554 *aFrame = fs->GetFrameForNodeOffset(content, aRange->StartOffset(),
555 fs->GetHint(), aOffsetInFrame);
556 NS_ENSURE_TRUE((*aFrame), NS_ERROR_FAILURE);
557 NS_ASSERTION((*aFrame)->GetType() == nsGkAtoms::textFrame,
558 "The frame is not textframe");
559 return NS_OK;
562 nsresult
563 nsQueryContentEventHandler::ConvertToRootViewRelativeOffset(nsIFrame* aFrame,
564 nsRect& aRect)
566 NS_ASSERTION(aFrame, "aFrame must not be null");
568 nsIView* view = nsnull;
569 nsPoint posInView;
570 aFrame->GetOffsetFromView(posInView, &view);
571 if (!view)
572 return NS_ERROR_FAILURE;
573 aRect += posInView + view->GetOffsetTo(nsnull);
574 return NS_OK;