Skip to content

Commit

Permalink
Initial implementation of ttf font caching. #691
Browse files Browse the repository at this point in the history
(Kerning on and optimized and fixed)
  • Loading branch information
frehwagen committed Nov 10, 2024
1 parent 59502eb commit 303cb4a
Show file tree
Hide file tree
Showing 14 changed files with 615 additions and 337 deletions.
301 changes: 301 additions & 0 deletions Driver/Font/TrueType/Adapter/ttacache.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
#include <geos.h>
#include <vm.h>
#include <file.h>
#include <geode.h>
#include "ttacache.h"
#include <Ansi/string.h>

VMFileHandle _pascal TrueType_Cache_Init() {

VMFileHandle cacheFile;
TCHAR cacheFileName[] = "TTF Cache";

/* Try to open/create TTF cache VM file */
FilePushDir();
FileSetStandardPath(SP_PRIVATE_DATA);
cacheFile = VMOpen(cacheFileName, VMAF_FORCE_READ_WRITE, VMO_OPEN, 0);
if( cacheFile == NullHandle ) {
cacheFile = VMOpen(cacheFileName, VMAF_FORCE_READ_WRITE, VMO_CREATE, 0);
}
if( cacheFile != NullHandle ) {
HandleModifyOwner(cacheFile, GeodeGetCodeProcessHandle());
}
FilePopDir();

return cacheFile;
}

static char* strcpy( char* dest, const char* source )
{
while( (*dest++ = *source++) != '\0' );
return dest;
}

static int strcmp( const char* s1, const char* s2 )
{
while ( *s1 && ( *s1 == *s2 ) )
{
++s1;
++s2;
}
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
}

void _pascal TrueType_Cache_Exit(VMFileHandle cacheFile) {

VMClose(cacheFile, FILE_NO_ERRORS);
}

Boolean _pascal TrueType_Cache_LoadFontBlock(VMFileHandle cacheFile, const TCHAR* fontFileName,
TrueTypeCacheBufSpec* bufSpec, MemHandle* fontHandle) {
VMBlockHandle dirBlock;

dirBlock = VMGetMapBlock(cacheFile);
if( dirBlock != NullHandle ) {

VMInfoStruct vmInfo;

if ( VMInfo(cacheFile, dirBlock, &vmInfo) ) {

MemHandle dirMem;
TrueTypeCacheDirEntry* dirEntry;
word entryCount = vmInfo.size / sizeof(TrueTypeCacheDirEntry);
word loopCount = 0;

dirEntry = VMLock(cacheFile, dirBlock, &dirMem);

while( loopCount < entryCount ) {

if( strcmp(dirEntry[loopCount].TTCE_ttfFileName, fontFileName) == 0 ) {

word loopCount2 = 0;

while(loopCount2 < dirEntry[loopCount].TTCE_bufEntryCount) {

if( (dirEntry[loopCount].TTCE_bufEntry[loopCount2].TTCBE_spec.TTCBS_pointSize == bufSpec->TTCBS_pointSize) &&
(dirEntry[loopCount].TTCE_bufEntry[loopCount2].TTCBE_spec.TTCBS_width == bufSpec->TTCBS_width) &&
(dirEntry[loopCount].TTCE_bufEntry[loopCount2].TTCBE_spec.TTCBS_weight == bufSpec->TTCBS_weight) &&
(dirEntry[loopCount].TTCE_bufEntry[loopCount2].TTCBE_spec.TTCBS_stylesToImplement == bufSpec->TTCBS_stylesToImplement)
) {

MemHandle blockMem;
word size = dirEntry[loopCount].TTCE_bufEntry[loopCount2].TTCBE_bufSize;
VMBlockHandle block = dirEntry[loopCount].TTCE_bufEntry[loopCount2].TTCBE_block;

VMUnlock(dirMem);

/* found block, alloc */
if( *fontHandle == NullHandle )
{
*fontHandle = MemAllocSetOwner( FONT_MAN_ID, MAX( size, MAX_FONTBUF_SIZE ),
HF_SWAPABLE | HF_SHARABLE,
HAF_NO_ERR | HAF_LOCK | HAF_ZERO_INIT );
EC( ECCheckMemHandle( *fontHandle ) );
HandleP( *fontHandle );
}
else
{
MemReAlloc( *fontHandle, MAX( size, MAX_FONTBUF_SIZE ), HAF_NO_ERR | HAF_LOCK );
EC( ECCheckMemHandle( *fontHandle ) );
}

{
byte* srcPtr = VMLock(cacheFile, block, &blockMem);
byte* destPtr = MemLock(*fontHandle);
memcpy(destPtr, srcPtr, size);
MemUnlock(*fontHandle);
VMUnlock(blockMem);
}

return TRUE;
}
loopCount2++;
}

}
loopCount++;
}
VMUnlock(dirMem);
}
}
return FALSE;
}

