vcl/inc/font/PhysicalFontFace.hxx | 4 +- vcl/inc/sft.hxx | 7 ++-- vcl/source/font/PhysicalFontFace.cxx | 17 +++-------- vcl/source/fontsubset/sft.cxx | 44 +++++++++++++++++++++--------- vcl/source/fontsubset/ttcr.cxx | 16 ++++------- vcl/source/fontsubset/ttcr.hxx | 2 - vcl/source/gdi/pdfwriter_impl.cxx | 50 +++++++---------------------------- 7 files changed, 60 insertions(+), 80 deletions(-)
New commits: commit 92d67d4d32dee25c6b40ade5924f9d1ab488a16c Author: Khaled Hosny <kha...@aliftype.com> AuthorDate: Sun Sep 11 18:28:54 2022 +0200 Commit: خالد حسني <kha...@aliftype.com> CommitDate: Mon Sep 19 12:23:47 2022 +0200 vcl: Don’t use temporary files for CreateFontSubset() The callers pass a path to a temporary file for the function to write to, then they immediately read from it. This change cuts the unnecessary use of temporary files and passes the subset font data around instead. The CFF subsetting code really wants files and needs more invasive change, so it still uses a temporary files but this is hidden from its caller. Change-Id: I2a2117e967b76fb903ff0d32c435925049bc6e56 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140122 Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> Tested-by: Jenkins Reviewed-by: خالد حسني <kha...@aliftype.com> diff --git a/vcl/inc/font/PhysicalFontFace.hxx b/vcl/inc/font/PhysicalFontFace.hxx index 706f7c68510e..01ad46dea54e 100644 --- a/vcl/inc/font/PhysicalFontFace.hxx +++ b/vcl/inc/font/PhysicalFontFace.hxx @@ -115,14 +115,14 @@ public: // CreateFontSubset: a method to get a subset of glyphs of a font inside a // new valid font file // returns true if creation of subset was successful - // parameters: rToFile: contains an osl file URL to write the subset to + // parameters: rOutBuffer: vector to write the subset to // pGlyphIDs: the glyph ids to be extracted // pEncoding: the character code corresponding to each glyph // nGlyphs: the number of glyphs // rInfo: additional outgoing information // implementation note: encoding 0 with glyph id 0 should be added implicitly // as "undefined character" - bool CreateFontSubset(const OUString&, const sal_GlyphId*, const sal_uInt8*, const int, + bool CreateFontSubset(std::vector<sal_uInt8>&, const sal_GlyphId*, const sal_uInt8*, const int, FontSubsetInfo&) const; virtual hb_face_t* GetHbFace() const; diff --git a/vcl/inc/sft.hxx b/vcl/inc/sft.hxx index 06a394491cc8..55464aa85973 100644 --- a/vcl/inc/sft.hxx +++ b/vcl/inc/sft.hxx @@ -614,20 +614,21 @@ class TrueTypeFace; * */ VCL_DLLPUBLIC SFErrCodes CreateTTFromTTGlyphs(AbstractTrueTypeFont *ttf, - const char *fname, + std::vector<sal_uInt8>& rOutBuffer, sal_uInt16 const *glyphArray, sal_uInt8 const *encoding, int nGlyphs); VCL_DLLPUBLIC bool CreateTTFfontSubset(AbstractTrueTypeFont& aTTF, - const OString& rSysPath, + std::vector<sal_uInt8>& rOutBuffer, const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding, int nGlyphCount); VCL_DLLPUBLIC bool CreateCFFfontSubset(const unsigned char* pFontBytes, int nByteLength, - const OString& rSysPath, const sal_GlyphId* pGlyphIds, + std::vector<sal_uInt8>& rOutBuffer, + const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding, int nGlyphCount, FontSubsetInfo& rInfo); diff --git a/vcl/source/font/PhysicalFontFace.cxx b/vcl/source/font/PhysicalFontFace.cxx index b8b0bf0316cd..66cd3aae584b 100644 --- a/vcl/source/font/PhysicalFontFace.cxx +++ b/vcl/source/font/PhysicalFontFace.cxx @@ -284,21 +284,14 @@ bool PhysicalFontFace::GetFontCapabilities(vcl::FontCapabilities& rFontCapabilit return rFontCapabilities.oUnicodeRange || rFontCapabilities.oCodePageRange; } -bool PhysicalFontFace::CreateFontSubset(const OUString& rToFile, const sal_GlyphId* pGlyphIds, - const sal_uInt8* pEncoding, const int nGlyphCount, - FontSubsetInfo& rInfo) const +bool PhysicalFontFace::CreateFontSubset(std::vector<sal_uInt8>& rOutBuffer, + const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding, + const int nGlyphCount, FontSubsetInfo& rInfo) const { - // Prepare the requested file name for writing the font-subset file - OUString aSysPath; - if (osl_File_E_None != osl_getSystemPathFromFileURL(rToFile.pData, &aSysPath.pData)) - return false; - - const OString aToFile(OUStringToOString(aSysPath, osl_getThreadTextEncoding())); - // Shortcut for CFF-subsetting. auto aData = GetRawFontData(T_CFF); if (!aData.empty()) - return CreateCFFfontSubset(aData.data(), aData.size(), aToFile, pGlyphIds, pEncoding, + return CreateCFFfontSubset(aData.data(), aData.size(), rOutBuffer, pGlyphIds, pEncoding, nGlyphCount, rInfo); // Prepare data for font subsetter. @@ -310,7 +303,7 @@ bool PhysicalFontFace::CreateFontSubset(const OUString& rToFile, const sal_Glyph FillFontSubsetInfo(&aSftFont, rInfo); // write subset into destination file - return CreateTTFfontSubset(aSftFont, aToFile, pGlyphIds, pEncoding, nGlyphCount); + return CreateTTFfontSubset(aSftFont, rOutBuffer, pGlyphIds, pEncoding, nGlyphCount); } } diff --git a/vcl/source/fontsubset/sft.cxx b/vcl/source/fontsubset/sft.cxx index dea49a70a3bf..de2461d07e48 100644 --- a/vcl/source/fontsubset/sft.cxx +++ b/vcl/source/fontsubset/sft.cxx @@ -48,6 +48,8 @@ #include <sal/log.hxx> #include <o3tl/safeint.hxx> #include <osl/endian.h> +#include <osl/thread.h> +#include <unotools/tempfile.hxx> #include <fontsubset.hxx> #include <algorithm> @@ -1746,7 +1748,7 @@ SFErrCodes CreateT3FromTTGlyphs(TrueTypeFont *ttf, FILE *outf, const char *fname } SFErrCodes CreateTTFromTTGlyphs(AbstractTrueTypeFont *ttf, - const char *fname, + std::vector<sal_uInt8>& rOutBuffer, sal_uInt16 const *glyphArray, sal_uInt8 const *encoding, int nGlyphs) @@ -1841,9 +1843,9 @@ SFErrCodes CreateTTFromTTGlyphs(AbstractTrueTypeFont *ttf, AddTable(ttcr, cvt ); AddTable(ttcr, prep); AddTable(ttcr, fpgm); AddTable(ttcr, post); AddTable(ttcr, os2); - res = StreamToFile(ttcr, fname); + res = StreamToMemory(ttcr, rOutBuffer); #if OSL_DEBUG_LEVEL > 1 - SAL_WARN_IF(res != SFErrCodes::Ok, "vcl.fonts", "StreamToFile: error code: " + SAL_WARN_IF(res != SFErrCodes::Ok, "vcl.fonts", "StreamToMemory: error code: " << (int) res << "."); #endif @@ -1853,7 +1855,7 @@ SFErrCodes CreateTTFromTTGlyphs(AbstractTrueTypeFont *ttf, return res; } -bool CreateTTFfontSubset(vcl::AbstractTrueTypeFont& rTTF, const OString& rSysPath, +bool CreateTTFfontSubset(vcl::AbstractTrueTypeFont& rTTF, std::vector<sal_uInt8>& rOutBuffer, const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding, const int nOrigGlyphCount) { @@ -1907,22 +1909,39 @@ bool CreateTTFfontSubset(vcl::AbstractTrueTypeFont& rTTF, const OString& rSysPat } // write subset into destination file - return (CreateTTFromTTGlyphs(&rTTF, rSysPath.getStr(), aShortIDs, aTempEncs, nGlyphCount) + return (CreateTTFromTTGlyphs(&rTTF, rOutBuffer, aShortIDs, aTempEncs, nGlyphCount) == vcl::SFErrCodes::Ok); } bool CreateCFFfontSubset(const unsigned char* pFontBytes, int nByteLength, - const OString& rSysPath, const sal_GlyphId* pGlyphIds, + std::vector<sal_uInt8>& rOutBuffer, const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding, int nGlyphCount, FontSubsetInfo& rInfo) { - FILE* pOutFile = fopen(rSysPath.getStr(), "wb"); + utl::TempFile aTempFile; + const OString aToFile(OUStringToOString(aTempFile.GetFileName(), osl_getThreadTextEncoding())); + + FILE* pOutFile = fopen(aToFile.getStr(), "wb"); if (!pOutFile) return false; + rInfo.LoadFont(FontType::CFF_FONT, pFontBytes, nByteLength); bool bRet = rInfo.CreateFontSubset(FontType::TYPE1_PFB, pOutFile, nullptr, pGlyphIds, pEncoding, nGlyphCount); fclose(pOutFile); + + if (bRet) + { + SvStream* pStream = aTempFile.GetStream(StreamMode::READ); + rOutBuffer.resize(pStream->TellEnd()); + auto nRead = pStream->ReadBytes(rOutBuffer.data(), rOutBuffer.size()); + if (nRead != rOutBuffer.size()) + { + rOutBuffer.clear(); + return false; + } + } + return bRet; } @@ -2105,8 +2124,6 @@ SFErrCodes CreateT42FromTTGlyphs(TrueTypeFont *ttf, sal_uInt16 ver; sal_Int32 rev; - sal_uInt8 *sfntP; - sal_uInt32 sfntLen; int UPEm = ttf->unitsPerEm(); if (nGlyphs >= 256) return SFErrCodes::GlyphNum; @@ -2158,7 +2175,8 @@ SFErrCodes CreateT42FromTTGlyphs(TrueTypeFont *ttf, AddTable(ttcr, head); AddTable(ttcr, hhea); AddTable(ttcr, maxp); AddTable(ttcr, cvt); AddTable(ttcr, prep); AddTable(ttcr, glyf); AddTable(ttcr, fpgm); - if ((res = StreamToMemory(ttcr, &sfntP, &sfntLen)) != SFErrCodes::Ok) { + std::vector<sal_uInt8> aOutBuffer; + if ((res = StreamToMemory(ttcr, aOutBuffer)) != SFErrCodes::Ok) { TrueTypeCreatorDispose(ttcr); free(gID); return res; @@ -2184,7 +2202,7 @@ SFErrCodes CreateT42FromTTGlyphs(TrueTypeFont *ttf, } fprintf(outf, "/XUID [103 0 1 16#%08X %u 16#%08X 16#%08X] def\n", static_cast<unsigned int>(rtl_crc32(0, ttf->ptr, ttf->fsize)), static_cast<unsigned int>(nGlyphs), static_cast<unsigned int>(rtl_crc32(0, glyphArray, nGlyphs * 2)), static_cast<unsigned int>(rtl_crc32(0, encoding, nGlyphs))); - DumpSfnts(outf, sfntP, sfntLen); + DumpSfnts(outf, aOutBuffer.data(), aOutBuffer.size()); /* dump charstrings */ fprintf(outf, "/CharStrings %d dict dup begin\n", nGlyphs); @@ -2197,7 +2215,6 @@ SFErrCodes CreateT42FromTTGlyphs(TrueTypeFont *ttf, fprintf(outf, "FontName currentdict end definefont pop\n"); TrueTypeCreatorDispose(ttcr); free(gID); - free(sfntP); return SFErrCodes::Ok; } @@ -2602,7 +2619,8 @@ int TestFontSubset(const void* data, sal_uInt32 size) aGlyphIds[c] = c - 31; } - CreateTTFromTTGlyphs(pTTF, nullptr, aGlyphIds, aEncoding, 256); + std::vector<sal_uInt8> aBuffer; + CreateTTFromTTGlyphs(pTTF, aBuffer, aGlyphIds, aEncoding, 256); // cleanup diff --git a/vcl/source/fontsubset/ttcr.cxx b/vcl/source/fontsubset/ttcr.cxx index 40729ffd101d..db9d9e60d024 100644 --- a/vcl/source/fontsubset/ttcr.cxx +++ b/vcl/source/fontsubset/ttcr.cxx @@ -188,7 +188,7 @@ void RemoveTable(TrueTypeCreator *_this, sal_uInt32 tag) static void ProcessTables(TrueTypeCreator *); -SFErrCodes StreamToMemory(TrueTypeCreator *_this, sal_uInt8 **ptr, sal_uInt32 *length) +SFErrCodes StreamToMemory(TrueTypeCreator *_this, std::vector<sal_uInt8>& rOutBuffer) { sal_uInt16 searchRange=1, entrySelector=0, rangeShift; sal_uInt32 s, offset, checkSumAdjustment = 0; @@ -230,7 +230,8 @@ SFErrCodes StreamToMemory(TrueTypeCreator *_this, sal_uInt8 **ptr, sal_uInt32 *l /* if ((te[i].length & 3) != 0) s += (4 - (te[i].length & 3)) & 3; */ } - sal_uInt8* ttf = static_cast<sal_uInt8*>(smalloc(s)); + rOutBuffer.resize(s); + sal_uInt8* ttf = rOutBuffer.data(); /* Offset Table */ PutUInt32(_this->tag, ttf, 0); @@ -261,26 +262,22 @@ SFErrCodes StreamToMemory(TrueTypeCreator *_this, sal_uInt8 **ptr, sal_uInt32 *l for (int i = 0; i < static_cast<int>(s) / 4; ++i) checkSumAdjustment += p[i]; PutUInt32(0xB1B0AFBA - checkSumAdjustment, head, 8); - *ptr = ttf; - *length = s; - return SFErrCodes::Ok; } SFErrCodes StreamToFile(TrueTypeCreator *_this, const char* fname) { - sal_uInt8 *ptr; - sal_uInt32 length; SFErrCodes r; + std::vector<sal_uInt8> aOutBuffer; - if ((r = StreamToMemory(_this, &ptr, &length)) != SFErrCodes::Ok) return r; + if ((r = StreamToMemory(_this, aOutBuffer)) != SFErrCodes::Ok) return r; r = SFErrCodes::BadFile; if (fname) { FILE* fd = fopen(fname, "wb"); if (fd) { - if (fwrite(ptr, 1, length, fd) != length) { + if (fwrite(aOutBuffer.data(), 1, aOutBuffer.size(), fd) != aOutBuffer.size()) { r = SFErrCodes::FileIo; } else { r = SFErrCodes::Ok; @@ -288,7 +285,6 @@ SFErrCodes StreamToFile(TrueTypeCreator *_this, const char* fname) fclose(fd); } } - free(ptr); return r; } diff --git a/vcl/source/fontsubset/ttcr.hxx b/vcl/source/fontsubset/ttcr.hxx index 4ae1eebed8db..e1bfb5013e0f 100644 --- a/vcl/source/fontsubset/ttcr.hxx +++ b/vcl/source/fontsubset/ttcr.hxx @@ -79,7 +79,7 @@ namespace vcl * is supposed to call free() on it. * @return value of SFErrCodes type */ - SFErrCodes StreamToMemory(TrueTypeCreator *_this, sal_uInt8 **ptr, sal_uInt32 *length); + SFErrCodes StreamToMemory(TrueTypeCreator *_this, std::vector<sal_uInt8>& rOutBuffer); /** * Writes a TrueType font generated by the TrueTypeCreator to a file diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 4f4c2cbfde4b..b9d601b4a20a 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -2329,9 +2329,6 @@ std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitSystemFont( const vcl::font: aSubType = OString( "/TrueType" ); - OUString aTmpName; - osl_createTempFile( nullptr, nullptr, &aTmpName.pData ); - sal_Int32 pWidths[256] = { 0 }; const LogicalFontInstance* pFontInstance = rEmbed.m_pFontInstance; for( sal_Ucs c = 32; c < 256; c++ ) @@ -2343,8 +2340,8 @@ std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitSystemFont( const vcl::font: // We are interested only in filling aInfo sal_GlyphId aGlyphIds[256] = { 0 }; sal_uInt8 pEncoding[256] = { 0 }; - pFont->CreateFontSubset(aTmpName, aGlyphIds, pEncoding, 256, aInfo); - osl_removeFile( aTmpName.pData ); + std::vector<sal_uInt8> aBuffer; + pFont->CreateFontSubset(aBuffer, aGlyphIds, pEncoding, 256, aInfo); // write font descriptor nFontDescriptor = emitFontDescriptor( pFont, aInfo, 0, 0 ); @@ -2639,8 +2636,6 @@ bool PDFWriterImpl::emitFonts() std::map< sal_Int32, sal_Int32 > aFontIDToObject; - OUString aTmpName; - osl_createTempFile( nullptr, nullptr, &aTmpName.pData ); for (const auto & subset : m_aSubsets) { for (auto & s_subset :subset.second.m_aSubsets) @@ -2681,19 +2676,12 @@ bool PDFWriterImpl::emitFonts() OSL_FAIL( "too many glyphs for subset" ); } } + std::vector<sal_uInt8> aBuffer; FontSubsetInfo aSubsetInfo; const auto* pFace = subset.first; - if (pFace->CreateFontSubset(aTmpName, aGlyphIds, pEncoding, nGlyphs, aSubsetInfo)) + if (pFace->CreateFontSubset(aBuffer, aGlyphIds, pEncoding, nGlyphs, aSubsetInfo)) { // create font stream - osl::File aFontFile(aTmpName); - if (osl::File::E_None != aFontFile.open(osl_File_OpenFlag_Read)) return false; - // get file size - sal_uInt64 nLength1; - if ( osl::File::E_None != aFontFile.setPos(osl_Pos_End, 0) ) return false; - if ( osl::File::E_None != aFontFile.getPos(nLength1) ) return false; - if ( osl::File::E_None != aFontFile.setPos(osl_Pos_Absolut, 0) ) return false; - if (g_bDebugDisableCompression) { emitComment( "PDFWriterImpl::emitFonts" ); @@ -2717,7 +2705,7 @@ bool PDFWriterImpl::emitFonts() sal_uInt64 nStartPos = 0; if( aSubsetInfo.m_nFontType == FontType::SFNT_TTF ) { - aLine.append( static_cast<sal_Int32>(nLength1) ); + aLine.append( static_cast<sal_Int32>(aBuffer.size()) ); aLine.append( ">>\n" "stream\n" ); @@ -2727,15 +2715,8 @@ bool PDFWriterImpl::emitFonts() // copy font file beginCompression(); checkAndEnableStreamEncryption( nFontStream ); - sal_Bool bEOF = false; - do - { - char buf[8192]; - sal_uInt64 nRead; - if ( osl::File::E_None != aFontFile.read(buf, sizeof(buf), nRead) ) return false; - if ( !writeBuffer( buf, nRead ) ) return false; - if ( osl::File::E_None != aFontFile.isEndOfFile(&bEOF) ) return false; - } while( ! bEOF ); + if (!writeBuffer(aBuffer.data(), aBuffer.size())) + return false; } else if( aSubsetInfo.m_nFontType & FontType::CFF_FONT) { @@ -2744,15 +2725,9 @@ bool PDFWriterImpl::emitFonts() } else if( aSubsetInfo.m_nFontType & FontType::TYPE1_PFB) // TODO: also support PFA? { - std::unique_ptr<unsigned char[]> xBuffer(new unsigned char[nLength1]); - - sal_uInt64 nBytesRead = 0; - if ( osl::File::E_None != aFontFile.read(xBuffer.get(), nLength1, nBytesRead) ) return false; - SAL_WARN_IF( nBytesRead!=nLength1, "vcl.pdfwriter", "PDF-FontSubset read incomplete!" ); - if ( osl::File::E_None != aFontFile.setPos(osl_Pos_Absolut, 0) ) return false; // get the PFB-segment lengths ThreeInts aSegmentLengths = {0,0,0}; - getPfbSegmentLengths(xBuffer.get(), static_cast<int>(nBytesRead), aSegmentLengths); + getPfbSegmentLengths(aBuffer.data(), static_cast<int>(aBuffer.size()), aSegmentLengths); // the lengths below are mandatory for PDF-exported Type1 fonts // because the PFB segment headers get stripped! WhyOhWhy. aLine.append( static_cast<sal_Int32>(aSegmentLengths[0]) ); @@ -2769,9 +2744,9 @@ bool PDFWriterImpl::emitFonts() // emit PFB-sections without section headers beginCompression(); checkAndEnableStreamEncryption( nFontStream ); - if ( !writeBuffer( &xBuffer[6], aSegmentLengths[0] ) ) return false; - if ( !writeBuffer( &xBuffer[12] + aSegmentLengths[0], aSegmentLengths[1] ) ) return false; - if ( !writeBuffer( &xBuffer[18] + aSegmentLengths[0] + aSegmentLengths[1], aSegmentLengths[2] ) ) return false; + if ( !writeBuffer( &aBuffer[6], aSegmentLengths[0] ) ) return false; + if ( !writeBuffer( &aBuffer[12] + aSegmentLengths[0], aSegmentLengths[1] ) ) return false; + if ( !writeBuffer( &aBuffer[18] + aSegmentLengths[0] + aSegmentLengths[1], aSegmentLengths[2] ) ) return false; } else { @@ -2781,8 +2756,6 @@ bool PDFWriterImpl::emitFonts() endCompression(); disableStreamEncryption(); - // close the file - aFontFile.close(); sal_uInt64 nEndPos = 0; if ( osl::File::E_None != m_aFile.getPos(nEndPos) ) return false; @@ -2860,7 +2833,6 @@ bool PDFWriterImpl::emitFonts() } } } - osl_removeFile( aTmpName.pData ); if (g_bDebugDisableCompression) emitComment( "PDFWriterImpl::emitSystemFonts" );