if (nsnull == aReflowState.lineLayout) {
if (nsnull == aReflowState.mLineLayout) {
nsTextFrame::Reflow(nsIPresContext& aPresContext,                    nsHTMLReflowMetrics& aMetrics,                    const nsHTMLReflowState& aReflowState,                    nsReflowStatus& aStatus){  //  NS_PRECONDITION(nsnull != aReflowState.lineLayout, "no line layout");  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,     ("enter nsTextFrame::Reflow: aMaxSize=%d,%d",      aReflowState.availableWidth, aReflowState.availableHeight));  // XXX If there's no line layout, we shouldn't even have created this  // frame. This may happen if, for example, this is text inside a table  // but not inside a cell. For now, just don't reflow.  if (nsnull == aReflowState.lineLayout) {    // XXX Add a method to aMetrics that does this; we do it several places    aMetrics.width = 0;    aMetrics.height = 0;    aMetrics.ascent = 0;    aMetrics.descent = 0;    if (nsnull != aMetrics.maxElementSize) {      aMetrics.maxElementSize->width = 0;      aMetrics.maxElementSize->height = 0;    }    return NS_OK;  }  // Get starting offset into the content  PRInt32 startingOffset = 0;  if (nsnull != mPrevInFlow) {    nsTextFrame* prev = (nsTextFrame*) mPrevInFlow;    startingOffset = prev->mContentOffset + prev->mContentLength;  }  nsLineLayout& lineLayout = *aReflowState.lineLayout;  TextStyle ts(&aPresContext, *aReflowState.rendContext, mStyleContext);  // Initialize mFlags (without destroying the TEXT_BLINK_ON bit) bits  // that are filled in by the reflow routines.  mFlags &= TEXT_BLINK_ON;  if (ts.mFont->mFont.decorations & NS_STYLE_TEXT_DECORATION_BLINK) {    if (0 == (mFlags & TEXT_BLINK_ON)) {      mFlags |= TEXT_BLINK_ON;      gTextBlinker->AddFrame(this);    }  }  else {    if (0 != (mFlags & TEXT_BLINK_ON)) {      mFlags &= ~TEXT_BLINK_ON;      gTextBlinker->RemoveFrame(this);    }  }  PRBool wrapping = (NS_STYLE_WHITESPACE_NORMAL == ts.mText->mWhiteSpace) ||    (NS_STYLE_WHITESPACE_MOZ_PRE_WRAP == ts.mText->mWhiteSpace);  PRBool firstLetterOK = lineLayout.GetFirstLetterStyleOK();  PRBool justDidFirstLetter = PR_FALSE;  // Set whitespace skip flag  PRBool skipWhitespace = PR_FALSE;  if (!ts.mPreformatted) {    if (lineLayout.GetEndsInWhiteSpace()) {      skipWhitespace = PR_TRUE;    }  }  nscoord x = 0;  nscoord maxWidth = aReflowState.availableWidth;  nscoord maxWordWidth = 0;  nscoord prevMaxWordWidth = 0;  PRBool endsInWhitespace = PR_FALSE;  PRBool endsInNewline = PR_FALSE;  nsCOMPtr<nsIPresShell> shell;  aPresContext.GetShell(getter_AddRefs(shell));  nsCOMPtr<nsIDocument> doc;  shell->GetDocument(getter_AddRefs(doc));  // Setup text transformer to transform this frames text content  PRUnichar wordBuf[WORD_BUF_SIZE];  nsCOMPtr<nsILineBreaker> lb;  doc->GetLineBreaker(getter_AddRefs(lb));  nsCOMPtr<nsIWordBreaker> wb;  doc->GetWordBreaker(getter_AddRefs(wb));  nsTextTransformer tx(wordBuf, WORD_BUF_SIZE,lb,wb);  nsresult rv = tx.Init(/**textRun, XXX*/ this, startingOffset);  if (NS_OK != rv) {    return rv;  }  PRInt32 contentLength = tx.GetContentLength();  // Offset tracks how far along we are in the content  PRInt32 offset = startingOffset;  PRInt32 prevOffset = -1;  nscoord lastWordWidth = 0;  // Loop over words and whitespace in content and measure. Set inWord  // to true if we are part of a previous piece of text's word. This  // is only valid for one pass through the measuring loop.  PRBool inWord = lineLayout.InWord() ||    ((nsnull != mPrevInFlow) &&     (((nsTextFrame*)mPrevInFlow)->mFlags & TEXT_FIRST_LETTER));  if (inWord) {    mFlags |= TEXT_IN_WORD;  }  mFlags &= ~TEXT_FIRST_LETTER;  PRInt32 column = lineLayout.GetColumn();  PRInt32 prevColumn = column;  mColumn = column;  PRBool breakable = lineLayout.LineIsBreakable();  for (;;) {    // Get next word/whitespace from the text    PRBool isWhitespace;    PRInt32 wordLen, contentLen;    PRUnichar* bp = tx.GetNextWord(inWord, wordLen, contentLen, isWhitespace);    if (nsnull == bp) {      break;    }    inWord = PR_FALSE;    // Measure the word/whitespace    nscoord width;    if (isWhitespace) {      if (0 == wordLen) {        // We hit a newline. Stop looping.        prevOffset = offset;        offset++;        endsInWhitespace = PR_TRUE;        if (ts.mPreformatted) {          endsInNewline = PR_TRUE;        }        break;      }      if (skipWhitespace) {        offset += contentLen;        skipWhitespace = PR_FALSE;        // Only set flag when we actually do skip whitespace        mFlags |= TEXT_SKIP_LEADING_WS;        continue;      }      if ('\t' == bp[0]) {        // Expand tabs to the proper width        wordLen = 8 - (7 & column);        width = ts.mSpaceWidth * wordLen;      }      else {        width = ts.mSpaceWidth + ts.mWordSpacing;/* XXX simplistic */      }      breakable = PR_TRUE;      firstLetterOK = PR_FALSE;    } else {      if (firstLetterOK) {        // XXX need a lookup function here; plus look ahead using the        // text-runs        if ((bp[0] == '\'') || (bp[0] == '\"')) {          wordLen = 2;          contentLen = 2;        }        else {          wordLen = 1;          contentLen = 1;        }        justDidFirstLetter = PR_TRUE;      }      if (ts.mSmallCaps) {        MeasureSmallCapsText(aReflowState, ts, bp, wordLen, &width);      }      else {        aReflowState.rendContext->GetWidth(bp, wordLen, width);        if (ts.mLetterSpacing) {          width += ts.mLetterSpacing * wordLen;        }      }      skipWhitespace = PR_FALSE;      lastWordWidth = width;    }    // See if there is room for the text    if ((0 != x) && wrapping && (x + width > maxWidth)) {      // The text will not fit.      break;    }    prevColumn = column;    column += wordLen;    x += width;    prevMaxWordWidth = maxWordWidth;    if (width > maxWordWidth) {      maxWordWidth = width;    }    endsInWhitespace = isWhitespace;    prevOffset = offset;    offset += contentLen;    if (!isWhitespace && justDidFirstLetter) {      // Time to stop      break;    }  }  if (tx.HasMultibyte()) {    mFlags |= TEXT_HAS_MULTIBYTE;  }  // Post processing logic to deal with word-breaking that spans  // multiple frames.  if (lineLayout.InWord()) {    // We are already in a word. This means a text frame prior to this    // one had a fragment of a nbword that is joined with this    // frame. It also means that the prior frame already found this    // frame and recorded it as part of the word.#ifdef DEBUG_WORD_WRAPPING    ListTag(stdout);    printf(": in word; skipping\n");#endif    lineLayout.ForgetWordFrame(this);  }  if (!lineLayout.InWord()) {    // There is no currently active word. This frame may contain the    // start of one.    if (endsInWhitespace) {      // Nope, this frame doesn't start a word.      lineLayout.ForgetWordFrames();    }    else if ((offset == contentLength) && (prevOffset >= 0)) {      // Force breakable to false when we aren't wrapping (this      // guarantees that the combined word will stay together)      if (!wrapping) {        breakable = PR_FALSE;      }      // This frame does start a word. However, there is no point      // messing around with it if we are already out of room. We      // always have room if we are not breakable.      if (!breakable || (x <= maxWidth)) {        // There is room for this word fragment. It's possible that        // this word fragment is the end of the text-run. If it's not        // then we continue with the look-ahead processing.        nsIFrame* next = lineLayout.FindNextText(this);        if (nsnull != next) {#ifdef DEBUG_WORD_WRAPPING          nsAutoString tmp(tx.GetTextAt(0), offset-prevOffset);          ListTag(stdout);          printf(": start='");          fputs(tmp, stdout);          printf("' baseWidth=%d [%d,%d]\n", lastWordWidth, prevOffset, offset);#endif          // Look ahead in the text-run and compute the final word          // width, taking into account any style changes and stopping          // at the first breakable point.          nscoord wordWidth = ComputeTotalWordWidth(&aPresContext, lineLayout,                                                    aReflowState, next,                                                    lastWordWidth);          if (!breakable || (x - lastWordWidth + wordWidth <= maxWidth)) {            // The fully joined word has fit. Account for the joined            // word's affect on the max-element-size here (since the            // joined word is large than it's pieces, the right effect            // will occur from the perspective of the container            // reflowing this frame)            if (wordWidth > maxWordWidth) {              maxWordWidth = wordWidth;            }          }          else {            // The fully joined word won't fit. We need to reduce our            // size by the lastWordWidth.            x -= lastWordWidth;            maxWordWidth = prevMaxWordWidth;            offset = prevOffset;            column = prevColumn;#ifdef DEBUG_WORD_WRAPPING            printf("  x=%d maxWordWidth=%d len=%d\n", x, maxWordWidth,                   offset - startingOffset);#endif            lineLayout.ForgetWordFrames();          }        }      }    }  }  lineLayout.SetColumn(column);  // Inform line layout of how this piece of text ends in whitespace  // (only text objects do this). Note that if x is zero then this  // text object collapsed into nothingness which means it shouldn't  // effect the current setting of the ends-in-whitespace flag.  lineLayout.SetUnderstandsWhiteSpace(PR_TRUE);  if (0 != x) {    lineLayout.SetEndsInWhiteSpace(endsInWhitespace);  }  if (justDidFirstLetter) {    lineLayout.SetFirstLetterFrame(this);    lineLayout.SetFirstLetterStyleOK(PR_FALSE);    mFlags |= TEXT_FIRST_LETTER;  }  // Setup metrics for caller; store final max-element-size information  aMetrics.width = x;  mComputedWidth = x;  if ((0 == x) && !ts.mPreformatted) {    aMetrics.height = 0;    aMetrics.ascent = 0;    aMetrics.descent = 0;  }  else {    ts.mNormalFont->GetHeight(aMetrics.height);    ts.mNormalFont->GetMaxAscent(aMetrics.ascent);    ts.mNormalFont->GetMaxDescent(aMetrics.descent);  }  if (!wrapping) {    maxWordWidth = x;  }  if (nsnull != aMetrics.maxElementSize) {    aMetrics.maxElementSize->width = maxWordWidth;    aMetrics.maxElementSize->height = aMetrics.height;  }  // Set content offset and length  mContentOffset = startingOffset;  mContentLength = offset - startingOffset;  // If it's an incremental reflow command, then invalidate our existing  // bounds.  // XXX We need a finer granularity than this, but it isn't clear what  // has actually changed...  if (eReflowReason_Incremental == aReflowState.reason) {    Invalidate(mRect);  }  //go to selection and ask if we are selected here. and where!!  nsReflowStatus rs = (offset == contentLength)    ? NS_FRAME_COMPLETE    : NS_FRAME_NOT_COMPLETE;  if (endsInNewline) {    rs = NS_INLINE_LINE_BREAK_AFTER(rs);  }  else if ((offset != contentLength) && (offset == startingOffset)) {    // Break-before a long-word that doesn't fit here    rs = NS_INLINE_LINE_BREAK_BEFORE();  }  aStatus = rs;  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,                 ("exit nsTextFrame::Reflow: status=%x width=%d",                  aStatus, aMetrics.width));  return NS_OK;}