void _pascal TrueType_Cache_UpdateFontBlock(VMFileHandle cacheFile, const TCHAR* fontFileName,
TrueTypeCacheBufSpec* bufSpec, MemHandle fontBuf) {

VMBlockHandle dirBlock;

dirBlock = VMGetMapBlock(cacheFile);
if( dirBlock != NullHandle ) {

VMInfoStruct vmInfo;

if ( VMInfo(cacheFile, dirBlock, &vmInfo) ) {

MemHandle dirMem;
TrueTypeCacheDirEntry* dirEntry;
word entryCount = vmInfo.size / sizeof(TrueTypeCacheDirEntry);
word loopCount = 0;

dirEntry = VMLock(cacheFile, dirBlock, &dirMem);

while( loopCount < entryCount ) {

if( strcmp(dirEntry[loopCount].TTCE_ttfFileName, fontFileName) == 0 ) {

word loopCount2 = 0;
word memSize = MemGetInfo(fontBuf, MGIT_SIZE);

while(loopCount2 < dirEntry[loopCount].TTCE_bufEntryCount) {

if( (dirEntry[loopCount].TTCE_bufEntry[loopCount2].TTCBE_spec.TTCBS_pointSize == bufSpec->TTCBS_pointSize) &&
(dirEntry[loopCount].TTCE_bufEntry[loopCount2].TTCBE_spec.TTCBS_width == bufSpec->TTCBS_width) &&
(dirEntry[loopCount].TTCE_bufEntry[loopCount2].TTCBE_spec.TTCBS_weight == bufSpec->TTCBS_weight) &&
(dirEntry[loopCount].TTCE_bufEntry[loopCount2].TTCBE_spec.TTCBS_stylesToImplement == bufSpec->TTCBS_stylesToImplement)
) {

/* update if new/current block is large*/
if(memSize > dirEntry[loopCount].TTCE_bufEntry[loopCount2].TTCBE_bufSize) {

VMBlockHandle thisBlock = dirEntry[loopCount].TTCE_bufEntry[loopCount2].TTCBE_block;
MemHandle blockMem;

dirEntry[loopCount].TTCE_bufEntry[loopCount2].TTCBE_bufSize = memSize;
VMDirty(dirMem);
VMUnlock(dirMem);

VMLock(cacheFile, thisBlock, &blockMem);
MemReAlloc(blockMem, memSize, HAF_NO_ERR);
{
byte* destPtr = MemDeref(blockMem);

byte* srcPtr = MemLock(fontBuf);
memcpy(destPtr, srcPtr, memSize);
MemUnlock(fontBuf);
VMDirty(blockMem);
VMUnlock(blockMem);
VMSave(cacheFile);
}
} else {
VMUnlock(dirMem);
}
return;
}
loopCount2++;
}
/* not found append entry if free slots*/
if(loopCount2 < TRUETYPE_CACHE_MAX_BUF_ENTRIES) {

VMBlockHandle newBlock = VMAlloc(cacheFile, memSize, 0);
if( newBlock != NullHandle ) {
dirEntry[loopCount].TTCE_bufEntry[loopCount2].TTCBE_spec = *bufSpec;
dirEntry[loopCount].TTCE_bufEntry[loopCount2].TTCBE_block = newBlock;
dirEntry[loopCount].TTCE_bufEntry[loopCount2].TTCBE_bufSize = memSize;
dirEntry[loopCount].TTCE_bufEntryCount++;
VMDirty(dirMem);
}
VMUnlock(dirMem);
if( newBlock != NullHandle ) {

MemHandle newBlockMem;
byte* destPtr = VMLock(cacheFile, newBlock, &newBlockMem);
/* fill in the block */
byte* srcPtr = MemLock(fontBuf);
memcpy(destPtr, srcPtr, memSize);
MemUnlock(fontBuf);
VMDirty(newBlockMem);
VMUnlock(newBlockMem);
}
return;
}
break;
}
loopCount++;
}
VMUnlock(dirMem);
}
}
}

Boolean _pascal TrueType_Cache_ReadHeader(VMFileHandle cacheFile, const TCHAR* fontFileName, FontHeader* headerPtr) {

VMBlockHandle dirBlock;
Boolean result = FALSE;

dirBlock = VMGetMapBlock(cacheFile);
if ( dirBlock != NullHandle ) {
VMInfoStruct vmInfo;

if ( VMInfo(cacheFile, dirBlock, &vmInfo) ) {

MemHandle dirMem;
TrueTypeCacheDirEntry* dirEntry;
word entryCount = vmInfo.size / sizeof(TrueTypeCacheDirEntry);
word loopCount = 0;

dirEntry = VMLock(cacheFile, dirBlock, &dirMem);

while( loopCount < entryCount ) {

if( strcmp(dirEntry[loopCount].TTCE_ttfFileName, fontFileName) == 0 ){

*headerPtr = dirEntry[loopCount].TTCE_fontHeader;
result = TRUE;
break;
}
loopCount++;
}

VMUnlock(dirMem);
}
}
return result;
}

void _pascal TrueType_Cache_WriteHeader(VMFileHandle cacheFile, const TCHAR* fontFileName, FontHeader* headerPtr) {

VMBlockHandle dirBlock;

dirBlock = VMGetMapBlock(cacheFile);
if ( dirBlock == NullHandle ) {

MemHandle dirMem;
TrueTypeCacheDirEntry* dirEntry;

/* handle first entry */
dirBlock = VMAlloc(cacheFile, sizeof(TrueTypeCacheDirEntry), 0);
VMSetMapBlock(cacheFile, dirBlock);

dirEntry = VMLock(cacheFile, dirBlock, &dirMem);
dirEntry->TTCE_bufEntryCount = 0;
strcpy(dirEntry->TTCE_ttfFileName, fontFileName);
dirEntry->TTCE_fontHeader = *headerPtr;

VMDirty(dirMem);
VMUnlock(dirMem);

} else {

VMInfoStruct vmInfo;

if ( VMInfo(cacheFile, dirBlock, &vmInfo) ) {

TrueTypeCacheDirEntry* dirEntry;
MemHandle dirMem;
word entryCount = vmInfo.size / sizeof(TrueTypeCacheDirEntry);

VMLock(cacheFile, dirBlock, &dirMem);

/* handle append */
MemReAlloc(dirMem, sizeof(TrueTypeCacheDirEntry) * (entryCount + 1), HAF_NO_ERR | HAF_ZERO_INIT);
dirEntry = MemDeref(dirMem);

strcpy(dirEntry[entryCount].TTCE_ttfFileName, fontFileName);
dirEntry[entryCount].TTCE_fontHeader = *headerPtr;

VMDirty(dirMem);
VMUnlock(dirMem);
}
}
}
46 changes: 46 additions & 0 deletions Driver/Font/TrueType/Adapter/ttacache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#ifndef _TTACACHE_H_
#define _TTACACHE_H_

#include <geos.h>
#include "ttadapter.h"

#define TRUETYPE_CACHE_MAX_BUF_ENTRIES 10

typedef struct {
WWFixedAsDWord TTCBS_pointSize;
byte TTCBS_width;
byte TTCBS_weight;
TextStyle TTCBS_stylesToImplement;
} TrueTypeCacheBufSpec;

typedef struct {
TrueTypeCacheBufSpec TTCBE_spec;
word TTCBE_bufSize;
VMBlockHandle TTCBE_block;
} TrueTypeCacheBufEntry;

typedef struct {
TCHAR TTCE_ttfFileName[FILE_LONGNAME_BUFFER_SIZE];
FontHeader TTCE_fontHeader;
byte TTCE_bufEntryCount;
TrueTypeCacheBufEntry TTCE_bufEntry[TRUETYPE_CACHE_MAX_BUF_ENTRIES];
} TrueTypeCacheDirEntry;


VMFileHandle _pascal TrueType_Cache_Init();

void _pascal TrueType_Cache_Exit(VMFileHandle cacheFile);

Boolean _pascal TrueType_Cache_LoadFontBlock(
VMFileHandle cacheFile, const TCHAR* fontFileName,
TrueTypeCacheBufSpec* bufSpec, MemHandle *fontHandle
);

void _pascal TrueType_Cache_UpdateFontBlock(VMFileHandle cacheFile, const TCHAR* fontFileName,
TrueTypeCacheBufSpec* bufSpec, MemHandle fontBuf);

Boolean _pascal TrueType_Cache_ReadHeader(VMFileHandle cacheFile, const TCHAR* fontFileName, FontHeader* headerPtr);

void _pascal TrueType_Cache_WriteHeader();

#endif /* _TTCACHE_H_ */
6 changes: 5 additions & 1 deletion Driver/Font/TrueType/Adapter/ttadapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ extern TEngine_Instance engineInstance;
#define FAMILY_NAME_LENGTH 20
#define STYLE_NAME_LENGTH 16

#define KERN_VALUE_DIVIDENT 100
#define KERN_VALUE_DIVIDENT 30

#define STANDARD_GRIDSIZE 1000
#define MAX_NUM_GLYPHS 2000
Expand Down Expand Up @@ -398,6 +398,10 @@ typedef struct

/* lookuptable for truetype indices */
MemHandle lookupTable;

/* cache file handle */
VMFileHandle cacheFile;

} TrueTypeVars;


Expand Down
Loading

0 comments on commit 303cb4a

Please sign in to comment.