@ -345,7 +345,14 @@ void plFont::IRenderString( plMipmap *mip, UInt16 x, UInt16 y, const wchar_t *st
{
{
if ( fRenderInfo . fFlags & kRenderIntoAlpha )
if ( fRenderInfo . fFlags & kRenderIntoAlpha )
{
{
if ( ( fRenderInfo . fColor & 0xff000000 ) ! = 0xff000000 )
if ( fRenderInfo . fFlags & kRenderAlphaPremultiplied )
{
if ( fRenderInfo . fFlags & kRenderShadow )
fRenderInfo . fRenderFunc = & plFont : : IRenderChar8To32AlphaPremShadow ;
else
fRenderInfo . fRenderFunc = & plFont : : IRenderChar8To32AlphaPremultiplied ;
}
else if ( ( fRenderInfo . fColor & 0xff000000 ) ! = 0xff000000 )
fRenderInfo . fRenderFunc = & plFont : : IRenderChar8To32Alpha ;
fRenderInfo . fRenderFunc = & plFont : : IRenderChar8To32Alpha ;
else
else
fRenderInfo . fRenderFunc = & plFont : : IRenderChar8To32FullAlpha ;
fRenderInfo . fRenderFunc = & plFont : : IRenderChar8To32FullAlpha ;
@ -659,24 +666,27 @@ void plFont::IRenderString( plMipmap *mip, UInt16 x, UInt16 y, const wchar_t *st
// Advance left past any clipping area
// Advance left past any clipping area
CharRenderFunc oldFunc = fRenderInfo . fRenderFunc ;
CharRenderFunc oldFunc = fRenderInfo . fRenderFunc ;
fRenderInfo . fRenderFunc = & plFont : : IRenderCharNull ;
fRenderInfo . fRenderFunc = & plFont : : IRenderCharNull ;
while ( fRenderInfo . fX < fRenderInfo . fClipRect . fX & & * string ! = 0 )
Int16 prevX ;
do
{
{
prevX = fRenderInfo . fX ;
IRenderLoop ( string , 1 ) ;
IRenderLoop ( string , 1 ) ;
string + + ;
}
}
while ( fRenderInfo . fX < = fRenderInfo . fClipRect . fX & & * + + string ! = 0 ) ;
fRenderInfo . fMaxWidth + = fRenderInfo . fX - prevX ;
fRenderInfo . fDestPtr - = ( fRenderInfo . fX - prevX ) * fRenderInfo . fDestBPP ;
fRenderInfo . fX = prevX ;
fRenderInfo . fRenderFunc = oldFunc ;
fRenderInfo . fRenderFunc = oldFunc ;
}
}
// Adjust for left kern
// There used to be an adjustment of the X coordinate by -ch.fLeftKern for the case
if ( ( fRenderInfo . fFlags & kRenderJustXMask ) = = kRenderJustXForceLeft )
// of kRenderJustXForceLeft here, but it was buggy in that it neglected to adjust
{
// fRenderInfo.fDestPtr and therefore had no visible effect (or almost none - only
// See note at top of file
// at the end of the line). Fixing the bug however (making kRenderJustXForceLeft
plCharacter & ch = fCharacters [ ( UInt16 ) string [ 0 ] - fFirstChar ] ;
// work as intended) causes the text shadow to be cut off in some places. To ensure
Int32 newX = x - ( Int16 ) ch . fLeftKern ;
// enough space for the shadow, and considering that all content was developed and
if ( newX < 0 )
// visually optimized with the bug in place, it seems better to preserve the buggy
newX = 0 ;
// behavior and make kRenderJustXForceLeft work exactly like kRenderJustXLeft.
fRenderInfo . fX = fRenderInfo . fFarthestX = ( Int16 ) newX ;
}
fRenderInfo . fVolatileStringPtr = string ; // Just so we can keep track of when we clip
fRenderInfo . fVolatileStringPtr = string ; // Just so we can keep track of when we clip
IRenderLoop ( string , - 1 ) ;
IRenderLoop ( string , - 1 ) ;
@ -715,9 +725,6 @@ void plFont::IRenderLoop( const wchar_t *string, Int32 maxCount )
if ( fRenderInfo . fFlags & kRenderScaleAA )
if ( fRenderInfo . fFlags & kRenderScaleAA )
thisWidth > > = 1 ;
thisWidth > > = 1 ;
if ( thisWidth > = fRenderInfo . fMaxWidth )
break ;
( this - > * ( fRenderInfo . fRenderFunc ) ) ( fCharacters [ c ] ) ;
( this - > * ( fRenderInfo . fRenderFunc ) ) ( fCharacters [ c ] ) ;
fRenderInfo . fX + = thisWidth ;
fRenderInfo . fX + = thisWidth ;
@ -848,8 +855,8 @@ void plFont::IRenderChar8To32( const plFont::plCharacter &c )
{
{
UInt8 * src = fBMapData + c . fBitmapOff ;
UInt8 * src = fBMapData + c . fBitmapOff ;
UInt32 * destPtr , * destBasePtr = ( UInt32 * ) ( fRenderInfo . fDestPtr - c . fBaseline * fRenderInfo . fDestStride ) ;
UInt32 * destPtr , * destBasePtr = ( UInt32 * ) ( fRenderInfo . fDestPtr - c . fBaseline * fRenderInfo . fDestStride ) ;
U Int16 x , y ;
Int16 x , y , thisHeight , xstart , thisWidth ;
UInt32 srcAlpha , oneMinusAlpha , r , g , b , dR , dG , dB , destAlpha , thisWidth ;
UInt32 srcAlpha , oneMinusAlpha , r , g , b , dR , dG , dB , destAlpha ;
UInt8 srcR , srcG , srcB ;
UInt8 srcR , srcG , srcB ;
@ -860,19 +867,35 @@ void plFont::IRenderChar8To32( const plFont::plCharacter &c )
// difference, especially since the dest pixels that we end up overlapping
// difference, especially since the dest pixels that we end up overlapping
// should already be in the cache. If it does, time to upgrade the font
// should already be in the cache. If it does, time to upgrade the font
// format (again)
// format (again)
thisWidth = fWidth ; // + (Int32)c.fRightKern;
thisWidth = ( Int16 ) fWidth ; // + (Int32)c.fRightKern;
if ( thisWidth > = fRenderInfo . fMaxWidth )
thisWidth = fRenderInfo . fMaxWidth ;
if ( ( Int32 ) c . fHeight - ( Int32 ) c . fBaseline > = fRenderInfo . fMaxHeight | | thisWidth > = fRenderInfo . fMaxWidth | | c . fBaseline > fRenderInfo . fY )
xstart = fRenderInfo . fClipRect . fX - fRenderInfo . fX ;
return ;
if ( xstart < 0 )
xstart = 0 ;
srcR = ( UInt8 ) ( ( fRenderInfo . fColor > > 16 ) & 0x000000ff ) ;
srcR = ( UInt8 ) ( ( fRenderInfo . fColor > > 16 ) & 0x000000ff ) ;
srcG = ( UInt8 ) ( ( fRenderInfo . fColor > > 8 ) & 0x000000ff ) ;
srcG = ( UInt8 ) ( ( fRenderInfo . fColor > > 8 ) & 0x000000ff ) ;
srcB = ( UInt8 ) ( ( fRenderInfo . fColor ) & 0x000000ff ) ;
srcB = ( UInt8 ) ( ( fRenderInfo . fColor ) & 0x000000ff ) ;
for ( y = 0 ; y < c . fHeight ; y + + )
y = fRenderInfo . fClipRect . fY - fRenderInfo . fY + ( Int16 ) c . fBaseline ;
if ( y < 0 )
y = 0 ;
else
{
destBasePtr = ( UInt32 * ) ( ( UInt8 * ) destBasePtr + y * fRenderInfo . fDestStride ) ;
src + = y * fRenderInfo . fNumCols ;
}
thisHeight = fRenderInfo . fMaxHeight + ( Int16 ) c . fBaseline ;
if ( thisHeight > ( Int16 ) c . fHeight )
thisHeight = ( Int16 ) c . fHeight ;
for ( ; y < thisHeight ; y + + )
{
{
destPtr = destBasePtr ;
destPtr = destBasePtr ;
for ( x = 0 ; x < thisWidth ; x + + )
for ( x = xstart ; x < thisWidth ; x + + )
{
{
if ( src [ x ] = = 255 )
if ( src [ x ] = = 255 )
destPtr [ x ] = fRenderInfo . fColor ;
destPtr [ x ] = fRenderInfo . fColor ;
@ -907,8 +930,8 @@ void plFont::IRenderChar8To32FullAlpha( const plFont::plCharacter &c )
{
{
UInt8 * src = fBMapData + c . fBitmapOff ;
UInt8 * src = fBMapData + c . fBitmapOff ;
UInt32 * destPtr , * destBasePtr = ( UInt32 * ) ( fRenderInfo . fDestPtr - c . fBaseline * fRenderInfo . fDestStride ) ;
UInt32 * destPtr , * destBasePtr = ( UInt32 * ) ( fRenderInfo . fDestPtr - c . fBaseline * fRenderInfo . fDestStride ) ;
U Int16 x , y ;
Int16 x , y , thisHeight , xstart , thisWidth ;
UInt32 destColorOnly , thisWidth ;
UInt32 destColorOnly ;
// Unfortunately for some fonts, their right kern value actually is
// Unfortunately for some fonts, their right kern value actually is
@ -918,17 +941,33 @@ void plFont::IRenderChar8To32FullAlpha( const plFont::plCharacter &c )
// difference, especially since the dest pixels that we end up overlapping
// difference, especially since the dest pixels that we end up overlapping
// should already be in the cache. If it does, time to upgrade the font
// should already be in the cache. If it does, time to upgrade the font
// format (again)
// format (again)
thisWidth = fWidth ; // + (Int32)c.fRightKern;
thisWidth = ( Int16 ) fWidth ; // + (Int32)c.fRightKern;
if ( thisWidth > = fRenderInfo . fMaxWidth )
thisWidth = fRenderInfo . fMaxWidth ;
if ( ( Int32 ) c . fHeight - ( Int32 ) c . fBaseline > = fRenderInfo . fMaxHeight | | thisWidth > = fRenderInfo . fMaxWidth | | c . fBaseline > fRenderInfo . fY )
xstart = fRenderInfo . fClipRect . fX - fRenderInfo . fX ;
return ;
if ( xstart < 0 )
xstart = 0 ;
destColorOnly = fRenderInfo . fColor & 0x00ffffff ;
destColorOnly = fRenderInfo . fColor & 0x00ffffff ;
for ( y = 0 ; y < c . fHeight ; y + + )
y = fRenderInfo . fClipRect . fY - fRenderInfo . fY + ( Int16 ) c . fBaseline ;
if ( y < 0 )
y = 0 ;
else
{
destBasePtr = ( UInt32 * ) ( ( UInt8 * ) destBasePtr + y * fRenderInfo . fDestStride ) ;
src + = y * fRenderInfo . fNumCols ;
}
thisHeight = fRenderInfo . fMaxHeight + ( Int16 ) c . fBaseline ;
if ( thisHeight > ( Int16 ) c . fHeight )
thisHeight = ( Int16 ) c . fHeight ;
for ( ; y < thisHeight ; y + + )
{
{
destPtr = destBasePtr ;
destPtr = destBasePtr ;
for ( x = 0 ; x < thisWidth ; x + + )
for ( x = xstart ; x < thisWidth ; x + + )
{
{
if ( src [ x ] ! = 0 )
if ( src [ x ] ! = 0 )
destPtr [ x ] = ( src [ x ] < < 24 ) | destColorOnly ;
destPtr [ x ] = ( src [ x ] < < 24 ) | destColorOnly ;
@ -942,8 +981,8 @@ void plFont::IRenderChar8To32Alpha( const plFont::plCharacter &c )
{
{
UInt8 val , * src = fBMapData + c . fBitmapOff ;
UInt8 val , * src = fBMapData + c . fBitmapOff ;
UInt32 * destPtr , * destBasePtr = ( UInt32 * ) ( fRenderInfo . fDestPtr - c . fBaseline * fRenderInfo . fDestStride ) ;
UInt32 * destPtr , * destBasePtr = ( UInt32 * ) ( fRenderInfo . fDestPtr - c . fBaseline * fRenderInfo . fDestStride ) ;
U Int16 x , y ;
Int16 x , y , thisHeight , xstart , thisWidth ;
UInt32 destColorOnly , alphaMult , fullAlpha , thisWidth ;
UInt32 destColorOnly , alphaMult , fullAlpha ;
// Unfortunately for some fonts, their right kern value actually is
// Unfortunately for some fonts, their right kern value actually is
@ -953,10 +992,13 @@ void plFont::IRenderChar8To32Alpha( const plFont::plCharacter &c )
// difference, especially since the dest pixels that we end up overlapping
// difference, especially since the dest pixels that we end up overlapping
// should already be in the cache. If it does, time to upgrade the font
// should already be in the cache. If it does, time to upgrade the font
// format (again)
// format (again)
thisWidth = fWidth ; // + (Int32)c.fRightKern;
thisWidth = ( Int16 ) fWidth ; // + (Int32)c.fRightKern;
if ( thisWidth > = fRenderInfo . fMaxWidth )
thisWidth = fRenderInfo . fMaxWidth ;
if ( ( Int32 ) c . fHeight - ( Int32 ) c . fBaseline > = fRenderInfo . fMaxHeight | | thisWidth > = fRenderInfo . fMaxWidth | | c . fBaseline > fRenderInfo . fY )
xstart = fRenderInfo . fClipRect . fX - fRenderInfo . fX ;
return ;
if ( xstart < 0 )
xstart = 0 ;
destColorOnly = fRenderInfo . fColor & 0x00ffffff ;
destColorOnly = fRenderInfo . fColor & 0x00ffffff ;
// alphaMult should come out to be a value to satisfy (fontAlpha * alphaMult >> 8) as the right alpha,
// alphaMult should come out to be a value to satisfy (fontAlpha * alphaMult >> 8) as the right alpha,
@ -964,10 +1006,23 @@ void plFont::IRenderChar8To32Alpha( const plFont::plCharacter &c )
fullAlpha = fRenderInfo . fColor & 0xff000000 ;
fullAlpha = fRenderInfo . fColor & 0xff000000 ;
alphaMult = fullAlpha / 255 ;
alphaMult = fullAlpha / 255 ;
for ( y = 0 ; y < c . fHeight ; y + + )
y = fRenderInfo . fClipRect . fY - fRenderInfo . fY + ( Int16 ) c . fBaseline ;
if ( y < 0 )
y = 0 ;
else
{
destBasePtr = ( UInt32 * ) ( ( UInt8 * ) destBasePtr + y * fRenderInfo . fDestStride ) ;
src + = y * fRenderInfo . fNumCols ;
}
thisHeight = fRenderInfo . fMaxHeight + ( Int16 ) c . fBaseline ;
if ( thisHeight > ( Int16 ) c . fHeight )
thisHeight = ( Int16 ) c . fHeight ;
for ( ; y < thisHeight ; y + + )
{
{
destPtr = destBasePtr ;
destPtr = destBasePtr ;
for ( x = 0 ; x < thisWidth ; x + + )
for ( x = xstart ; x < thisWidth ; x + + )
{
{
val = src [ x ] ;
val = src [ x ] ;
if ( val = = 0xff )
if ( val = = 0xff )
@ -982,6 +1037,145 @@ void plFont::IRenderChar8To32Alpha( const plFont::plCharacter &c )
}
}
}
}
void plFont : : IRenderChar8To32AlphaPremultiplied ( const plFont : : plCharacter & c )
{
UInt8 * src = fBMapData + c . fBitmapOff ;
UInt32 * destPtr , * destBasePtr = ( UInt32 * ) ( fRenderInfo . fDestPtr - c . fBaseline * fRenderInfo . fDestStride ) ;
Int16 x , y , thisHeight , xstart , thisWidth ;
UInt8 srcA , srcR , srcG , srcB ;
// Unfortunately for some fonts, their right kern value actually is
// farther left than the right edge of the bitmap (think of overlapping
// script fonts). Ideally, we should store the actual width of each char's
// bitmap and use that here. However, it really shouldn't make too big of a
// difference, especially since the dest pixels that we end up overlapping
// should already be in the cache. If it does, time to upgrade the font
// format (again)
thisWidth = ( Int16 ) fWidth ; // + (Int32)c.fRightKern;
if ( thisWidth > = fRenderInfo . fMaxWidth )
thisWidth = fRenderInfo . fMaxWidth ;
xstart = fRenderInfo . fClipRect . fX - fRenderInfo . fX ;
if ( xstart < 0 )
xstart = 0 ;
srcA = ( UInt8 ) ( ( fRenderInfo . fColor > > 24 ) & 0x000000ff ) ;
srcR = ( UInt8 ) ( ( fRenderInfo . fColor > > 16 ) & 0x000000ff ) ;
srcG = ( UInt8 ) ( ( fRenderInfo . fColor > > 8 ) & 0x000000ff ) ;
srcB = ( UInt8 ) ( ( fRenderInfo . fColor ) & 0x000000ff ) ;
y = fRenderInfo . fClipRect . fY - fRenderInfo . fY + ( Int16 ) c . fBaseline ;
if ( y < 0 )
y = 0 ;
else
{
destBasePtr = ( UInt32 * ) ( ( UInt8 * ) destBasePtr + y * fRenderInfo . fDestStride ) ;
src + = y * fRenderInfo . fNumCols ;
}
thisHeight = fRenderInfo . fMaxHeight + ( Int16 ) c . fBaseline ;
if ( thisHeight > ( Int16 ) c . fHeight )
thisHeight = ( Int16 ) c . fHeight ;
for ( ; y < thisHeight ; y + + )
{
destPtr = destBasePtr ;
for ( x = xstart ; x < thisWidth ; x + + )
{
UInt32 a = src [ x ] ;
if ( a ! = 0 )
{
if ( srcA ! = 0xff )
a = ( srcA * a + 127 ) / 255 ;
destPtr [ x ] = ( a < < 24 ) | ( ( ( srcR * a + 127 ) / 255 ) < < 16 ) | ( ( ( srcG * a + 127 ) / 255 ) < < 8 ) | ( ( srcB * a + 127 ) / 255 ) ;
}
}
destBasePtr = ( UInt32 * ) ( ( UInt8 * ) destBasePtr + fRenderInfo . fDestStride ) ;
src + = fWidth ;
}
}
void plFont : : IRenderChar8To32AlphaPremShadow ( const plFont : : plCharacter & c )
{
UInt32 * destPtr , * destBasePtr = ( UInt32 * ) ( fRenderInfo . fDestPtr - c . fBaseline * fRenderInfo . fDestStride ) ;
Int16 x , y , thisHeight , xstart , thisWidth ;
UInt8 srcA , srcR , srcG , srcB ;
// Unfortunately for some fonts, their right kern value actually is
// farther left than the right edge of the bitmap (think of overlapping
// script fonts). Ideally, we should store the actual width of each char's
// bitmap and use that here. However, it really shouldn't make too big of a
// difference, especially since the dest pixels that we end up overlapping
// should already be in the cache. If it does, time to upgrade the font
// format (again)
thisWidth = ( Int16 ) fWidth + 2 ; // + (Int32)c.fRightKern;
if ( thisWidth > = fRenderInfo . fMaxWidth )
thisWidth = fRenderInfo . fMaxWidth ;
xstart = fRenderInfo . fClipRect . fX - fRenderInfo . fX ;
if ( xstart < - 2 )
xstart = - 2 ;
srcA = ( UInt8 ) ( ( fRenderInfo . fColor > > 24 ) & 0x000000ff ) ;
if ( srcA = = 0 )
return ;
srcR = ( UInt8 ) ( ( fRenderInfo . fColor > > 16 ) & 0x000000ff ) ;
srcG = ( UInt8 ) ( ( fRenderInfo . fColor > > 8 ) & 0x000000ff ) ;
srcB = ( UInt8 ) ( ( fRenderInfo . fColor ) & 0x000000ff ) ;
static const UInt32 kernel [ 5 ] [ 5 ] = {
{ 1 , 2 , 2 , 2 , 1 } ,
{ 1 , 13 , 13 , 13 , 1 } ,
{ 1 , 10 , 10 , 10 , 1 } ,
{ 1 , 7 , 7 , 7 , 1 } ,
{ 1 , 1 , 1 , 1 , 1 }
} ;
UInt32 clamp = 220 - ( ( 2 * srcR + 4 * srcG + srcB ) > > 4 ) ;
y = fRenderInfo . fClipRect . fY - fRenderInfo . fY + ( Int16 ) c . fBaseline ;
if ( y < - 2 )
y = - 2 ;
destBasePtr = ( UInt32 * ) ( ( UInt8 * ) destBasePtr + y * fRenderInfo . fDestStride ) ;
thisHeight = fRenderInfo . fMaxHeight + ( Int16 ) c . fBaseline ;
if ( thisHeight > ( Int16 ) c . fHeight + 2 )
thisHeight = ( Int16 ) c . fHeight + 2 ;
for ( ; y < thisHeight ; y + + )
{
destPtr = destBasePtr ;
for ( x = xstart ; x < thisWidth ; x + + )
{
UInt32 sa = 0 ;
for ( Int32 i = - 2 ; i < = 2 ; i + + ) {
for ( Int32 j = - 2 ; j < = 2 ; j + + ) {
UInt32 m = kernel [ j + 2 ] [ i + 2 ] ;
if ( m ! = 0 )
sa + = m * IGetCharPixel ( c , x + i , y + j ) ;
}
}
sa = ( sa * clamp ) > > 13 ;
if ( sa > clamp )
sa = clamp ;
UInt32 a = IGetCharPixel ( c , x , y ) ;
if ( srcA ! = 0xff )
{
a = ( srcA * a + 127 ) / 255 ;
sa = ( srcA * sa + 127 ) / 255 ;
}
UInt32 ta = a + sa - ( ( a * sa + 127 ) / 255 ) ;
if ( ta > ( destPtr [ x ] > > 24 ) )
destPtr [ x ] = ( ta < < 24 ) | ( ( ( srcR * a + 127 ) / 255 ) < < 16 ) |
( ( ( srcG * a + 127 ) / 255 ) < < 8 ) |
( ( ( srcB * a + 127 ) / 255 ) < < 0 ) ;
}
destBasePtr = ( UInt32 * ) ( ( UInt8 * ) destBasePtr + fRenderInfo . fDestStride ) ;
}
}
void plFont : : IRenderCharNull ( const plCharacter & c )
void plFont : : IRenderCharNull ( const plCharacter & c )
{
{