/*---------------------------------------------------------------------------* Project: NintendoWare File: font_PackedFont.cpp Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. 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. $Revision: 24754 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include #include #include #include #include #include #include namespace nw { namespace font { namespace { #ifdef NW_PLATFORM_CTR /*!--------------------------------------------------------------------------* @brief 蓄積された3Dコマンドを順次実行開始し、 それらが終了するまで待機します。 予約されたコマンドリストオブジェクト0がバインドされている場合は 何も行われません。 *---------------------------------------------------------------------------*/ void RunCmdlistDone() { // 3Dコマンドを区切り、実行を開始します。 nngxSplitDrawCmdlist(); nngxRunCmdlist(); nngxWaitCmdlistDone(); } #endif // PODでどのようになるか未定 void GXDrawDone() { #ifdef NW_PLATFORM_CTR RunCmdlistDone(); #endif } } // namespace /* ======================================================================= PackedFont public ======================================================================== */ /* ------------------------------------------------------------------------ コンストラクタ/デストラクタ ------------------------------------------------------------------------ */ PackedFont::PackedFont() : m_NumCompSheet(0), m_NumSheetCache(0), m_pCacheIndexArray(NULL), m_pCacheUserArray(NULL), m_pCompSheetArray(NULL), m_pSheetCache(NULL) { } PackedFont::~PackedFont() { Destroy(); } /* ------------------------------------------------------------------------ バッファサイズ計算 ------------------------------------------------------------------------ */ u32 PackedFont::GetRequireBufferSize( const void* bfnt, const char* glyphGroups, int numSheetCache ) { NN_POINTER_ASSERT(bfnt); NN_POINTER_ASSERT(glyphGroups); //---- 妥当性のチェック if (! IsValidResource(bfnt, 16*1024)) { return 0; } FontGlyphGroupsAcs gg(bfnt); u32 copySize = CalcCopySize (gg, glyphGroups, NULL); u32 cacheSize = CalcCacheSize(gg, numSheetCache); return copySize + cacheSize; } u32 PackedFont::GetRequireBufferSize( const void* bfnt, const char* glyphGroups, f32 rateSheetCache ) { NN_POINTER_ASSERT(bfnt); NN_POINTER_ASSERT(glyphGroups); NW_FONT_FLOAT_ASSERT(rateSheetCache); //---- 妥当性のチェック if (! IsValidResource(bfnt, 16*1024)) { return 0; } FontGlyphGroupsAcs gg(bfnt); int numLoadSheet; u32 copySize = CalcCopySize (gg, glyphGroups, &numLoadSheet); int numSheetCache = static_cast(numLoadSheet * rateSheetCache); u32 cacheSize = CalcCacheSize(gg, numSheetCache); return copySize + cacheSize; } /* ------------------------------------------------------------------------ 構築/破棄 ------------------------------------------------------------------------ */ void PackedFont::InitStreamingConstruct( PackedFont::ConstructContext* pContext, void* outBuffer, u32 outBufferSize, const char* glyphGroups ) { NN_POINTER_ASSERT(pContext); NN_POINTER_ASSERT(outBuffer); NN_ALIGN_ASSERT(outBuffer, GlyphDataAlignment); NW_FONT_BUFFERSIZE_ASSERT(outBufferSize); NN_POINTER_ASSERT(glyphGroups); pContext->Init( outBuffer, outBufferSize, glyphGroups ); pContext->op = ConstructContext::ANALYZE_FILE_HEADER; } PackedFont::ConstructResult PackedFont::StreamingConstruct( PackedFont::ConstructContext* pContext, const void* stream, u32 streamSize ) { NN_POINTER_ASSERT(pContext); NN_POINTER_ASSERT(stream); NW_FONT_BUFFERSIZE_ASSERT(streamSize); //---- 既に構築済みなら失敗とする if (GetFINF() != NULL) { // ただし CONSTRUCT_FINISH を返した後であるなら // エラーではなく CONSTRUCT_FINISH とする。 return pContext->HasMoreBlock() ? CONSTRUCT_ERROR: CONSTRUCT_FINISH; } PackedFont::ConstructResult ret = CONSTRUCT_CONTINUE; CachedStreamReader& s = pContext->GetStreamReader(); s.Attach(stream, streamSize); while (ret == CONSTRUCT_CONTINUE) { switch (pContext->op) { case ConstructContext::DISPATCH: ret = ConstructOpDispatch(pContext, &s); break; case ConstructContext::ANALYZE_FILE_HEADER: ret = ConstructOpAnalyzeFileHeader(pContext, &s); break; case ConstructContext::ANALYZE_GLGR: ret = ConstructOpAnalyzeGLGRPacked(pContext, &s); break; case ConstructContext::ANALYZE_FINF: ret = ConstructOpAnalyzeFINF(pContext, &s); break; case ConstructContext::ANALYZE_CMAP: ret = ConstructOpAnalyzeCMAP(pContext, &s); break; case ConstructContext::ANALYZE_CWDH: ret = ConstructOpAnalyzeCWDH(pContext, &s); break; case ConstructContext::COPY: ret = ConstructOpCopy(pContext, &s); break; case ConstructContext::SKIP: ret = ConstructOpSkip(pContext, &s); break; case ConstructContext::FATAL_ERROR: ret = ConstructOpFatalError(pContext, &s); break; case ConstructContext::ANALYZE_TGLP: ret = ConstructOpAnalyzeTGLP(pContext, &s); break; case ConstructContext::PREPAIR_EXPAND_SHEET: { ret = ConstructOpPrepairCopyPackedSheet(pContext, &s); if (pContext->op == PackedFont::ConstructContext::COPY) { // 圧縮シートデータ先頭へのポインタを収集する m_pCompSheetArray[m_NumCompSheet] = pContext->GetCurrentPtr(); m_NumCompSheet++; } } break; case ConstructContext::PREPAIR_COPY_SHEET: NN_LOG("PackedFont: specified font is not compressed."); pContext->op = ConstructContext::FATAL_ERROR; return CONSTRUCT_ERROR; default: NN_ASSERTMSG(false, "NW FONT Internal error\n" "invalid operation(%d)", pContext->op); pContext->op = ConstructContext::FATAL_ERROR; return CONSTRUCT_ERROR; } } //---- フォントリソースに対する処理終了時 if (ret == CONSTRUCT_FINISH && GetFINF() == NULL) { void* pUserBuffer; FontInformation* pFontInfo; u16* pAdjustArray; pContext->Finish(&pUserBuffer, &pFontInfo, &pAdjustArray); SetResourceBuffer(pUserBuffer, pFontInfo, pAdjustArray); if (AdjustIndex(GetFINF()->alterCharIndex) == GLYPH_INDEX_NOT_FOUND) { GetFINF()->alterCharIndex = 0; } // 全てのシートを未ロードとする for (int i = 0; i < m_NumCompSheet; ++i) { m_pCacheIndexArray[i] = SHEET_INDEX_NOT_LOADED; } // 全てのシートを未ロードとする for (int i = 0; i < m_NumSheetCache; ++i) { m_pCacheUserArray[i] = SHEET_INDEX_NOT_LOADED; } } return ret; } bool PackedFont::Construct( void* pBuffer, u32 bufferSize, const void* bfnt, const char* glyphGroups ) { NN_POINTER_ASSERT(pBuffer); NN_ALIGN_ASSERT(pBuffer, GlyphDataAlignment); NW_FONT_BUFFERSIZE_ASSERT(bufferSize); NN_POINTER_ASSERT(bfnt); NN_POINTER_ASSERT(glyphGroups); PackedFont::ConstructResult ret; PackedFont::ConstructContext context; const u32 fileSize = reinterpret_cast(bfnt)->fileSize; NW_FONT_BUFFERSIZE_ASSERT(fileSize); InitStreamingConstruct(&context, pBuffer, bufferSize, glyphGroups); ret = StreamingConstruct(&context, bfnt, fileSize); return ret == CONSTRUCT_FINISH; } void* PackedFont::Destroy() { if (IsManaging(NULL)) { return 0; } // テクスチャ名を削除する際に m_NumSheetCache を // 参照するため、m_NumSheetCacheを初期化する前に呼び出す。 void *const buffer = RemoveResourceBuffer(); m_NumSheetCache = 0; m_pCacheIndexArray = NULL; m_pCacheUserArray = NULL; m_pCompSheetArray = NULL; m_pSheetCache = NULL; return buffer; } /* ------------------------------------------------------------------------ Fontクラスオーバーライド ------------------------------------------------------------------------ */ void PackedFont::GetGlyph( Glyph* pGlyph, CharCode c ) const { NN_POINTER_ASSERT(pGlyph); NN_POINTER_ASSERT(GetFINF()); GlyphIndex index = GetGlyphIndex(c); u16 adjustedIndex = AdjustIndex(index); if (adjustedIndex == GLYPH_INDEX_NOT_FOUND) { index = GetFINF()->alterCharIndex; adjustedIndex = AdjustIndex(index); } NN_ASSERT( adjustedIndex != GLYPH_INDEX_NOT_FOUND ); int compIndex = CalcSheetIndex(adjustedIndex); int cacheIndex = GetCacheIndex(compIndex); if (cacheIndex == SHEET_INDEX_NOT_LOADED) { cacheIndex = LoadSheet(compIndex); pGlyph->isSheetUpdated = true; } m_LRUMan.Use(cacheIndex); MakeGlyph(pGlyph, index, cacheIndex); } int PackedFont::GetActiveSheetNum() const { return m_NumSheetCache; } /* ------------------------------------------------------------------------ シート管理 ------------------------------------------------------------------------ */ bool PackedFont::PreloadSheet(CharCode c) { NN_POINTER_ASSERT(GetFINF()); bool bCacheNow = false; int compIndex = GetSheetIndex(c); int cacheIndex = GetCacheIndex(compIndex); if (cacheIndex == SHEET_INDEX_NOT_LOADED) { cacheIndex = LoadSheet(compIndex); bCacheNow = true; } NN_ASSERT( cacheIndex != SHEET_INDEX_NOT_LOADED ); m_LRUMan.Use(cacheIndex); return bCacheNow; } bool PackedFont::LockSheet(CharCode c) { NN_POINTER_ASSERT(GetFINF()); int compIndex = GetSheetIndex(c); int cacheIndex = GetCacheIndex(compIndex); //---- キャッシュされていないならキャッシュする if (cacheIndex == SHEET_INDEX_NOT_LOADED) { if (m_LRUMan.GetNumLocked() >= m_NumSheetCache - 1) { return false; } cacheIndex = LoadSheet(compIndex); } //---- ロック m_LRUMan.Lock(cacheIndex); return true; } bool PackedFont::UnlockSheet( CharCode c, bool bUnload ) { int compIndex = GetSheetIndex(c); int cacheIndex = GetCacheIndex(compIndex); //---- キャッシュ上に存在しなければならない if (cacheIndex == SHEET_INDEX_NOT_LOADED) { return false; } //---- ロック解除 m_LRUMan.Unlock(cacheIndex); if (bUnload) { //---- キャッシュ破棄 UnloadSheet(compIndex); m_LRUMan.Unuse(cacheIndex); } return true; } void PackedFont::UnlockSheetAll() { for (int i = 0; i < m_NumSheetCache; ++i) { m_LRUMan.Unlock(i); } } /* ======================================================================= PackedFont private ======================================================================== */ /* ------------------------------------------------------------------------ バッファサイズ計算 ------------------------------------------------------------------------ */ u32 PackedFont::CalcCopySize( const FontGlyphGroupsAcs& gg, const char* glyphGroups, int* pNumLoadSheet ) { NN_POINTER_ASSERT(glyphGroups); u32 sizeSumSheet = 0; u32 sizeSumCWDH = 0; u32 sizeSumCMAP = 0; int numLoadSheet = 0; // ロードするシートのサイズを計算 for (int flagSetNo = 0; flagSetNo * 32 < gg.GetNumSheet(); ++flagSetNo) { u32 useSheets = 0x0; for (int setNo = 0; setNo < gg.GetNumSet(); ++setNo) { const char* setName = gg.GetSetName(setNo); if (IsNullString(glyphGroups) || IncludeName(glyphGroups, setName)) { useSheets |= gg.GetUseSheetFlags(setNo, flagSetNo); } } for (int b = 0; b < 32; ++b) { if (((useSheets << b) & (1u << 31)) != 0) { sizeSumSheet += gg.GetSizeCompSheet(flagSetNo * 32 + b); numLoadSheet++; } } } // CWDH ブロック用に必要なバッファサイズを計算 for (int flagSetNo = 0; flagSetNo * 32 < gg.GetNumCWDH(); ++flagSetNo) { u32 useCWDH = 0x0; for (int setNo = 0; setNo < gg.GetNumSet(); ++setNo) { const char* setName = gg.GetSetName(setNo); if (IsNullString(glyphGroups) || IncludeName(glyphGroups, setName)) { useCWDH |= gg.GetUseCWDHFlags(setNo, flagSetNo); } } for (int b = 0; b < 32; ++b) { if (((useCWDH << b) & (1u << 31)) != 0) { sizeSumCWDH += gg.GetSizeCWDH(flagSetNo * 32 + b) - sizeof(ut::BinaryBlockHeader); } } } // CMAP ブロック用に必要なバッファサイズを計算 for (int flagSetNo = 0; flagSetNo * 32 < gg.GetNumCMAP(); ++flagSetNo) { u32 useCMAP = 0x0; for (int setNo = 0; setNo < gg.GetNumSet(); ++setNo) { const char* setName = gg.GetSetName(setNo); if (IsNullString(glyphGroups) || IncludeName(glyphGroups, setName)) { useCMAP |= gg.GetUseCMAPFlags(setNo, flagSetNo); } } for (int b = 0; b < 32; ++b) { if ( ((useCMAP << b) & (1u << 31)) != 0) { sizeSumCMAP += gg.GetSizeCMAP(flagSetNo * 32 + b) - sizeof(ut::BinaryBlockHeader); } } } if (pNumLoadSheet != NULL) { *pNumLoadSheet = numLoadSheet; } //---- 必要バッファサイズの計算 const u32 sizeFINF = math::RoundUp(sizeof(FontInformation), 4); const u32 sizeTGLP = math::RoundUp(sizeof(FontTextureGlyph), 4); // GLGR ブロックの処理に必要なテンポラリバッファのサイズ // バッファサイズはこの値以上になるようにする // 通常、このサイズより小さくなる事は無い const u32 glgrSize = (sizeof(ut::BinaryFileHeader) + gg.GetGLGRSize()) * 2; // 圧縮されたシートにアライメントは不要だが処理の都合上アライメントを入れる const u32 loadResSize = math::RoundUp(sizeFINF + sizeTGLP, GlyphDataAlignment) + sizeSumSheet + sizeSumCWDH + sizeSumCMAP; return math::Max(loadResSize, glgrSize); } u32 PackedFont::CalcCacheSize( const FontGlyphGroupsAcs& gg, int numSheetCache ) { const u32 numResSheet = gg.GetNumSheet(); numSheetCache = math::Clamp(numSheetCache, 1, static_cast(numResSheet)); u32 sizeLRUBuffer = LRUManager::GetRequireBufferSize(numSheetCache); u32 sizeCompSheetArray = sizeof(u8*) * numResSheet; u32 sizeResSheetIndexArray = sizeof(u16) * numSheetCache; u32 sizeSheetCached = gg.GetSheetSize() * numSheetCache; u32 sizeTextureNamesArray = sizeof(internal::TextureObject) * numSheetCache; u32 offsetLRUBuffer = 0; u32 offsetCompSheetArray = math::RoundUp(offsetLRUBuffer + sizeLRUBuffer, 4); u32 offsetSheetIndexArray = math::RoundUp(offsetCompSheetArray + sizeCompSheetArray, 2); u32 offsetResSheetIndexArray = math::RoundUp(offsetSheetIndexArray + sizeCompSheetArray, 2); u32 offsetSheetCached = math::RoundUp(offsetResSheetIndexArray + sizeResSheetIndexArray, GlyphDataAlignment); u32 size = math::RoundUp(offsetSheetCached + sizeSheetCached, 4); size = math::RoundUp(size + sizeTextureNamesArray, 4); return size; } /* ------------------------------------------------------------------------ 構築/破棄 ------------------------------------------------------------------------ */ u16* PackedFont::AssignMemory( u8* buffer, u32 bufferSize, u32 numResSheet, u32 numLoadSheet, u32 sheetSize ) { NN_POINTER_ASSERT(buffer); NW_FONT_BUFFERSIZE_ASSERT(bufferSize); NN_ASSERT( numLoadSheet <= numResSheet ); u16* pGlyphIndexAdjustArray; // シートキャッシュ数計算 u32 sizeGlyphIndexAdjustArray = math::RoundUp(sizeof(u16) * numResSheet, 2); u32 sizeCacheIndexArray = math::RoundUp(sizeof(u16) * numLoadSheet, 2); u32 sizeCompSheetArray = math::RoundUp(sizeof(u8*) * numLoadSheet, 4); u32 varibaleAreaSize = bufferSize - sizeGlyphIndexAdjustArray - sizeCacheIndexArray - sizeCompSheetArray - sizeof(LRUManager::OrderNode); if (varibaleAreaSize > bufferSize) { // varibaleAreaSize が負になった return NULL; } int numSheetCache = static_cast(varibaleAreaSize / (sheetSize + sizeof(LRUManager::OrderNode) + sizeof(u16) + sizeof(internal::TextureObject) ) ); u32 sizeLRUBuffer = LRUManager::GetRequireBufferSize(numSheetCache); u32 sizeCacheUserArray = sizeof(u16) * numSheetCache; u32 sizeSheetCached = sheetSize * numSheetCache; // バッファ割り当て計算 u32 offsetLRUBuffer = 0; u32 offsetGlyphIndexAdjustArray = math::RoundUp(offsetLRUBuffer + sizeLRUBuffer, 2); u32 offsetCacheIndexArray = math::RoundUp(offsetGlyphIndexAdjustArray + sizeGlyphIndexAdjustArray, 2); u32 offsetCacheUserArray = math::RoundUp(offsetCacheIndexArray + sizeCacheIndexArray, 2); u32 offsetCompSheetArray = math::RoundUp(offsetCacheUserArray + sizeCacheUserArray, 4); u32 offsetSheetCache = math::RoundUp(offsetCompSheetArray + sizeCompSheetArray, GlyphDataAlignment); u32 offsetTextureObjectsArray = math::RoundUp(offsetSheetCache + sizeSheetCached, 4); // バッファ割り当て m_LRUMan.Init(buffer + offsetLRUBuffer, numSheetCache); m_NumCompSheet = 0; // ConstructContext::PREPAIR_EXPAND_SHEET で設定される m_NumSheetCache = static_cast(numSheetCache); pGlyphIndexAdjustArray = reinterpret_cast (buffer + offsetGlyphIndexAdjustArray); m_pCacheIndexArray = reinterpret_cast (buffer + offsetCacheIndexArray); m_pCacheUserArray = reinterpret_cast (buffer + offsetCacheUserArray); m_pCompSheetArray = reinterpret_cast(buffer + offsetCompSheetArray); m_pSheetCache = reinterpret_cast (buffer + offsetSheetCache); SetTextureObjectsBufferPtr(buffer + offsetTextureObjectsArray); return pGlyphIndexAdjustArray; } /* ------------------------------------------------------------------------ グリフ取得/シート管理 ------------------------------------------------------------------------ */ void PackedFont::MakeGlyph( Glyph* glyph, GlyphIndex gindex, int cacheIndex ) const { const FontTextureGlyph& tg = *GetFINF()->pGlyph; glyph->pTexture = GetLoadedSheet(cacheIndex); glyph->widths = GetCharWidthsFromIndex(gindex); glyph->pTextureObject = GetTextureObject(cacheIndex); SetGlyphMember(glyph, gindex, tg); } int PackedFont::LoadSheet(int compIndex) const { int nextCacheIndex = m_LRUMan.GetLastIndex(); int oldCacheUser = GetCacheUser(nextCacheIndex); u8* pSheetDst = GetLoadedSheet(nextCacheIndex); const u8* pCompSheet = GetCompSheet(compIndex); if (oldCacheUser != SHEET_INDEX_NOT_LOADED) { GXDrawDone(); UnloadSheet(oldCacheUser); } nn::cx::UncompressHuffman(pCompSheet, pSheetDst); SetCacheUser(compIndex, nextCacheIndex); return nextCacheIndex; } void PackedFont::UnloadSheet(int compIndex) const { int cacheIndex = GetCacheIndex(compIndex); ResetCacheUser(compIndex, cacheIndex); } int PackedFont::GetSheetIndex(CharCode c) const { NN_POINTER_ASSERT(GetFINF()); GlyphIndex index = GetGlyphIndex(c); u16 adjustedIndex = AdjustIndex(index); if (adjustedIndex == GLYPH_INDEX_NOT_FOUND) { index = GetFINF()->alterCharIndex; adjustedIndex = AdjustIndex(index); } NN_ASSERT( adjustedIndex != GLYPH_INDEX_NOT_FOUND ); return CalcSheetIndex(adjustedIndex); } int PackedFont::CalcSheetIndex(GlyphIndex index) const { const FontTextureGlyph& tg = *GetFINF()->pGlyph; const int cellsInASheet = internal::GetCellsInASheet(tg); return index / cellsInASheet; } int PackedFont::GetCacheIndex(int compIndex) const { NW_FONT_MINMAX_ASSERT( compIndex, 0, m_NumCompSheet - 1 ); return m_pCacheIndexArray[compIndex]; } int PackedFont::GetCacheUser(int cacheIndex) const { NW_FONT_MINMAX_ASSERT( cacheIndex, 0, m_NumSheetCache - 1 ); return m_pCacheUserArray[cacheIndex]; } void PackedFont::SetCacheUser( int compIndex, int cacheIndex ) const { NW_FONT_MINMAX_ASSERT( compIndex, 0, m_NumCompSheet - 1 ); NW_FONT_MINMAX_ASSERT( cacheIndex, 0, m_NumSheetCache - 1 ); m_pCacheIndexArray[compIndex] = static_cast(cacheIndex); m_pCacheUserArray[cacheIndex] = static_cast(compIndex); } void PackedFont::ResetCacheUser( int compIndex, int cacheIndex ) const { NW_FONT_MINMAX_ASSERT( compIndex, 0, m_NumCompSheet - 1 ); NW_FONT_MINMAX_ASSERT( cacheIndex, 0, m_NumSheetCache - 1 ); NN_ASSERT( m_pCacheIndexArray[compIndex] == cacheIndex ); NN_ASSERT( m_pCacheUserArray[cacheIndex] == compIndex ); m_pCacheIndexArray[compIndex] = SHEET_INDEX_NOT_LOADED; m_pCacheUserArray[cacheIndex] = SHEET_INDEX_NOT_LOADED; } u8* PackedFont::GetLoadedSheet(int cacheIndex) const { NW_FONT_MINMAX_ASSERT( cacheIndex, 0, m_NumSheetCache - 1 ); const u32 offsetBytes = cacheIndex * GetFINF()->pGlyph->sheetSize; return m_pSheetCache + offsetBytes; } const u8* PackedFont::GetCompSheet(int compIndex) const { NW_FONT_MINMAX_ASSERT( compIndex, 0, m_NumCompSheet - 1 ); return m_pCompSheetArray[compIndex]; } /* ------------------------------------------------------------------------ 構築処理置き換え ------------------------------------------------------------------------ */ PackedFont::ConstructResult PackedFont::ConstructOpAnalyzeGLGRPacked( PackedFont::ConstructContext* pContext, PackedFont::CachedStreamReader* pStream ) { NN_POINTER_ASSERT(pContext); NN_POINTER_ASSERT(pStream); u8* pTempFileHead; u8* pTempGLGRTail; // GLGR ブロックの確保 { const ut::BinaryFileHeader& header = *pContext->GetCurrentPtr(); const u32 requireSize = pContext->header.size - sizeof(ut::BinaryBlockHeader); const u32 infoSize = sizeof(ut::BinaryFileHeader) + pContext->header.size; 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() < infoSize) { // 出力先バッファのサイズが足らなかった NN_LOG("buffer size too small"); return CONSTRUCT_ERROR; } // GLGR ブロックを一時的にコピー // CopyTo(pContext, ...) だとバッファ位置が進んでしまうので CopyTo(void*, ...) を使う 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; } } const u32 bufferSize = pContext->GetRemain(); u16 numResSheet; u32 numLoadSheet; u16 numGlyphsPerSheet; u32 numBlock; u32 sheetSize; u16* pTempAdjustArray; u32 sizeAdjustTable; u32 sizeResLoadBuffer; //---- グリフインデックス調整テーブルの構築 { FontGlyphGroupsAcs gg(pTempFileHead); numResSheet = gg.GetNumSheet(); numLoadSheet = 0; numGlyphsPerSheet = gg.GetNumGlyphsPerSheet(); numBlock = gg.GetNumBlock(); sheetSize = gg.GetSheetSize(); sizeAdjustTable = math::RoundUp(numResSheet * sizeof(u16), 4); // 4 バイトアライメント pTempAdjustArray = reinterpret_cast(math::RoundDown( reinterpret_cast(pTempFileHead + bufferSize - sizeAdjustTable), 2)); if (bufferSize < (pTempGLGRTail - pTempFileHead) + sizeAdjustTable) { // 出力先バッファのサイズが足らなかった NN_LOG("buffer size too small"); return CONSTRUCT_ERROR; } // 以下 AdjustTable を一時的にフラグ配列として使う。 // フラグを全て落とす。 for (int sheetNo = 0; sheetNo < numResSheet; ++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 < numResSheet; ++sheetNo) { if (gg.IsUseSheet(setNo, sheetNo)) { pTempAdjustArray[sheetNo] = 1; } } } } // フラグを元に AdjustTable を構築する。 u16 adjust = 0; for (int sheetNo = 0; sheetNo < numResSheet; ++sheetNo) { u16 &entry = pTempAdjustArray[sheetNo]; if (entry == 1) { entry = adjust; numLoadSheet++; } else { entry = 0xFFFF; adjust += gg.GetNumGlyphsPerSheet(); } } sizeResLoadBuffer = CalcCopySize(gg, pContext->GetGlyphGroups(), NULL); } // 以下では一時的にコピーした GLGR ブロックを破壊するので以降アクセスする事はできない。 // メモリの配分 { const u32 sizeValiableBuffer = math::RoundDown(bufferSize - sizeResLoadBuffer, 4); const u32 offsetValiableBuffer = 0; const u32 offsetResLoadBuffer = offsetValiableBuffer + sizeValiableBuffer; if (sizeResLoadBuffer >= bufferSize) { // 出力先バッファのサイズが足らなかった NN_LOG("buffer size too small"); return CONSTRUCT_ERROR; } u8* const pValiableBuffer = pTempFileHead + offsetValiableBuffer; u16* pTrueAdjustArray = AssignMemory(pValiableBuffer, sizeValiableBuffer, numResSheet, numLoadSheet, sheetSize); if (pTrueAdjustArray == NULL) { // 出力先バッファのサイズが足らなかった NN_LOG("buffer size too small"); return CONSTRUCT_ERROR; } std::copy(pTempAdjustArray, pTempAdjustArray + numResSheet, NW_CHECKED_ARRAY_ITERATOR(pTrueAdjustArray, numResSheet)); pContext->SetGLGR( pTrueAdjustArray, numResSheet, numGlyphsPerSheet, numBlock ); pContext->Advance(offsetResLoadBuffer); // 既に確保した分 pContext->op = ConstructContext::DISPATCH; } return CONSTRUCT_CONTINUE; } PackedFont::ConstructResult PackedFont::ConstructOpPrepairCopyPackedSheet( PackedFont::ConstructContext* pContext, PackedFont::CachedStreamReader* pStream ) { NN_POINTER_ASSERT(pContext); NN_POINTER_ASSERT(pStream); // 全てのシートに対して処理が終わっているか? if (! pContext->HasMoreSheet()) { pContext->op = ConstructContext::DISPATCH; return CONSTRUCT_CONTINUE; } u32 compSize; const u32 requireSize = sizeof(compSize); if (pStream->GetRemain() < requireSize) { return RequestData(pContext, pStream, requireSize); } // 圧縮データサイズを読み込む pStream->CopyTo(&compSize, sizeof(compSize)); const u32 srcSize = compSize; // ロードしなければならないシートか? if (pContext->IsRequireSheet()) { // ロードする if (pContext->GetRemain() < srcSize) { NN_LOG("buffer size too small"); return CONSTRUCT_ERROR; } // CXヘッダ + CXデータをコピー pContext->SetupCopyTask(srcSize, ConstructContext::PREPAIR_EXPAND_SHEET); } else { // CXヘッダ + CXデータをスキップ pContext->SetupSkipTask(srcSize, ConstructContext::PREPAIR_EXPAND_SHEET); } // カレントシート番号を更新 pContext->NextSheet(); return CONSTRUCT_CONTINUE; } /* ======================================================================= LRUManager ======================================================================== */ void PackedFont::LRUManager::Init( void* buffer, int numOrderNode ) { mpOrderNodeArray = reinterpret_cast(buffer); mNumOrderNode = static_cast(numOrderNode); mNumLockedNode = 0; // index = numOrderNode をルートとして双方向循環リストを構成する // index=0 が LRU となる int i = 0; for ( ; i < numOrderNode; ++i) { OrderNode& node = GetNode(i); node.prevIndex = static_cast(i + 1); node.nextIndex = static_cast((i <= 0) ? numOrderNode: i - 1); } OrderNode& root = GetRootNode(); root.prevIndex = 0; root.nextIndex = static_cast(numOrderNode - 1); } void PackedFont::LRUManager::Use(int index) { NW_FONT_MINMAX_ASSERT( index, 0, mNumOrderNode - 1 ); OrderNode& target = GetNode(index); if (! IsLockedNode(target)) { // target をリンクリストからはずす Unlink(target); // target を先頭に挿入 OrderNode& root = GetRootNode(); OrderNode& first = GetNode(root.nextIndex); target.nextIndex = root.nextIndex; target.prevIndex = first.prevIndex; root.nextIndex = static_cast(index); first.prevIndex = static_cast(index); } } void PackedFont::LRUManager::Unuse(int index) { NW_FONT_MINMAX_ASSERT( index, 0, mNumOrderNode - 1 ); OrderNode& target = GetNode(index); if (! IsLockedNode(target)) { // target をリンクリストからはずす Unlink(target); } // target を最後に挿入 OrderNode& root = GetRootNode(); OrderNode& last = GetNode(root.prevIndex); target.prevIndex = root.prevIndex; target.nextIndex = last.nextIndex; root.prevIndex = static_cast(index); last.nextIndex = static_cast(index); } void PackedFont::LRUManager::Lock(int index) { NW_FONT_MINMAX_ASSERT( index, 0, mNumOrderNode - 1 ); OrderNode& target = GetNode(index); if (! IsLockedNode(target)) { // target をリンクリストからはずす Unlink(target); // ロック状態にする MarkLocked(target); mNumLockedNode++; } } void PackedFont::LRUManager::Unlock(int index) { NW_FONT_MINMAX_ASSERT( index, 0, mNumOrderNode - 1 ); OrderNode& target = GetNode(index); if (IsLockedNode(target)) { mNumLockedNode--; // target を先頭に挿入 OrderNode& root = GetRootNode(); OrderNode& first = GetNode(root.nextIndex); target.nextIndex = root.nextIndex; target.prevIndex = first.prevIndex; root.nextIndex = static_cast(index); first.prevIndex = static_cast(index); } } } // namespace font } // namespace nw