mirror of
https://github.com/VincentWei/MiniGUI.git
synced 2026-10-01 12:23:22 +08:00
725 lines
21 KiB
C
725 lines
21 KiB
C
/*
|
|
* This file is part of MiniGUI, a mature cross-platform windowing
|
|
* and Graphics User Interface (GUI) support system for embedded systems
|
|
* and smart IoT devices.
|
|
*
|
|
* Copyright (C) 2002~2018, Beijing FMSoft Technologies Co., Ltd.
|
|
* Copyright (C) 1998~2002, WEI Yongming
|
|
*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Or,
|
|
*
|
|
* As this program is a library, any link to this program must follow
|
|
* GNU General Public License version 3 (GPLv3). If you cannot accept
|
|
* GPLv3, you need to be licensed from FMSoft.
|
|
*
|
|
* If you have got a commercial license of this program, please use it
|
|
* under the terms and conditions of the commercial license.
|
|
*
|
|
* For more information about the commercial license, please refer to
|
|
* <http://www.minigui.com/en/about/licensing-policy/>.
|
|
*/
|
|
/*
|
|
** fontcache.c: Font cache for TrueType fonts.
|
|
**
|
|
** Create date: 2006/02/01
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "common.h"
|
|
|
|
#if defined(_MGFONT_FT2) && defined(_MGFONT_TTF_CACHE)
|
|
|
|
#include "minigui.h"
|
|
#include "gdi.h"
|
|
#include "freetype2.h"
|
|
|
|
typedef struct _MemBlk {
|
|
void *data;
|
|
int len;
|
|
struct _MemBlk *hashPrev;
|
|
struct _MemBlk *hashNext;
|
|
struct _MemBlk *lruPrev;
|
|
struct _MemBlk *lruNext;
|
|
} MemBlk;
|
|
|
|
typedef MemBlk LruQueueDummyHead;
|
|
typedef MemBlk HashQueueDummyHead;
|
|
|
|
/* hash directory array in every cache */
|
|
typedef struct _HashDirectory {
|
|
HashQueueDummyHead hashHead;
|
|
} HashDirectory;
|
|
|
|
/* The structure is description of Cache
|
|
blkSize : the size of each block in cache(in byte)
|
|
nBlk : how many blocks in cache
|
|
nDir : how many directory entries in cache
|
|
*memPool : the memory pool(data use it) pointer.
|
|
*lruQueueNodes : point all nodes by malloc. just
|
|
release function use it
|
|
*hashDir : the hash directory pointer
|
|
lruQueueDummyHead : head node of lru queue
|
|
makeHashKeyFunc : the function which make hash key */
|
|
typedef struct _FontCache {
|
|
/* Information about font */
|
|
char df_name[LEN_UNIDEVFONT_NAME + 1];
|
|
int style;
|
|
int fontsize;
|
|
int rotation;
|
|
int refers;
|
|
int blkSize;
|
|
int nBlk;
|
|
int nDir;
|
|
void *memPool;
|
|
MemBlk *lruQueueNodes;
|
|
HashDirectory *hashDir;
|
|
LruQueueDummyHead lruQueueDummyHead;
|
|
MakeHashKeyFunc makeHashKeyFunc;
|
|
} FontCache;
|
|
|
|
/* Least-Recently-Used-Order
|
|
global cache LRU queue */
|
|
typedef struct _CacheQueueNode
|
|
{
|
|
/* hold global cache queue
|
|
max cache node maybe 10 */
|
|
FontCache cache;
|
|
struct _CacheQueueNode *prevCache;
|
|
struct _CacheQueueNode *nextCache;
|
|
}CacheQueueNode;
|
|
|
|
/* cache system. global cache descriptor,
|
|
but user don't touch it, we use it!
|
|
queueDummyHead : the head node of cache queue.
|
|
|
|
maxCache : the max count of cache in programm
|
|
cacheSize : each cache's size(in BYTE and
|
|
everyone has the same size!)
|
|
nCache : how many cache Now!! */
|
|
struct _CacheSystem {
|
|
CacheQueueNode queueDummyHead;
|
|
|
|
int maxCache;
|
|
int cacheSize;
|
|
int nCache;
|
|
};
|
|
|
|
struct _CacheSystem __mg_globalCache;
|
|
|
|
|
|
|
|
/* functions */
|
|
|
|
static void
|
|
AppendCache(CacheQueueNode *new)
|
|
{
|
|
new->nextCache = &(__mg_globalCache.queueDummyHead);
|
|
new->prevCache = __mg_globalCache.queueDummyHead.prevCache;
|
|
(__mg_globalCache.queueDummyHead.prevCache)->nextCache = new;
|
|
__mg_globalCache.queueDummyHead.prevCache = new;
|
|
}
|
|
|
|
/* create a new LRU-Queue. */
|
|
static int
|
|
CreateCacheLruQueue(FontCache *cache, int nblk)
|
|
{
|
|
int i;
|
|
MemBlk *blk;
|
|
|
|
blk = malloc(nblk * sizeof(MemBlk));
|
|
DP(("Allocate cache %p LRU == %p\n", cache, blk));
|
|
if (blk == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
memset(blk, 0, nblk * sizeof(MemBlk));
|
|
cache->lruQueueNodes = blk;
|
|
/* link the node as a double-linked-loop-list */
|
|
blk->lruPrev = &cache->lruQueueDummyHead;
|
|
blk->lruNext = (blk + 1);
|
|
for (i = 1; i < nblk - 1; i++) {
|
|
(blk + i)->lruPrev = (blk + i - 1);
|
|
(blk + i)->lruNext = (blk + i + 1);
|
|
}
|
|
(blk + nblk - 1)->lruPrev = blk + nblk - 2;
|
|
(blk + nblk - 1)->lruNext = &cache->lruQueueDummyHead;
|
|
|
|
cache->lruQueueDummyHead.lruPrev = blk + nblk - 1;
|
|
cache->lruQueueDummyHead.lruNext = blk;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
InitCache(CacheQueueNode *new, int ndir, int nblock)
|
|
{
|
|
int i;
|
|
/* allocate Hash directory array and LRU queue nodes
|
|
follow code is bad, but no way to fix it. */
|
|
if (new->cache.hashDir) {
|
|
free(new->cache.hashDir);
|
|
DP(("free a old hash-dir, %p\n", new->cache.hashDir));
|
|
}
|
|
new->cache.hashDir = malloc(ndir * sizeof(HashDirectory));
|
|
DP(("Allocate %p hash dir %p\n", new, new->cache.hashDir));
|
|
if (new->cache.hashDir == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
memset(new->cache.hashDir, 0, ndir * sizeof(HashDirectory));
|
|
for (i = 0; i < ndir; i++) {
|
|
new->cache.hashDir[i].hashHead.hashPrev =
|
|
&(new->cache.hashDir[i].hashHead);
|
|
new->cache.hashDir[i].hashHead.hashNext =
|
|
&(new->cache.hashDir[i].hashHead);
|
|
}
|
|
|
|
if (new->cache.lruQueueDummyHead.lruNext !=
|
|
&(new->cache.lruQueueDummyHead)) {
|
|
/* It's a old node, not malloced,
|
|
so we must release the old LRU-queue */
|
|
free(new->cache.lruQueueNodes);
|
|
DP(("free a old lru. %p\n", new->cache.lruQueueNodes));
|
|
}
|
|
if (CreateCacheLruQueue(&new->cache, nblock) == -1) {
|
|
if (new->cache.lruQueueNodes) {
|
|
free(new->cache.lruQueueNodes);
|
|
DP(("free a old lru. %p\n", new->cache.lruQueueNodes));
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void
|
|
LruQueueBufferSplit(FontCache *cache, int bufsize)
|
|
{
|
|
MemBlk *blk;
|
|
unsigned char *buff;
|
|
|
|
blk = cache->lruQueueDummyHead.lruNext;
|
|
buff = cache->memPool;
|
|
while (blk != &cache->lruQueueDummyHead) {
|
|
blk->data = buff;
|
|
blk = blk->lruNext;
|
|
buff = buff + bufsize;
|
|
}
|
|
}
|
|
|
|
static void
|
|
DestroyCache(FontCache *cache)
|
|
{
|
|
if (cache->hashDir != NULL) {
|
|
free(cache->hashDir);
|
|
DP(("destory cache %p hash dir %p\n", cache, cache->hashDir));
|
|
}
|
|
if (cache->memPool != NULL) {
|
|
DP(("destory cache %p memory pool %p\n", cache, cache->memPool));
|
|
free(cache->memPool);
|
|
}
|
|
if (cache->lruQueueNodes) {
|
|
DP(("destory cache %p LRU_QUEUE %p\n", cache, cache->lruQueueNodes));
|
|
free(cache->lruQueueNodes);
|
|
}
|
|
}
|
|
|
|
/* release a cache node from the global LRU cache queue.
|
|
Free the memory and unlink the pointers. */
|
|
static void
|
|
ReleaseCache(CacheQueueNode *cache)
|
|
{
|
|
/* Re-Link the double link queue */
|
|
if (cache->prevCache != NULL && cache->nextCache != NULL) {
|
|
cache->nextCache->prevCache = cache->prevCache;
|
|
cache->prevCache->nextCache = cache->nextCache;
|
|
}
|
|
DestroyCache(&cache->cache);
|
|
}
|
|
|
|
|
|
|
|
/* allocate a new cache and append at the end of the global cache queue.
|
|
* If global cache queue is full, we should kill the first node of the queue,
|
|
* and we call this : Least-Recently-Used-Order
|
|
* If global cache is not full, just allocate a new one.
|
|
* the func return pointer to the cache if succeed, return NULL means failed. */
|
|
static CacheQueueNode *
|
|
GetCache(int nblock, int ndir)
|
|
{
|
|
CacheQueueNode *temp;
|
|
|
|
if (__mg_globalCache.nCache == __mg_globalCache.maxCache) {
|
|
/* The Queue is Full!! in this case, we don't
|
|
release any node, just return NULL */
|
|
return NULL;
|
|
}
|
|
/* there is empty space in the queue
|
|
we should allocate a new CacheQueueNode and
|
|
allocate Memory-Pool for it */
|
|
if ((temp = malloc(sizeof(CacheQueueNode))) == NULL) {
|
|
return NULL;
|
|
}
|
|
DP(("New a cache node %p\n", temp));
|
|
/* Set zero the new CacheQueueNode
|
|
and link the head to itself */
|
|
memset(temp, 0, sizeof(CacheQueueNode));
|
|
temp->cache.lruQueueDummyHead.lruPrev = &(temp->cache.lruQueueDummyHead);
|
|
temp->cache.lruQueueDummyHead.lruNext = &(temp->cache.lruQueueDummyHead);
|
|
/* allocate Memory-Pool for new new CacheQueueNode */
|
|
temp->cache.memPool = malloc(__mg_globalCache.cacheSize);
|
|
DP(("allocate cache %p mem pool %p\n", temp, temp->cache.memPool));
|
|
if (temp->cache.memPool == NULL) {
|
|
free(temp);
|
|
return NULL;
|
|
}
|
|
__mg_globalCache.nCache++;
|
|
|
|
/* init hash directory, lru-queue
|
|
the function should release the old hash directory
|
|
and lru-queue and allocate new one. */
|
|
if (InitCache(temp, ndir, nblock) == -1) {
|
|
/* init node failed. we must FREE has directory
|
|
Memory-Poll and Lru-queue in follow function.
|
|
And unlink the global cache queue if required */
|
|
ReleaseCache(temp);
|
|
free(temp);
|
|
__mg_globalCache.nCache--;
|
|
return NULL;
|
|
}
|
|
/* link the node at the end of global cache queue */
|
|
AppendCache(temp);
|
|
return temp;
|
|
}
|
|
|
|
|
|
/* Pick-off a block from the head of cache's
|
|
lru-queue and also Hash queue(anywhere in hash q).
|
|
Relink the lru queue and hash queue */
|
|
static MemBlk *
|
|
PickOffBlk(FontCache *cache)
|
|
{
|
|
MemBlk *blk;
|
|
|
|
if (cache->lruQueueDummyHead.lruNext ==
|
|
&cache->lruQueueDummyHead) {
|
|
return NULL;
|
|
}
|
|
/* get the head of the lru-queue
|
|
it is a Least-Recently-Used-Order Node
|
|
and we should re-link the queue */
|
|
blk = cache->lruQueueDummyHead.lruNext;
|
|
|
|
cache->lruQueueDummyHead.lruNext=
|
|
(cache->lruQueueDummyHead.lruNext)->lruNext;
|
|
(cache->lruQueueDummyHead.lruNext)->lruPrev =
|
|
&cache->lruQueueDummyHead;
|
|
/* we pick the block, and if the block already
|
|
in a hash q, so we must re-link the hash q */
|
|
if (blk->hashNext && blk->hashPrev) {
|
|
blk->hashNext->hashPrev = blk->hashPrev;
|
|
blk->hashPrev->hashNext = blk->hashNext;
|
|
}
|
|
return blk;
|
|
}
|
|
|
|
static void
|
|
AppendBlk(FontCache *cache, MemBlk *blk, int key)
|
|
{
|
|
/* first, append the blcok at the end of the
|
|
lru-queue. */
|
|
blk->lruNext = &(cache->lruQueueDummyHead);
|
|
blk->lruPrev = cache->lruQueueDummyHead.lruPrev;
|
|
(cache->lruQueueDummyHead.lruPrev)->lruNext = blk;
|
|
cache->lruQueueDummyHead.lruPrev = blk;
|
|
|
|
/* Then, insert the block at the head of
|
|
the hash queue which KEY==key */
|
|
blk->hashNext = cache->hashDir[key].hashHead.hashNext;
|
|
(cache->hashDir[key].hashHead.hashNext)->hashPrev = blk;
|
|
cache->hashDir[key].hashHead.hashNext = blk;
|
|
blk->hashPrev = &(cache->hashDir[key].hashHead);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************
|
|
* extern functions *
|
|
**********************************************************/
|
|
/* search a data in cache,
|
|
hCache : which cache
|
|
*cmpdata : your data pointer point to data for compare
|
|
*size : if found the data, how long is the data(return val)
|
|
reutrn = pointer to the data */
|
|
TTFCACHEINFO *
|
|
__mg_ttc_search(HCACHE hCache, Glyph32 gv, int *size)
|
|
{
|
|
int key;
|
|
CacheQueueNode *ca;
|
|
MemBlk *blk;
|
|
|
|
if (hCache == 0 || size == NULL) {
|
|
return NULL;
|
|
}
|
|
ca = (CacheQueueNode *)(hCache);
|
|
key = ca->cache.makeHashKeyFunc(gv);
|
|
if (key > (ca->cache.nDir - 1)) {
|
|
return NULL;
|
|
}
|
|
blk = ca->cache.hashDir[key].hashHead.hashNext;
|
|
|
|
for ( ; blk != &(ca->cache.hashDir[key].hashHead);
|
|
blk = blk->hashNext) {
|
|
TTFCACHEINFO* tci = (TTFCACHEINFO*)blk->data;
|
|
if (tci->glyph_code == gv) {
|
|
/* If found the blk, we should pick off it
|
|
and link it at the end of LRU-q */
|
|
*size = blk->len;
|
|
blk->lruNext->lruPrev = blk->lruPrev;
|
|
blk->lruPrev->lruNext = blk->lruNext;
|
|
blk->lruNext = &(ca->cache.lruQueueDummyHead);
|
|
blk->lruPrev = ca->cache.lruQueueDummyHead.lruPrev;
|
|
(ca->cache.lruQueueDummyHead.lruPrev)->lruNext = blk;
|
|
ca->cache.lruQueueDummyHead.lruPrev = blk;
|
|
return tci;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* add data into the specific cache
|
|
hCache : which cache ,
|
|
*data : your data pointer
|
|
size : your data's bytes
|
|
key : hash key of your data
|
|
*/
|
|
int
|
|
__mg_ttc_write(HCACHE hCache, TTFCACHEINFO *data, int size)
|
|
{
|
|
CacheQueueNode *ca;
|
|
MemBlk *blk;
|
|
int key;
|
|
|
|
if (hCache == 0 || data == NULL) {
|
|
return -1;
|
|
}
|
|
ca = (CacheQueueNode *)(hCache);
|
|
if (ca->cache.blkSize < size) {
|
|
return -1;
|
|
}
|
|
key = ca->cache.makeHashKeyFunc(data->glyph_code);
|
|
|
|
/* pick off a block from lru queue */
|
|
if ((blk = PickOffBlk(&ca->cache)) == NULL) {
|
|
return -1;
|
|
}
|
|
/* 1. copy the TTFCACHEINFO structure
|
|
2. copy the BITMAP data by data->bitmap
|
|
3. change the bitmap pointer */
|
|
memcpy(blk->data, data, sizeof(TTFCACHEINFO));
|
|
if (data->bitmap)
|
|
memcpy((blk->data + sizeof(TTFCACHEINFO)),
|
|
data->bitmap,
|
|
(size - sizeof(TTFCACHEINFO)));
|
|
blk->len = size;
|
|
((TTFCACHEINFO *)(blk->data))->bitmap = blk->data + sizeof(TTFCACHEINFO);
|
|
/* append the block to the end of lru-queue */
|
|
AppendBlk(&ca->cache, blk, key);
|
|
return 0;
|
|
}
|
|
|
|
/* create a cache for a font instance.
|
|
nblk : how many block in the cache.
|
|
blksize : each block's size
|
|
ndir : how many hash entries in the cache
|
|
makeHashKey : the function which make the hash key */
|
|
HCACHE
|
|
__mg_ttc_create(const char *df_name, int style, int size, int rotation,
|
|
int nblk, int blksize, int ndir, MakeHashKeyFunc makeHashKey)
|
|
{
|
|
CacheQueueNode *temp;
|
|
if (df_name == NULL || makeHashKey == NULL) {
|
|
return (HCACHE)(0);
|
|
}
|
|
if (nblk <= 0 || blksize <= 0 || size <= 0 || ndir <= 0) {
|
|
return (HCACHE)(0);
|
|
}
|
|
|
|
if ((nblk * blksize) > __mg_globalCache.cacheSize) {
|
|
return (HCACHE)(0);
|
|
}
|
|
if ((temp = GetCache(nblk, ndir)) == NULL) {
|
|
return (HCACHE)(0);
|
|
}
|
|
|
|
memset(temp->cache.df_name, 0, LEN_UNIDEVFONT_NAME + 1);
|
|
strncpy(temp->cache.df_name, df_name, LEN_UNIDEVFONT_NAME);
|
|
temp->cache.style = style & FS_RENDER_MASK;
|
|
temp->cache.fontsize = size;
|
|
temp->cache.rotation = rotation;
|
|
temp->cache.blkSize = blksize;
|
|
temp->cache.nBlk = nblk;
|
|
temp->cache.nDir = ndir;
|
|
temp->cache.makeHashKeyFunc = makeHashKey;
|
|
/* Cut the Big memory pool into some small block */
|
|
LruQueueBufferSplit(&temp->cache, blksize);
|
|
temp->cache.refers = 1;
|
|
return (HCACHE)(temp);
|
|
}
|
|
|
|
void
|
|
__mg_ttc_refer(HCACHE hCache)
|
|
{
|
|
CacheQueueNode *ca;
|
|
if (hCache == 0) {
|
|
return;
|
|
}
|
|
ca = (CacheQueueNode *)(hCache);
|
|
ca->cache.refers++;
|
|
}
|
|
|
|
void
|
|
__mg_ttc_release(HCACHE hCache)
|
|
{
|
|
CacheQueueNode *ca;
|
|
if (hCache == 0) {
|
|
return;
|
|
}
|
|
ca = (CacheQueueNode *)(hCache);
|
|
ca->cache.refers--;
|
|
DP(("cache %p -- %d\n", ca, ca->cache.refers));
|
|
if (ca->cache.refers == 0) {
|
|
/* It will re-link the global cache list in ReleaseCache() */
|
|
ReleaseCache(ca);
|
|
free(ca);
|
|
DP(("Free cache==%p\n", ca));
|
|
__mg_globalCache.nCache--;
|
|
}
|
|
}
|
|
|
|
/* init cache system, create cache queue, and clear cache counter,
|
|
if need use cache, should call this function first */
|
|
int
|
|
__mg_ttc_sys_init(int maxCache, int cacheSize)
|
|
{
|
|
if (maxCache <= 0 || cacheSize <= 0) {
|
|
return -1;
|
|
}
|
|
__mg_globalCache.queueDummyHead.prevCache = &__mg_globalCache.queueDummyHead;
|
|
__mg_globalCache.queueDummyHead.nextCache = &__mg_globalCache.queueDummyHead;
|
|
__mg_globalCache.maxCache = maxCache;
|
|
__mg_globalCache.nCache = 0;
|
|
__mg_globalCache.cacheSize = cacheSize;
|
|
return 0;
|
|
}
|
|
|
|
|
|
void
|
|
__mg_ttc_sys_deinit(void)
|
|
{
|
|
CacheQueueNode *q, *pfree;
|
|
|
|
if (__mg_globalCache.nCache == 0) {
|
|
/* it means just no cache in our system,
|
|
no malloc at all, just set zero global val
|
|
and return safe :) */
|
|
memset(&__mg_globalCache, 0, sizeof(__mg_globalCache));
|
|
return;
|
|
}
|
|
/* In this case, it means more than ONE cache in
|
|
our system. we should release follow structures:
|
|
a. every CacheQueueNode(s) in global cache queue
|
|
b. every Memory-Pool in every cache
|
|
c. every Hash-Directory in every cache
|
|
d. every LRU queue nodes in every cache
|
|
that's all, may be~~ :( */
|
|
q = __mg_globalCache.queueDummyHead.nextCache;
|
|
|
|
while (q != &__mg_globalCache.queueDummyHead) {
|
|
pfree = q;
|
|
q = q->nextCache;
|
|
DestroyCache(&pfree->cache);
|
|
free(pfree);
|
|
DP(("Free cache==%p\n", pfree));
|
|
}
|
|
}
|
|
|
|
HCACHE
|
|
__mg_ttc_is_exist(const char *df_name, int style, int size, int rotation)
|
|
{
|
|
CacheQueueNode *p;
|
|
|
|
if (__mg_globalCache.nCache == 0) {
|
|
return (HCACHE)0;
|
|
}
|
|
|
|
p = __mg_globalCache.queueDummyHead.nextCache;
|
|
while (p != &__mg_globalCache.queueDummyHead) {
|
|
if (strncmp(p->cache.df_name, df_name, LEN_UNIDEVFONT_NAME) == 0
|
|
&& p->cache.style == (style & FS_RENDER_MASK)
|
|
&& p->cache.fontsize == size
|
|
&& p->cache.rotation == rotation) {
|
|
return (HCACHE) p;
|
|
}
|
|
|
|
p = p->nextCache;
|
|
}
|
|
|
|
return (HCACHE)0;
|
|
}
|
|
|
|
#if 0
|
|
|
|
static void
|
|
queue_traversal(LruQueueDummyHead *pQ)
|
|
{
|
|
MemBlk *ptr;
|
|
|
|
ptr = pQ->lruNext;
|
|
for (; ptr != pQ; ptr = ptr->lruNext) {
|
|
DP(("MemBlk = %p, MemBlk->prev = %p, "
|
|
"MemBlk->next = %p, MemBlk->data : %d\n",
|
|
ptr, ptr->lruPrev, ptr->lruNext, *(int *)(ptr->data)));
|
|
}
|
|
}
|
|
|
|
static void
|
|
queue_traversal_reverse(LruQueueDummyHead *pQ)
|
|
{
|
|
MemBlk *ptr;
|
|
|
|
ptr = pQ->lruPrev;
|
|
for ( ; ptr != pQ; ptr = ptr->lruPrev) {
|
|
DP(("MemBlk = %p, MemBlk->prev = %p, "
|
|
"MemBlk->next = %p, MemBlk->data : %d\n",
|
|
ptr, ptr->lruPrev, ptr->lruNext, *(int *)(ptr->data)));
|
|
}
|
|
}
|
|
|
|
|
|
void __mg_ttc_dump_all(void)
|
|
{
|
|
CacheQueueNode* pc;
|
|
#if 0
|
|
DP(("__mg_globalCache.maxCache = %d\n", __mg_globalCache.maxCache));
|
|
DP(("__mg_globalCache.cacheSize = %d\n", __mg_globalCache.cacheSize));
|
|
DP(("__mg_globalCache.nCache = %d\n", __mg_globalCache.nCache));
|
|
|
|
DP(("__mg_globalCache.queueDummyHead.prevCache = %p\n",
|
|
__mg_globalCache.queueDummyHead.prevCache));
|
|
DP(("__mg_globalCache.queueDummyHead.nextCache = %p\n",
|
|
__mg_globalCache.queueDummyHead.nextCache));
|
|
#endif
|
|
pc = __mg_globalCache.queueDummyHead.nextCache;
|
|
for ( ; pc != &__mg_globalCache.queueDummyHead; pc = pc->nextCache) {
|
|
__mg_ttc_dump(&pc->cache);
|
|
DP(("* * * * * * * * * * * * * * * * * * * * * * * * * * * *\n"));
|
|
}
|
|
}
|
|
|
|
void __mg_ttc_dump(FontCache *cache)
|
|
{
|
|
int i, j, k;
|
|
MemBlk *ptr;
|
|
#if 0
|
|
DP(("&cache = %p\n", cache));
|
|
DP(("cache.df_name = %s\n", cache->df_name));
|
|
DP(("cache.fontsize = %d\n", cache->fontsize));
|
|
DP(("cache.blkSize = %d\n", cache->blkSize));
|
|
DP(("cache.refers = %d\n", cache->refers));
|
|
DP(("cache.nBlk = %d\n", cache->nBlk));
|
|
DP(("cache.nDir = %d\n", cache->nDir));
|
|
DP(("cache.memPool = %d, (HEX) = %p\n",
|
|
cache->memPool, cache->memPool));
|
|
DP(("cache.lruQueueNodes=%p\n", cache->lruQueueNodes));
|
|
DP(("cache.hashDir = %p\n", cache->hashDir));
|
|
#endif
|
|
DP(("&cache.lruQueueDummyHead=%p\n",
|
|
&cache->lruQueueDummyHead));
|
|
DP(("cache.lruQueueDummyHead.lruPrev=%p\n",
|
|
cache->lruQueueDummyHead.lruPrev));
|
|
DP(("cache.lruQueueDummyHead.lruNext=%p\n",
|
|
cache->lruQueueDummyHead.lruNext));
|
|
//queue_traversal(&cache->lruQueueDummyHead);
|
|
//DP(("----\n"));
|
|
//queue_traversal_reverse(&cache->lruQueueDummyHead);
|
|
#if 0
|
|
for (i=0; i<cache->nDir; i++) {
|
|
MemBlk *p;
|
|
printf("hash[%d]:", i);
|
|
p = (cache->hashDir)[i].hashHead.hashNext;
|
|
while(p != &(cache->hashDir[i].hashHead)) {
|
|
printf("-->%d(%d)", *(unsigned short *)(p->data), p->len);
|
|
p = p->hashNext;
|
|
}
|
|
printf("\n");
|
|
}
|
|
#endif
|
|
//printf("LRU: ");
|
|
|
|
ptr = cache->lruQueueDummyHead.lruNext;
|
|
for ( ; ptr != &cache->lruQueueDummyHead; ptr = ptr->lruNext) {
|
|
DP(("-->%p(len:%d, data:%d)",
|
|
ptr, ptr->len, *(unsigned short *)(ptr->data)));
|
|
}
|
|
//printf("\n");
|
|
}
|
|
|
|
void
|
|
__mg_ttc_dump_cacheinfo(TTFCACHEINFO *ca)
|
|
{
|
|
DP(("Dump TTFCACHEINFO %p...\n", ca));
|
|
DP(("cacheInfo->glyph_code = %d\n", ca->glyph_code));
|
|
|
|
DP(("cacheInfo->cur_xmin = %d, cacheInfo->cur_ymin = %d\n",
|
|
ca->cur_xmin, ca->cur_ymin));
|
|
DP(("cacheInfo->width = %d, cacheInfo->height = %d\n",
|
|
ca->width, ca->height));
|
|
DP(("cacheInfo->advance = %d\n", ca->advance));
|
|
DP(("cacheInfo->cur_bbox = %d, %d, %d, %d\n",
|
|
ca->bbox.xMin, ca->bbox.yMin,
|
|
ca->bbox.xMax, ca->bbox.yMax));
|
|
|
|
DP(("\n"));
|
|
}
|
|
|
|
void
|
|
__mg_ttc_dump_instance(TTFINSTANCEINFO *in)
|
|
{
|
|
DP(("Dump TTFINSTANCEINFO %p...\n", in));
|
|
DP(("Instance->cur_glyph_code = %d\n", in->cur_glyph_code));
|
|
DP(("Instance->outline(addr) = %p\n", &in->cur_outline));
|
|
DP(("Instance->cur_xmin = %d, Instance->cur_ymin = %d\n",
|
|
in->cur_xmin, in->cur_ymin));
|
|
DP(("Instance->cur_width = %d, Instance->cur_height = %d\n",
|
|
in->cur_width, in->cur_height));
|
|
DP(("Instance->advance = %d\n", in->cur_advance));
|
|
DP(("Instance->cur_bbox = %d, %d, %d, %d\n",
|
|
in->cur_bbox.xMin, in->cur_bbox.yMin,
|
|
in->cur_bbox.xMax, in->cur_bbox.yMax));
|
|
|
|
DP(("\n"));
|
|
}
|
|
|
|
#endif /* 0 */
|
|
|
|
#endif /* defined(_MGFONT_FT2) && defined(_MGFONT_TTF_CACHE) */
|
|
|