Chinaunix首页 | 论坛 | 博客
  • 博客访问: 299485
  • 博文数量: 76
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 715
  • 用 户 组: 普通用户
  • 注册时间: 2015-05-20 20:38
文章分类
文章存档

2016年(20)

2015年(56)

分类: 嵌入式

2015-08-23 16:41:17

Draw.c
15年8月23日13:54:14
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <config.h>
#include <draw.h>
#include <encoding_manager.h>
#include <fonts_manager.h>
#include <disp_manager.h>
#include <string.h>


typedef struct PageDesc {
    int iPage;
    unsigned char *pucLcdFirstPosAtFile;
    unsigned char *pucLcdNextPageFirstPosAtFile;
    struct PageDesc *ptPrePage;
    struct PageDesc *ptNextPage;
} T_PageDesc, *PT_PageDesc;

static int g_iFdTextFile;
static unsigned char *g_pucTextFileMem;
static unsigned char *g_pucTextFileMemEnd;
static PT_EncodingOpr g_ptEncodingOprForFile;

static PT_DispOpr g_ptDispOpr;

static unsigned char *g_pucLcdFirstPosAtFile;
static unsigned char *g_pucLcdNextPosAtFile;

static int g_dwFontSize;

static PT_PageDesc g_ptPages   = NULL;
static PT_PageDesc g_ptCurPage = NULL;


int OpenTextFile(char *pcFileName)
{
    struct stat tStat;

    g_iFdTextFile = open(pcFileName, O_RDONLY);
    if (0 > g_iFdTextFile)
    {
        DBG_PRINTF("can't open text file %s\n", pcFileName);
        return -1;
    }

    if(fstat(g_iFdTextFile, &tStat))
    {
        DBG_PRINTF("can't get fstat\n");
        return -1;
    }
    g_pucTextFileMem = (unsigned char *)mmap(NULL, tStat.st_size, PROT_READ,                                 MAP_SHARED, g_iFdTextFile, 0);
    if (g_pucTextFileMem == (unsigned char *)-1)
    {
        DBG_PRINTF("can't mmap for text file\n");
        return -1;
    }

    g_pucTextFileMemEnd = g_pucTextFileMem + tStat.st_size;
    
    g_ptEncodingOprForFile =                                             SelectEncodingOprForFile(g_pucTextFileMem);

    if (g_ptEncodingOprForFile)
    {
        g_pucLcdFirstPosAtFile = g_pucTextFileMem +                                     g_ptEncodingOprForFile->iHeadLen;
        return 0;
    }
    else
    {
        return -1;
    }

}


int SetFontsDetail(char *pcHZKFile, char *pcFileFreetype, unsigned                                         int dwFontSize)
{
    int iError = 0;
    PT_FontOpr ptFontOpr;
    PT_FontOpr ptTmp;
    int iRet = -1;

    g_dwFontSize = dwFontSize;     

    ptFontOpr = g_ptEncodingOprForFile->ptFontOprSupportedHead;
    while (ptFontOpr)
    {
        if (strcmp(ptFontOpr->name, "ascii") == 0)
        {
            iError = ptFontOpr->FontInit(NULL, dwFontSize);
        }
        else if (strcmp(ptFontOpr->name, "gbk") == 0)
        {
            iError = ptFontOpr->FontInit(pcHZKFile, dwFontSize);
        }
        else
        {
            iError = ptFontOpr->FontInit(pcFileFreetype, dwFontSize);
        }

        DBG_PRINTF("%s, %d\n", ptFontOpr->name, iError);

        ptTmp = ptFontOpr->ptNext;

        if (iError == 0)
        {
            /* 比如对于ascii编码的文件, 可能用ascii字体也可能用gbk字体,
             * 所以只要有一个FontInit成功, SetTextDetail最终就返回成功
             */
            iRet = 0;
        }
        else
        {
            DelFontOprFrmEncoding(g_ptEncodingOprForFile,                                             ptFontOpr);
        }
        ptFontOpr = ptTmp;
    }
    return iRet;
}

