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
nsContentEventHandler::GetFlatTextOffsetOfRange(nsIContent* aRootContent,
                                                nsIRange* aRange,
                                                PRUint32* aNativeOffset)
{
  nsINode* startNode = aRange->GetStartParent();
  NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
  PRInt32 startOffset = aRange->StartOffset();
  return GetFlatTextOffsetOfRange(aRootContent, startNode, startOffset,
                                  aNativeOffset);
}
nsresult
nsContentEventHandler::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(mRootContent,
                                mFirstSelectedRange, &aEvent->mReply.mOffset);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsIDOMNode> anchorDomNode, focusDomNode;
  rv = mSelection->GetAnchorNode(getter_AddRefs(anchorDomNode));
  NS_ENSURE_TRUE(anchorDomNode, NS_ERROR_FAILURE);
  rv = mSelection->GetFocusNode(getter_AddRefs(focusDomNode));
  NS_ENSURE_TRUE(focusDomNode, NS_ERROR_FAILURE);

  PRInt32 anchorOffset, focusOffset;
  rv = mSelection->GetAnchorOffset(&anchorOffset);
  NS_ENSURE_SUCCESS(rv, rv);
  rv = mSelection->GetFocusOffset(&focusOffset);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsINode> anchorNode(do_QueryInterface(anchorDomNode));
  nsCOMPtr<nsINode> focusNode(do_QueryInterface(focusDomNode));
  NS_ENSURE_TRUE(anchorNode && focusNode, NS_ERROR_UNEXPECTED);

  PRInt16 compare = nsContentUtils::ComparePoints(anchorNode, anchorOffset,
                                                  focusNode, focusOffset);
  aEvent->mReply.mReversed = compare > 0;

  if (compare) {
    nsCOMPtr<nsIRange> range = mFirstSelectedRange;
    rv = GenerateFlatTextContent(range, aEvent->mReply.mString);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  aEvent->mSucceeded = PR_TRUE;
  return NS_OK;
}
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
nsContentEventHandler::OnQueryCharacterAtPoint(nsQueryContentEvent* aEvent)
{
  nsresult rv = Init(aEvent);
  if (NS_FAILED(rv))
    return rv;

  nsIFrame* rootFrame = mPresShell->GetRootFrame();
  NS_ENSURE_TRUE(rootFrame, NS_ERROR_FAILURE);
  nsIWidget* rootWidget = rootFrame->GetNearestWidget();
  NS_ENSURE_TRUE(rootWidget, NS_ERROR_FAILURE);

  // The root frame's widget might be different, e.g., the event was fired on
  // a popup but the rootFrame is the document root.
  if (rootWidget != aEvent->widget) {
    NS_PRECONDITION(aEvent->widget, "The event must have the widget");
    nsIView* view = nsIView::GetViewFor(aEvent->widget);
    NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
    rootFrame = nsLayoutUtils::GetFrameFor(view);
    NS_ENSURE_TRUE(rootFrame, NS_ERROR_FAILURE);
    rootWidget = rootFrame->GetNearestWidget();
    NS_ENSURE_TRUE(rootWidget, NS_ERROR_FAILURE);
  }

  nsQueryContentEvent eventOnRoot(PR_TRUE, NS_QUERY_CHARACTER_AT_POINT,
                                  rootWidget);
  eventOnRoot.refPoint = aEvent->refPoint;
  if (rootWidget != aEvent->widget) {
    eventOnRoot.refPoint += aEvent->widget->WidgetToScreenOffset();
    eventOnRoot.refPoint -= rootWidget->WidgetToScreenOffset();
  }
  nsPoint ptInRoot =
    nsLayoutUtils::GetEventCoordinatesRelativeTo(&eventOnRoot, rootFrame);

  nsIFrame* targetFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, ptInRoot);
  if (!targetFrame || targetFrame->GetType() != nsGkAtoms::textFrame ||
      !targetFrame->GetContent() ||
      !nsContentUtils::ContentIsDescendantOf(targetFrame->GetContent(),
                                             mRootContent)) {
    // there is no character at the point.
    aEvent->mReply.mOffset = nsQueryContentEvent::NOT_FOUND;
    aEvent->mSucceeded = PR_TRUE;
    return NS_OK;
  }
  nsPoint ptInTarget = ptInRoot + rootFrame->GetOffsetToCrossDoc(targetFrame);
  PRInt32 rootAPD = rootFrame->PresContext()->AppUnitsPerDevPixel();
  PRInt32 targetAPD = targetFrame->PresContext()->AppUnitsPerDevPixel();
  ptInTarget = ptInTarget.ConvertAppUnits(rootAPD, targetAPD);

  nsTextFrame* textframe = static_cast<nsTextFrame*>(targetFrame);
  nsIFrame::ContentOffsets offsets =
    textframe->GetCharacterOffsetAtFramePoint(ptInTarget);
  NS_ENSURE_TRUE(offsets.content, NS_ERROR_FAILURE);
  PRUint32 nativeOffset;
  rv = GetFlatTextOffsetOfRange(mRootContent, offsets.content, offsets.offset,
                                &nativeOffset);
  NS_ENSURE_SUCCESS(rv, rv);

  nsQueryContentEvent textRect(PR_TRUE, NS_QUERY_TEXT_RECT, aEvent->widget);
  textRect.InitForQueryTextRect(nativeOffset, 1);
  rv = OnQueryTextRect(&textRect);
  NS_ENSURE_SUCCESS(rv, rv);
  NS_ENSURE_TRUE(textRect.mSucceeded, NS_ERROR_FAILURE);

  // currently, we don't need to get the actual text.
  aEvent->mReply.mOffset = nativeOffset;
  aEvent->mReply.mRect = textRect.mReply.mRect;
  aEvent->mSucceeded = PR_TRUE;
  return NS_OK;
}
nsresult
nsContentEventHandler::OnQueryCaretRect(nsQueryContentEvent* aEvent)
{
  nsresult rv = Init(aEvent);
  if (NS_FAILED(rv))
    return rv;

  nsRefPtr<nsCaret> caret = mPresShell->GetCaret();
  NS_ASSERTION(caret, "GetCaret returned 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(mRootContent, mFirstSelectedRange, &offset);
    NS_ENSURE_SUCCESS(rv, rv);
    if (offset == aEvent->mInput.mOffset) {
      nsRect rect;
      nsIFrame* caretFrame = caret->GetGeometry(mSelection, &rect);
      if (!caretFrame)
        return NS_ERROR_FAILURE;
      rv = ConvertToRootViewRelativeOffset(caretFrame, rect);
      NS_ENSURE_SUCCESS(rv, rv);
      aEvent->mReply.mRect =
        rect.ToOutsidePixels(caretFrame->PresContext()->AppUnitsPerDevPixel());
      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);

  PRInt32 offsetInFrame;
  nsIFrame* frame;
  rv = GetStartFrameAndOffset(range, &frame, &offsetInFrame);
  NS_ENSURE_SUCCESS(rv, rv);

  nsPoint posInFrame;
  rv = frame->GetPointFromOffset(range->StartOffset(), &posInFrame);
  NS_ENSURE_SUCCESS(rv, rv);

  nsRect rect;
  rect.x = posInFrame.x;
  rect.y = posInFrame.y;
  rect.width = caret->GetCaretRect().width;
  rect.height = frame->GetSize().height;

  rv = ConvertToRootViewRelativeOffset(frame, rect);
  NS_ENSURE_SUCCESS(rv, rv);

  aEvent->mReply.mRect =
      rect.ToOutsidePixels(mPresContext->AppUnitsPerDevPixel());
  aEvent->mSucceeded = PR_TRUE;
  return NS_OK;
}