/*
font_pcf.cpp
Copyright (C) 2008-2009 somebody
Copyright (C) 2009 yellow wood goblin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "font_pcf.h"
#include "font_pcf_internals.h"
#include "language.h"
#include
#include
cFontPcf::cFontPcf(): cFont(),iGlyphs(NULL),iData(NULL),iCount(0),iDataSize(0),iHeight(0),iAscent(0),iDescent(0)
{
//FIXME: test on nds
//printf("%d\n",sizeof(cFontPcf::SGlyph));
}
cFontPcf::~cFontPcf()
{
delete[]iGlyphs;
delete[]iData;
}
void cFontPcf::Info(const char* aString,u32* aWidth,u32* aSymbolCount)
{
u32 len;
u32 code=utf8toucs2((const u8*)aString,&len);
if(aSymbolCount) *aSymbolCount=len;
if(aWidth)
{
s32 index=Search(code);
*aWidth=(index>=0)?iGlyphs[index].iWidth:((code>0&&code<8)?10:0);
}
}
bool cFontPcf::ParseAccels(int aFont,u32 aSize,u32 aOffset)
{
bool res=false;
if(lseek(aFont,aOffset,SEEK_SET)<0) return false;
SPcfAccel header;
if(read(aFont,&header,sizeof(header))!=sizeof(header)) return false;
res=true;
iAscent=header.iFontAscent;
iDescent=header.iFontDescent;
iHeight=iAscent+iDescent;
return res;
}
bool cFontPcf::ParseBitmaps(int aFont,u32 aSize,u32 aOffset)
{
bool res=false;
if(lseek(aFont,aOffset,SEEK_SET)<0) return false;
SPcfBitmapsHeader header;
if(read(aFont,&header,sizeof(header))!=sizeof(header)) return false;
iGlyphs=new(std::nothrow)SGlyph[header.iCount];
if(!iGlyphs) return false;
iCount=header.iCount;
iDataSize=aSize-sizeof(SPcfBitmapsHeader)-header.iCount*sizeof(u32)-16;
iData=new(std::nothrow)u8[iDataSize];
if(iData)
{
u32* offsets=new(std::nothrow)u32[header.iCount];
if(offsets)
{
do
{
if(read(aFont,offsets,sizeof(u32)*header.iCount)!=(ssize_t)(sizeof(u32)*header.iCount)) break;
for(u32 ii=0;ii(a)->iCode-static_cast(b)->iCode);
}
bool cFontPcf::Load(const char* aFileName)
{
bool res=false;
int font=open(aFileName,O_RDONLY);
if(font>=0)
{
do
{
SPcfHeader header;
if(read(font,&header,sizeof(header))!=sizeof(header)) break;
if(header.iVersion!=PCF_FILE_VERSION) break;
SPcfEntry entries[header.iCount];
if(read(font,entries,sizeof(SPcfEntry)*header.iCount)!=(ssize_t)(sizeof(SPcfEntry)*header.iCount)) break;
s32 accelsIndex=-1,bitmapsIndex=-1,metricsIndex=-1,encodingsIndex=-1;
for(u32 ii=0;ii=0&&bitmapsIndex>=0&&metricsIndex>=0&&encodingsIndex>=0)
{
if(!ParseAccels(font,entries[accelsIndex].iSize,entries[accelsIndex].iOffset)) break;
if(!ParseBitmaps(font,entries[bitmapsIndex].iSize,entries[bitmapsIndex].iOffset)) break;
if(!ParseMetrics(font,entries[metricsIndex].iSize,entries[metricsIndex].iOffset)) break;
if(!ParseEncodings(font,entries[encodingsIndex].iSize,entries[encodingsIndex].iOffset)) break;
if(lang().GetInt("font","sort",0)) qsort(iGlyphs,iCount,sizeof(SGlyph),Compare);
res=true;
}
} while(false);
close(font);
}
return res;
}
s32 cFontPcf::Search(u16 aCode)
{
s32 result=SearchInternal(aCode);
if(result<0&&aCode>' ') result=SearchInternal('?');
return result;
}
s32 cFontPcf::SearchInternal(u16 aCode)
{
s32 low=0,high=iCount-1,curr;
while(true)
{
curr=(low+high)/2;
//curr=((aCode-iGlyphs[low].iCode)*(high-low)/(iGlyphs[high].iCode-iGlyphs[low].iCode))+low;
if(aCodeiGlyphs[curr].iCode)
{
low=curr+1;
}
else
{
return curr;
}
if(low>high) return -1;
}
}
void cFontPcf::DrawInternal(u16* mem,s16 x,s16 y,const u8* data,u16 color,u32 width,u32 height)
{
u32 byteW=width;
byteW=byteW/8+(byteW&7?1:0);
for(u32 ii=0;ii8)?8:cur_width;
for(u32 kk=0;kk=0&&x+jj>=0)
{
*(mem+x+(jj<<3)+kk+((y+ii)<<8))=color;
}
}
}
cur_width-=8;
}
}
}
void cFontPcf::Draw(u16* mem,s16 x,s16 y,const u8* aText,u16 color)
{
if(!(iData&&iGlyphs)) return;
u32 code=utf8toucs2(aText,NULL);
s32 index=Search(code);
if(index>=0)
{
x+=iGlyphs[index].iLeft;
y+=-iGlyphs[index].iAscent+iAscent;
DrawInternal(mem,x,y,iData+iGlyphs[index].iOffset,color,-iGlyphs[index].iLeft+iGlyphs[index].iRight,iGlyphs[index].iAscent+iGlyphs[index].iDescent);
}
else if(code>0&&code<8)
{
y+=-9+iAscent;
u8 special[]=
{
0x7c,0,0xfe,0,0xef,1,0xd7,1,0xd7,1,0x83,1,0xbb,1,0xfe,0,0x7c,0,
0x7c,0,0xfe,0,0xc3,1,0xbb,1,0xc3,1,0xbb,1,0xc3,1,0xfe,0,0x7c,0,
0x7c,0,0xfe,0,0xbb,1,0xd7,1,0xef,1,0xd7,1,0xbb,1,0xfe,0,0x7c,0,
0x7c,0,0xfe,0,0xbb,1,0xd7,1,0xef,1,0xef,1,0xef,1,0xfe,0,0x7c,0,
0xf8,1,0xfc,1,0xf6,1,0xf7,1,0xf7,1,0xf7,1,0x87,1,0xff,1,0xff,1,
0x3f,0,0x7f,0,0xc3,0,0xbb,1,0xc3,1,0xdb,1,0xbb,1,0xff,1,0xff,1,
0x38,0,0x38,0,0x38,0,0xff,1,0xef,1,0xff,1,0x38,0,0x38,0,0x38,0,
};
DrawInternal(mem,x,y,special+(code-1)*18,color,9,9);
}
}
#define ONE_BYTE_MASK 0x80
#define ONE_BYTE_SIGN 0x00
#define TWO_BYTE_MASK 0xc0e0
#define TWO_BYTE_SIGN 0x80c0
#define THREE_BYTE_MASK 0xc0c0f0
#define THREE_BYTE_SIGN 0x8080e0
#define FIRST_BYTE 0xff
#define SECOND_BYTE 0xff00
#define THIRD_BYTE 0xff0000
u32 cFontPcf::utf8toucs2(const u8* aSource,u32* aLength)
{
u32 data=aSource[0],len=1,res='?';
if((data&ONE_BYTE_MASK)==ONE_BYTE_SIGN)
{
res=data;
}
else
{
data+=aSource[1]*0x100;
if((data&TWO_BYTE_MASK)==TWO_BYTE_SIGN)
{
res=data&~TWO_BYTE_MASK;
res=((res&SECOND_BYTE)>>8)|((res&FIRST_BYTE)<<6);
len=2;
}
else
{
data+=aSource[2]*0x10000;
if((data&THREE_BYTE_MASK)==THREE_BYTE_SIGN)
{
res=data&~THREE_BYTE_MASK;
res=((res&FIRST_BYTE)<<12)|((res&SECOND_BYTE)>>2)|((res&THIRD_BYTE)>>16);
len=3;
}
}
}
if(aLength) *aLength=len;
return res;
}
u32 cFontPcf::FontRAM(void)
{
return iDataSize+sizeof(SGlyph)*iCount;
}