예제 #1
0
// WARNING: This function is expensive
nsresult nsContentIterator::RebuildIndexStack()
{
  // Make sure we start at the right indexes on the stack!  Build array up
  // to common parent of start and end.  Perhaps it's too many entries, but
  // that's far better than too few.
  nsINode* parent;
  nsINode* current;

  mIndexes.Clear();
  current = mCurNode;
  if (!current) {
    return NS_OK;
  }

  while (current != mCommonParent)
  {
    parent = current->GetNodeParent();
    
    if (!parent)
      return NS_ERROR_FAILURE;
  
    mIndexes.InsertElementAt(0, parent->IndexOf(current));

    current = parent;
  }
  return NS_OK;
}
예제 #2
0
nsresult
nsContentIterator::Init(nsINode* aRoot)
{
  if (!aRoot) 
    return NS_ERROR_NULL_POINTER; 

  mIsDone = PR_FALSE;
  mIndexes.Clear();
  
  if (mPre)
  {
    mFirst = aRoot;
    mLast  = GetDeepLastChild(aRoot, nsnull);
  }
  else
  {
    mFirst = GetDeepFirstChild(aRoot, nsnull); 
    mLast  = aRoot;
  }

  mCommonParent = aRoot;
  mCurNode = mFirst;
  RebuildIndexStack();
  return NS_OK;
}
예제 #3
0
void
nsContentIterator::MakeEmpty()
{
  mCurNode      = nsnull;
  mFirst        = nsnull;
  mLast         = nsnull;
  mCommonParent = nsnull;
  mIsDone       = PR_TRUE;
  mIndexes.Clear();
}
예제 #4
0
nsresult
nsContentIterator::Init(nsIRange* aRange)
{
  NS_ENSURE_ARG_POINTER(aRange);

  mIsDone = PR_FALSE;

  // get common content parent
  mCommonParent = aRange->GetCommonAncestor();
  NS_ENSURE_TRUE(mCommonParent, NS_ERROR_FAILURE);

  // get the start node and offset
  PRInt32 startIndx = aRange->StartOffset();
  nsINode* startNode = aRange->GetStartParent();
  NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);

  // get the end node and offset
  PRInt32 endIndx = aRange->EndOffset();
  nsINode* endNode = aRange->GetEndParent();
  NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE);

  PRBool startIsData = startNode->IsNodeOfType(nsINode::eDATA_NODE);

  // short circuit when start node == end node
  if (startNode == endNode)
  {
    // Check to see if we have a collapsed range, if so,
    // there is nothing to iterate over.
    //
    // XXX: CharacterDataNodes (text nodes) are currently an exception,
    //      since we always want to be able to iterate text nodes at
    //      the end points of a range.

    if (!startIsData && startIndx == endIndx)
    {
      MakeEmpty();
      return NS_OK;
    }

    if (startIsData)
    {
      // It's a textnode.
      NS_ASSERTION(startNode->IsNodeOfType(nsINode::eCONTENT),
                   "Data node that's not content?");

      mFirst   = static_cast<nsIContent*>(startNode);
      mLast    = mFirst;
      mCurNode = mFirst;

      RebuildIndexStack();
      return NS_OK;
    }
  }
  
  // Find first node in range.

  nsIContent *cChild = nsnull;

  if (!startIsData && NodeHasChildren(startNode))
    cChild = startNode->GetChildAt(startIndx);

  if (!cChild) // no children, must be a text node
  {
    // XXXbz no children might also just mean no children.  So I'm not
    // sure what that comment above is talking about.
    if (mPre)
    {
      // XXX: In the future, if start offset is after the last
      //      character in the cdata node, should we set mFirst to
      //      the next sibling?

      if (!startIsData)
      {
        mFirst = GetNextSibling(startNode, nsnull);

        // Does mFirst node really intersect the range?
        // The range could be 'degenerate', ie not collapsed 
        // but still contain no content.
  
        if (mFirst &&
            !NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx,
                                    endNode, endIndx)) {
          mFirst = nsnull;
        }
      }
      else {
        NS_ASSERTION(startNode->IsNodeOfType(nsINode::eCONTENT),
                   "Data node that's not content?");

        mFirst = static_cast<nsIContent*>(startNode);
      }
    }
    else {
      // post-order
      if (startNode->IsNodeOfType(nsINode::eCONTENT)) {
        mFirst = static_cast<nsIContent*>(startNode);
      } else {
        // What else can we do?
        mFirst = nsnull;
      }
    }
  }
  else
  {
    if (mPre)
      mFirst = cChild;
    else // post-order
    {
      mFirst = GetDeepFirstChild(cChild, nsnull);

      // Does mFirst node really intersect the range?
      // The range could be 'degenerate', ie not collapsed 
      // but still contain no content.
  
      if (mFirst &&
          !NodeIsInTraversalRange(mFirst, mPre, startNode, startIndx,
                                  endNode, endIndx))
        mFirst = nsnull;
    }
  }


  // Find last node in range.

  PRBool endIsData = endNode->IsNodeOfType(nsINode::eDATA_NODE);

  if (endIsData || !NodeHasChildren(endNode) || endIndx == 0)
  {
    if (mPre) {
      if (endNode->IsNodeOfType(nsINode::eCONTENT)) {
        mLast = static_cast<nsIContent*>(endNode);
      } else {
        // Not much else to do here...
        mLast = nsnull;
      }
    }
    else // post-order
    {
      // XXX: In the future, if end offset is before the first
      //      character in the cdata node, should we set mLast to
      //      the prev sibling?

      if (!endIsData)
      {
        mLast = GetPrevSibling(endNode, nsnull);

        if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx,
                                    endNode, endIndx))
          mLast = nsnull;
      }
      else {
        NS_ASSERTION(endNode->IsNodeOfType(nsINode::eCONTENT),
                     "Data node that's not content?");

        mLast = static_cast<nsIContent*>(endNode);
      }
    }
  }
  else
  {
    PRInt32 indx = endIndx;

    cChild = endNode->GetChildAt(--indx);

    if (!cChild)  // No child at offset!
    {
      NS_NOTREACHED("nsContentIterator::nsContentIterator");
      return NS_ERROR_FAILURE; 
    }

    if (mPre)
    {
      mLast  = GetDeepLastChild(cChild, nsnull);

      if (!NodeIsInTraversalRange(mLast, mPre, startNode, startIndx,
                                  endNode, endIndx)) {
        mLast = nsnull;
      }
    }
    else { // post-order 
      mLast = cChild;
    }
  }

  // If either first or last is null, they both
  // have to be null!

  if (!mFirst || !mLast)
  {
    mFirst = nsnull;
    mLast  = nsnull;
  }
  
  mCurNode = mFirst;
  mIsDone  = !mCurNode;

  if (!mCurNode)
    mIndexes.Clear();
  else
    RebuildIndexStack();

  return NS_OK;
}