int SelectAndInitDisplay(char *pcName)
{
    int iError;
    g_ptDispOpr = GetDispOpr(pcName);
    if (!g_ptDispOpr)
    {
        return -1;
    }

    iError = g_ptDispOpr->DeviceInit();
    return iError;
}

int IncLcdX(int iX)
{
    if (iX + 1 < g_ptDispOpr->iXres)
        return (iX + 1);
    else
        return 0;
}

int IncLcdY(int iY)
{
    if (iY + g_dwFontSize < g_ptDispOpr->iYres)
        return (iY + g_dwFontSize);
    else
        return 0;
}

int RelocateFontPos(PT_FontBitMap ptFontBitMap)
{
    int iLcdY;
    int iDeltaX;
    int iDeltaY;

    if (ptFontBitMap->iYMax > g_ptDispOpr->iYres)
    {
        /* 满页了 */
        return -1;
    }

    /* 超过LCD最右边 */
    if (ptFontBitMap->iXMax > g_ptDispOpr->iXres)
    {
        /* 换行 */            
        iLcdY = IncLcdY(ptFontBitMap->iCurOriginY);
        if (0 == iLcdY)
        {
            /* 满页了 */
            return -1;
        }
        else
        {
            /* 没满页 */
            iDeltaX = 0 - ptFontBitMap->iCurOriginX;
            iDeltaY = iLcdY - ptFontBitMap->iCurOriginY;

            ptFontBitMap->iCurOriginX  += iDeltaX;
            ptFontBitMap->iCurOriginY  += iDeltaY;

            ptFontBitMap->iNextOriginX += iDeltaX;
            ptFontBitMap->iNextOriginY += iDeltaY;

            ptFontBitMap->iXLeft += iDeltaX;
            ptFontBitMap->iXMax  += iDeltaX;
 
            ptFontBitMap->iYTop  += iDeltaY;
            ptFontBitMap->iYMax  += iDeltaY;;
            
            return 0;    
        }
    }
    
    return 0;
}

int ShowOneFont(PT_FontBitMap ptFontBitMap)
{
    int x;
    int y;
    unsigned char ucByte = 0;
    int i = 0;
    int bit;
    
    if (ptFontBitMap->iBpp == 1)
    {
        for (y = ptFontBitMap->iYTop; y < ptFontBitMap->iYMax;y++)
        {
            i = (y - ptFontBitMap->iYTop) * ptFontBitMap->iPitch;
            for (x = ptFontBitMap->iXLeft, bit = 7; x < ptFontBitMap-                                            >iXMax; x++)
            {
                if (bit == 7)
                {
                    ucByte = ptFontBitMap->pucBuffer[i++];
                }
                
                if (ucByte & (1<<bit))
                {
                    g_ptDispOpr->ShowPixel(x, y, COLOR_FOREGROUND);
                }
                else
                {
                    /* 使用背景色, 不用描画 */
                    // g_ptDispOpr->ShowPixel(x, y, 0);
                }
                bit--;
                if (bit == -1)
                {
                    bit = 7;
                }
            }
        }
    }
    else if (ptFontBitMap->iBpp == 8)
    {
        for (y = ptFontBitMap->iYTop; y < ptFontBitMap->iYMax;y++)
            for (x = ptFontBitMap->iXLeft; x < ptFontBitMap->iXMax; x++)
            {
                //g_ptDispOpr->ShowPixel(x, y, ptFontBitMap-                                                >pucBuffer[i++]);
                if (ptFontBitMap->pucBuffer[i++])
                    g_ptDispOpr->ShowPixel(x, y, COLOR_FOREGROUND);
            }
    }
    else
    {
        DBG_PRINTF("ShowOneFont error, can't support %d bpp\n",                                         ptFontBitMap->iBpp);
        return -1;
    }
    return 0;
}

int ShowOnePage(unsigned char *pucTextFileMemCurPos)
{
    int iLen;
    int iError;
    unsigned char *pucBufStart;
    unsigned int dwCode;
    PT_FontOpr ptFontOpr;
    T_FontBitMap tFontBitMap;
    
    int bHasNotClrSceen = 1;
    int bHasGetCode = 0;

    tFontBitMap.iCurOriginX = 0;
    tFontBitMap.iCurOriginY = g_dwFontSize;
    pucBufStart = pucTextFileMemCurPos;

    
    while (1)
    {
        iLen = g_ptEncodingOprForFile->GetCodeFrmBuf(pucBufStart,                                 g_pucTextFileMemEnd, &dwCode);
        if (0 == iLen)
        {
            /* 文件结束 */
            if (!bHasGetCode)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        bHasGetCode = 1;
        
        pucBufStart += iLen;

        /* 有些文本, \n\r两个一起才表示回车换行
         * 碰到这种连续的\n\r, 只处理一次*/
        if (dwCode == '\n')
        {
            g_pucLcdNextPosAtFile = pucBufStart;
            
            /* 回车换行 */
            tFontBitMap.iCurOriginX = 0;
            tFontBitMap.iCurOriginY = IncLcdY(tFontBitMap.iCurOriginY);
            if (0 == tFontBitMap.iCurOriginY)
            {
                /* 显示完当前一屏了 */
                return 0;
            }
            else
            {
                continue;
            }
        }
        else if (dwCode == '\r')
        {
            continue;
        }
        else if (dwCode == '\t')
        {
            /* TAB键用一个空格代替 */
            dwCode = ' ';
        }

        DBG_PRINTF("dwCode = 0x%x\n", dwCode);
        
        ptFontOpr = g_ptEncodingOprForFile->ptFontOprSupportedHead;
        while (ptFontOpr)
        {
            iError = ptFontOpr->GetFontBitmap(dwCode, &tFontBitMap);
            if (0 == iError)
            {
                if (RelocateFontPos(&tFontBitMap))
                {
                    /* 剩下的LCD空间不能满足显示这个字符 */
                    return 0;
                }

                if (bHasNotClrSceen)
                {
                    /* 首先清屏
                    g_ptDispOpr->CleanScreen(COLOR_BACKGROUND);
                    bHasNotClrSceen = 0;
                }
                /* 显示一个字符 */
                if (ShowOneFont(&tFontBitMap))
                {
                    return -1;
                }
                
                tFontBitMap.iCurOriginX = tFontBitMap.iNextOriginX;
                tFontBitMap.iCurOriginY = tFontBitMap.iNextOriginY;
                g_pucLcdNextPosAtFile = pucBufStart;

                /* 继续取出下一个编码来显示 */
                break;
            }
            ptFontOpr = ptFontOpr->ptNext;
        }        
    }

    return 0;
}

static void RecordPage(PT_PageDesc ptPageNew)
{
    PT_PageDesc ptPage;
        
    if (!g_ptPages)
    {
        g_ptPages = ptPageNew;
    }
    else
    {
        ptPage = g_ptPages;
        while (ptPage->ptNextPage)
        {
            ptPage = ptPage->ptNextPage;
        }
        ptPage->ptNextPage   = ptPageNew;
        ptPageNew->ptPrePage = ptPage;
    }
}

int ShowNextPage(void)
{
    int iError;
    PT_PageDesc ptPage;
    unsigned char *pucTextFileMemCurPos;

    if (g_ptCurPage)
    {
        pucTextFileMemCurPos = g_ptCurPage->pucLcdNextPageFirstPosAtFile;
    }
    else
    {
        pucTextFileMemCurPos = g_pucLcdFirstPosAtFile;
    }
    iError = ShowOnePage(pucTextFileMemCurPos);
    DBG_PRINTF("%s %d, %d\n", __FUNCTION__, __LINE__, iError);
    if (iError == 0)
    {
        if (g_ptCurPage && g_ptCurPage->ptNextPage)
        {
            g_ptCurPage = g_ptCurPage->ptNextPage;
            return 0;
        }
        
        ptPage = malloc(sizeof(T_PageDesc));
        if (ptPage)
        {
            ptPage->pucLcdFirstPosAtFile = pucTextFileMemCurPos;
            ptPage->pucLcdNextPageFirstPosAtFile = g_pucLcdNextPosAtFile;
            ptPage->ptPrePage                    = NULL;
            ptPage->ptNextPage                   = NULL;
            g_ptCurPage = ptPage;

            RecordPage(ptPage);
            return 0;
        }
        else
        {
            return -1;
        }
    }
    return iError;
}

int ShowPrePage(void)
{
    int iError;

    DBG_PRINTF("%s %d\n", __FUNCTION__, __LINE__);
    if (!g_ptCurPage || !g_ptCurPage->ptPrePage)
    {
        return -1;
    }

    iError = ShowOnePage(g_ptCurPage->ptPrePage->pucLcdFirstPosAtFile);
    if (iError == 0)
    {
        DBG_PRINTF("%s %d\n", __FUNCTION__, __LINE__);
        g_ptCurPage = g_ptCurPage->ptPrePage;
    }
    return iError;
}

下面来分析这段代码:
(1)首先是这个 PageDesc结构体:
typedef struct PageDesc {
    int iPage;
    unsigned char *pucLcdFirstPosAtFile;
    unsigned char *pucLcdNextPageFirstPosAtFile;
    struct PageDesc *ptPrePage;
    struct PageDesc *ptNextPage;
} T_PageDesc, *PT_PageDesc;
电子书里面需要上下翻页,这时候,就需要记录下来每一页第一个显示的位置,以及下一页第一个显示的位置。
(2)static unsigned char *g_pucTextFileMemEnd;
为什么要定义这个MemEnd变量呢?这个变量主要是在GetCodeFrmBuf函数中使用,用来确定取码的时候,是否到了文件的最后。
(3)下面来看第一个函数:
int OpenTextFile(char * pcFileName)
{
    struct stat tStat;

    /* 用open函数来打开文件,对返回值进行判定 */
    g_iFdTextFile = open(pcFileName, O_RDONLY);
    if (g_iFdTextFile < 0)
    {
        DBG_PRINTF("Open %s failed!\n", pcFileName);
        return -1;
    }
    /* 用fstat函数来获取文件的一些统计信息,并存在tStat这个结构体中 */
    if (fstat(g_iFdTextFile, &tStat))
    {
        DBG_PRINTF("cannot get fstat!\n");
        return -1;
    }

    /* 将文件映射到内存中,这样操作起来方便,用mmap函数映射以后,是返回指向这一块内存首地址     * 的一个指针 */
    g_pucTextFileMem = (unsigned char *)mmap(NULL, tStat.st_size, PROT_READ,                                 MAP_SHARED, g_iFdTextFile, 0);
    if (g_pucTextFileMem == (unsigned char *)-1)  /* 如果函数返回-1说明出错 */
    {
        DBG_PRINTF("cannot mmap for text file!\n");
        return -1;
    }

    /* 计算出来mem最后的位置,用于确定取码的最后位置 */
    g_pucTextFileMemEnd = g_pucTextFileMem + tStat.st_size;

/* 根据映射到内存中的文件内容,来选择一种支持的编码方式,成功返回一个结构体,失败返回NULL */
    g_ptEncodingOprForFile = SelectEncodingOprForFile(g_pucTextFileMem);
    if (g_ptEncodingOprForFile)
    {
        /* 选定编码方式以后,也就确定了这种编码方式的iHeadLen,根据g_pucTextFileMem         * 和g_ptEncodingOprForFile->iHeadLen这两项,就可以确定想要在LCD上面显示         * 的第一个字符编码在内存中的位置了。每个编码格式的头部不同,如果为ascii,头部为         * 0,如果为utf-8,头部就为3.为了获得真正的编码,应该将头部舍去。
         */
        g_pucLcdFirstPosAtFile = g_pucTextFileMem +
                        g_ptEncodingOprForFile->iHeadLen;
        return 0;
    }
    else
    {
        return -1;  /* 如果没有获得编码方式,就返回-1 */
    }    
}
(4)设置字体细节函数:
int SetFontsDetail(char *pcHZKFile, char *pcFileFreeTypem, unsigned int                                             dwFontSize)
{
    int iError = 0;
    PT_FontOpr ptFontOpr;
    PT_FontOpr ptTmp;
    int iRet = -1;
    
    g_dwFontSize = dwFontSize;

    /* 从对应的编码方式结构体中取出ptFontOprSupportedHead链表,遍历链表中的每一项的,根     * 据名字来确定是哪一项,然后进行相应字体的初始化 */
    ptFontOpr = g_ptEncodingOprForFile->ptFontOprSupportedHead;
    while (ptFontOpr)
    {
        if (strcmp(ptFontOpr->name, "ascii") == 0)
        {
            iError = ptFontOpr->FontInit(NULL, dwFontSize);
        }
        else if (strcmp(ptFontOpr->name, "gbk") == 0)
        {
            iError = ptFontOpr->FontInit(pcHZKFile, dwFontSize);
        }
        else
        {
            iError = ptFontOpr->FontInit(pcFileFreeTypem, dwFontSize);
        }
        
        DBG_PRINTF("%s %d\n", ptFontOpr->name, iError);
        ptTmp = ptFontOpr->ptNext;

        if (iError == 0)
        {
            /* 比如对于ascii编码的文件, 可能用ascii字体也可能用gbk字体,
             * 所以只要有一个FontInit成功, SetTextDetail最终就返回成功
             */
            iRet = 0;
        }
        else
        {
            DelFontOprFrmEncoding(g_ptEncodingOprForFile, ptFontOpr);
        }
        ptFontOpr = ptTmp;
    }
    return iRet;
}
(5)选择设置显示器函数:
int SelectAndInitDisplay(char *pcname)
{
    int iError;
    g_ptDispOpr = GetDispOpr(pcname);
    /* 这个函数根据函数的参数pcname来获取相应的显示器,并返回一个DispOpr结构体 */
    
    if (!g_ptDispOpr)
    {
        return -1;
    }

    iError = g_ptDispOpr->DeviceInit();
    /* 调用返回的结构体里面的DeviceInit函数来进行显示器设备的初始化 */
    return iError;
}
(6)X方向增加判断函数:
int IncLcdX (int iX)
{
    if (iX + 1 < g_ptDispOpr->iXres)
        return (iX + 1);
    else
        return 0;    
}

这个是x方向位移增加判断函数,在显示的时候,如果下一个字符已经超出LCD的边界,那么我们不应直接显示这个字符,而应该换行显示,这个IncLcdX函数非常巧妙。如果iX + 1 < g_ptDispOpr->iXres(LCD的x方向的最大值)的话,函数返回iX + 1,如果超出LCD的x方向的最大值的话,则返回0。这个函数先判断再返回。
(7)Y方向增加判断函数:
int IncLcdY (int iY)
{
    if (iY + g_dwFontSize < g_ptDispOpr->iYres)
        return (iY + g_dwFontSize);
    else
        return 0;
}
同理,这个函数是y方向的增加判断函数,在x方向,增量为1,在y方向上面,增量就是g_dwFontSize,也就是所设置的字体大小。
(8)重新计算字体位置函数:
int RelocateFontPos(PT_FontBitMap ptFontBitMap)
{
    int iLcdY;
    int iDeltaX;
    int iDeltaY;

    /* 这个函数应该是为了防止字体设置过大,比如,字体设置为100,获取的位图Y方向的最大值已     * 经超过LCD显示器Y方向的最大值的话,就直接返回-1,不再显示
     */
    if (ptFontBitMap->iYMax > g_ptDispOpr->iYres)
        return -1;

    /* 如果位图X方向的最大值超出LCD显示器的最大值的话,就换行显示,换行的时候需要判断Y方     * 向是否满页,用IncLcdY函数来判断显示
     */
    if (ptFontBitMap->iXMax > g_ptDispOpr->iXres)
    {
        iLcdY = IncLcdY(ptFontBitMap->iCurOriginY);
        if (iLcdY == 0) /* 说明满页了 */
        {
            return -1;
        }
        else
        {
            iDeltaX = 0 - ptFontBitMap->iCurOriginX;
            iDeltaY = iLcdY - ptFontBitMap->iCurOriginY;

            ptFontBitMap->iCurOriginX += iDeltaX;
            ptFontBitMap->iCurOriginY += iDeltaY;

            ptFontBitMap->iNextOriginX += iDeltaX;
            ptFontBitMap->iNextOriginY += iDeltaY;

            ptFontBitMap->iXLeft += iDeltaX;
            ptFontBitMap->iXMax += iDeltaX;

            ptFontBitMap->iYTop += iDeltaY;
            ptFontBitMap->iYMax += iDeltaY;

            return 0;
        }
    }
    return 0;
}

(9)显示一个字:

int ShowOneFont(PT_FontBitMap ptFontBitMap)
{
    int x;
    int y;
    unsigned char ucByte = 0;
    int i = 0;
    int bit;

    if (ptFontBitMap->iBpp == 1)
    {
        for (y = ptFontBitMap->iYTop; y < ptFontBitMap->iYMax; y++)
        {
            i = (y - ptFontBitMap->iYTop) * ptFontBitMap->iPitch;
            for (x = ptFontBitMap->iXLeft, bit = 7; x < ptFontBitMap-                                                >iXMax; x++)
            {
                if (bit == 7)
                {
                    ucByte = ptFontBitMap->pucBuffer[i++];
                }

                if (ucByte & (1<<bit))
                {
                    g_ptDispOpr->ShowPixel(x, y, COLOR_FOREGROUND);
                }
                else
                {
                    g_ptDispOpr->ShowPixel(x, y, 0);
                }
                bit--;

                if (bit == -1)
                {
                    bit = 7;
                }
            }
        }
    }
    /* 上面一段的解释我用一张图代替了,用图解释比较清楚 */
    else if (ptFontBitMap->iBpp == 8)
    {
        for (y = ptFontBitMap->iYTop; y < ptFontBitMap->iYMax; y++)
            for (x = ptFontBitMap->iXLeft; x < ptFontBitMap->iXMax; x++)
            {
                if (ptFontBitMap->pucBuffer[i++])
                g_ptDispOpr->ShowPixel(x, y, COLOR_FOREGROUND);
            }
    }
    /* 如果bpp==8的话,说明bit per pixel = 8,即1字节=1像素。每一个pucBuffer[i]即     * 代表一个像素,直接用ShowPixel来描画即可。 */

    else
    {
        DBG_PRINTF("ShowOneFont error! cannot support %d bpp!\n",                                             ptFontBitMap->iBpp);
        return -1;
    }
    return 0;
}


(10)显示一页函数:
int ShowOnePage (unsigned char *pucTextFileMemCurPos)
{
    int iLen;
    int iError;
    unsigned char *pucBufStart;
    unsigned int dwCode;
    PT_FontOpr ptFontOpr;
    T_FontBitMap tFontBitMap;

    int bHasNotClrScreen = 1;
    int bHasGetCode = 0;
    
    tFontBitMap.iCurOriginX = 0;
    tFontBitMap.iCurOriginY = g_dwFontSize;
    pucBufStart = pucTextFileMemCurPos;  /* 圈1 */

    while (1)
    {
        iLen = g_ptEncodingOprForFile->GetCodeFrmBuf(pucBufStart,                                     g_pucTextFileMemEnd, &dwCode);
        /* 一次GetCodeFrmBuf只能获得dwCode大小的编码,所以取一次,只能获得一个字符,         * 所以这个函数用一个while(1)循环,不断地取,直到满足的条件才退出。
         */
        if (iLen == 0)
        {
            /* 文件结束 */
            if (!bHasGetCode)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        bHasGetCode = 1;

        pucBufStart += iLen;

        /* 有些文本, \n\r两个一起才表示回车换行
         * 碰到这种连续的\n\r, 只处理一次*/
        if (dwCode == '\n')
        {
            g_pucLcdNextPosAtFile = pucBufStart; /* 圈2 */
            
            /* 回车换行 */
            tFontBitMap.iCurOriginX = 0;
            tFontBitMap.iCurOriginY = IncLcdY(tFontBitMap.iCurOriginY);
            /* 回车换行就是x不变,y增加1,y增加的话用IncLcdY这个增加判断函数 */
            if (0 == tFontBitMap.iCurOriginY)
            {
                /* 显示完当前一屏了 */
                return 0;
            }
            else
            {
                continue;
            }
        }
        else if (dwCode == '\r')
        {
            continue;
        }
        else if (dwCode == '\t')
        {
            /* TAB键用一个空格代替 */
            dwCode = ' ';
        }

        DBG_PRINTF("dwCode = 0x%x\n", dwCode);
        
        ptFontOpr = g_ptEncodingOprForFile->ptFontOprSupportedHead;
        /* 对于一种编码方式,可以用一种或几种字体来显示,这些字体就在                      * g_ptEncodingOprForFile->ptFontOprSupportedHead这个链表中,从这个链表         * 中一一取出试验,来获取字体的位图。
         */
        while (ptFontOpr)
        {
            iError = ptFontOpr->GetFontBitmap(dwCode, &tFontBitMap);
            /* 这个函数成功返回0,失败返回-1 */
            if (0 == iError)
            {
                if (RelocateFontPos(&tFontBitMap))
                {
                    /* 剩下的LCD空间不能满足显示这个字符 */
                    return 0;
                }

                if (bHasNotClrSceen)
                {
                    /* 首先清屏
                    g_ptDispOpr->CleanScreen(COLOR_BACKGROUND);
                    bHasNotClrSceen = 0;
                }
                /* 显示一个字符 */
                if (ShowOneFont(&tFontBitMap))
                {
                    return -1;
                }
                /* 更新下一个字符的显示位置 */
                tFontBitMap.iCurOriginX = tFontBitMap.iNextOriginX;
                tFontBitMap.iCurOriginY = tFontBitMap.iNextOriginY;
                g_pucLcdNextPosAtFile = pucBufStart;  /* 圈3 */

                /* 继续取出下一个编码来显示 */
                break;
            }
            ptFontOpr = ptFontOpr->ptNext;
        }        
    }

    return 0;
}

可以总结ShowOnePage的过程:
while(1)
{
    1)GetCideFrmBuf
    2)GetFontBitMap
    3)重新计算位置
    4)显示
}
我用红色字体显示pucBufStart在这个函数中的位置,根据这个变量的变化,我们可以屡清很多关系:
1)解释/*圈1*/:pucBufStart这个参数是指从内存中的哪个地方来取值,用于GetCodeFrmBuf()函数的第一个参数,它的初始值是ShowOnePage()函数的参数,而这个参数是从ShowNextPage()中传过来的,所以pucBufStart = g_pucLcdFirstPosAtFile = g_pucTextFileMem + g_ptEncodingOprForFile->iHeadLen(这个是在OpenTextfile中确定的)
2)解释/*圈2*/:iLen是GetCodeFrmBuf()函数的返回值,pucBufStart += iLen;
g_pucLcdNextPosAtFile这个参数是值LCD上显示的下一个字符编码在内存中的位置,注意到/*圈2*/下面有一个continue,退出本次while循环,即如果获得的编码是'\n'字符,x不变,y增加1,然后就不再显示这个字符,直接换行就可以了(回车),但是还要记录下一个字符在内存中的位置,所以有/*圈2*/语句。
3)如果程序继续执行,从内存中取编码,获取位图,显示,显示完一个字符以后,需要用/*圈3*/语句来记录下一个字符在内存中的位置。
4)注意,ShowOnePage()这个函数,其实是一个字符一个字符来处理显示的,也就是说,会经历很多次while()循环,除非文件结束或LCD不能满足显示字符的条件(即满屏了),这时候,pucBufStart参数记录的是lcd下一页第一个字符在内存中的位置,也即g_pucLcdNextPosAtFile这个参数(因为他俩相同),在ShowNextPage()函数中赋给pucLcdNextPageFirstPosAtFile这个参数。
(11)记录页面函数:
static void RecordPage(PT_PageDesc ptPageNew)
{
    PT_PageDesc ptPage;
    if (!g_ptPages)
    {
        g_ptPages = ptPageNew;
    }
    else
    {
        ptPage = g_ptPages;
        while (ptPage->ptNextPage)
        {
            ptPage = ptPage->ptNextPage;
        }
        ptPage->ptNextPage = ptPageNew;
        ptPage->ptPrePage = ptPage;
    }
}
这个函数是链表操作的普通操作,将ptPageNew这个结构体添加到g_ptPages这个链表中,重要的是这样做的目的,是为了以后方便上下翻页。
(12)显示下一页函数:
int ShowNextPage (void)
{
    int iError;
    PT_PageDesc ptPage;
    unsigned char *pucTextFileMemCurPos;

    if (g_ptCurPage) /* g_ptCurPage初始值为NULL,第一次执行这个函数不会执行这句 */
    {
        pucTextFileMemCurPos = g_ptCurPage->pucLcdNextPageFirstPosAtFile;
    }
    else
    {
        pucTextFileMemCurPos = g_pucLcdFirstPosAtFile;
        /* g_pucLcdFirstPosAtFile这个参数在OpenTextFile里面进行了设置 */
    }

    iError = ShowOnePage(pucTextFileMemCurPos);
    if (iError == 0) /* success to show ont page */
    {
        /* 第一次调用ShowNextPage时不会执行这一步 */
        if (g_ptCurPage && g_ptCurPage->ptNextPage)
        {
            g_ptCurPage = g_ptCurPage->ptNextPage;
            return 0;
        }

/* 执行这一步的目的是想执行一次ShowNextPage生成一个ptPage结构体,包含
 * pucLcdFirstPosAtFile和pucLcdNextPageFirstPosAtFile等信息,同时将ptPage赋值给
 * g_ptCurPage。这样再次调用ShowNextPage()函数时,就可以使用这些信息。
 * 同时调用RecordPage()这个函数,将每一页都加入链表(g_ptPages)中,这样这个链表中就有每一
 * 页的一些信息,比如显示了1~10页,现在返回到第3页,输入n显示下一页,函数就会执行上面if
 * (g_ptCurPage)和if (g_ptCurPage && g_ptCurPage->ptNextPage)两个if语句。
 */
        ptPage = malloc(sizeof(T_PageDesc));
        if (ptPage)
        {
            /* 初始化ptPage */
            ptPage->pucLcdFirstPosAtFile = pucTextFileMemCurPos;
            ptPage->pucLcdNextPageFirstPosAtFile = g_pucLcdNextPosAtFile;
            ptPage->ptPrePage = NULL;
            ptPage->ptNextPage = NULL;
            g_ptCurPage = ptPage;
            RecordPage(ptPage);
            return 0;
        }
        else
        {
            return -1;
        }
    }
    return iError;
}
阅读(1699) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~