NS_IMETHODIMP
nsPlaceholderFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
{
  IndentBy(out, aIndent);
  ListTag(out);
  if (HasView()) {
    fprintf(out, " [view=%p]", (void*)GetView());
  }
  fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
  if (0 != mState) {
    fprintf(out, " [state=%016llx]", (unsigned long long)mState);
  }
  nsIFrame* prevInFlow = GetPrevInFlow();
  nsIFrame* nextInFlow = GetNextInFlow();
  if (prevInFlow) {
    fprintf(out, " prev-in-flow=%p", static_cast<void*>(prevInFlow));
  }
  if (nextInFlow) {
    fprintf(out, " next-in-flow=%p", static_cast<void*>(nextInFlow));
  }
  if (mContent) {
    fprintf(out, " [content=%p]", static_cast<void*>(mContent));
  }
  if (mStyleContext) {
    fprintf(out, " [sc=%p]", static_cast<void*>(mStyleContext));
  }
  if (mOutOfFlowFrame) {
    fprintf(out, " outOfFlowFrame=");
    nsFrame::ListTag(out, mOutOfFlowFrame);
  }
  fputs("\n", out);
  return NS_OK;
}
Exemple #2
0
NS_IMETHODIMP
nsPlaceholderFrame::List(FILE* out, PRInt32 aIndent) const
{
  IndentBy(out, aIndent);
  ListTag(out);
#ifdef DEBUG_waterson
  fprintf(out, " [parent=%p]", static_cast<void*>(mParent));
#endif
  if (HasView()) {
    fprintf(out, " [view=%p]", (void*)GetView());
  }
  fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
  if (0 != mState) {
    fprintf(out, " [state=%08x]", mState);
  }
  nsIFrame* prevInFlow = GetPrevInFlow();
  nsIFrame* nextInFlow = GetNextInFlow();
  if (nsnull != prevInFlow) {
    fprintf(out, " prev-in-flow=%p", static_cast<void*>(prevInFlow));
  }
  if (nsnull != nextInFlow) {
    fprintf(out, " next-in-flow=%p", static_cast<void*>(nextInFlow));
  }
  if (mOutOfFlowFrame) {
    fprintf(out, " outOfFlowFrame=");
    nsFrame::ListTag(out, mOutOfFlowFrame);
  }
  fputs("\n", out);
  return NS_OK;
}
void
nsPopupSetFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
{
  ListGeneric(out, aIndent, aFlags);

  // Output the children
  bool outputOneList = false;
  ChildListIterator lists(this);
  for (; !lists.IsDone(); lists.Next()) {
    if (outputOneList) {
      IndentBy(out, aIndent);
    }
    outputOneList = true;
    fprintf(out, "%s<\n", mozilla::layout::ChildListName(lists.CurrentID()));
    nsFrameList::Enumerator childFrames(lists.CurrentList());
    for (; !childFrames.AtEnd(); childFrames.Next()) {
      nsIFrame* kid = childFrames.get();
      // Verify the child frame's parent frame pointer is correct
      NS_ASSERTION(kid->GetParent() == this, "bad parent frame pointer");

      // Have the child frame list
      kid->List(out, aIndent + 1, aFlags);
    }
    IndentBy(out, aIndent);
    fputs(">\n", out);
  }

  // XXXmats the above is copy-pasted from nsContainerFrame::List which is lame,
  // clean this up after bug 399111 is implemented.

  if (!mPopupList.IsEmpty()) {
    fputs("<\n", out);
    ++aIndent;
    IndentBy(out, aIndent);
    fputs(mozilla::layout::ChildListName(kPopupList), out);
    fputs(" for ", out);
    ListTag(out);
    fputs(" <\n", out);
    ++aIndent;
    for (nsFrameList::Enumerator e(mPopupList); !e.AtEnd(); e.Next()) {
      e.get()->List(out, aIndent, aFlags);
    }
    --aIndent;
    IndentBy(out, aIndent);
    fputs(">\n", out);
    --aIndent;
    IndentBy(out, aIndent);
    fputs(">\n", out);
    outputOneList = true;
  }

  if (!outputOneList) {
    fputs("<>\n", out);
  }
}
NS_IMETHODIMP
nsPlaceholderFrame::List(nsPresContext* aPresContext, FILE* out, PRInt32 aIndent) const
{
  IndentBy(out, aIndent);
  ListTag(out);
#ifdef DEBUG_waterson
  fprintf(out, " [parent=%p]", NS_STATIC_CAST(void*, mParent));
#endif
  if (HasView()) {
    fprintf(out, " [view=%p]", (void*)GetView());
  }
  fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
  if (0 != mState) {
    fprintf(out, " [state=%08x]", mState);
  }
  nsIFrame* prevInFlow = GetPrevInFlow();
  nsIFrame* nextInFlow = GetNextInFlow();
  if (nsnull != prevInFlow) {
    fprintf(out, " prev-in-flow=%p", NS_STATIC_CAST(void*, prevInFlow));
  }
NS_IMETHODIMP
nsPopupSetFrame::List(FILE* out, PRInt32 aIndent) const
{
  IndentBy(out, aIndent);
  ListTag(out);
#ifdef DEBUG_waterson
  fprintf(out, " [parent=%p]", static_cast<void*>(mParent));
#endif
  if (HasView()) {
    fprintf(out, " [view=%p]", static_cast<void*>(GetView()));
  }
  if (nsnull != mNextSibling) {
    fprintf(out, " next=%p", static_cast<void*>(mNextSibling));
  }
  if (nsnull != GetPrevContinuation()) {
    fprintf(out, " prev-continuation=%p", static_cast<void*>(GetPrevContinuation()));
  }
  if (nsnull != GetNextContinuation()) {
    fprintf(out, " next-continuation=%p", static_cast<void*>(GetNextContinuation()));
  }
  fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
  if (0 != mState) {
    fprintf(out, " [state=%08x]", mState);
  }
  fprintf(out, " [content=%p]", static_cast<void*>(mContent));
  nsPopupSetFrame* f = const_cast<nsPopupSetFrame*>(this);
  if (f->HasOverflowRect()) {
    nsRect overflowArea = f->GetOverflowRect();
    fprintf(out, " [overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
            overflowArea.width, overflowArea.height);
  }
  fprintf(out, " [sc=%p]", static_cast<void*>(mStyleContext));
  nsIAtom* pseudoTag = mStyleContext->GetPseudoType();
  if (pseudoTag) {
    nsAutoString atomString;
    pseudoTag->ToString(atomString);
    fprintf(out, " pst=%s",
            NS_LossyConvertUTF16toASCII(atomString).get());
  }

  // Output the children
  nsIAtom* listName = nsnull;
  PRInt32 listIndex = 0;
  PRBool outputOneList = PR_FALSE;
  do {
    nsIFrame* kid = GetFirstChild(listName);
    if (nsnull != kid) {
      if (outputOneList) {
        IndentBy(out, aIndent);
      }
      outputOneList = PR_TRUE;
      nsAutoString tmp;
      if (nsnull != listName) {
        listName->ToString(tmp);
        fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
      }
      fputs("<\n", out);
      while (nsnull != kid) {
        // Verify the child frame's parent frame pointer is correct
        NS_ASSERTION(kid->GetParent() == (nsIFrame*)this, "bad parent frame pointer");

        // Have the child frame list
        nsIFrameDebug*  frameDebug = do_QueryFrame(kid);
        if (frameDebug) {
          frameDebug->List(out, aIndent + 1);
        }
        kid = kid->GetNextSibling();
      }
      IndentBy(out, aIndent);
      fputs(">\n", out);
    }
    listName = GetAdditionalChildListName(listIndex++);
  } while(nsnull != listName);

  // XXXmats the above is copy-pasted from nsContainerFrame::List which is lame,
  // clean this up after bug 399111 is implemented.

  if (mPopupList) {
    fputs("<\n", out);
    ++aIndent;
    IndentBy(out, aIndent);
    nsAutoString tmp;
    nsGkAtoms::popupList->ToString(tmp);
    fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
    fputs(" for ", out);
    ListTag(out);
    fputs(" <\n", out);
    ++aIndent;
    for (nsPopupFrameList* l = mPopupList; l; l = l->mNextPopup) {
      nsIFrameDebug* frameDebug = do_QueryFrame(l->mPopupFrame);
      if (frameDebug) {
        frameDebug->List(out, aIndent);
      }
    }
    --aIndent;
    IndentBy(out, aIndent);
    fputs(">\n", out);
    --aIndent;
    IndentBy(out, aIndent);
    fputs(">\n", out);
    outputOneList = PR_TRUE;
  }

  if (!outputOneList) {
    fputs("<>\n", out);
  }

  return NS_OK;
}
Exemple #6
0
nsresult
nsInlineFrame::ReflowFrames(nsPresContext* aPresContext,
                            const nsHTMLReflowState& aReflowState,
                            InlineReflowState& irs,
                            nsHTMLReflowMetrics& aMetrics,
                            nsReflowStatus& aStatus)
{
  nsresult rv = NS_OK;
  aStatus = NS_FRAME_COMPLETE;

  nsLineLayout* lineLayout = aReflowState.mLineLayout;
  PRBool ltr = (NS_STYLE_DIRECTION_LTR == aReflowState.mStyleVisibility->mDirection);
  nscoord leftEdge = 0;
  // Don't offset by our start borderpadding if we have a prev continuation or
  // if we're in the last part of an {ib} split.
  if (!GetPrevContinuation() &&
      !nsLayoutUtils::FrameIsInLastPartOfIBSplit(this)) {
    leftEdge = ltr ? aReflowState.mComputedBorderPadding.left
                   : aReflowState.mComputedBorderPadding.right;
  }
  nscoord availableWidth = aReflowState.availableWidth;
  NS_ASSERTION(availableWidth != NS_UNCONSTRAINEDSIZE,
               "should no longer use available widths");
  // Subtract off left and right border+padding from availableWidth
  availableWidth -= leftEdge;
  availableWidth -= ltr ? aReflowState.mComputedBorderPadding.right
                        : aReflowState.mComputedBorderPadding.left;
  lineLayout->BeginSpan(this, &aReflowState, leftEdge, leftEdge + availableWidth);

  // First reflow our current children
  nsIFrame* frame = mFrames.FirstChild();
  PRBool done = PR_FALSE;
  while (nsnull != frame) {
    PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();

    // Check if we should lazily set the child frame's parent pointer
    if (irs.mSetParentPointer) {
      PRBool havePrevBlock =
        irs.mLineContainer && irs.mLineContainer->GetPrevContinuation();
      // If our block is the first in flow, then any floats under the pulled
      // frame must already belong to our block.
      if (havePrevBlock) {
        // This has to happen before we update frame's parent; we need to
        // know frame's ancestry under its old block.
        // The blockChildren.ContainsFrame check performed by
        // ReparentFloatsForInlineChild here may be slow, but we can't
        // easily avoid it because we don't know where 'frame' originally
        // came from. If we really really have to optimize this we could
        // cache whether frame->GetParent() is under its containing blocks
        // overflowList or not.
        ReparentFloatsForInlineChild(irs.mLineContainer, frame, PR_FALSE);
      }
      frame->SetParent(this);
      // We also need to check if frame has a next-in-flow. If it does, then set
      // its parent frame pointer, too. Otherwise, if we reflow frame and it's
      // complete we'll fail when deleting its next-in-flow which is no longer
      // needed. This scenario doesn't happen often, but it can happen
      nsIFrame* nextInFlow = frame->GetNextInFlow();
      for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
        // Since we only do lazy setting of parent pointers for the frame's
        // initial reflow, this frame can't have a next-in-flow. That means
        // the continuing child frame must be in our child list as well. If
        // not, then something is wrong
        NS_ASSERTION(mFrames.ContainsFrame(nextInFlow), "unexpected flow");
        if (havePrevBlock) {
          ReparentFloatsForInlineChild(irs.mLineContainer, nextInFlow, PR_FALSE);
        }
        nextInFlow->SetParent(this);
      }

      // Fix the parent pointer for ::first-letter child frame next-in-flows,
      // so nsFirstLetterFrame::Reflow can destroy them safely (bug 401042).
      nsIFrame* realFrame = nsPlaceholderFrame::GetRealFrameFor(frame);
      if (realFrame->GetType() == nsGkAtoms::letterFrame) {
        nsIFrame* child = realFrame->GetFirstChild(nsnull);
        if (child) {
          NS_ASSERTION(child->GetType() == nsGkAtoms::textFrame,
                       "unexpected frame type");
          nsIFrame* nextInFlow = child->GetNextInFlow();
          for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
            NS_ASSERTION(nextInFlow->GetType() == nsGkAtoms::textFrame,
                         "unexpected frame type");
            if (mFrames.ContainsFrame(nextInFlow)) {
              nextInFlow->SetParent(this);
            }
            else {
#ifdef DEBUG              
              // Once we find a next-in-flow that isn't ours none of the
              // remaining next-in-flows should be either.
              for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
                NS_ASSERTION(!mFrames.ContainsFrame(nextInFlow),
                             "unexpected letter frame flow");
              }
#endif
              break;
            }
          }
        }
      }
    }
    rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
    if (NS_FAILED(rv)) {
      done = PR_TRUE;
      break;
    }
    if (NS_INLINE_IS_BREAK(aStatus) || 
        (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus))) {
      done = PR_TRUE;
      break;
    }
    irs.mPrevFrame = frame;
    frame = frame->GetNextSibling();
  }

  // Attempt to pull frames from our next-in-flow until we can't
  if (!done && (nsnull != GetNextInFlow())) {
    while (!done) {
      PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
      PRBool isComplete;
      if (!frame) { // Could be non-null if we pulled a first-letter frame and
                    // it created a continuation, since we don't push those.
        frame = PullOneFrame(aPresContext, irs, &isComplete);
      }
#ifdef NOISY_PUSHING
      printf("%p pulled up %p\n", this, frame);
#endif
      if (nsnull == frame) {
        if (!isComplete) {
          aStatus = NS_FRAME_NOT_COMPLETE;
        }
        break;
      }
      rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
      if (NS_FAILED(rv)) {
        done = PR_TRUE;
        break;
      }
      if (NS_INLINE_IS_BREAK(aStatus) || 
          (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus))) {
        done = PR_TRUE;
        break;
      }
      irs.mPrevFrame = frame;
      frame = frame->GetNextSibling();
    }
  }
