同步操作将从 Gitee 极速下载/MiniGUI 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
/////////////////////////////////////////////////////////////////////////////////// IMPORTANT NOTICE//// The following open source license statement does not apply to any// entity in the Exception List published by FMSoft.//// For more information, please visit://// https://www.fmsoft.cn/exception-list/////////////////////////////////////////////////////////////////////////////////** 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 CacheblkSize : the size of each block in cache(in byte)nBlk : how many blocks in cachenDir : how many directory entries in cache*memPool : the memory pool(data use it) pointer.*lruQueueNodes : point all nodes by malloc. justrelease function use it*hashDir : the hash directory pointerlruQueueDummyHead : head node of lru queuemakeHashKeyFunc : 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-Orderglobal cache LRU queue */typedef struct _CacheQueueNode{/* hold global cache queuemax 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 programmcacheSize : each cache's size(in BYTE andeveryone 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 voidAppendCache(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 intCreateCacheLruQueue(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 intInitCache(CacheQueueNode *new, int ndir, int nblock){int i;/* allocate Hash directory array and LRU queue nodesfollow 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 voidLruQueueBufferSplit(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 voidDestroyCache(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 voidReleaseCache(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'trelease any node, just return NULL */return NULL;}/* there is empty space in the queuewe should allocate a new CacheQueueNode andallocate Memory-Pool for it */if ((temp = malloc(sizeof(CacheQueueNode))) == NULL) {return NULL;}DP(("New a cache node %p\n", temp));/* Set zero the new CacheQueueNodeand 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-queuethe function should release the old hash directoryand lru-queue and allocate new one. */if (InitCache(temp, ndir, nblock) == -1) {/* init node failed. we must FREE has directoryMemory-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'slru-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-queueit is a Least-Recently-Used-Order Nodeand 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 alreadyin 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 voidAppendBlk(FontCache *cache, MemBlk *blk, int key){/* first, append the blcok at the end of thelru-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 ofthe 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 itand 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 cachehCache : which cache ,*data : your data pointersize : your data's byteskey : 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 structure2. copy the BITMAP data by data->bitmap3. 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 sizendir : how many hash entries in the cachemakeHashKey : 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 valand return safe :) */memset(&__mg_globalCache, 0, sizeof(__mg_globalCache));return;}/* In this case, it means more than ONE cache inour system. we should release follow structures:a. every CacheQueueNode(s) in global cache queueb. every Memory-Pool in every cachec. every Hash-Directory in every cached. every LRU queue nodes in every cachethat'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 0static voidqueue_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 voidqueue_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 0DP(("__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));#endifpc = __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 0DP(("&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));#endifDP(("&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 0for (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) */
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。