PRUnichar* aBuffer, PRInt32 aLength,
PRUnichar* aBuffer, PRInt32 aLength, PRBool aIsEndOfFrame,
nsTextFrame::RenderString(nsIRenderingContext& aRenderingContext,                          nsStyleContext* aStyleContext,                          nsPresContext* aPresContext,                          TextPaintStyle& aTextStyle,                          PRUnichar* aBuffer, PRInt32 aLength,                          nscoord aX, nscoord aY,                          nscoord aWidth,                           SelectionDetails *aDetails /*=nsnull*/){  PRUnichar buf[TEXT_BUF_SIZE];  PRUnichar* bp0 = buf;  nscoord spacingMem[TEXT_BUF_SIZE];  nscoord* sp0 = spacingMem;     PRBool spacing = (0 != aTextStyle.mLetterSpacing) ||    (0 != aTextStyle.mWordSpacing) || aTextStyle.mJustifying;  PRBool justifying = aTextStyle.mJustifying &&    (aTextStyle.mNumJustifiableCharacterReceivingExtraJot != 0 || aTextStyle.mExtraSpacePerJustifiableCharacter != 0);  PRBool isCJ = IsChineseJapaneseLangGroup();  //German 0x00df might expand to "SS", but no need to count it for speed reason  if (aTextStyle.mSmallCaps) {     if (aLength*2 > TEXT_BUF_SIZE) {       bp0 = new PRUnichar[aLength*2];       if (spacing)         sp0 = new nscoord[aLength*2];     }  }  else if (aLength > TEXT_BUF_SIZE) {    bp0 = new PRUnichar[aLength];    if (spacing)      sp0 = new nscoord[aLength];  }  PRUnichar* bp = bp0;  nscoord* sp = sp0;  nsIFontMetrics* lastFont = aTextStyle.mLastFont;  PRInt32 pendingCount;  PRUnichar* runStart = bp;  nscoord charWidth, width = 0;  PRInt32 countSoFar = 0;  for (; --aLength >= 0; aBuffer++) {    nsIFontMetrics* nextFont;    nscoord glyphWidth;    PRUnichar ch = *aBuffer;    if (aTextStyle.mSmallCaps &&        (IsLowerCase(ch) || (ch == kSZLIG))) {      nextFont = aTextStyle.mSmallFont;      PRUnichar upper_ch;      // German szlig should be expanded to "SS".      if (ch == kSZLIG)        upper_ch = (PRUnichar)'S';      else        upper_ch = ToUpperCase(ch);      if (lastFont != aTextStyle.mSmallFont) {        aRenderingContext.SetFont(aTextStyle.mSmallFont);        aRenderingContext.GetWidth(upper_ch, charWidth);        aRenderingContext.SetFont(aTextStyle.mNormalFont);      }      else {        aRenderingContext.GetWidth(upper_ch, charWidth);      }      glyphWidth = charWidth + aTextStyle.mLetterSpacing;      if (ch == kSZLIG)   //add an additional 'S' here.      {        *bp++ = upper_ch;        if (spacing)          *sp++ = glyphWidth;        width += glyphWidth;      }      ch = upper_ch;    }    else if (ch == ' ') {      nextFont = aTextStyle.mNormalFont;      glyphWidth = aTextStyle.mSpaceWidth + aTextStyle.mWordSpacing + aTextStyle.mLetterSpacing;    }    else {      if (lastFont != aTextStyle.mNormalFont) {        aRenderingContext.SetFont(aTextStyle.mNormalFont);      }      if (IS_HIGH_SURROGATE(ch) && aLength > 0 &&        IS_LOW_SURROGATE(*(aBuffer+1))) {              // special handling for surrogate pair        aRenderingContext.GetWidth(aBuffer, 2, charWidth);        glyphWidth = charWidth + aTextStyle.mLetterSpacing;        // copy the surrogate low        *bp++ = ch;        --aLength;        aBuffer++;        ch = *aBuffer;        // put the width into the space buffer        width += glyphWidth;        *sp++ = glyphWidth;        // set the glyphWidth to 0 so the code later will         // set a 0 for one element in space array for surrogate low to 0        glyphWidth = 0;      } else {        aRenderingContext.GetWidth(ch, charWidth);        glyphWidth = charWidth + aTextStyle.mLetterSpacing;      }      if (lastFont != aTextStyle.mNormalFont) {        aRenderingContext.SetFont(aTextStyle.mSmallFont);      }      nextFont = aTextStyle.mNormalFont;    }    if (justifying && IsJustifiableCharacter(ch, isCJ)) {      glyphWidth += aTextStyle.mExtraSpacePerJustifiableCharacter;      if ((PRUint32)--aTextStyle.mNumJustifiableCharacterToRender            < (PRUint32)aTextStyle.mNumJustifiableCharacterReceivingExtraJot) {        glyphWidth++;      }    }    if (nextFont != lastFont) {      pendingCount = bp - runStart;      if (0 != pendingCount) {        // Measure previous run of characters using the previous font        aRenderingContext.SetColor(aTextStyle.mColor->mColor);        aRenderingContext.DrawString(runStart, pendingCount,                                     aX, aY + mAscent, -1,                                     spacing ? sp0 : nsnull);        // Note: use aY not small-y so that decorations are drawn with        // respect to the normal-font not the current font.        PaintTextDecorations(aRenderingContext, aStyleContext, aPresContext,                             aTextStyle, aX, aY, width, runStart, aDetails,                             countSoFar, pendingCount, spacing ? sp0 : nsnull);        countSoFar += pendingCount;        aWidth -= width;        aX += width;        runStart = bp = bp0;        sp = sp0;        width = 0;      }      aRenderingContext.SetFont(nextFont);      lastFont = nextFont;    }    *bp++ = ch;    if (spacing)      *sp++ = glyphWidth;    width += glyphWidth;  }  pendingCount = bp - runStart;  if (0 != pendingCount) {    // Measure previous run of characters using the previous font    aRenderingContext.DrawString(runStart, pendingCount, aX, aY + mAscent, -1,                                 spacing ? sp0 : nsnull);    // Note: use aY not small-y so that decorations are drawn with    // respect to the normal-font not the current font.    PaintTextDecorations(aRenderingContext, aStyleContext, aPresContext,                         aTextStyle, aX, aY, aWidth, runStart, aDetails,                         countSoFar, pendingCount, spacing ? sp0 : nsnull);  }  aTextStyle.mLastFont = lastFont;  if (bp0 != buf) {    delete [] bp0;  }  if (sp0 != spacingMem) {    delete [] sp0;  }}