#ifdef DEBUG
  if (NS_FRAME_IS_COMPLETE(aStatus)) {
    // We can't be complete AND have overflow frames!
    NS_ASSERTION(!GetOverflowFrames(), "whoops");
  }
#endif

  // If after reflowing our children they take up no area then make
  // sure that we don't either.
  //
  // Note: CSS demands that empty inline elements still affect the
  // line-height calculations. However, continuations of an inline
  // that are empty we force to empty so that things like collapsed
  // whitespace in an inline element don't affect the line-height.
  aMetrics.width = lineLayout->EndSpan(this);

  // Compute final width.

  // Make sure to not include our start border and padding if we have a prev
  // continuation or if we're in the last part of an {ib} split.
  if (!GetPrevContinuation() &&
      !nsLayoutUtils::FrameIsInLastPartOfIBSplit(this)) {
    aMetrics.width += ltr ? aReflowState.mComputedBorderPadding.left
                          : aReflowState.mComputedBorderPadding.right;
  }

  /*
   * We want to only apply the end border and padding if we're the last
   * continuation and not in the first part of an {ib} split.  To be the last
   * continuation we have to be complete (so that we won't get a next-in-flow)
   * and have no non-fluid continuations on our continuation chain.
   */
  if (NS_FRAME_IS_COMPLETE(aStatus) &&
      !GetLastInFlow()->GetNextContinuation() &&
      !nsLayoutUtils::FrameIsInFirstPartOfIBSplit(this)) {
    aMetrics.width += ltr ? aReflowState.mComputedBorderPadding.right
                          : aReflowState.mComputedBorderPadding.left;
  }

  nsLayoutUtils::SetFontFromStyle(aReflowState.rendContext, mStyleContext);
  nsCOMPtr<nsIFontMetrics> fm;
  aReflowState.rendContext->GetFontMetrics(*getter_AddRefs(fm));

  if (fm) {
    // Compute final height of the frame.
    //
    // Do things the standard css2 way -- though it's hard to find it
    // in the css2 spec! It's actually found in the css1 spec section
    // 4.4 (you will have to read between the lines to really see
    // it).
    //
    // The height of our box is the sum of our font size plus the top
    // and bottom border and padding. The height of children do not
    // affect our height.
    fm->GetMaxAscent(aMetrics.ascent);
    fm->GetHeight(aMetrics.height);
  } else {
    NS_WARNING("Cannot get font metrics - defaulting sizes to 0");
    aMetrics.ascent = aMetrics.height = 0;
  }
  aMetrics.ascent += aReflowState.mComputedBorderPadding.top;
  aMetrics.height += aReflowState.mComputedBorderPadding.top +
    aReflowState.mComputedBorderPadding.bottom;

  // For now our overflow area is zero. The real value will be
  // computed in |nsLineLayout::RelativePositionFrames|.
  aMetrics.mOverflowArea.SetRect(0, 0, 0, 0);

