static nsresult 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();
  NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
  nsINode* endNode = aRange->GetEndParent();
  NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE);

  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()) {
    nsINode* node = iter->GetCurrentNode();
    if (!node || !node->IsNodeOfType(nsINode::eCONTENT))
      continue;
    nsIContent* content = static_cast<nsIContent*>(node);

    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 (IsContentBR(content))
        aString.Append(PRUnichar('\n'));
  }
  ConvertToNativeNewlines(aString);
  return NS_OK;
}
//------------------------------------------------------------
nsresult
nsFilteredContentIterator::Init(nsINode* aRoot)
{
  NS_ENSURE_TRUE(mPreIterator, NS_ERROR_FAILURE);
  NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
  mIsOutOfRange    = PR_FALSE;
  mDirection       = eForward;
  mCurrentIterator = mPreIterator;

  nsresult rv;
  mRange = do_CreateInstance("@mozilla.org/content/range;1", &rv);
  NS_ENSURE_SUCCESS(rv, rv);
  nsCOMPtr<nsIDOMRange> domRange(do_QueryInterface(mRange));
  nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(aRoot));
  if (domRange && domNode) {
    domRange->SelectNode(domNode);
  }

  rv = mPreIterator->Init(domRange);
  NS_ENSURE_SUCCESS(rv, rv);
  return mIterator->Init(domRange);
}
nsresult
nsContentEventHandler::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;
  nsCOMPtr<nsIContent> content;
  for (; !iter->IsDone(); iter->Next()) {
    nsINode* node = iter->GetCurrentNode();
    if (!node || !node->IsNodeOfType(nsINode::eCONTENT))
      continue;
    nsIContent* content = static_cast<nsIContent*>(node);

    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;
}