/* 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; }