Fixed underlining bug; support justification

This commit is contained in:
kipp%netscape.com 1998-10-27 16:52:34 +00:00
Родитель 585f02420a
Коммит 178db0aa2c
2 изменённых файлов: 396 добавлений и 64 удалений

Просмотреть файл

@ -69,6 +69,9 @@ static NS_DEFINE_IID(kIDOMTextIID, NS_IDOMTEXT_IID);
#define XP_TO_UPPER(_ch) ((_ch) & ~32) #define XP_TO_UPPER(_ch) ((_ch) & ~32)
#define XP_IS_SPACE(_ch) \
(((_ch) == ' ') || ((_ch) == '\t') || ((_ch) == '\n'))
static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID); static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);
class TextFrame; class TextFrame;
@ -137,6 +140,10 @@ public:
nsHTMLReflowMetrics& aMetrics, nsHTMLReflowMetrics& aMetrics,
const nsHTMLReflowState& aReflowState, const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus); nsReflowStatus& aStatus);
NS_IMETHOD AdjustFrameSize(nscoord aExtraSpace, nscoord& aUsedSpace);
NS_IMETHOD TrimTrailingWhiteSpace(nsIPresContext& aPresContext,
nsIRenderingContext& aRC,
nscoord& aDeltaWidth);
// TextFrame methods // TextFrame methods
struct SelectionInfo { struct SelectionInfo {
@ -163,6 +170,10 @@ public:
nscolor mSelectionTextColor; nscolor mSelectionTextColor;
nscolor mSelectionBGColor; nscolor mSelectionBGColor;
nscoord mSpaceWidth; nscoord mSpaceWidth;
PRBool mJustifying;
PRIntn mNumSpaces;
nscoord mExtraSpacePerSpace;
nscoord mRemainingExtraSpace;
TextStyle(nsIPresContext& aPresContext, TextStyle(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext, nsIRenderingContext& aRenderingContext,
@ -209,6 +220,9 @@ public:
mLetterSpacing = mText->mLetterSpacing.GetCoordValue(); mLetterSpacing = mText->mLetterSpacing.GetCoordValue();
} }
} }
mNumSpaces = 0;
mRemainingExtraSpace = 0;
mExtraSpacePerSpace = 0;
} }
~TextStyle() { ~TextStyle() {
@ -217,12 +231,12 @@ public:
} }
}; };
void PrepareUnicodeText(nsIRenderingContext& aRenderingContext, PRIntn PrepareUnicodeText(nsIRenderingContext& aRenderingContext,
nsTextTransformer& aTransformer, nsTextTransformer& aTransformer,
PRInt32* aIndicies, PRInt32* aIndicies,
PRUnichar* aBuffer, PRUnichar* aBuffer,
PRInt32& aTextLen, PRInt32& aTextLen,
nscoord& aNewWidth); nscoord& aNewWidth);
void PaintTextDecorations(nsIRenderingContext& aRenderingContext, void PaintTextDecorations(nsIRenderingContext& aRenderingContext,
nsIStyleContext* aStyleContext, nsIStyleContext* aStyleContext,
@ -286,6 +300,7 @@ protected:
PRInt32 mContentLength; PRInt32 mContentLength;
PRUint32 mFlags; PRUint32 mFlags;
PRInt32 mColumn; PRInt32 mColumn;
nscoord mComputedWidth;
}; };
// Flag information used by rendering code. This information is // Flag information used by rendering code. This information is
@ -305,6 +320,8 @@ protected:
#define TEXT_FIRST_LETTER 0x20 #define TEXT_FIRST_LETTER 0x20
#define TEXT_TRIMMED_WS 0x40
//---------------------------------------------------------------------- //----------------------------------------------------------------------
static PRBool gBlinkTextOff; static PRBool gBlinkTextOff;
@ -512,7 +529,8 @@ TextFrame::Paint(nsIPresContext& aPresContext,
if (disp->mVisible) { if (disp->mVisible) {
TextStyle ts(aPresContext, aRenderingContext, sc); TextStyle ts(aPresContext, aRenderingContext, sc);
if (ts.mSmallCaps || (0 != ts.mWordSpacing) || (0 != ts.mLetterSpacing) || if (ts.mSmallCaps || (0 != ts.mWordSpacing) || (0 != ts.mLetterSpacing) ||
(NS_STYLE_TEXT_ALIGN_JUSTIFY == ts.mText->mTextAlign)) { ((NS_STYLE_TEXT_ALIGN_JUSTIFY == ts.mText->mTextAlign) &&
(mRect.width > mComputedWidth))) {
PaintTextSlowly(aPresContext, aRenderingContext, sc, ts, 0, 0); PaintTextSlowly(aPresContext, aRenderingContext, sc, ts, 0, 0);
} }
else { else {
@ -671,7 +689,7 @@ TextFrame::ComputeSelectionInfo(nsIRenderingContext& aRenderingContext,
* then fill in aIndexes's with the mapping from the original input to * then fill in aIndexes's with the mapping from the original input to
* the prepared output. * the prepared output.
*/ */
void PRIntn
TextFrame::PrepareUnicodeText(nsIRenderingContext& aRenderingContext, TextFrame::PrepareUnicodeText(nsIRenderingContext& aRenderingContext,
nsTextTransformer& aTX, nsTextTransformer& aTX,
PRInt32* aIndexes, PRInt32* aIndexes,
@ -679,6 +697,7 @@ TextFrame::PrepareUnicodeText(nsIRenderingContext& aRenderingContext,
PRInt32& aTextLen, PRInt32& aTextLen,
nscoord& aNewWidth) nscoord& aNewWidth)
{ {
PRIntn numSpaces = 0;
PRUnichar* dst = aBuffer; PRUnichar* dst = aBuffer;
// Setup transform to operate starting in the content at our content // Setup transform to operate starting in the content at our content
@ -727,6 +746,7 @@ TextFrame::PrepareUnicodeText(nsIRenderingContext& aRenderingContext,
} }
inWord = PR_FALSE; inWord = PR_FALSE;
if (isWhitespace) { if (isWhitespace) {
numSpaces++;
if ('\t' == bp[0]) { if ('\t' == bp[0]) {
PRInt32 spaces = 8 - (7 & column); PRInt32 spaces = 8 - (7 & column);
PRUnichar* tp = bp; PRUnichar* tp = bp;
@ -771,28 +791,19 @@ TextFrame::PrepareUnicodeText(nsIRenderingContext& aRenderingContext,
NS_ASSERTION(n >= 0, "whoops"); NS_ASSERTION(n >= 0, "whoops");
} }
// Now remove trailing whitespace if appropriate. It's appropriate // Remove trailing whitespace if it was trimmed after reflow
// if this frame is continued. And it's also appropriate if this is if (TEXT_TRIMMED_WS & mFlags) {
// not last (or only) frame in a text-run. if (--dst >= aBuffer) {
// XXX fix this to fully obey the comment! PRUnichar ch = *dst;
if (nsnull != mNextInFlow) { if (XP_IS_SPACE(ch)) {
PRIntn zapped = 0;
while (dst > aBuffer) {
if (dst[-1] == ' ') {
dst--;
textLength--; textLength--;
zapped++;
} }
else
break;
}
if (0 != zapped) {
nscoord spaceWidth;
aRenderingContext.GetWidth(' ', spaceWidth);
aNewWidth = aNewWidth - spaceWidth*zapped;
} }
numSpaces--;
} }
aTextLen = textLength; aTextLen = textLength;
return numSpaces;
} }
// XXX This clearly needs to be done by the container, *somehow* // XXX This clearly needs to be done by the container, *somehow*
@ -836,8 +847,8 @@ TextFrame::PaintTextDecorations(nsIRenderingContext& aRenderingContext,
nscolor underColor; nscolor underColor;
nscolor strikeColor; nscolor strikeColor;
nsIStyleContext* context = aStyleContext; nsIStyleContext* context = aStyleContext;
PRUint8 decorations = aTextStyle.mText->mTextDecoration; PRUint8 decorations = aTextStyle.mFont->mFont.decorations;
PRUint8 decorMask = decorMask; PRUint8 decorMask = decorations;
NS_ADDREF(context); NS_ADDREF(context);
do { // find decoration colors do { // find decoration colors
@ -1017,7 +1028,7 @@ TextFrame::RenderString(nsIRenderingContext& aRenderingContext,
PRUnichar* bp = bp0; PRUnichar* bp = bp0;
PRBool spacing = (0 != aTextStyle.mLetterSpacing) || PRBool spacing = (0 != aTextStyle.mLetterSpacing) ||
(0 != aTextStyle.mWordSpacing); (0 != aTextStyle.mWordSpacing) || (mRect.width > mComputedWidth);
nscoord spacingMem[TEXT_BUF_SIZE]; nscoord spacingMem[TEXT_BUF_SIZE];
PRIntn* sp0 = spacingMem; PRIntn* sp0 = spacingMem;
if (spacing && (aLength > TEXT_BUF_SIZE)) { if (spacing && (aLength > TEXT_BUF_SIZE)) {
@ -1065,6 +1076,11 @@ TextFrame::RenderString(nsIRenderingContext& aRenderingContext,
nextFont = aTextStyle.mNormalFont; nextFont = aTextStyle.mNormalFont;
nextY = aY; nextY = aY;
glyphWidth = aTextStyle.mSpaceWidth + aTextStyle.mWordSpacing; glyphWidth = aTextStyle.mSpaceWidth + aTextStyle.mWordSpacing;
nscoord extra = aTextStyle.mExtraSpacePerSpace;
if (--aTextStyle.mNumSpaces == 0) {
extra += aTextStyle.mRemainingExtraSpace;
}
glyphWidth += extra;
} }
else { else {
if (lastFont != aTextStyle.mNormalFont) { if (lastFont != aTextStyle.mNormalFont) {
@ -1088,6 +1104,7 @@ TextFrame::RenderString(nsIRenderingContext& aRenderingContext,
spacing ? sp0 : nsnull); spacing ? sp0 : nsnull);
PaintTextDecorations(aRenderingContext, aStyleContext, aTextStyle, PaintTextDecorations(aRenderingContext, aStyleContext, aTextStyle,
aX, lastY, width); aX, lastY, width);
aWidth -= width;
aX += width; aX += width;
runStart = bp = bp0; runStart = bp = bp0;
sp = sp0; sp = sp0;
@ -1107,7 +1124,7 @@ TextFrame::RenderString(nsIRenderingContext& aRenderingContext,
aRenderingContext.DrawString(runStart, pendingCount, aX, lastY, width, aRenderingContext.DrawString(runStart, pendingCount, aX, lastY, width,
spacing ? sp0 : nsnull); spacing ? sp0 : nsnull);
PaintTextDecorations(aRenderingContext, aStyleContext, aTextStyle, PaintTextDecorations(aRenderingContext, aStyleContext, aTextStyle,
aX, lastY, width); aX, lastY, aWidth);
} }
aTextStyle.mLastFont = lastFont; aTextStyle.mLastFont = lastFont;
@ -1134,6 +1151,7 @@ TextFrame::MeasureSmallCapsText(const nsHTMLReflowState& aReflowState,
} }
} }
// XXX factor in logic from RenderString into here; gaps, justification, etc.
void void
TextFrame::GetWidth(nsIRenderingContext& aRenderingContext, TextFrame::GetWidth(nsIRenderingContext& aRenderingContext,
TextStyle& aTextStyle, TextStyle& aTextStyle,
@ -1214,9 +1232,24 @@ TextFrame::PaintTextSlowly(nsIPresContext& aPresContext,
// Transform text from content into renderable form // Transform text from content into renderable form
nsTextTransformer tx(wordBufMem, WORD_BUF_SIZE); nsTextTransformer tx(wordBufMem, WORD_BUF_SIZE);
PrepareUnicodeText(aRenderingContext, tx, aTextStyle.mNumSpaces = PrepareUnicodeText(aRenderingContext, tx,
displaySelection ? ip : nsnull, displaySelection ? ip : nsnull,
paintBuf, textLength, width); paintBuf, textLength, width);
if (mRect.width > mComputedWidth) {
if (0 != aTextStyle.mNumSpaces) {
nscoord extra = mRect.width - mComputedWidth;
nscoord adjustPerSpace =
aTextStyle.mExtraSpacePerSpace = extra / aTextStyle.mNumSpaces;
aTextStyle.mRemainingExtraSpace = extra -
(aTextStyle.mExtraSpacePerSpace * aTextStyle.mNumSpaces);
}
else {
// We have no whitespace but were given some extra space. There
// are two plausible places to put the extra space: to the left
// and to the right. If this is anywhere but the last place on
// the line then the correct answer is to the right.
}
}
PRUnichar* text = paintBuf; PRUnichar* text = paintBuf;
if (0 != textLength) { if (0 != textLength) {
@ -1807,6 +1840,7 @@ TextFrame::Reflow(nsIPresContext& aPresContext,
// Setup metrics for caller; store final max-element-size information // Setup metrics for caller; store final max-element-size information
aMetrics.width = x; aMetrics.width = x;
mComputedWidth = x;
if (0 == x) { if (0 == x) {
aMetrics.height = 0; aMetrics.height = 0;
aMetrics.ascent = 0; aMetrics.ascent = 0;
@ -1850,6 +1884,138 @@ TextFrame::Reflow(nsIPresContext& aPresContext,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
TextFrame::AdjustFrameSize(nscoord aExtraSpace, nscoord& aUsedSpace)
{
// Get the text fragments that make up our content
nsTextFragment* frag;
PRInt32 numFrags;
nsITextContent* tc;
if (NS_OK == mContent->QueryInterface(kITextContentIID, (void**) &tc)) {
tc->GetText(frag, numFrags);
NS_RELEASE(tc);
// Find fragment that contains the end of the mapped content
PRInt32 endIndex = mContentOffset + mContentLength;
PRInt32 offset = 0;
nsTextFragment* lastFrag = frag + numFrags;
while (frag < lastFrag) {
PRInt32 fragLen = frag->GetLength();
if (endIndex <= offset + fragLen) {
offset = mContentOffset - offset;
if (frag->Is2b()) {
const PRUnichar* cp = frag->Get2b() + offset;
const PRUnichar* end = cp + mContentLength;
while (cp < end) {
PRUnichar ch = *cp++;
if (XP_IS_SPACE(ch)) {
aUsedSpace = aExtraSpace;
mRect.width += aExtraSpace;
return NS_OK;
}
}
}
else {
const unsigned char* cp =
((const unsigned char*)frag->Get1b()) + offset;
const unsigned char* end = cp + mContentLength;
while (cp < end) {
PRUnichar ch = PRUnichar(*cp++);
if (XP_IS_SPACE(ch)) {
aUsedSpace = aExtraSpace;
mRect.width += aExtraSpace;
return NS_OK;
}
}
}
break;
}
offset += fragLen;
frag++;
}
}
aUsedSpace = 0;
return NS_OK;
}
NS_IMETHODIMP
TextFrame::TrimTrailingWhiteSpace(nsIPresContext& aPresContext,
nsIRenderingContext& aRC,
nscoord& aDeltaWidth)
{
nscoord dw = 0;
const nsStyleText* textStyle = (const nsStyleText*)
mStyleContext->GetStyleData(eStyleStruct_Text);
if (NS_STYLE_WHITESPACE_PRE != textStyle->mWhiteSpace) {
// Get font metrics for a space so we can adjust the width by the
// right amount.
const nsStyleFont* fontStyle = (const nsStyleFont*)
mStyleContext->GetStyleData(eStyleStruct_Font);
nscoord spaceWidth;
aRC.SetFont(fontStyle->mFont);
aRC.GetWidth(' ', spaceWidth);
// Get the text fragments that make up our content
nsTextFragment* frag;
PRInt32 numFrags;
nsITextContent* tc;
if (NS_OK == mContent->QueryInterface(kITextContentIID, (void**) &tc)) {
tc->GetText(frag, numFrags);
NS_RELEASE(tc);
// Find fragment that contains the end of the mapped content
PRInt32 endIndex = mContentOffset + mContentLength;
PRInt32 offset = 0;
nsTextFragment* lastFrag = frag + numFrags;
while (frag < lastFrag) {
PRInt32 fragLen = frag->GetLength();
if (endIndex <= offset + fragLen) {
// Look inside the fragments last few characters and see if they
// are whitespace. If so, count how much width was supplied by
// them.
offset = mContentOffset - offset;
if (frag->Is2b()) {
// XXX If by chance the last content fragment is *all*
// whitespace then this won't back up far enough.
const PRUnichar* cp = frag->Get2b() + offset;
const PRUnichar* end = cp + mContentLength;
if (--end >= cp) {
PRUnichar ch = *end;
if (XP_IS_SPACE(ch)) {
dw = spaceWidth;
}
}
}
else {
const unsigned char* cp =
((const unsigned char*)frag->Get1b()) + offset;
const unsigned char* end = cp + mContentLength;
if (--end >= cp) {
PRUnichar ch = PRUnichar(*end);
if (XP_IS_SPACE(ch)) {
dw = spaceWidth;
}
}
}
break;
}
offset += fragLen;
frag++;
}
}
mRect.width -= dw;
mComputedWidth -= dw;
}
if (0 != dw) {
mFlags |= TEXT_TRIMMED_WS;
}
else {
mFlags &= ~TEXT_TRIMMED_WS;
}
aDeltaWidth = dw;
return NS_OK;
}
nscoord nscoord
TextFrame::ComputeTotalWordWidth(nsLineLayout& aLineLayout, TextFrame::ComputeTotalWordWidth(nsLineLayout& aLineLayout,
const nsHTMLReflowState& aReflowState, const nsHTMLReflowState& aReflowState,

Просмотреть файл

@ -69,6 +69,9 @@ static NS_DEFINE_IID(kIDOMTextIID, NS_IDOMTEXT_IID);
#define XP_TO_UPPER(_ch) ((_ch) & ~32) #define XP_TO_UPPER(_ch) ((_ch) & ~32)
#define XP_IS_SPACE(_ch) \
(((_ch) == ' ') || ((_ch) == '\t') || ((_ch) == '\n'))
static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID); static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID);
class TextFrame; class TextFrame;
@ -137,6 +140,10 @@ public:
nsHTMLReflowMetrics& aMetrics, nsHTMLReflowMetrics& aMetrics,
const nsHTMLReflowState& aReflowState, const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus); nsReflowStatus& aStatus);
NS_IMETHOD AdjustFrameSize(nscoord aExtraSpace, nscoord& aUsedSpace);
NS_IMETHOD TrimTrailingWhiteSpace(nsIPresContext& aPresContext,
nsIRenderingContext& aRC,
nscoord& aDeltaWidth);
// TextFrame methods // TextFrame methods
struct SelectionInfo { struct SelectionInfo {
@ -163,6 +170,10 @@ public:
nscolor mSelectionTextColor; nscolor mSelectionTextColor;
nscolor mSelectionBGColor; nscolor mSelectionBGColor;
nscoord mSpaceWidth; nscoord mSpaceWidth;
PRBool mJustifying;
PRIntn mNumSpaces;
nscoord mExtraSpacePerSpace;
nscoord mRemainingExtraSpace;
TextStyle(nsIPresContext& aPresContext, TextStyle(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext, nsIRenderingContext& aRenderingContext,
@ -209,6 +220,9 @@ public:
mLetterSpacing = mText->mLetterSpacing.GetCoordValue(); mLetterSpacing = mText->mLetterSpacing.GetCoordValue();
} }
} }
mNumSpaces = 0;
mRemainingExtraSpace = 0;
mExtraSpacePerSpace = 0;
} }
~TextStyle() { ~TextStyle() {
@ -217,12 +231,12 @@ public:
} }
}; };
void PrepareUnicodeText(nsIRenderingContext& aRenderingContext, PRIntn PrepareUnicodeText(nsIRenderingContext& aRenderingContext,
nsTextTransformer& aTransformer, nsTextTransformer& aTransformer,
PRInt32* aIndicies, PRInt32* aIndicies,
PRUnichar* aBuffer, PRUnichar* aBuffer,
PRInt32& aTextLen, PRInt32& aTextLen,
nscoord& aNewWidth); nscoord& aNewWidth);
void PaintTextDecorations(nsIRenderingContext& aRenderingContext, void PaintTextDecorations(nsIRenderingContext& aRenderingContext,
nsIStyleContext* aStyleContext, nsIStyleContext* aStyleContext,
@ -286,6 +300,7 @@ protected:
PRInt32 mContentLength; PRInt32 mContentLength;
PRUint32 mFlags; PRUint32 mFlags;
PRInt32 mColumn; PRInt32 mColumn;
nscoord mComputedWidth;
}; };
// Flag information used by rendering code. This information is // Flag information used by rendering code. This information is
@ -305,6 +320,8 @@ protected:
#define TEXT_FIRST_LETTER 0x20 #define TEXT_FIRST_LETTER 0x20
#define TEXT_TRIMMED_WS 0x40
//---------------------------------------------------------------------- //----------------------------------------------------------------------
static PRBool gBlinkTextOff; static PRBool gBlinkTextOff;
@ -512,7 +529,8 @@ TextFrame::Paint(nsIPresContext& aPresContext,
if (disp->mVisible) { if (disp->mVisible) {
TextStyle ts(aPresContext, aRenderingContext, sc); TextStyle ts(aPresContext, aRenderingContext, sc);
if (ts.mSmallCaps || (0 != ts.mWordSpacing) || (0 != ts.mLetterSpacing) || if (ts.mSmallCaps || (0 != ts.mWordSpacing) || (0 != ts.mLetterSpacing) ||
(NS_STYLE_TEXT_ALIGN_JUSTIFY == ts.mText->mTextAlign)) { ((NS_STYLE_TEXT_ALIGN_JUSTIFY == ts.mText->mTextAlign) &&
(mRect.width > mComputedWidth))) {
PaintTextSlowly(aPresContext, aRenderingContext, sc, ts, 0, 0); PaintTextSlowly(aPresContext, aRenderingContext, sc, ts, 0, 0);
} }
else { else {
@ -671,7 +689,7 @@ TextFrame::ComputeSelectionInfo(nsIRenderingContext& aRenderingContext,
* then fill in aIndexes's with the mapping from the original input to * then fill in aIndexes's with the mapping from the original input to
* the prepared output. * the prepared output.
*/ */
void PRIntn
TextFrame::PrepareUnicodeText(nsIRenderingContext& aRenderingContext, TextFrame::PrepareUnicodeText(nsIRenderingContext& aRenderingContext,
nsTextTransformer& aTX, nsTextTransformer& aTX,
PRInt32* aIndexes, PRInt32* aIndexes,
@ -679,6 +697,7 @@ TextFrame::PrepareUnicodeText(nsIRenderingContext& aRenderingContext,
PRInt32& aTextLen, PRInt32& aTextLen,
nscoord& aNewWidth) nscoord& aNewWidth)
{ {
PRIntn numSpaces = 0;
PRUnichar* dst = aBuffer; PRUnichar* dst = aBuffer;
// Setup transform to operate starting in the content at our content // Setup transform to operate starting in the content at our content
@ -727,6 +746,7 @@ TextFrame::PrepareUnicodeText(nsIRenderingContext& aRenderingContext,
} }
inWord = PR_FALSE; inWord = PR_FALSE;
if (isWhitespace) { if (isWhitespace) {
numSpaces++;
if ('\t' == bp[0]) { if ('\t' == bp[0]) {
PRInt32 spaces = 8 - (7 & column); PRInt32 spaces = 8 - (7 & column);
PRUnichar* tp = bp; PRUnichar* tp = bp;
@ -771,28 +791,19 @@ TextFrame::PrepareUnicodeText(nsIRenderingContext& aRenderingContext,
NS_ASSERTION(n >= 0, "whoops"); NS_ASSERTION(n >= 0, "whoops");
} }
// Now remove trailing whitespace if appropriate. It's appropriate // Remove trailing whitespace if it was trimmed after reflow
// if this frame is continued. And it's also appropriate if this is if (TEXT_TRIMMED_WS & mFlags) {
// not last (or only) frame in a text-run. if (--dst >= aBuffer) {
// XXX fix this to fully obey the comment! PRUnichar ch = *dst;
if (nsnull != mNextInFlow) { if (XP_IS_SPACE(ch)) {
PRIntn zapped = 0;
while (dst > aBuffer) {
if (dst[-1] == ' ') {
dst--;
textLength--; textLength--;
zapped++;
} }
else
break;
}
if (0 != zapped) {
nscoord spaceWidth;
aRenderingContext.GetWidth(' ', spaceWidth);
aNewWidth = aNewWidth - spaceWidth*zapped;
} }
numSpaces--;
} }
aTextLen = textLength; aTextLen = textLength;
return numSpaces;
} }
// XXX This clearly needs to be done by the container, *somehow* // XXX This clearly needs to be done by the container, *somehow*
@ -836,8 +847,8 @@ TextFrame::PaintTextDecorations(nsIRenderingContext& aRenderingContext,
nscolor underColor; nscolor underColor;
nscolor strikeColor; nscolor strikeColor;
nsIStyleContext* context = aStyleContext; nsIStyleContext* context = aStyleContext;
PRUint8 decorations = aTextStyle.mText->mTextDecoration; PRUint8 decorations = aTextStyle.mFont->mFont.decorations;
PRUint8 decorMask = decorMask; PRUint8 decorMask = decorations;
NS_ADDREF(context); NS_ADDREF(context);
do { // find decoration colors do { // find decoration colors
@ -1017,7 +1028,7 @@ TextFrame::RenderString(nsIRenderingContext& aRenderingContext,
PRUnichar* bp = bp0; PRUnichar* bp = bp0;
PRBool spacing = (0 != aTextStyle.mLetterSpacing) || PRBool spacing = (0 != aTextStyle.mLetterSpacing) ||
(0 != aTextStyle.mWordSpacing); (0 != aTextStyle.mWordSpacing) || (mRect.width > mComputedWidth);
nscoord spacingMem[TEXT_BUF_SIZE]; nscoord spacingMem[TEXT_BUF_SIZE];
PRIntn* sp0 = spacingMem; PRIntn* sp0 = spacingMem;
if (spacing && (aLength > TEXT_BUF_SIZE)) { if (spacing && (aLength > TEXT_BUF_SIZE)) {
@ -1065,6 +1076,11 @@ TextFrame::RenderString(nsIRenderingContext& aRenderingContext,
nextFont = aTextStyle.mNormalFont; nextFont = aTextStyle.mNormalFont;
nextY = aY; nextY = aY;
glyphWidth = aTextStyle.mSpaceWidth + aTextStyle.mWordSpacing; glyphWidth = aTextStyle.mSpaceWidth + aTextStyle.mWordSpacing;
nscoord extra = aTextStyle.mExtraSpacePerSpace;
if (--aTextStyle.mNumSpaces == 0) {
extra += aTextStyle.mRemainingExtraSpace;
}
glyphWidth += extra;
} }
else { else {
if (lastFont != aTextStyle.mNormalFont) { if (lastFont != aTextStyle.mNormalFont) {
@ -1088,6 +1104,7 @@ TextFrame::RenderString(nsIRenderingContext& aRenderingContext,
spacing ? sp0 : nsnull); spacing ? sp0 : nsnull);
PaintTextDecorations(aRenderingContext, aStyleContext, aTextStyle, PaintTextDecorations(aRenderingContext, aStyleContext, aTextStyle,
aX, lastY, width); aX, lastY, width);
aWidth -= width;
aX += width; aX += width;
runStart = bp = bp0; runStart = bp = bp0;
sp = sp0; sp = sp0;
@ -1107,7 +1124,7 @@ TextFrame::RenderString(nsIRenderingContext& aRenderingContext,
aRenderingContext.DrawString(runStart, pendingCount, aX, lastY, width, aRenderingContext.DrawString(runStart, pendingCount, aX, lastY, width,
spacing ? sp0 : nsnull); spacing ? sp0 : nsnull);
PaintTextDecorations(aRenderingContext, aStyleContext, aTextStyle, PaintTextDecorations(aRenderingContext, aStyleContext, aTextStyle,
aX, lastY, width); aX, lastY, aWidth);
} }
aTextStyle.mLastFont = lastFont; aTextStyle.mLastFont = lastFont;
@ -1134,6 +1151,7 @@ TextFrame::MeasureSmallCapsText(const nsHTMLReflowState& aReflowState,
} }
} }
// XXX factor in logic from RenderString into here; gaps, justification, etc.
void void
TextFrame::GetWidth(nsIRenderingContext& aRenderingContext, TextFrame::GetWidth(nsIRenderingContext& aRenderingContext,
TextStyle& aTextStyle, TextStyle& aTextStyle,
@ -1214,9 +1232,24 @@ TextFrame::PaintTextSlowly(nsIPresContext& aPresContext,
// Transform text from content into renderable form // Transform text from content into renderable form
nsTextTransformer tx(wordBufMem, WORD_BUF_SIZE); nsTextTransformer tx(wordBufMem, WORD_BUF_SIZE);
PrepareUnicodeText(aRenderingContext, tx, aTextStyle.mNumSpaces = PrepareUnicodeText(aRenderingContext, tx,
displaySelection ? ip : nsnull, displaySelection ? ip : nsnull,
paintBuf, textLength, width); paintBuf, textLength, width);
if (mRect.width > mComputedWidth) {
if (0 != aTextStyle.mNumSpaces) {
nscoord extra = mRect.width - mComputedWidth;
nscoord adjustPerSpace =
aTextStyle.mExtraSpacePerSpace = extra / aTextStyle.mNumSpaces;
aTextStyle.mRemainingExtraSpace = extra -
(aTextStyle.mExtraSpacePerSpace * aTextStyle.mNumSpaces);
}
else {
// We have no whitespace but were given some extra space. There
// are two plausible places to put the extra space: to the left
// and to the right. If this is anywhere but the last place on
// the line then the correct answer is to the right.
}
}
PRUnichar* text = paintBuf; PRUnichar* text = paintBuf;
if (0 != textLength) { if (0 != textLength) {
@ -1807,6 +1840,7 @@ TextFrame::Reflow(nsIPresContext& aPresContext,
// Setup metrics for caller; store final max-element-size information // Setup metrics for caller; store final max-element-size information
aMetrics.width = x; aMetrics.width = x;
mComputedWidth = x;
if (0 == x) { if (0 == x) {
aMetrics.height = 0; aMetrics.height = 0;
aMetrics.ascent = 0; aMetrics.ascent = 0;
@ -1850,6 +1884,138 @@ TextFrame::Reflow(nsIPresContext& aPresContext,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
TextFrame::AdjustFrameSize(nscoord aExtraSpace, nscoord& aUsedSpace)
{
// Get the text fragments that make up our content
nsTextFragment* frag;
PRInt32 numFrags;
nsITextContent* tc;
if (NS_OK == mContent->QueryInterface(kITextContentIID, (void**) &tc)) {
tc->GetText(frag, numFrags);
NS_RELEASE(tc);
// Find fragment that contains the end of the mapped content
PRInt32 endIndex = mContentOffset + mContentLength;
PRInt32 offset = 0;
nsTextFragment* lastFrag = frag + numFrags;
while (frag < lastFrag) {
PRInt32 fragLen = frag->GetLength();
if (endIndex <= offset + fragLen) {
offset = mContentOffset - offset;
if (frag->Is2b()) {
const PRUnichar* cp = frag->Get2b() + offset;
const PRUnichar* end = cp + mContentLength;
while (cp < end) {
PRUnichar ch = *cp++;
if (XP_IS_SPACE(ch)) {
aUsedSpace = aExtraSpace;
mRect.width += aExtraSpace;
return NS_OK;
}
}
}
else {
const unsigned char* cp =
((const unsigned char*)frag->Get1b()) + offset;
const unsigned char* end = cp + mContentLength;
while (cp < end) {
PRUnichar ch = PRUnichar(*cp++);
if (XP_IS_SPACE(ch)) {
aUsedSpace = aExtraSpace;
mRect.width += aExtraSpace;
return NS_OK;
}
}
}
break;
}
offset += fragLen;
frag++;
}
}
aUsedSpace = 0;
return NS_OK;
}
NS_IMETHODIMP
TextFrame::TrimTrailingWhiteSpace(nsIPresContext& aPresContext,
nsIRenderingContext& aRC,
nscoord& aDeltaWidth)
{
nscoord dw = 0;
const nsStyleText* textStyle = (const nsStyleText*)
mStyleContext->GetStyleData(eStyleStruct_Text);
if (NS_STYLE_WHITESPACE_PRE != textStyle->mWhiteSpace) {
// Get font metrics for a space so we can adjust the width by the
// right amount.
const nsStyleFont* fontStyle = (const nsStyleFont*)
mStyleContext->GetStyleData(eStyleStruct_Font);
nscoord spaceWidth;
aRC.SetFont(fontStyle->mFont);
aRC.GetWidth(' ', spaceWidth);
// Get the text fragments that make up our content
nsTextFragment* frag;
PRInt32 numFrags;
nsITextContent* tc;
if (NS_OK == mContent->QueryInterface(kITextContentIID, (void**) &tc)) {
tc->GetText(frag, numFrags);
NS_RELEASE(tc);
// Find fragment that contains the end of the mapped content
PRInt32 endIndex = mContentOffset + mContentLength;
PRInt32 offset = 0;
nsTextFragment* lastFrag = frag + numFrags;
while (frag < lastFrag) {
PRInt32 fragLen = frag->GetLength();
if (endIndex <= offset + fragLen) {
// Look inside the fragments last few characters and see if they
// are whitespace. If so, count how much width was supplied by
// them.
offset = mContentOffset - offset;
if (frag->Is2b()) {
// XXX If by chance the last content fragment is *all*
// whitespace then this won't back up far enough.
const PRUnichar* cp = frag->Get2b() + offset;
const PRUnichar* end = cp + mContentLength;
if (--end >= cp) {
PRUnichar ch = *end;
if (XP_IS_SPACE(ch)) {
dw = spaceWidth;
}
}
}
else {
const unsigned char* cp =
((const unsigned char*)frag->Get1b()) + offset;
const unsigned char* end = cp + mContentLength;
if (--end >= cp) {
PRUnichar ch = PRUnichar(*end);
if (XP_IS_SPACE(ch)) {
dw = spaceWidth;
}
}
}
break;
}
offset += fragLen;
frag++;
}
}
mRect.width -= dw;
mComputedWidth -= dw;
}
if (0 != dw) {
mFlags |= TEXT_TRIMMED_WS;
}
else {
mFlags &= ~TEXT_TRIMMED_WS;
}
aDeltaWidth = dw;
return NS_OK;
}
nscoord nscoord
TextFrame::ComputeTotalWordWidth(nsLineLayout& aLineLayout, TextFrame::ComputeTotalWordWidth(nsLineLayout& aLineLayout,
const nsHTMLReflowState& aReflowState, const nsHTMLReflowState& aReflowState,