#ifdef NOISY_FINAL_SIZE
  ListTag(stdout);
  printf(": metrics=%d,%d ascent=%d\n",
         aMetrics.width, aMetrics.height, aMetrics.ascent);
#endif

  return rv;
}
NS_IMETHODIMP
nsPopupSetFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
{
  IndentBy(out, aIndent);
  ListTag(out);
#ifdef DEBUG_waterson
  fprintf(out, " [parent=%p]", static_cast<void*>(mParent));
#endif
  if (HasView()) {
    fprintf(out, " [view=%p]", static_cast<void*>(GetView()));
  }
  if (GetNextSibling()) {
    fprintf(out, " next=%p", static_cast<void*>(GetNextSibling()));
  }
  if (nullptr != GetPrevContinuation()) {
    fprintf(out, " prev-continuation=%p", static_cast<void*>(GetPrevContinuation()));
  }
  if (nullptr != GetNextContinuation()) {
    fprintf(out, " next-continuation=%p", static_cast<void*>(GetNextContinuation()));
  }
  fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
  if (0 != mState) {
    fprintf(out, " [state=%016llx]", (unsigned long long)mState);
  }
  fprintf(out, " [content=%p]", static_cast<void*>(mContent));
  nsPopupSetFrame* f = const_cast<nsPopupSetFrame*>(this);
  if (f->HasOverflowAreas()) {
    nsRect overflowArea = f->GetVisualOverflowRect();
    fprintf(out, " [vis-overflow=%d,%d,%d,%d]",
            overflowArea.x, overflowArea.y,
            overflowArea.width, overflowArea.height);
    overflowArea = f->GetScrollableOverflowRect();
    fprintf(out, " [scr-overflow=%d,%d,%d,%d]",
            overflowArea.x, overflowArea.y,
            overflowArea.width, overflowArea.height);
  }
  fprintf(out, " [sc=%p]", static_cast<void*>(mStyleContext));
  nsIAtom* pseudoTag = mStyleContext->GetPseudo();
  if (pseudoTag) {
    nsAutoString atomString;
    pseudoTag->ToString(atomString);
    fprintf(out, " pst=%s",
            NS_LossyConvertUTF16toASCII(atomString).get());
  }

  // Output the children
  bool outputOneList = false;
  ChildListIterator lists(this);
  for (; !lists.IsDone(); lists.Next()) {
    if (outputOneList) {
      IndentBy(out, aIndent);
    }
    outputOneList = true;
    fprintf(out, "%s<\n", mozilla::layout::ChildListName(lists.CurrentID()));
    nsFrameList::Enumerator childFrames(lists.CurrentList());
    for (; !childFrames.AtEnd(); childFrames.Next()) {
      nsIFrame* kid = childFrames.get();
      // Verify the child frame's parent frame pointer is correct
      NS_ASSERTION(kid->GetParent() == this, "bad parent frame pointer");

      // Have the child frame list
      kid->List(out, aIndent + 1, aFlags);
    }
    IndentBy(out, aIndent);
    fputs(">\n", out);
  }

  // XXXmats the above is copy-pasted from nsContainerFrame::List which is lame,
  // clean this up after bug 399111 is implemented.

  if (!mPopupList.IsEmpty()) {
    fputs("<\n", out);
    ++aIndent;
    IndentBy(out, aIndent);
    fputs(mozilla::layout::ChildListName(kPopupList), out);
    fputs(" for ", out);
    ListTag(out);
    fputs(" <\n", out);
    ++aIndent;
    for (nsFrameList::Enumerator e(mPopupList); !e.AtEnd(); e.Next()) {
      e.get()->List(out, aIndent, aFlags);
    }
    --aIndent;
    IndentBy(out, aIndent);
    fputs(">\n", out);
    --aIndent;
    IndentBy(out, aIndent);
    fputs(">\n", out);
    outputOneList = true;
  }

  if (!outputOneList) {
    fputs("<>\n", out);
  }

  return NS_OK;
}
NS_IMETHODIMP
CVE_2013_1732_firefox12_0_nsBlockFrame::Reflow(nsPresContext*           aPresContext,
                     nsHTMLReflowMetrics&     aMetrics,
                     const nsHTMLReflowState& aReflowState,
                     nsReflowStatus&          aStatus)
{
  DO_GLOBAL_REFLOW_COUNT("nsBlockFrame");
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
#ifdef DEBUG
  if (gNoisyReflow) {
    IndentBy(stdout, gNoiseIndent);
    ListTag(stdout);
    printf(": begin reflow availSize=%d,%d computedSize=%d,%d\n",
           aReflowState.availableWidth, aReflowState.availableHeight,
           aReflowState.ComputedWidth(), aReflowState.ComputedHeight());
  }
  AutoNoisyIndenter indent(gNoisy);
  PRTime start = LL_ZERO; // Initialize these variablies to silence the compiler.
  PRInt32 ctc = 0;        // We only use these if they are set (gLameReflowMetrics).
  if (gLameReflowMetrics) {
    start = PR_Now();
    ctc = nsLineBox::GetCtorCount();
  }
#endif

  const nsHTMLReflowState *reflowState = &aReflowState;
  nsAutoPtr<nsHTMLReflowState> mutableReflowState;
  // If we have non-auto height, we're clipping our kids and we fit,
  // make sure our kids fit too.
  if (aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE &&
      aReflowState.ComputedHeight() != NS_AUTOHEIGHT &&
      ApplyOverflowClipping(this, aReflowState.mStyleDisplay)) {
    nsMargin heightExtras = aReflowState.mComputedBorderPadding;
    if (GetSkipSides() & NS_SIDE_TOP) {
      heightExtras.top = 0;
    } else {
      // Bottom margin never causes us to create continuations, so we
      // don't need to worry about whether it fits in its entirety.
      heightExtras.top += aReflowState.mComputedMargin.top;
    }

    if (GetEffectiveComputedHeight(aReflowState) + heightExtras.TopBottom() <=
        aReflowState.availableHeight) {
      mutableReflowState = new nsHTMLReflowState(aReflowState);
      mutableReflowState->availableHeight = NS_UNCONSTRAINEDSIZE;
      reflowState = mutableReflowState;
    }
  }

  // See comment below about oldSize. Use *only* for the
  // abs-pos-containing-block-size-change optimization!
  nsSize oldSize = GetSize();

  // Should we create a float manager?
  nsAutoFloatManager autoFloatManager(const_cast<nsHTMLReflowState&>(*reflowState));

  // XXXldb If we start storing the float manager in the frame rather
  // than keeping it around only during reflow then we should create it
  // only when there are actually floats to manage.  Otherwise things
  // like tables will gain significant bloat.
  bool needFloatManager = nsBlockFrame::BlockNeedsFloatManager(this);
  if (needFloatManager)
    autoFloatManager.CreateFloatManager(aPresContext);

  // OK, some lines may be reflowed. Blow away any saved line cursor
  // because we may invalidate the nondecreasing
  // overflowArea.VisualOverflow().y/yMost invariant, and we may even
  // delete the line with the line cursor.
  ClearLineCursor();

  if (IsFrameTreeTooDeep(*reflowState, aMetrics, aStatus)) {
    return NS_OK;
  }

  bool marginRoot = BlockIsMarginRoot(this);
  nsBlockReflowState state(*reflowState, aPresContext, this, aMetrics,
                           marginRoot, marginRoot, needFloatManager);

#ifdef IBMBIDI
  if (GetStateBits() & NS_BLOCK_NEEDS_BIDI_RESOLUTION)
    static_cast<nsBlockFrame*>(GetFirstContinuation())->ResolveBidi();
#endif // IBMBIDI

  if (RenumberLists(aPresContext)) {
    AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
  }

  nsresult rv = NS_OK;

  // ALWAYS drain overflow. We never want to leave the previnflow's
  // overflow lines hanging around; block reflow depends on the
  // overflow line lists being cleared out between reflow passes.
  DrainOverflowLines();

  // Handle paginated overflow (see nsContainerFrame.h)
  nsOverflowAreas ocBounds;
  nsReflowStatus ocStatus = NS_FRAME_COMPLETE;
  if (GetPrevInFlow()) {
    ReflowOverflowContainerChildren(aPresContext, *reflowState, ocBounds, 0,
                                    ocStatus);
  }

  // Now that we're done cleaning up our overflow container lists, we can
  // give |state| its nsOverflowContinuationTracker.
  nsOverflowContinuationTracker tracker(aPresContext, this, false);
  state.mOverflowTracker = &tracker;

  // Drain & handle pushed floats
  DrainPushedFloats(state);
  nsOverflowAreas fcBounds;
  nsReflowStatus fcStatus = NS_FRAME_COMPLETE;
  rv = ReflowPushedFloats(state, fcBounds, fcStatus);
  NS_ENSURE_SUCCESS(rv, rv);

  // If we're not dirty (which means we'll mark everything dirty later)
  // and our width has changed, mark the lines dirty that we need to
  // mark dirty for a resize reflow.
  if (reflowState->mFlags.mHResize)
    PrepareResizeReflow(state);

  mState &= ~NS_FRAME_FIRST_REFLOW;

  // Now reflow...
  rv = ReflowDirtyLines(state);
  NS_ASSERTION(NS_SUCCEEDED(rv), "reflow dirty lines failed");
  if (NS_FAILED(rv)) return rv;

  NS_MergeReflowStatusInto(&state.mReflowStatus, ocStatus);
  NS_MergeReflowStatusInto(&state.mReflowStatus, fcStatus);

  // If we end in a BR with clear and affected floats continue,
  // we need to continue, too.
  if (NS_UNCONSTRAINEDSIZE != reflowState->availableHeight &&
      NS_FRAME_IS_COMPLETE(state.mReflowStatus) &&
      state.mFloatManager->ClearContinues(FindTrailingClear())) {
    NS_FRAME_SET_INCOMPLETE(state.mReflowStatus);
  }

  if (!NS_FRAME_IS_FULLY_COMPLETE(state.mReflowStatus)) {
    if (GetOverflowLines() || GetPushedFloats()) {
      state.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
    }

#ifdef DEBUG_kipp
    ListTag(stdout); printf(": block is not fully complete\n");
#endif
  }

  CheckFloats(state);

  // Place the "marker" (bullet) frame if it is placed next to a block
  // child.
  //
  // According to the CSS2 spec, section 12.6.1, the "marker" box
  // participates in the height calculation of the list-item box's
  // first line box.
  //
  // There are exactly two places a bullet can be placed: near the
  // first or second line. It's only placed on the second line in a
  // rare case: an empty first line followed by a second line that
  // contains a block (example: <LI>\n<P>... ). This is where
  // the second case can happen.
  if (mBullet && HaveOutsideBullet() && !mLines.empty() &&
      (mLines.front()->IsBlock() ||
       (0 == mLines.front()->mBounds.height &&
        mLines.front() != mLines.back() &&
        mLines.begin().next()->IsBlock()))) {
    // Reflow the bullet
    nsHTMLReflowMetrics metrics;
    // XXX Use the entire line when we fix bug 25888.
    nsLayoutUtils::LinePosition position;
    bool havePosition = nsLayoutUtils::GetFirstLinePosition(this, &position);
    nscoord lineTop = havePosition ? position.mTop
                                   : reflowState->mComputedBorderPadding.top;
    ReflowBullet(state, metrics, lineTop);
    NS_ASSERTION(!BulletIsEmpty() || metrics.height == 0,
                 "empty bullet took up space");

    if (havePosition && !BulletIsEmpty()) {
      // We have some lines to align the bullet with.  

      // Doing the alignment using the baseline will also cater for
      // bullets that are placed next to a child block (bug 92896)
    
      // Tall bullets won't look particularly nice here...
      nsRect bbox = mBullet->GetRect();
      bbox.y = position.mBaseline - metrics.ascent;
      mBullet->SetRect(bbox);
    }
    // Otherwise just leave the bullet where it is, up against our top padding.
  }

  // Compute our final size
  nscoord bottomEdgeOfChildren;
  ComputeFinalSize(*reflowState, state, aMetrics, &bottomEdgeOfChildren);
  nsRect areaBounds = nsRect(0, 0, aMetrics.width, aMetrics.height);
  ComputeOverflowAreas(areaBounds, reflowState->mStyleDisplay,
                       bottomEdgeOfChildren, aMetrics.mOverflowAreas);
  // Factor overflow container child bounds into the overflow area
  aMetrics.mOverflowAreas.UnionWith(ocBounds);
  // Factor pushed float child bounds into the overflow area
  aMetrics.mOverflowAreas.UnionWith(fcBounds);

  // Let the absolutely positioned container reflow any absolutely positioned
  // child frames that need to be reflowed, e.g., elements with a percentage
  // based width/height
  // We want to do this under either of two conditions:
  //  1. If we didn't do the incremental reflow above.
  //  2. If our size changed.
  // Even though it's the padding edge that's the containing block, we
  // can use our rect (the border edge) since if the border style
  // changed, the reflow would have been targeted at us so we'd satisfy
  // condition 1.
  // XXX checking oldSize is bogus, there are various reasons we might have
  // reflowed but our size might not have been changed to what we
  // asked for (e.g., we ended up being pushed to a new page)
  // When WillReflowAgainForClearance is true, we will reflow again without
  // resetting the size. Because of this, we must not reflow our abs-pos children
  // in that situation --- what we think is our "new size"
  // will not be our real new size. This also happens to be more efficient.
  if (HasAbsolutelyPositionedChildren()) {
    nsAbsoluteContainingBlock* absoluteContainer = GetAbsoluteContainingBlock();
    bool haveInterrupt = aPresContext->HasPendingInterrupt();
    if (reflowState->WillReflowAgainForClearance() ||
        haveInterrupt) {
      // Make sure that when we reflow again we'll actually reflow all the abs
      // pos frames that might conceivably depend on our size (or all of them,
      // if we're dirty right now and interrupted; in that case we also need
      // to mark them all with NS_FRAME_IS_DIRTY).  Sadly, we can't do much
      // better than that, because we don't really know what our size will be,
      // and it might in fact not change on the followup reflow!
      if (haveInterrupt && (GetStateBits() & NS_FRAME_IS_DIRTY)) {
        absoluteContainer->MarkAllFramesDirty();
      } else {
        absoluteContainer->MarkSizeDependentFramesDirty();
      }
    } else {
      nsSize containingBlockSize =
        CalculateContainingBlockSizeForAbsolutes(*reflowState,
                                                 nsSize(aMetrics.width,
                                                        aMetrics.height));

      // Mark frames that depend on changes we just made to this frame as dirty:
      // Now we can assume that the padding edge hasn't moved.
      // We need to reflow the absolutes if one of them depends on
      // its placeholder position, or the containing block size in a
      // direction in which the containing block size might have
      // changed.
      bool cbWidthChanged = aMetrics.width != oldSize.width;
      bool isRoot = !GetContent()->GetParent();
      // If isRoot and we have auto height, then we are the initial
      // containing block and the containing block height is the
      // viewport height, which can't change during incremental
      // reflow.
      bool cbHeightChanged =
        !(isRoot && NS_UNCONSTRAINEDSIZE == reflowState->ComputedHeight()) &&
        aMetrics.height != oldSize.height;

      absoluteContainer->Reflow(this, aPresContext, *reflowState,
                                state.mReflowStatus,
                                containingBlockSize.width,
                                containingBlockSize.height, true,
                                cbWidthChanged, cbHeightChanged,
                                &aMetrics.mOverflowAreas);

      //XXXfr Why isn't this rv (and others in this file) checked/returned?
    }
  }

  // Determine if we need to repaint our border, background or outline
  CheckInvalidateSizeChange(aMetrics);

  FinishAndStoreOverflow(&aMetrics);

  // Clear the float manager pointer in the block reflow state so we
  // don't waste time translating the coordinate system back on a dead
  // float manager.
  if (needFloatManager)
    state.mFloatManager = nsnull;

  aStatus = state.mReflowStatus;

#ifdef DEBUG
  // Between when we drain pushed floats and when we complete reflow,
  // we're allowed to have multiple continuations of the same float on
  // our floats list, since a first-in-flow might get pushed to a later
  // continuation of its containing block.  But it's not permitted
  // outside that time.
  nsLayoutUtils::AssertNoDuplicateContinuations(this, mFloats);

  if (gNoisyReflow) {
    IndentBy(stdout, gNoiseIndent);
    ListTag(stdout);
    printf(": status=%x (%scomplete) metrics=%d,%d carriedMargin=%d",
           aStatus, NS_FRAME_IS_COMPLETE(aStatus) ? "" : "not ",
           aMetrics.width, aMetrics.height,
           aMetrics.mCarriedOutBottomMargin.get());
    if (HasOverflowAreas()) {
      printf(" overflow-vis={%d,%d,%d,%d}",
             aMetrics.VisualOverflow().x,
             aMetrics.VisualOverflow().y,
             aMetrics.VisualOverflow().width,
             aMetrics.VisualOverflow().height);
      printf(" overflow-scr={%d,%d,%d,%d}",
             aMetrics.ScrollableOverflow().x,
             aMetrics.ScrollableOverflow().y,
             aMetrics.ScrollableOverflow().width,
             aMetrics.ScrollableOverflow().height);
    }
    printf("\n");
  }

  if (gLameReflowMetrics) {
    PRTime end = PR_Now();

    PRInt32 ectc = nsLineBox::GetCtorCount();
    PRInt32 numLines = mLines.size();
    if (!numLines) numLines = 1;
    PRTime delta, perLineDelta, lines;
    LL_I2L(lines, numLines);
    LL_SUB(delta, end, start);
    LL_DIV(perLineDelta, delta, lines);

    ListTag(stdout);
    char buf[400];
    PR_snprintf(buf, sizeof(buf),
                ": %lld elapsed (%lld per line) (%d lines; %d new lines)",
                delta, perLineDelta, numLines, ectc - ctc);
    printf("%s\n", buf);
  }
#endif

  NS_FRAME_SET_TRUNCATION(aStatus, (*reflowState), aMetrics);
  return rv;
}
Exemple #9
0
int main( int argc, char *argv[])
{
  int iOpt;
  int argCounter = 0;
  int ii;
  char tmp[TMPSIZE];
  FILE * fp;
  
  struct frameInfo {
    enum ID3_FrameID id;
    char *data;
  } frameList[MAXNOFRAMES];
  
  int frameCounter = 0;
  
  while (true)
  {
    int option_index = 0;
    int iLongOpt = 0;
    int optFrameID = ID3FID_NOFRAME;
    static struct option long_options[] = 
    { 
    // help and info
      { "help",    no_argument,       &iLongOpt, 'h' },
      { "list-frames",
                   no_argument,       &iLongOpt, 'f' },
      { "list-genres",   
                  no_argument,        &iLongOpt, 'L' },
      { "version", no_argument,       &iLongOpt, 'v' },

    // list / remove / convert
      { "list",   no_argument,        &iLongOpt, 'l' },
      { "list-rfc822",   
                   no_argument,       &iLongOpt, 'R' },
      { "delete-v2",  no_argument,    &iLongOpt, 'd' },
      { "delete-v1",  
                   no_argument,       &iLongOpt, 's' },
      { "delete-all",  
                   no_argument,       &iLongOpt, 'D' },
      { "convert", no_argument,       &iLongOpt, 'C' },
      { "id3v1-only", no_argument,       &iLongOpt, '1' },
      { "id3v2-only", no_argument,       &iLongOpt, '2' },

    // infomation to tag
      { "artist",  required_argument, &iLongOpt, 'a' },
      { "album",   required_argument, &iLongOpt, 'A' },
      { "song",    required_argument, &iLongOpt, 't' },
      { "comment", required_argument, &iLongOpt, 'c' },
      { "genre",   required_argument, &iLongOpt, 'g' },
      { "year",    required_argument, &iLongOpt, 'y' },
      { "track",   required_argument, &iLongOpt, 'T' },
      { "AENC",    required_argument, &optFrameID, ID3FID_AUDIOCRYPTO },
      { "APIC",    required_argument, &optFrameID, ID3FID_PICTURE },
      { "COMM",    required_argument, &optFrameID, ID3FID_COMMENT },
    /* COMR too complex */
      { "ENCR",    required_argument, &optFrameID, ID3FID_CRYPTOREG },
      { "EQUA",    required_argument, &optFrameID, ID3FID_EQUALIZATION },
      { "ETCO",    required_argument, &optFrameID, ID3FID_EVENTTIMING },
      { "GEOB",    required_argument, &optFrameID, ID3FID_GENERALOBJECT },
      { "GRID",    required_argument, &optFrameID, ID3FID_GROUPINGREG },
      { "IPLS",    required_argument, &optFrameID, ID3FID_INVOLVEDPEOPLE },
      { "LINK",    required_argument, &optFrameID, ID3FID_LINKEDINFO },
      { "MCDI",    required_argument, &optFrameID, ID3FID_CDID },
      { "MLLT",    required_argument, &optFrameID, ID3FID_MPEGLOOKUP },
      { "OWNE",    required_argument, &optFrameID, ID3FID_OWNERSHIP },
      { "PRIV",    required_argument, &optFrameID, ID3FID_PRIVATE },
      { "PCNT",    required_argument, &optFrameID, ID3FID_PLAYCOUNTER },
      { "POPM",    required_argument, &optFrameID, ID3FID_POPULARIMETER },
      { "POSS",    required_argument, &optFrameID, ID3FID_POSITIONSYNC },
      { "RBUF",    required_argument, &optFrameID, ID3FID_BUFFERSIZE },
      { "RVAD",    required_argument, &optFrameID, ID3FID_VOLUMEADJ },
      { "RVRB",    required_argument, &optFrameID, ID3FID_REVERB },
      { "SYLT",    required_argument, &optFrameID, ID3FID_SYNCEDLYRICS },
      { "SYTC",    required_argument, &optFrameID, ID3FID_SYNCEDTEMPO },
      { "TALB",    required_argument, &optFrameID, ID3FID_ALBUM },
      { "TBPM",    required_argument, &optFrameID, ID3FID_BPM },
      { "TCOM",    required_argument, &optFrameID, ID3FID_COMPOSER },
      { "TCON",    required_argument, &optFrameID, ID3FID_CONTENTTYPE },
      { "TCOP",    required_argument, &optFrameID, ID3FID_COPYRIGHT },
      { "TDAT",    required_argument, &optFrameID, ID3FID_DATE },
      { "TDLY",    required_argument, &optFrameID, ID3FID_PLAYLISTDELAY },
      { "TENC",    required_argument, &optFrameID, ID3FID_ENCODEDBY },
      { "TEXT",    required_argument, &optFrameID, ID3FID_LYRICIST },
      { "TFLT",    required_argument, &optFrameID, ID3FID_FILETYPE },
      { "TIME",    required_argument, &optFrameID, ID3FID_TIME },
      { "TIT1",    required_argument, &optFrameID, ID3FID_CONTENTGROUP },
      { "TIT2",    required_argument, &optFrameID, ID3FID_TITLE },
      { "TIT3",    required_argument, &optFrameID, ID3FID_SUBTITLE },
      { "TKEY",    required_argument, &optFrameID, ID3FID_INITIALKEY },
      { "TLAN",    required_argument, &optFrameID, ID3FID_LANGUAGE },
      { "TLEN",    required_argument, &optFrameID, ID3FID_SONGLEN },
      { "TMED",    required_argument, &optFrameID, ID3FID_MEDIATYPE },
      { "TOAL",    required_argument, &optFrameID, ID3FID_ORIGALBUM },
      { "TOFN",    required_argument, &optFrameID, ID3FID_ORIGFILENAME },
      { "TOLY",    required_argument, &optFrameID, ID3FID_ORIGLYRICIST },
      { "TOPE",    required_argument, &optFrameID, ID3FID_ORIGARTIST },
      { "TORY",    required_argument, &optFrameID, ID3FID_ORIGYEAR },
      { "TOWN",    required_argument, &optFrameID, ID3FID_FILEOWNER },
      { "TPE1",    required_argument, &optFrameID, ID3FID_LEADARTIST },
      { "TPE2",    required_argument, &optFrameID, ID3FID_BAND },
      { "TPE3",    required_argument, &optFrameID, ID3FID_CONDUCTOR },
      { "TPE4",    required_argument, &optFrameID, ID3FID_MIXARTIST },
      { "TPOS",    required_argument, &optFrameID, ID3FID_PARTINSET },
      { "TPUB",    required_argument, &optFrameID, ID3FID_PUBLISHER },
      { "TRCK",    required_argument, &optFrameID, ID3FID_TRACKNUM },
      { "TRDA",    required_argument, &optFrameID, ID3FID_RECORDINGDATES },
      { "TRSN",    required_argument, &optFrameID, ID3FID_NETRADIOSTATION },
      { "TRSO",    required_argument, &optFrameID, ID3FID_NETRADIOOWNER },
      { "TSIZ",    required_argument, &optFrameID, ID3FID_SIZE },
      { "TSRC",    required_argument, &optFrameID, ID3FID_ISRC },
      { "TSSE",    required_argument, &optFrameID, ID3FID_ENCODERSETTINGS },
      { "TXXX",    required_argument, &optFrameID, ID3FID_USERTEXT },
      { "TYER",    required_argument, &optFrameID, ID3FID_YEAR },
      { "UFID",    required_argument, &optFrameID, ID3FID_UNIQUEFILEID },
      { "USER",    required_argument, &optFrameID, ID3FID_TERMSOFUSE },
      { "USLT",    required_argument, &optFrameID, ID3FID_UNSYNCEDLYRICS },
      { "WCOM",    required_argument, &optFrameID, ID3FID_WWWCOMMERCIALINFO },
      { "WCOP",    required_argument, &optFrameID, ID3FID_WWWCOPYRIGHT },
      { "WOAF",    required_argument, &optFrameID, ID3FID_WWWAUDIOFILE },
      { "WOAR",    required_argument, &optFrameID, ID3FID_WWWARTIST },
      { "WOAS",    required_argument, &optFrameID, ID3FID_WWWAUDIOSOURCE },
      { "WORS",    required_argument, &optFrameID, ID3FID_WWWRADIOPAGE },
      { "WPAY",    required_argument, &optFrameID, ID3FID_WWWPAYMENT },
      { "WPUB",    required_argument, &optFrameID, ID3FID_WWWPUBLISHER },
      { "WXXX",    required_argument, &optFrameID, ID3FID_WWWUSER },
      { 0, 0, 0, 0 }
    };
    iOpt = getopt_long (argc, argv, "12hfLvlRdsDCa:A:t:c:g:y:T:",
                        long_options, &option_index);

    if (iOpt == -1  && argCounter == 0)
    {
      PrintUsage(argv[0]);
      exit(0);
    } 
    else if (iOpt == -1)
      break;
    argCounter++;

    if (iOpt == 0) iOpt = iLongOpt;
//    if (iOpt == 0) iOpt = optFrameID;

#ifdef SORT_RUNTIME
    InitGenres();
#endif  // SORT_RUNTIME

    switch (iOpt)
    {
      case 0:
                frameList[frameCounter].id   = (enum ID3_FrameID)optFrameID;
                frameList[frameCounter].data = optarg;
                frameCounter++;
                break;
      case '?': 
      case 'h': PrintUsage(argv[0]);    exit (0);
      case 'f': PrintFrameHelp(argv[0]);exit (0);
      case 'L': PrintGenreList();       exit (0);
      case 'v': PrintVersion(argv[0]);  exit (0);

    // listing / remove / convert -- see list.cpp and convert.cpp
      case 'l': ListTag(argc, argv, optind, 0);    
                                        exit (0);
      case 'R': ListTag(argc, argv, optind, 1);    
                                        exit (0);
      case 'd': DeleteTag(argc, argv, optind, 2);    
                                        exit (0);
      case 's': DeleteTag(argc, argv, optind, 1);    
                                        exit (0);
      case 'D': DeleteTag(argc, argv, optind, 0);    
                                        exit (0);
      case 'C': ConvertTag(argc, argv, optind);    
                                        exit (0);
      case '1':
		UpdFlags = ID3TT_ID3V1;
		break;
      case '2':
		UpdFlags = ID3TT_ID3V2;
		break;
    // Tagging stuff 
      case 'a': 
                frameList[frameCounter].id   = ID3FID_LEADARTIST;
                frameList[frameCounter].data = optarg;
                frameCounter++;
                break;
      case 'A': 
                frameList[frameCounter].id   = ID3FID_ALBUM;
                frameList[frameCounter].data = optarg;
                frameCounter++;
                break;
      case 't': 
                frameList[frameCounter].id   = ID3FID_TITLE;
                frameList[frameCounter].data = optarg;
                frameCounter++;
                break;
      case 'c': 
                frameList[frameCounter].id   = ID3FID_COMMENT;
                frameList[frameCounter].data = optarg;
                frameCounter++;
                break;
      case 'g': 
          {
                int genre_id = 255;
                char *genre_str;
                sscanf(optarg, "%d", &genre_id);
                if (genre_id == 255)
                    genre_id = GetNumFromGenre(optarg);
                if (genre_id == 255)
                    genre_str = optarg;
                else {
                    sprintf(tmp, "(%d)", genre_id);
                    genre_str = tmp;
                }
                frameList[frameCounter].id   = ID3FID_CONTENTTYPE;
                frameList[frameCounter].data = genre_str;
                frameCounter++;
          }
                break;
      case 'y': 
                frameList[frameCounter].id   = ID3FID_YEAR;
                frameList[frameCounter].data = optarg;
                frameCounter++;
                break;
      case 'T': 
                frameList[frameCounter].id   = ID3FID_TRACKNUM;
                frameList[frameCounter].data = optarg;
                frameCounter++;
                break;
    // other tags
    
      default:
		std::cerr << "This isn't supposed to happen" << std::endl;
                exit(1);
    }
  }
  
  // loop thru the files
  if (optind == argc) 
  {
	  std::cerr << "No file to work on." << std::endl;
    exit(1);
  }
  
  for (size_t nIndex = optind; (unsigned int) nIndex < argc; nIndex++)
  {
    ID3_Tag myTag;
    struct stat filestat;
    
    // std::cout << "Tagging " << argv[nIndex] << ": ";

    // fix me - not checking to see if we can link to it
    
    
    if (stat(argv[nIndex], &filestat)) 
    {
      std::cerr << "Couldn't stat file '" << argv[nIndex] << "'\n";
      break;
    }
    
    /* cludgy to check if we have the proper perms */
    fp = fopen(argv[nIndex], "r+");
    if (fp == NULL) { /* file didn't open */
      fprintf(stderr, "fopen: %s: ", argv[nIndex]);
      perror("id3v2");
      continue;
    }
    fclose(fp);

    size_t ret;
    ret = myTag.Link(argv[nIndex] /*, ID3TT_ID3V2 */);

    // loop thru the frames we need to add/modify
    for (ii = 0; ii < frameCounter; ii++) 
    {
      ID3_Frame *myFrame;
      myFrame = new ID3_Frame;
      if (NULL == myFrame)
      {
         std::cout << "\nOut of memory\n" << std::endl;
         exit(1);
      }
      
      myFrame->SetID(frameList[ii].id);
      
      ID3_Frame *pFrame;
      pFrame = myTag.Find(frameList[ii].id);
                          
      switch (frameList[ii].id)
      {
      //  strings
        case ID3FID_ALBUM:
        case ID3FID_BPM:
        case ID3FID_COMPOSER:
        case ID3FID_CONTENTTYPE:
        case ID3FID_COPYRIGHT:
        case ID3FID_DATE:
        case ID3FID_PLAYLISTDELAY:
        case ID3FID_ENCODEDBY:
        case ID3FID_LYRICIST:
        case ID3FID_FILETYPE:
        case ID3FID_TIME:
        case ID3FID_CONTENTGROUP:
        case ID3FID_TITLE:
        case ID3FID_SUBTITLE:
        case ID3FID_INITIALKEY:
        case ID3FID_LANGUAGE:
        case ID3FID_SONGLEN:
        case ID3FID_MEDIATYPE:
        case ID3FID_ORIGALBUM:
        case ID3FID_ORIGFILENAME:
        case ID3FID_ORIGLYRICIST:
        case ID3FID_ORIGARTIST:
        case ID3FID_ORIGYEAR:
        case ID3FID_FILEOWNER:
        case ID3FID_LEADARTIST:
        case ID3FID_BAND:
        case ID3FID_CONDUCTOR:
        case ID3FID_MIXARTIST:
        case ID3FID_PARTINSET:
        case ID3FID_PUBLISHER:
        case ID3FID_RECORDINGDATES:
        case ID3FID_NETRADIOSTATION:
        case ID3FID_NETRADIOOWNER:
        case ID3FID_SIZE:
        case ID3FID_ISRC:
        case ID3FID_ENCODERSETTINGS:
        case ID3FID_YEAR:
        {
          if (pFrame != NULL) 
          {
            myTag.RemoveFrame(pFrame);
          }
          if (strlen(frameList[ii].data) > 0) {
            myFrame->Field(ID3FN_TEXT) = frameList[ii].data;
            myTag.AttachFrame(myFrame);
          }
          break;
        }
        case ID3FID_TRACKNUM:
        {
          // this ought to check if there is a total track number and
          // combine it with the given track number, but it doesn't.
          char *currentTrackNum = NULL;
          char *newTrackNum = NULL;

          if (pFrame != NULL) 
          {
            currentTrackNum = ID3_GetString(pFrame, ID3FN_TEXT);
            if (*currentTrackNum == '/') 
            {
              newTrackNum = (char *)malloc(strlen(currentTrackNum) 
                                   + strlen(frameList[ii].data)); 
              strcpy(newTrackNum, frameList[ii].data);
              strcat(newTrackNum, currentTrackNum);
            }
            else
            {
              myTag.RemoveFrame(pFrame);
            }
          }
          
          myFrame->Field(ID3FN_TEXT) = frameList[ii].data;
          myTag.AttachFrame(myFrame);

          free(newTrackNum);
          break;
        }
        case ID3FID_USERTEXT:
        {
          if (pFrame != NULL) 
          {
            myTag.RemoveFrame(pFrame);
          }

          // split the string at the ':' remember if no : then leave
          // descrip empty
          char *text;
          text = strchr(frameList[ii].data, ':');
          if (text == NULL) 
          {
            myFrame->Field(ID3FN_TEXT) = frameList[ii].data;
          } else {
            *text = '\0';
            text++;
            myFrame->Field(ID3FN_DESCRIPTION) = frameList[ii].data;
            myFrame->Field(ID3FN_TEXT) = text;
          }
          if (strlen(ID3_GetString(myFrame, ID3FN_TEXT)) > 0) {
            myTag.AttachFrame(myFrame);
          }
          
          break;
        }
        case ID3FID_COMMENT:
        case ID3FID_UNSYNCEDLYRICS:
        {
          // split the string at the ':' remember if no : then leave
          // descrip/lang empty
          char *text;
          text = strchr(frameList[ii].data, ':');
          if (text == NULL) 
          {
            myFrame->Field(ID3FN_TEXT) = frameList[ii].data;
          } else {
         	*text = '\0';
          	text++;
          	char *lang;
          	lang = strchr(text, ':');
          	if (lang == NULL) 
          	{
          	  myFrame->Field(ID3FN_DESCRIPTION) = frameList[ii].data;
          	  myFrame->Field(ID3FN_TEXT) = text;
          	} else {
          	  *lang = '\0';
          	  lang++;
          	  myFrame->Field(ID3FN_DESCRIPTION) = frameList[ii].data;
              myFrame->Field(ID3FN_TEXT) = text;
              myFrame->Field(ID3FN_LANGUAGE) = lang;
            }
          }
          /* debug
          std::cout << ID3_GetString(myFrame, ID3FN_DESCRIPTION) << std::endl
               << ID3_GetString(myFrame, ID3FN_TEXT) << std::endl
               << ID3_GetString(myFrame, ID3FN_LANGUAGE) << std::endl;
          */

          // now try and find a comment/lyrics with the same descript 
          // and lang as what we have
          ID3_Frame *pFirstFrame = NULL;
          do {
            // if pFrame is NULL, either there were no comments/lyrics 
            // to begin with, or we removed them all in the process          
            if (pFrame == NULL) break;
            
            if (pFirstFrame == NULL) 
            {
              pFirstFrame = pFrame;
            }

            char *tmp_desc = ID3_GetString(pFrame, ID3FN_DESCRIPTION);
            char *tmp_my_desc = ID3_GetString(myFrame, ID3FN_DESCRIPTION);
            char *tmp_lang = ID3_GetString(pFrame, ID3FN_LANGUAGE);
            char *tmp_my_lang = ID3_GetString(myFrame, ID3FN_LANGUAGE);
            if ((strcmp(tmp_desc, tmp_my_desc) == 0) &&
                (strcmp(tmp_lang, tmp_my_lang) == 0)) 
            {
              myTag.RemoveFrame(pFrame);
              if (pFrame == pFirstFrame) 
              {
                pFirstFrame = NULL;
              }
            }
            delete [] tmp_desc;
            delete [] tmp_my_desc;
            delete [] tmp_lang;
            delete [] tmp_my_lang;
            
            // get the next frame until it wraps around
          } while ((pFrame = myTag.Find(frameList[ii].id)) != pFirstFrame);
          
          if (strlen(ID3_GetString(myFrame, ID3FN_TEXT)) > 0) {
            myTag.AttachFrame(myFrame);
          }
          
          break;
        }
        case ID3FID_WWWAUDIOFILE:
        case ID3FID_WWWARTIST:
        case ID3FID_WWWAUDIOSOURCE:
        case ID3FID_WWWCOMMERCIALINFO:
        case ID3FID_WWWCOPYRIGHT:
        case ID3FID_WWWPUBLISHER:
        case ID3FID_WWWPAYMENT:
        case ID3FID_WWWRADIOPAGE:
        {
          if (pFrame != NULL) 
          {
            char *sURL = ID3_GetString(pFrame, ID3FN_URL);
            if (strcmp(frameList[ii].data, sURL) == 0)
              myTag.RemoveFrame(pFrame);  
          }

          if (strlen(frameList[ii].data) > 0) {
            myFrame->Field(ID3FN_URL) = frameList[ii].data;
            myTag.AttachFrame(myFrame);
          }
                  
          break;
                                
        }
        case ID3FID_WWWUSER:
        {
          char 
            *sURL = ID3_GetString(myFrame, ID3FN_URL),
            *sDesc = ID3_GetString(myFrame, ID3FN_DESCRIPTION);
          std::cout << "(" << sDesc << "): " << sURL << std::endl;
          delete [] sURL;
          delete [] sDesc;
          break;
        }
        case ID3FID_INVOLVEDPEOPLE:
        {
          // This isn't the right way to do it---will only get first person
          size_t nItems = myFrame->Field(ID3FN_TEXT).GetNumTextItems();
          for (size_t nIndex = 1; nIndex <= nItems; nIndex++)
          {
            char *sPeople = ID3_GetString(myFrame, ID3FN_TEXT, nIndex);
            std::cout << sPeople;
            delete [] sPeople;
            if (nIndex < nItems)
            { 
              std::cout << ", ";
            }
          }
          std::cout << std::endl;
          break;
        }
        case ID3FID_PICTURE:
        {
          myFrame->Field(ID3FN_DATA).FromFile(frameList[ii].data);
          myTag.AttachFrame(myFrame);
          break;
        }
        case ID3FID_GENERALOBJECT:
        {
          char 
            *sMimeType = ID3_GetString(myFrame, ID3FN_TEXT), 
            *sDesc = ID3_GetString(myFrame, ID3FN_DESCRIPTION), 
            *sFileName = ID3_GetString(myFrame, ID3FN_FILENAME);
          size_t 
          nDataSize = myFrame->Field(ID3FN_DATA).Size();
          std::cout << "(" << sDesc << ")[" 
              << sFileName << "]: " << sMimeType << ", " << nDataSize
              << " bytes" << std::endl;
          delete [] sMimeType;
          delete [] sDesc;
          delete [] sFileName;
          break;
        }
        case ID3FID_UNIQUEFILEID:
        {
          if (pFrame != NULL) 
          {       
            char *sOwner = ID3_GetString(pFrame, ID3FN_TEXT);
            size_t nDataSize = pFrame->Field(ID3FN_DATA).Size();
            std::cout << sOwner << ", " << nDataSize
                 << " bytes" << std::endl;
            delete [] sOwner;
          }
          break;
        }
        case ID3FID_PLAYCOUNTER:
        {
          if (pFrame != NULL) 
          {
            size_t nCounter = pFrame->Field(ID3FN_COUNTER).Get();
            std::cout << nCounter << std::endl;
          }
          break;
        }
        case ID3FID_POPULARIMETER:
        {
          if (pFrame != NULL)
          {
            char *sEmail = ID3_GetString(pFrame, ID3FN_EMAIL);
            size_t
              nCounter = pFrame->Field(ID3FN_COUNTER).Get(),
              nRating = pFrame->Field(ID3FN_RATING).Get();
            std::cout << sEmail << ", counter=" 
                 << nCounter << " rating=" << nRating;
            delete [] sEmail;
          }
          break;
        }
        case ID3FID_CRYPTOREG:
        case ID3FID_GROUPINGREG:
        {
          char *sOwner = ID3_GetString(myFrame, ID3FN_OWNER);
          size_t 
            nSymbol = myFrame->Field(ID3FN_ID).Get(),
            nDataSize = myFrame->Field(ID3FN_DATA).Size();
          std::cout << "(" << nSymbol << "): " << sOwner
               << ", " << nDataSize << " bytes";
          break;
        }
        case ID3FID_AUDIOCRYPTO:
        case ID3FID_EQUALIZATION:
        case ID3FID_EVENTTIMING:
        case ID3FID_CDID:
        case ID3FID_MPEGLOOKUP:
        case ID3FID_OWNERSHIP:
        case ID3FID_PRIVATE:
        case ID3FID_POSITIONSYNC:
        case ID3FID_BUFFERSIZE:
        case ID3FID_VOLUMEADJ:
        case ID3FID_REVERB:
        case ID3FID_SYNCEDLYRICS:
        case ID3FID_SYNCEDTEMPO:
        case ID3FID_METACRYPTO:
        {
          std::cout << " (unimplemented)" << std::endl;
          break;
        }
        default:
        {
          std::cout << " frame" << std::endl;
          break;
        }
      }
    }  // steping thru frames
   
    luint nTags = myTag.Update(UpdFlags);

    /* update file with old mode */
    if (chmod(argv[nIndex], filestat.st_mode)) 
    {
	    std::cerr << "Couldn't reset permissions on '" << argv[nIndex] << "'\n";
    }    
  }

  return 0;
}