/*---------------------------------------------------------------------------* Project: NintendoWare File: font_ArchiveFont.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: 24154 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include #include #include namespace nw { namespace font { /* ------------------------------------------------------------------------ コンストラクタ/デストラクタ ------------------------------------------------------------------------ */ ArchiveFont::ArchiveFont() { } ArchiveFont::~ArchiveFont() { Destroy(); } /* ------------------------------------------------------------------------ 構築/破棄 ------------------------------------------------------------------------ */ u32 ArchiveFont::GetRequireBufferSize( const void* bfnt, const char* glyphGroups ) { NN_POINTER_ASSERT(bfnt); NN_POINTER_ASSERT(glyphGroups); // 妥当性のチェック if (! IsValidResource(bfnt, HEADER_SIZE)) { return 0; } FontGlyphGroupsAcs gg(bfnt); u32 numRequireSheets = 0; u32 sizeSumCWDH = 0; u32 sizeSumCMAP = 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); } } numRequireSheets += math::CntBit1(useSheets); } // 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); } } } //---- 必要バッファサイズの計算 const u32 sizeTable = math::RoundUp(sizeof(u16) * gg.GetNumSheet(), 4); const u32 sizeFINF = math::RoundUp(sizeof(FontInformation), 4); const u32 sizeTGLP = math::RoundUp(sizeof(FontTextureGlyph), 4); const u32 sizeSumSheet = math::RoundUp(gg.GetSheetSize() * numRequireSheets, 4); // シート領域以降はシート展開時に圧縮データのストリーム展開用コンテキストとして使用するので // ある程度以上のサイズを確保する。 // 通常はシート領域以降がこのサイズを下回ることは無いのでサイズ的な追加コストは発生しない。 const u32 sizeForContext = static_cast(sizeof(nn::cx::UncompContextHuffman)); const u32 sizeAfterSheet = math::Max(static_cast(sizeSumCWDH + sizeSumCMAP), sizeForContext); // math::RoundUp の中に入るのはバッファ上でシートより前に配置されるもの u32 totalSize = math::RoundUp(sizeTable + sizeFINF + sizeTGLP, GlyphDataAlignment) + sizeSumSheet + sizeAfterSheet; totalSize = math::RoundUp(totalSize, 4); totalSize += sizeof(internal::TextureObject) * numRequireSheets; return totalSize; } void ArchiveFont::InitStreamingConstruct( ArchiveFont::ConstructContext* pContext, void* pBuffer, u32 bufferSize, const char* glyphGroups ) { NN_POINTER_ASSERT(pContext); NN_POINTER_ASSERT(pBuffer); NN_ALIGN_ASSERT(pBuffer, GlyphDataAlignment); NW_FONT_BUFFERSIZE_ASSERT(bufferSize); NN_POINTER_ASSERT(glyphGroups); pContext->Init( pBuffer, bufferSize, glyphGroups ); pContext->op = ConstructContext::ANALYZE_FILE_HEADER; } ArchiveFont::ConstructResult ArchiveFont::StreamingConstruct( ArchiveFont::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; } ArchiveFont::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 = ConstructOpAnalyzeGLGR(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::ANALYZE_TGLP: ret = ConstructOpAnalyzeTGLP(pContext, &s); break; case ConstructContext::PREPAIR_COPY_SHEET: ret = ConstructOpPrepairCopySheet(pContext, &s); break; case ConstructContext::PREPAIR_EXPAND_SHEET: ret = ConstructOpPrepairExpandSheet(pContext, &s); break; case ConstructContext::COPY: ret = ConstructOpCopy(pContext, &s); break; case ConstructContext::SKIP: ret = ConstructOpSkip(pContext, &s); break; case ConstructContext::EXPAND: ret = ConstructOpExpand(pContext, &s); break; case ConstructContext::FATAL_ERROR: ret = ConstructOpFatalError(pContext, &s); break; default: NN_ASSERTMSG(false, "invalid operation(%d)", pContext->op); pContext->op = ArchiveFont::ConstructContext::FATAL_ERROR; ret = CONSTRUCT_ERROR; break; } } //---- フォントリソースに対する処理終了時 if (ret == CONSTRUCT_FINISH && GetFINF() == NULL) { pContext->Align(sizeof(GLuint)); u32 texNamesSize = pContext->pFINF->pGlyph->sheetNum * sizeof(internal::TextureObject); if (pContext->GetRemain() < texNamesSize) { // 出力先バッファのサイズが足らなかった NN_LOG("buffer size too small"); return CONSTRUCT_ERROR; } SetTextureObjectsBufferPtr(pContext->GetCurrentPtr()); pContext->Advance(texNamesSize); 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; } } return ret; } bool ArchiveFont::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); const u32 fileSize = reinterpret_cast(bfnt)->fileSize; NW_FONT_BUFFERSIZE_ASSERT(fileSize); ArchiveFont::ConstructContext context; InitStreamingConstruct(&context, pBuffer, bufferSize, glyphGroups); ArchiveFont::ConstructResult ret = StreamingConstruct(&context, bfnt, fileSize); return ret == CONSTRUCT_FINISH; } void* ArchiveFont::Destroy() { if (IsManaging(NULL)) { return 0; } return RemoveResourceBuffer(); } /* ------------------------------------------------------------------------ 文字単体情報アクセサ ------------------------------------------------------------------------ */ void ArchiveFont::GetGlyph( Glyph* glyph, CharCode c ) const { GlyphIndex index = GetGlyphIndex(c); GetGlyphFromIndex(glyph, index); } /* ------------------------------------------------------------------------ グリフインデックス ------------------------------------------------------------------------ */ void ArchiveFont::GetGlyphFromIndex( Glyph* glyph, GlyphIndex index ) const { NN_POINTER_ASSERT(GetFINF()); const FontTextureGlyph& tg = *GetFINF()->pGlyph; u16 adjustedIndex = AdjustIndex(index); if (adjustedIndex == GLYPH_INDEX_NOT_FOUND) { index = GetFINF()->alterCharIndex; adjustedIndex = AdjustIndex(index); } NN_ASSERT(adjustedIndex != GLYPH_INDEX_NOT_FOUND); const u32 cellsInASheet = internal::GetCellsInASheet(tg); const u32 sheetNo = adjustedIndex / cellsInASheet; const u32 offsetBytes = sheetNo * tg.sheetSize; const void* pSheet = tg.sheetImage + offsetBytes; glyph->pTexture = pSheet; glyph->widths = GetCharWidthsFromIndex(index); glyph->pTextureObject = GetTextureObject(sheetNo); SetGlyphMember(glyph, adjustedIndex, tg); } } // namespace font } // namespace nw