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
nsContentEventHandler::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");

  nsRefPtr<nsRange> range = new nsRange();
  rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset,
                                  aEvent->mInput.mLength, false);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = GenerateFlatTextContent(range, aEvent->mReply.mString);
  NS_ENSURE_SUCCESS(rv, rv);

  aEvent->mSucceeded = true;

  return NS_OK;
}
nsresult
nsContentEventHandler::OnSelectionEvent(nsSelectionEvent* aEvent)
{
  aEvent->mSucceeded = PR_FALSE;

  // Get selection to manipulate
  // XXX why do we need to get them from ISM? This method should work fine
  //     without ISM.
  nsresult rv = nsIMEStateManager::
      GetFocusSelectionAndRoot(getter_AddRefs(mSelection),
                               getter_AddRefs(mRootContent));
  if (rv != NS_ERROR_NOT_AVAILABLE) {
    NS_ENSURE_SUCCESS(rv, rv);
  } else {
    rv = Init(aEvent);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  // Get range from offset and length
  nsRefPtr<nsRange> range = new nsRange();
  NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY);
  rv = SetRangeFromFlatTextOffset(range, aEvent->mOffset, aEvent->mLength,
                                  aEvent->mExpandToClusterBoundary);
  NS_ENSURE_SUCCESS(rv, rv);

  nsINode* startNode = range->GetStartParent();
  nsINode* endNode = range->GetEndParent();
  PRInt32 startOffset = range->StartOffset();
  PRInt32 endOffset = range->EndOffset();
  AdjustRangeForSelection(mRootContent, &startNode, &startOffset);
  AdjustRangeForSelection(mRootContent, &endNode, &endOffset);

  nsCOMPtr<nsIDOMNode> startDomNode(do_QueryInterface(startNode));
  nsCOMPtr<nsIDOMNode> endDomNode(do_QueryInterface(endNode));
  NS_ENSURE_TRUE(startDomNode && endDomNode, NS_ERROR_UNEXPECTED);

  nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(mSelection);
  NS_ENSURE_TRUE(selPrivate, NS_ERROR_UNEXPECTED);
  selPrivate->StartBatchChanges();

  // Clear selection first before setting
  rv = mSelection->RemoveAllRanges();
  // Need to call EndBatchChanges at the end even if call failed
  if (NS_SUCCEEDED(rv)) {
    if (aEvent->mReversed) {
      rv = mSelection->Collapse(endDomNode, endOffset);
    } else {
      rv = mSelection->Collapse(startDomNode, startOffset);
    }
    if (NS_SUCCEEDED(rv) &&
        (startDomNode != endDomNode || startOffset != endOffset)) {
      if (aEvent->mReversed) {
        rv = mSelection->Extend(startDomNode, startOffset);
      } else {
        rv = mSelection->Extend(endDomNode, endOffset);
      }
    }
  }
  selPrivate->EndBatchChanges();
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsISelection2>(do_QueryInterface(mSelection))->ScrollIntoView(
      nsISelectionController::SELECTION_FOCUS_REGION, PR_FALSE, -1, -1);
  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;
}
nsresult
nsContentEventHandler::OnQueryTextRect(nsQueryContentEvent* aEvent)
{
  nsresult rv = Init(aEvent);
  if (NS_FAILED(rv))
    return rv;

  nsCOMPtr<nsIRange> range = new nsRange();
  if (!range) {
    return NS_ERROR_OUT_OF_MEMORY;
  }
  rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset,
                                  aEvent->mInput.mLength, PR_TRUE);
  NS_ENSURE_SUCCESS(rv, rv);

  // used to iterate over all contents and their frames
  nsCOMPtr<nsIContentIterator> iter;
  rv = NS_NewContentIterator(getter_AddRefs(iter));
  NS_ENSURE_SUCCESS(rv, rv);
  iter->Init(range);
  NS_ENSURE_SUCCESS(rv, rv);

  // get the starting frame
  PRInt32 offset = range->StartOffset();
  nsINode* node = iter->GetCurrentNode();
  if (!node) {
    node = AdjustTextRectNode(range->GetStartParent(), offset);
  }
  nsIFrame* firstFrame = nsnull;
  rv = GetFrameForTextRect(node, offset, PR_TRUE, &firstFrame);
  NS_ENSURE_SUCCESS(rv, rv);

  // get the starting frame rect
  nsRect rect(nsPoint(0, 0), firstFrame->GetRect().Size());
  rv = ConvertToRootViewRelativeOffset(firstFrame, rect);
  NS_ENSURE_SUCCESS(rv, rv);
  nsRect frameRect = rect;
  nsPoint ptOffset;
  firstFrame->GetPointFromOffset(offset, &ptOffset);
  // minus 1 to avoid creating an empty rect
  rect.x += ptOffset.x - 1;
  rect.width -= ptOffset.x - 1;

  // get the ending frame
  offset = range->EndOffset();
  node = AdjustTextRectNode(range->GetEndParent(), offset);
  nsIFrame* lastFrame = nsnull;
  rv = GetFrameForTextRect(node, offset, range->Collapsed(), &lastFrame);
  NS_ENSURE_SUCCESS(rv, rv);

  // iterate over all covered frames
  for (nsIFrame* frame = firstFrame; frame != lastFrame;) {
    frame = frame->GetNextContinuation();
    if (!frame) {
      do {
        iter->Next();
        node = iter->GetCurrentNode();
        if (!node || !node->IsNodeOfType(nsINode::eCONTENT))
          continue;
        frame = static_cast<nsIContent*>(node)->GetPrimaryFrame();
      } while (!frame && !iter->IsDone());
      if (!frame) {
        // this can happen when the end offset of the range is 0.
        frame = lastFrame;
      }
    }
    frameRect.SetRect(nsPoint(0, 0), frame->GetRect().Size());
    rv = ConvertToRootViewRelativeOffset(frame, frameRect);
    NS_ENSURE_SUCCESS(rv, rv);
    if (frame != lastFrame) {
      // not last frame, so just add rect to previous result
      rect.UnionRect(rect, frameRect);
    }
  }

  // get the ending frame rect
  lastFrame->GetPointFromOffset(offset, &ptOffset);
  // minus 1 to avoid creating an empty rect
  frameRect.width -= lastFrame->GetRect().width - ptOffset.x - 1;

  if (firstFrame == lastFrame) {
    rect.IntersectRect(rect, frameRect);
  } else {
    rect.UnionRect(rect, frameRect);
  }
  aEvent->mReply.mRect =
      rect.ToOutsidePixels(mPresContext->AppUnitsPerDevPixel());
  aEvent->mSucceeded = PR_TRUE;
  return NS_OK;
}