/*---------------------------------------------------------------------------* Project: NintendoWare File: font_ArchiveFontBase.cpp Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo and/or its licensed developers and are protected by national and international copyright laws. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. The content herein is highly confidential and should be handled accordingly. $Revision: 31311 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include #include #include #include namespace nw { namespace font { const char ArchiveFontBase::LOAD_GLYPH_ALL[1] = ""; /* ======================================================================= ArchiveFontBase public ======================================================================== */ /* ------------------------------------------------------------------------ コンストラクタ/デストラクタ ------------------------------------------------------------------------ */ ArchiveFontBase::ArchiveFontBase() : m_pGlyphIndexAdjustArray(NULL) { } ArchiveFontBase::~ArchiveFontBase() { } /* ------------------------------------------------------------------------ Fontクラスオーバーライド ------------------------------------------------------------------------ */ const CharWidths ArchiveFontBase::GetCharWidths(CharCode c) const { GlyphIndex index = GetGlyphIndex(c); // GetCharWidthsFromIndex に渡すグリフインデックスは補正前のインデックスだが // シートが存在しない場合は代替文字の文字幅を取得しなければならないため // AdjustIndex を使ってシートが存在するかテストする if (AdjustIndex(index) == GLYPH_INDEX_NOT_FOUND) { index = GetFINF()->alterCharIndex; } return GetCharWidthsFromIndex(index); } bool ArchiveFontBase::HasGlyph(CharCode c) const { GlyphIndex index = FindGlyphIndex(c); if (index != GLYPH_INDEX_NOT_FOUND ) { return ( GLYPH_INDEX_NOT_FOUND != AdjustIndex(index) ); } return false; } /* ======================================================================= ArchiveFontBase protected ======================================================================== */ /* ------------------------------------------------------------------------ 構築/破棄 ------------------------------------------------------------------------ */ void ArchiveFontBase::SetResourceBuffer( void* pUserBuffer, FontInformation* pFontInfo, u16* pAdjustTable ) { NN_POINTER_ASSERT( pUserBuffer ); NN_POINTER_ASSERT( pFontInfo ); NN_POINTER_ASSERT( pAdjustTable ); NN_ASSERT( m_pGlyphIndexAdjustArray == NULL ); ResFontBase::SetResourceBuffer(pUserBuffer, pFontInfo); m_pGlyphIndexAdjustArray = pAdjustTable; GenTextureNames(); } void* ArchiveFontBase::RemoveResourceBuffer() { m_pGlyphIndexAdjustArray = NULL; return ResFontBase::RemoveResourceBuffer(); } /* ------------------------------------------------------------------------ グリフインデックス ------------------------------------------------------------------------ */ u16 ArchiveFontBase::AdjustIndex(u16 index) const { const FontTextureGlyph& tg = *GetFINF()->pGlyph; const int glyphsPerSheet = internal::GetCellsInASheet(tg); const int sheetNo = index / glyphsPerSheet; const u16 adjustor = m_pGlyphIndexAdjustArray[sheetNo]; return (adjustor == ADJUST_OFFSET_SHEET_NOT_LOADED) ? GLYPH_INDEX_NOT_FOUND: static_cast(index - adjustor); } /* ------------------------------------------------------------------------ GLGRブロック走査 ------------------------------------------------------------------------ */ bool ArchiveFontBase::IncludeName( const char* nameList, const char* name ) { const u32 nameLen = std::strlen(name); const char* found = nameList - 1; // return $nameList =~ m/(^|, *)$name *(,|$)/; for (;;) { found = std::strstr(found+1, name); if (found == NULL) { return false; } // 先頭か? if (found != nameList) { // 先頭でなくても直前にデリミタがあればOK const char* pos = found - 1; while (nameList < pos && *pos == ' ') { pos--; } if (*pos != ',') { continue; } } // 次のデリミタを探す const char* delimitor = std::strchr(found, ','); u32 foundLen; // 見つかった文字列の長さを求める if (delimitor != NULL) { foundLen = static_cast(delimitor - found); } else { foundLen = std::strlen(found); } // 長さが同じかその末尾に空白が加わっただけなら発見 { const char* pos = found + nameLen; const char* end = found + foundLen; while (pos < end && *pos == ' ') { pos++; } if (pos == end) { return true; } } } // ここには届きません。 // return false; } bool ArchiveFontBase::IsValidResource( const void* bfnt, u32 dataSize ) { NW_FONT_MIN_ASSERT( dataSize, sizeof(ut::BinaryFileHeader) + sizeof(ut::BinaryBlockHeader) + reinterpret_cast(reinterpret_cast(0)->nameOffsets)); const ut::BinaryFileHeader* fileHeader = reinterpret_cast(bfnt); // バイナリファイルヘッダをチェック if (! IsValidBinaryFile(fileHeader, BINFILE_SIG_FONTA, FONT_FILE_VERSION, 2)) { // サポートしていない形式 NN_LOG("Invalid font resource."); return false; } const FontGlyphGroupsBlock* ggBlock = reinterpret_cast(fileHeader + 1); // 先頭ブロックのタイプをチェック if (ggBlock->header.kind != BINBLOCK_SIG_GLGR) { NN_LOG("invalid block header(%c%c%c%c) expect(%c%c%c%c)", (ggBlock->header.kind >> 24) & 0xFF, (ggBlock->header.kind >> 16) & 0xFF, (ggBlock->header.kind >> 8) & 0xFF, (ggBlock->header.kind >> 0) & 0xFF, (BINBLOCK_SIG_GLGR >> 24) & 0xFF, (BINBLOCK_SIG_GLGR >> 16) & 0xFF, (BINBLOCK_SIG_GLGR >> 8) & 0xFF, (BINBLOCK_SIG_GLGR >> 0) & 0xFF ); return false; } // 先頭ブロックを全て読み込めているかチェック if (sizeof(ut::BinaryFileHeader) + ggBlock->header.size > dataSize) { NN_LOG("First stream block must include all of GLGP block. " "Please use laerger stream buffer."); return false; } return true; } /* ------------------------------------------------------------------------ 構築処理 ------------------------------------------------------------------------ */ ArchiveFontBase::ConstructResult ArchiveFontBase::RequestData( ArchiveFontBase::ConstructContext* pContext, ArchiveFontBase::CachedStreamReader* pStream, u32 size ) { pContext->streamOffset += pStream->GetOffset(); bool bSuccess = pStream->RequestData(pContext, size); return bSuccess ? CONSTRUCT_MORE_DATA: CONSTRUCT_ERROR; } ArchiveFontBase::ConstructResult ArchiveFontBase::ConstructOpDispatch( ArchiveFontBase::ConstructContext* pContext, ArchiveFontBase::CachedStreamReader* pStream ) { if (! pContext->HasMoreBlock()) { return CONSTRUCT_FINISH; } const u32 requireSize = sizeof(ut::BinaryBlockHeader); if (pStream->GetRemain() < requireSize) { return RequestData(pContext, pStream, requireSize); } pStream->CopyTo(&pContext->header, sizeof(pContext->header)); switch (pContext->header.kind) { case BINBLOCK_SIG_GLGR: pContext->op = ConstructContext::ANALYZE_GLGR; break; case BINBLOCK_SIG_FINF: pContext->op = ConstructContext::ANALYZE_FINF; break; case BINBLOCK_SIG_CMAP: pContext->op = ConstructContext::ANALYZE_CMAP; break; case BINBLOCK_SIG_CWDH: pContext->op = ConstructContext::ANALYZE_CWDH; break; case BINBLOCK_SIG_TGLP: pContext->op = ConstructContext::ANALYZE_TGLP; break; default: NN_ASSERTMSG(false, "The font has unknown block(%c%c%c%c)", (pContext->header.kind >> 24) & 0xFF, (pContext->header.kind >> 16) & 0xFF, (pContext->header.kind >> 8) & 0xFF, (pContext->header.kind >> 0) & 0xFF ); pContext->op = ConstructContext::FATAL_ERROR; return CONSTRUCT_ERROR; } // カレントブロック番号を次に進める pContext->NextBlock(); // ブロックデータの先頭は 4 byte アライメントが必要 pContext->Align(4); return CONSTRUCT_CONTINUE; } ArchiveFontBase::ConstructResult ArchiveFontBase::ConstructOpAnalyzeFileHeader( ArchiveFontBase::ConstructContext* pContext, ArchiveFontBase::CachedStreamReader* pStream ) { const u32 requireSize = sizeof(ut::BinaryFileHeader); if (pStream->GetRemain() < requireSize) { return RequestData(pContext, pStream, requireSize); } if (pContext->GetRemain() < requireSize) { // 出力先バッファのサイズが足らなかった NN_LOG("buffer size too small"); return CONSTRUCT_ERROR; } // 一時的にコピー // CopyTo(pContext, ...) だとバッファ位置が進んでしまうので CopyTo(void*, ...) を使う pStream->CopyTo(pContext->GetCurrentPtr(), requireSize); pContext->op = ConstructContext::DISPATCH; return CONSTRUCT_CONTINUE; } ArchiveFontBase::ConstructResult ArchiveFontBase::ConstructOpAnalyzeGLGR( ArchiveFontBase::ConstructContext* pContext, ArchiveFontBase::CachedStreamReader* pStream ) { u8* pTempFileHead; u8* pTempGLGRTail; // GLGR ブロックの確保 { const ut::BinaryFileHeader& header = *pContext->GetCurrentPtr(); const u32 requireSize = pContext->header.size - sizeof(ut::BinaryBlockHeader); if (header.signature != BINFILE_SIG_FONTA) { // バイナリファイルヘッダがロードされていない or これはフォントリソースではない NN_LOG("invalid font binary file."); return CONSTRUCT_ERROR; } if (pStream->GetRemain() < requireSize) { return RequestData(pContext, pStream, requireSize); } if (pContext->GetRemain() < requireSize) { // 出力先バッファのサイズが足らなかった NN_LOG("buffer size too small"); return CONSTRUCT_ERROR; } // GLGR ブロックを一時的にコピー // CopyTo(pContext, ...) だとバッファ位置が進んでしまうので CopyTo(void*, ...) を使う const u32 infoSize = sizeof(ut::BinaryFileHeader) + pContext->header.size; pTempFileHead = pContext->GetCurrentPtr(); u8* blockHeaderPos = pTempFileHead + sizeof(ut::BinaryFileHeader); u8* blockBodyPos = blockHeaderPos + sizeof(ut::BinaryBlockHeader); pTempGLGRTail = blockHeaderPos + pContext->header.size; std::memcpy(blockHeaderPos, &pContext->header, sizeof(ut::BinaryBlockHeader)); pStream->CopyTo(blockBodyPos, requireSize); //---- 妥当性のチェック if (! IsValidResource(pTempFileHead, infoSize)) { return CONSTRUCT_ERROR; } } u16 numSheet; u16 numGlyphsPerSheet; u32 numBlock; u16* pTempAdjustArray; u32 sizeAdjustTable; //---- グリフインデックス調整テーブルの構築 { FontGlyphGroupsAcs gg(pTempFileHead); numSheet = gg.GetNumSheet(); numGlyphsPerSheet = gg.GetNumGlyphsPerSheet(); numBlock = gg.GetNumBlock(); sizeAdjustTable = math::RoundUp(gg.GetNumSheet() * sizeof(u16), 4); // 4 バイトアライメント pTempAdjustArray = reinterpret_cast( math::RoundDown(reinterpret_cast(pTempFileHead + pContext->GetRemain() - sizeAdjustTable), 2)); if (pContext->GetRemain() < (pTempGLGRTail - pTempFileHead) + sizeAdjustTable) { // 出力先バッファのサイズが足らなかった NN_LOG("buffer size too small"); return CONSTRUCT_ERROR; } // 以下 AdjustTable を一時的にフラグ配列として使う。 // フラグを全て落とす。 for (int sheetNo = 0; sheetNo < gg.GetNumSheet(); ++sheetNo) { pTempAdjustArray[sheetNo] = 0; } // 使用するシートに対応するフラグを立てていく。 for (int setNo = 0; setNo < gg.GetNumSet(); ++setNo) { const char* setName = gg.GetSetName(setNo); if ( IsNullString(pContext->GetGlyphGroups()) || IncludeName(pContext->GetGlyphGroups(), setName) ) { for (int sheetNo = 0; sheetNo < gg.GetNumSheet(); ++sheetNo) { if (gg.IsUseSheet(setNo, sheetNo)) { pTempAdjustArray[sheetNo] = 1; } } } } // フラグを元に AdjustTable を構築する。 u16 adjust = 0; for (int sheetNo = 0; sheetNo < gg.GetNumSheet(); ++sheetNo) { u16 &entry = pTempAdjustArray[sheetNo]; if (entry == 1) { entry = adjust; } else { entry = 0xFFFF; adjust += gg.GetNumGlyphsPerSheet(); } } } // 以下では一時的にコピーした GLGR ブロックを破壊するので以降アクセスする事はできない。 // Context の構築 { u16* pTrueAdjustArray = pContext->GetCurrentPtr(); pContext->Advance(sizeAdjustTable); std::copy(pTempAdjustArray, pTempAdjustArray + numSheet, NW_CHECKED_ARRAY_ITERATOR(pTrueAdjustArray, numSheet)); pContext->SetGLGR( pTrueAdjustArray, numSheet, numGlyphsPerSheet, numBlock ); pContext->op = ConstructContext::DISPATCH; } return CONSTRUCT_CONTINUE; } ArchiveFontBase::ConstructResult ArchiveFontBase::ConstructOpAnalyzeFINF( ArchiveFontBase::ConstructContext* pContext, ArchiveFontBase::CachedStreamReader* /* pStream */ ) { // バイナリブロックヘッダはコピーしない u32 copySize = pContext->header.size - sizeof(ut::BinaryBlockHeader); if (pContext->GetRemain() < copySize) { // 出力先バッファのサイズが足らなかった NN_LOG("buffer size too small"); return CONSTRUCT_ERROR; } // コピータスク起動 pContext->pFINF = pContext->GetCurrentPtr(); pContext->SetupCopyTask(copySize); return CONSTRUCT_CONTINUE; } ArchiveFontBase::ConstructResult ArchiveFontBase::ConstructOpAnalyzeCMAP( ArchiveFontBase::ConstructContext* pContext, ArchiveFontBase::CachedStreamReader* /* pStream */ ) { // 前の CMAP ブロックまたは FINF ブロックのリンクを更新する FontCodeMap* pDstCMAP = pContext->GetCurrentPtr(); if (pContext->pPrevCMAP != NULL) { pContext->pPrevCMAP->pNext = pDstCMAP; } else { NN_POINTER_ASSERT( pContext->pFINF ); pContext->pFINF->pMap = pDstCMAP; } pContext->pPrevCMAP = pDstCMAP; // バイナリブロックヘッダはコピーしない u32 copySize = pContext->header.size - sizeof(ut::BinaryBlockHeader); if (pContext->GetRemain() < copySize) { // 出力先バッファのサイズが足らなかった NN_LOG("buffer size too small"); return CONSTRUCT_ERROR; } // データ本体のコピータスク pContext->SetupCopyTask(copySize); return CONSTRUCT_CONTINUE; } ArchiveFontBase::ConstructResult ArchiveFontBase::ConstructOpAnalyzeCWDH( ArchiveFontBase::ConstructContext* pContext, ArchiveFontBase::CachedStreamReader* /* pStream */ ) { // 前の CWDH ブロックまたは FINF ブロックのリンクを更新する FontWidth* pDstCWDH = pContext->GetCurrentPtr(); if (pContext->pPrevCWDH != NULL) { pContext->pPrevCWDH->pNext = pDstCWDH; } else { NN_POINTER_ASSERT(pContext->pFINF); pContext->pFINF->pWidth = pDstCWDH; } pContext->pPrevCWDH = pDstCWDH; // バイナリブロックヘッダはコピーしない u32 copySize = pContext->header.size - sizeof(ut::BinaryBlockHeader); if (pContext->GetRemain() < copySize) { // 出力先バッファのサイズが足らなかった NN_LOG("buffer size too small"); return CONSTRUCT_ERROR; } // データ本体のコピータスク pContext->SetupCopyTask(copySize); return CONSTRUCT_CONTINUE; } ArchiveFontBase::ConstructResult ArchiveFontBase::ConstructOpAnalyzeTGLP( ArchiveFontBase::ConstructContext* pContext, ArchiveFontBase::CachedStreamReader* pStream ) { const u32 requireSize = sizeof(FontTextureGlyph); const u32 copySize = sizeof(FontTextureGlyph); if (pStream->GetRemain() < requireSize) { return RequestData(pContext, pStream, requireSize); } if (pContext->GetRemain() < copySize) { // 出力先バッファのサイズが足らなかった NN_LOG("buffer size too small"); return CONSTRUCT_ERROR; } NN_POINTER_ASSERT(pContext->pFINF); // FINF ブロックのリンクを更新する pContext->pFINF->pGlyph = pContext->GetCurrentPtr(); // シート以外の部分をコピー pStream->CopyTo(pContext, sizeof(FontTextureGlyph)); // シートが圧縮されているかを取得 const bool bSheetCompressed = ((pContext->pFINF->pGlyph->sheetFormat & FONT_SHEET_FORMAT_COMPRESSED_FLAG) != 0); pContext->pFINF->pGlyph->sheetFormat &= FONT_SHEET_FORMAT_MASK; // シート数を更新 { u16 numLoadSheet = 0; for (int i = 0; i < pContext->GetNumSheets(); ++i) { if (pContext->IsRequireSheet(i)) { numLoadSheet++; } } pContext->pFINF->pGlyph->sheetNum = numLoadSheet; } // シートのストリーム内オフセットを取得 u32 sheetOffset = reinterpret_cast(pContext->pFINF->pGlyph->sheetImage); // シートにはアライメントが必要 pContext->Align(GlyphDataAlignment); pContext->pFINF->pGlyph->sheetImage = pContext->GetCurrentPtr(); // シートが圧縮されているかに応じて分岐 const ConstructContext::Operation nextOp = bSheetCompressed ? ConstructContext::PREPAIR_EXPAND_SHEET: ConstructContext::PREPAIR_COPY_SHEET; // シートのある位置までスキップ u32 streamOffset = pContext->streamOffset + pStream->GetOffset(); u32 skipSize = sheetOffset - streamOffset; pContext->SetupSkipTask(skipSize, nextOp); return CONSTRUCT_CONTINUE; } ArchiveFontBase::ConstructResult ArchiveFontBase::ConstructOpPrepairCopySheet( ArchiveFontBase::ConstructContext* pContext, ArchiveFontBase::CachedStreamReader* /* pStream */ ) { // 全てのシートに対して処理が終わっているか? if (! pContext->HasMoreSheet()) { pContext->op = ConstructContext::DISPATCH; return CONSTRUCT_CONTINUE; } const u32 copySize = pContext->pFINF->pGlyph->sheetSize; // ロードしなければならないシートか? if (pContext->IsRequireSheet()) { // ロードする if (pContext->GetRemain() < copySize) { NN_LOG("buffer size too small"); return CONSTRUCT_ERROR; } // コピー pContext->SetupCopyTask(copySize, ConstructContext::PREPAIR_COPY_SHEET); } else { // ロードしない pContext->SetupSkipTask(copySize, ConstructContext::PREPAIR_COPY_SHEET); } // カレントシート番号を更新 pContext->NextSheet(); return CONSTRUCT_CONTINUE; } ArchiveFontBase::ConstructResult ArchiveFontBase::ConstructOpPrepairExpandSheet( ArchiveFontBase::ConstructContext* pContext, ArchiveFontBase::CachedStreamReader* pStream ) { // 全てのシートに対して処理が終わっているか? if (! pContext->HasMoreSheet()) { pContext->op = ConstructContext::DISPATCH; return CONSTRUCT_CONTINUE; } u32 compSize; u32 huffHead; const u32 requireSize = sizeof(compSize) + sizeof(huffHead); if (pStream->GetRemain() < requireSize) { return RequestData(pContext, pStream, requireSize); } // 圧縮データサイズを読み込む pStream->CopyTo(&compSize, sizeof(compSize)); std::memcpy(&huffHead, pStream->Get(0), sizeof(huffHead)); // Get(0) はよくないがストリーム位置を移動させないため const u32 srcSize = compSize; const u32 dstSize = nn::cx::GetUncompressedSize(&huffHead); // ロードしなければならないシートか? if (pContext->IsRequireSheet()) { // ロードする if (pContext->GetRemain() < srcSize + sizeof(*pContext->GetUncompContext())) { NN_LOG("buffer size too small"); return CONSTRUCT_ERROR; } // データ展開 nn::cx::InitUncompContextHuffman( pContext->GetUncompContext(), pContext->GetCurrentPtr()); pContext->SetupExtendTask(srcSize, ConstructContext::PREPAIR_EXPAND_SHEET); // ExtendTask では出力バッファ位置が更新されないので // 展開されるサイズ分あらかじめ進めておく必要がある pContext->Advance(dstSize); } else { // ロードしない pContext->SetupSkipTask(srcSize, ConstructContext::PREPAIR_EXPAND_SHEET); } // カレントシート番号を更新 pContext->NextSheet(); return CONSTRUCT_CONTINUE; } ArchiveFontBase::ConstructResult ArchiveFontBase::ConstructOpCopy( ArchiveFontBase::ConstructContext* pContext, ArchiveFontBase::CachedStreamReader* pStream ) { const u32 requireSize = pStream->ManagedCopy(pContext); if (requireSize == 0) { // コピー終了 pContext->EndTask(); } else { // 更なるデータが必要 return RequestData(pContext, pStream, requireSize); } return CONSTRUCT_CONTINUE; } ArchiveFontBase::ConstructResult ArchiveFontBase::ConstructOpSkip( ArchiveFontBase::ConstructContext* pContext, ArchiveFontBase::CachedStreamReader* pStream ) { u32 skipSize = math::Min(pContext->TaskRemain(), pStream->GetRemain()); pStream->Advance(skipSize); pContext->TaskProceed(skipSize); if (pContext->TaskRemain() == 0) { // スキップ終了 pContext->EndTask(); } else { // スキップ継続 return RequestData(pContext, pStream, pContext->TaskRemain()); } return CONSTRUCT_CONTINUE; } ArchiveFontBase::ConstructResult ArchiveFontBase::ConstructOpExpand( ArchiveFontBase::ConstructContext* pContext, ArchiveFontBase::CachedStreamReader* pStream ) { NN_ASSERT(! pStream->HasBufData()); u32 extendSize = math::Min(pContext->TaskRemain(), pStream->GetRemain()); s32 remain = nn::cx::ReadUncompHuffman( pContext->GetUncompContext(), reinterpret_cast(pStream->Get(extendSize)), extendSize ); NN_ASSERT(remain >= 0); pContext->TaskProceed(extendSize); if (pContext->TaskRemain() == 0) { // 展開終了 NN_ASSERT(remain == 0); pContext->EndTask(); } else { // 更なるデータが必要 NN_ASSERT(remain != 0); return RequestData(pContext, pStream, pContext->TaskRemain()); } return CONSTRUCT_CONTINUE; } ArchiveFontBase::ConstructResult ArchiveFontBase::ConstructOpFatalError( ArchiveFontBase::ConstructContext* pContext, ArchiveFontBase::CachedStreamReader* /* pStream */ ) { pContext->op = ConstructContext::FATAL_ERROR; return CONSTRUCT_ERROR; } /* ======================================================================= CachedStreamReader ======================================================================== */ void ArchiveFontBase::CachedStreamReader::Init() { mStreamBegin = NULL; mStreamPos = NULL; mStreamEnd = NULL; mpTempStrmBuf = NULL; mpTempStrmBufPos = NULL; mpTempStrmBufEnd = NULL; mRequireSize = 0; } void ArchiveFontBase::CachedStreamReader::Attach( const void* stream, u32 streamSize ) { mStreamBegin = reinterpret_cast(stream); mStreamPos = mStreamBegin; mStreamEnd = mStreamBegin + streamSize; } u32 ArchiveFontBase::CachedStreamReader::GetRemain() const { return static_cast((mStreamEnd - mStreamPos) + (mpTempStrmBufEnd - mpTempStrmBufPos)); } void ArchiveFontBase::CachedStreamReader::Advance(u32 dx) { const u32 sizeTempStrm = mpTempStrmBufEnd - mpTempStrmBufPos; if (sizeTempStrm > dx) { mpTempStrmBufPos += dx; } else { mpTempStrmBufPos = mpTempStrmBufEnd; mStreamPos += (dx - sizeTempStrm); } } void ArchiveFontBase::CachedStreamReader::CopyTo( ArchiveFontBase::ConstructContext* pContext, u32 size ) { NN_ASSERT(pContext->GetRemain() >= size); CopyTo(pContext->GetCurrentPtr(), size); pContext->Advance(size); } void ArchiveFontBase::CachedStreamReader::CopyTo( void* buf, u32 size ) { NN_ASSERT(size <= GetRemain()); const u32 sizeTempStrm = mpTempStrmBufEnd - mpTempStrmBufPos; u8* buf8 = reinterpret_cast(buf); if (sizeTempStrm >= size) { std::memcpy(buf8, mpTempStrmBufPos, size); mpTempStrmBufPos += size; } else { const u32 streamCopySize = size - sizeTempStrm; std::memcpy(buf8, mpTempStrmBufPos, static_cast(sizeTempStrm)); std::memcpy(buf8 + sizeTempStrm, mStreamPos, streamCopySize); mpTempStrmBufPos = mpTempStrmBufEnd; mStreamPos += streamCopySize; } } void ArchiveFontBase::CachedStreamReader::MoveTo( void* buf, u32 size ) { NN_ASSERT(size <= GetRemain()); const u32 sizeTempStrm = mpTempStrmBufEnd - mpTempStrmBufPos; u8* buf8 = reinterpret_cast(buf); if (sizeTempStrm >= size) { std::memmove(buf8, mpTempStrmBufPos, size); mpTempStrmBufPos += size; } else { const u32 streamCopySize = size - sizeTempStrm; std::memmove(buf8, mpTempStrmBufPos, static_cast(sizeTempStrm)); std::memmove(buf8 + sizeTempStrm, mStreamPos, streamCopySize); mpTempStrmBufPos = mpTempStrmBufEnd; mStreamPos += streamCopySize; } } u32 ArchiveFontBase::CachedStreamReader::ManagedCopy(ArchiveFontBase::ConstructContext* pContext) { NN_ASSERT(! HasBufData()); u32 copySize = math::Min(static_cast(mStreamEnd - mStreamPos), pContext->TaskRemain()); std::memcpy(pContext->GetCurrentPtr(), mStreamPos, copySize); mStreamPos += copySize; pContext->Advance(copySize); pContext->TaskProceed(copySize); return pContext->TaskRemain(); } const void* ArchiveFontBase::CachedStreamReader::Get(u32 size) { NN_ASSERT(size <= GetRemain()); const void* p = mStreamPos; mStreamPos += size; return p; } bool ArchiveFontBase::CachedStreamReader::RequestData( ArchiveFontBase::ConstructContext* pContext, u32 size ) { // ストリームにはデータが足りない状態でなければならない NN_ASSERT(GetRemain() < size); if (GetRemain() == 0) { // ストリームデータが全くない場合はテンポラリバッファを作成しない mpTempStrmBuf = NULL; mpTempStrmBufPos = NULL; mpTempStrmBufEnd = NULL; mRequireSize = 0; } else { // テンポラリバッファに必要な空き領域があるかチェック if (pContext->GetRemain() < size * 2) { // 無ければエラー return false; } u8* tempBuf = pContext->GetCurrentPtr() + size; u32 curSize = GetRemain(); // 既にテンポラリバッファが作られている場合があるので CopyTo は使えない MoveTo(tempBuf, curSize); mpTempStrmBuf = tempBuf; mpTempStrmBufPos = mpTempStrmBuf; mpTempStrmBufEnd = mpTempStrmBuf + curSize; mRequireSize = size; } return true; } u32 ArchiveFontBase::CachedStreamReader::GetOffset() const { return static_cast((mStreamPos - mStreamBegin) + (mpTempStrmBufPos - mpTempStrmBuf)); } /* ======================================================================= ConstructContext ======================================================================== */ void ArchiveFontBase::ConstructContext::Init( void* outBuffer, u32 outBufferSize, const char* glyphGroups ) { streamReader.Init(); pGlyphGroups = glyphGroups; pGlyphIndexAdjustTable = NULL; targetBuffer = reinterpret_cast(outBuffer); targetBufferEnd = targetBuffer + outBufferSize; targetBufferCur = targetBuffer; extendContext = reinterpret_cast( math::RoundDown( reinterpret_cast(targetBufferEnd - sizeof(*extendContext)), 4 )); op2 = INVALID_OPERATION; opSize = 0; resNumBlock = 1; // GLGR ブロックに DISPATCH するために必要 currentBlock = 0; sheetIndex = 0; numSheets = 0; glyphsPerSheet = 0; streamOffset = 0; pFINF = NULL; pPrevCWDH = NULL; pPrevCMAP = NULL; op = INVALID_OPERATION; } void ArchiveFontBase::ConstructContext::SetGLGR( u16* pAdjustTable, u16 nSheets, u16 nPerSheet, u32 numBlock ) { pGlyphIndexAdjustTable = pAdjustTable; numSheets = nSheets; glyphsPerSheet = nPerSheet; resNumBlock = numBlock; } void ArchiveFontBase::ConstructContext::Finish( void** ppData, FontInformation** ppFontInfo, u16** ppAdjustTable ) { *ppData = targetBuffer; *ppAdjustTable = pGlyphIndexAdjustTable; *ppFontInfo = pFINF; } /* ======================================================================= FontGlyphGroupsAcs ======================================================================== */ ArchiveFontBase::FontGlyphGroupsAcs::FontGlyphGroupsAcs(const void* bfnt) { mpHeader = reinterpret_cast(bfnt); mpData = reinterpret_cast(mpHeader + 1); mSizeSheetFlags = sizeof(u32) * math::DivUp(mpData->body.numSheet, (u16)32); mSizeCWDHFlags = sizeof(u32) * math::DivUp(mpData->body.numCWDH, (u16)32); mSizeCMAPFlags = sizeof(u32) * math::DivUp(mpData->body.numCMAP, (u16)32); // FontGlyphGroups はヘッダでは中途半端に定義されているため // 正確なサイズを得るためにオフセットで計算する const u32 sizePreBlock = sizeof(ut::BinaryFileHeader) + sizeof(ut::BinaryBlockHeader); const u32 sizeStatic = reinterpret_cast(reinterpret_cast(0)->nameOffsets); const u32 sizeNameOffsets = sizeof(u16) * mpData->body.numSet; const u32 sizeSizeSheets = sizeof(u32) * mpData->body.numSheet; const u32 sizeSizeCWDH = sizeof(u32) * mpData->body.numCWDH; const u32 sizeSizeCMAP = sizeof(u32) * mpData->body.numCMAP; const u32 sizeUseSheets = mSizeSheetFlags * mpData->body.numSet; const u32 sizeUseCWDH = mSizeCWDHFlags * mpData->body.numSet; // const u32 sizeUseCMAP = mSizeCMAPFlags * numSet; const u32 offsetStatic = math::RoundUp(sizePreBlock, 2); const u32 offsetNameOffsets = math::RoundUp(offsetStatic + sizeStatic, 2); const u32 offsetSizeSheets = math::RoundUp(offsetNameOffsets+ sizeNameOffsets, 4); const u32 offsetSizeCWDH = math::RoundUp(offsetSizeSheets + sizeSizeSheets, 4); const u32 offsetSizeCMAP = math::RoundUp(offsetSizeCWDH + sizeSizeCWDH, 4); const u32 offsetUseSheets = math::RoundUp(offsetSizeCMAP + sizeSizeCMAP, 4); const u32 offsetUseCWDH = math::RoundUp(offsetUseSheets + sizeUseSheets, 4); const u32 offsetUseCMAP = math::RoundUp(offsetUseCWDH + sizeUseCWDH, 4); mpSizeSheetsArray = reinterpret_cast(ut::AddOffsetToPtr(mpHeader, offsetSizeSheets)); mpSizeCWDHArray = reinterpret_cast(ut::AddOffsetToPtr(mpHeader, offsetSizeCWDH)); mpSizeCMAPArray = reinterpret_cast(ut::AddOffsetToPtr(mpHeader, offsetSizeCMAP)); mpUseSheetArray = reinterpret_cast(ut::AddOffsetToPtr(mpHeader, offsetUseSheets)); mpUseCWDHArray = reinterpret_cast(ut::AddOffsetToPtr(mpHeader, offsetUseCWDH)); mpUseCMAPArray = reinterpret_cast(ut::AddOffsetToPtr(mpHeader, offsetUseCMAP)); } } // namespace font } // namespace nw