📄 font.cc
字号:
//// Copyright (c) 2005 by Istv醤 V醨adi//// This file is part of dxr3Player, a DVD player written specifically // for the DXR3 (aka Hollywood+) decoder card, but now handles other// hardware as well. These files contain a (mostly) user-space driver // for the Unichrome board found on Via's EPIA motherboards.//// The information for implementing this driver has been gathered// from the following sources://// - The DirectFB Unichrome driver// Copyright (c) 2003 Andreas Robinson, All rights reserved.//// - Andreas Robinson's MPEG-2 decoder for the Unichrome board.// Copyright (c) 2003 Andreas Robinson, All rights reserved.//// - Via's Unichrome Framebuffer driver// Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.// Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.// 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 2 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, write to the Free Software// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA//------------------------------------------------------------------------------#include "Font.h"#include "Unichrome.h"#include "Window.h"#include "MemoryBlock.h"#include "util/FileReader.h"#include "util/FileWriter.h"#include "util/Log.h"//------------------------------------------------------------------------------using unichrome::Font;//------------------------------------------------------------------------------Font::Chunk::Chunk(Chunk* next, size_t numChars, size_t width, size_t height) : next(next), numChars(numChars), width(width), height(height), location(HOST_MEMORY), buffer(new unsigned char[width*height]){ memset(buffer, 0, width*height);} //------------------------------------------------------------------------------Font::Chunk::Chunk(Chunk* next, size_t numChars, Unichrome& unichrome, FileReader& reader, unsigned /*version*/) : next(next), numChars(numChars), width(reader.read8()), height(reader.read8()), location(BOARD_MEMORY){ memoryBlock = unichrome.allocateMemoryBlock(width*height); reader.read(const_cast<void*>(memoryBlock->getBuffer()), width*height);// printf("Read chunk of size %ux%u containining %u characters\n",// width, height, numChars);}//------------------------------------------------------------------------------Font::Chunk::~Chunk(){ switch(location) { case HOST_MEMORY: delete[] buffer; break; case BOARD_MEMORY: delete memoryBlock; break; default: assert(0); } delete next;}//------------------------------------------------------------------------------volatile unsigned char* Font::Chunk::getBuffer(){ switch(location) { case HOST_MEMORY: return buffer; break; case BOARD_MEMORY: return memoryBlock->getBuffer8(); break; default: assert(0); }}//------------------------------------------------------------------------------void Font::Chunk::setSource(){ assert(location==BOARD_MEMORY); memoryBlock->setSource(width);}//------------------------------------------------------------------------------void Font::Chunk::write(FileWriter& writer){ assert(location==HOST_MEMORY); writer.write8(numChars); writer.write8(width); writer.write8(height); writer.write(const_cast<unsigned char*>(getBuffer()), width*height);}//------------------------------------------------------------------------------//------------------------------------------------------------------------------Font::Glyph::Glyph(Glyph* next, char code, Chunk* chunk, size_t offset, size_t width, size_t height, ssize_t left, ssize_t top, ssize_t advance) : next(next), code(code), chunk(chunk), offset(offset), width(width), height(height), left(left), top(top), advance(advance){} //------------------------------------------------------------------------------Font::Glyph::Glyph(Glyph* next, Chunk* chunk, FileReader& reader, unsigned /*version*/) : next(next), code(reader.readS8()), chunk(chunk), offset(reader.read8()), width(reader.read8()), height(reader.read8()), left(reader.readS8()), top(reader.readS8()), advance(reader.readS8()){// printf("Read glyph %04x: offset=%u, width=%u, height=%u, left=%d, top=%d\n",// code, offset, width, height, left, top);} //------------------------------------------------------------------------------Font::Glyph::~Glyph(){ delete next;}//------------------------------------------------------------------------------void Font::Glyph::setPixel(size_t x, size_t y, bool bit){ size_t bufferOffset = (offset+x)/8 + y * chunk->width; size_t bufferShift = 7 - ( (offset+x)%8 ); if (bit) chunk->getBuffer()[bufferOffset] |= 1<<bufferShift; else chunk->getBuffer()[bufferOffset] &= ~(1<<bufferShift);}//------------------------------------------------------------------------------size_t Font::Glyph::blit(Window& window, size_t x, size_t y, bool transparent){ if (width==0 || height==0) return x; chunk->setSource(); window.blit(offset, 0, width, height, x + left, y - top, transparent ? Window::BLIT_MONO_TRANSPARENT_COPY : Window::BLIT_MONO_COPY); return x + advance;}//------------------------------------------------------------------------------void Font::Glyph::write(FileWriter& writer){ writer.writeS8(code); writer.write8(offset); writer.write8(width); writer.write8(height); writer.writeS8(left); writer.writeS8(top); writer.writeS8(advance);}//------------------------------------------------------------------------------//------------------------------------------------------------------------------const char Font::magic[4] = { 'D', '3', 'P', 'F' };//------------------------------------------------------------------------------inline size_t Font::char2Index(char code){ return static_cast<unsigned char>(code);}//------------------------------------------------------------------------------Font::Font() : firstChunk(0), firstGlyph(0), maxTop(-1000), maxBottom(1000){ memset(glyphTable, 0, sizeof(glyphTable));}//------------------------------------------------------------------------------Font::Font(Unichrome& unichrome, FILE* file) : maxTop(-1000), maxBottom(1000){ init(unichrome, file);}//------------------------------------------------------------------------------Font::Font(Unichrome& unichrome, const char* name, const char* directory) : maxTop(-1000), maxBottom(1000){ memset(glyphTable, 0, sizeof(glyphTable)); char fileName[256]; if (directory==0) { snprintf(fileName, sizeof(fileName), "%s", name); } else { snprintf(fileName, sizeof(fileName), "%s/%s", directory, name); } FILE* file = fopen(fileName, "rb"); if (file==0) { Log::fatal("unichrome::Font::Font: cannot open font file %s\n", fileName); abort(); } init(unichrome, file); fclose(file);}//------------------------------------------------------------------------------Font::~Font(){ delete firstGlyph; delete firstChunk;}//------------------------------------------------------------------------------void Font::startChunk(size_t numChars, size_t width, size_t height){ firstChunk = new Chunk(firstChunk, numChars, width, height);}//------------------------------------------------------------------------------void Font::startGlyph(char code, size_t offset, size_t width, size_t height, ssize_t top, ssize_t left, ssize_t advance) { assert(firstChunk!=0); size_t index = char2Index(code); assert(glyphTable[index]==0); firstGlyph = new Glyph(firstGlyph, code, firstChunk, offset, width, height, top, left, advance); glyphTable[index] = firstGlyph; if (top>maxTop) maxTop = top; ssize_t bottom = top - height; if (bottom<maxBottom) maxBottom = bottom;}//------------------------------------------------------------------------------void Font::setGlyphPixel(size_t x, size_t y, bool bit){ assert(firstGlyph!=0); firstGlyph->setPixel(x, y, bit);}//------------------------------------------------------------------------------inline Font::Glyph* Font::findGlyph(char code){ return glyphTable[char2Index(code)];}//------------------------------------------------------------------------------size_t Font::displayCharacter(Window& window, size_t x, size_t y, char code, bool transparent){ Glyph* glyph = findGlyph(code); if (glyph==0) return x; if (code==32 && glyph->width==0) { glyph = findGlyph('-'); return (glyph==0) ? x+5 : x+glyph->width; } else return glyph->blit(window, x, y, transparent);}//------------------------------------------------------------------------------size_t Font::displayText(Window& window, size_t x, size_t y, const char* text, bool transparent){ while( *text!='\0' ) { x = displayCharacter(window, x, y, *text, transparent); ++text; } return x;}//------------------------------------------------------------------------------void Font::displayTextAround(Window& window, size_t x, size_t y, const char* text, bool transparent){ size_t width, height; ssize_t left, top; getDimensions(text, width, height, left, top); x -= width / 2; y -= height / 2; y += top; displayText(window, x, y, text, transparent);}//------------------------------------------------------------------------------void Font::getDimensions(const char* text, size_t& width, size_t& height, ssize_t& left, ssize_t& top){ width = 0; height = 0; left = 0; top = 0; ssize_t maxTop = 0; ssize_t minBottom = 0; while( *text!='\0' ) { Glyph* glyph = findGlyph(*text); if (glyph!=0) { if (width==0) { left = glyph->left; } if (*text==' ' && glyph->advance==0) { glyph = findGlyph('-'); width += (glyph==0) ? 5 : glyph->advance; } else { width += glyph->advance; if (glyph->top > maxTop) { maxTop = glyph->top; } ssize_t bottom = glyph->top - glyph->height; if ( bottom<minBottom ) { minBottom = bottom; } } } ++text; } top = maxTop; height = maxTop + 1 - minBottom;}//------------------------------------------------------------------------------size_t Font::getHeight(ssize_t& maxTop, ssize_t& maxBottom, const char* charset){ if (charset==0) { maxTop = this->maxTop; maxBottom = this->maxBottom; } else { maxTop = -1000; maxBottom = 1000; while(*charset!='\0') { Glyph* glyph = findGlyph(*charset); if (glyph!=0) { if (glyph->top>maxTop) maxTop = glyph->top; ssize_t bottom = glyph->top - glyph->height; if (bottom<maxBottom) maxBottom = bottom; } ++charset; } } return maxTop + 1 - maxBottom;}//------------------------------------------------------------------------------void Font::write(FILE* f){ fwrite(magic, sizeof(magic), 1, f); FileWriter writer(f); writer.write32(currentVersion); Chunk* chunk = firstChunk; Glyph* glyph = firstGlyph; while(chunk!=0) { assert(glyph->chunk==chunk); chunk->write(writer); while(glyph!=0 && glyph->chunk==chunk) { glyph->write(writer); glyph = glyph->next; } chunk=chunk->next; } assert(glyph==0);}//------------------------------------------------------------------------------void Font::init(Unichrome& unichrome, FILE* file){ firstChunk = 0; firstGlyph = 0; memset(glyphTable, 0, sizeof(glyphTable)); char magicBuffer[sizeof(magic)]; fread(magicBuffer, sizeof(magicBuffer), 1, file); assert(memcmp(magic, magicBuffer, sizeof(magic))==0); FileReader reader(file); unsigned version = reader.read32(); uint8_t numChars; while(reader.read(numChars)) { firstChunk = new Chunk(firstChunk, numChars, unichrome, reader, version); for(size_t i = 0; i<numChars; ++i) { firstGlyph = new Glyph(firstGlyph, firstChunk, reader, version); size_t index = char2Index(firstGlyph->code); assert(glyphTable[index]==0); glyphTable[index] = firstGlyph; ssize_t top = firstGlyph->top; if (top>maxTop) maxTop = top; ssize_t bottom = top - firstGlyph->height; if (bottom<maxBottom) maxBottom = bottom; } }}//------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -