vcl/Library_vcl.mk | 2 vcl/inc/font/PhysicalFontFace.hxx | 1 vcl/inc/fontsubset.hxx | 45 - vcl/inc/sft.hxx | 117 --- vcl/source/fontsubset/cff.cxx | 35 - vcl/source/fontsubset/fontsubset.cxx | 89 -- vcl/source/fontsubset/sft.cxx | 827 ------------------------- vcl/source/fontsubset/ttcr.cxx | 1136 ----------------------------------- vcl/source/fontsubset/ttcr.hxx | 288 -------- 9 files changed, 42 insertions(+), 2498 deletions(-)
New commits: commit 7437ee232e89bee893bbd25118fd6047dd4b0b44 Author: Khaled Hosny <[email protected]> AuthorDate: Tue Feb 17 22:56:20 2026 +0200 Commit: Khaled Hosny <[email protected]> CommitDate: Fri Feb 20 22:29:45 2026 +0100 Reduce the levels of indirection in CreateCFFfontSubset() This is only ever used to create Type 1 subsets from CFF data, no need to pretend it can do anything else. Change-Id: I047fe67b1b7142590eb740e947bffe049a5cca45 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199580 Tested-by: Jenkins Reviewed-by: Khaled Hosny <[email protected]> diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 7c8c30f10042..d1cfab76dea7 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -562,7 +562,6 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/font/font \ vcl/source/font/EOTConverter \ vcl/source/fontsubset/cff \ - vcl/source/fontsubset/fontsubset \ vcl/source/fontsubset/sft \ vcl/source/pdf/COSWriter \ vcl/source/pdf/EncryptionHashTransporter \ diff --git a/vcl/inc/font/PhysicalFontFace.hxx b/vcl/inc/font/PhysicalFontFace.hxx index 9303daf7b4cd..5efdc4e2be41 100644 --- a/vcl/inc/font/PhysicalFontFace.hxx +++ b/vcl/inc/font/PhysicalFontFace.hxx @@ -31,6 +31,7 @@ #include <fontattributes.hxx> #include <fontsubset.hxx> +#include <glyphid.hxx> #include <hb.h> #include <hb-ot.h> diff --git a/vcl/inc/fontsubset.hxx b/vcl/inc/fontsubset.hxx index 066ace263376..ed3e1ce7e980 100644 --- a/vcl/inc/fontsubset.hxx +++ b/vcl/inc/fontsubset.hxx @@ -25,10 +25,6 @@ #include <vcl/dllapi.h> -#include "glyphid.hxx" - -class SvStream; - // Translate units from TT to PS (standard 1/1000) inline int XUnits(int nUPEM, int n) { return (n * 1000) / nUPEM; } @@ -48,44 +44,15 @@ namespace o3tl { class VCL_DLLPUBLIC FontSubsetInfo final { -public: - SAL_DLLPRIVATE explicit FontSubsetInfo(); - SAL_DLLPRIVATE ~FontSubsetInfo(); - - SAL_DLLPRIVATE void LoadFont( FontType eInFontType, - const unsigned char* pFontBytes, int nByteLength ); - - SAL_DLLPRIVATE bool CreateFontSubset( FontType nOutFontTypeMask, - SvStream* pOutFile, - const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncodedIds, - int nReqGlyphCount); - public: // TODO: make subsetter results private and provide accessor methods instead // subsetter-provided subset details needed by e.g. Postscript or PDF OUString m_aPSName; - int m_nAscent; ///< all metrics in PS font units - int m_nDescent; - int m_nCapHeight; - tools::Rectangle m_aFontBBox; - FontType m_nFontType; ///< font-type of subset result - bool m_bFilled; - -private: - // input-font-specific details - unsigned const char* mpInFontBytes; - int mnInByteLength; - FontType meInFontType; ///< allowed mask of input font-types - - // subset-request details - FontType mnReqFontTypeMask; ///< allowed subset-target font types - SvStream* mpOutFile; - OString maReqFontName; - const sal_GlyphId* mpReqGlyphIds; - const sal_uInt8* mpReqEncodedIds; - int mnReqGlyphCount; - - SAL_DLLPRIVATE bool CreateFontSubsetFromCff(); + int m_nAscent = 0; ///< all metrics in PS font units + int m_nDescent = 0; + int m_nCapHeight = 0; + tools::Rectangle m_aFontBBox; + FontType m_nFontType = FontType::NO_FONT; ///< font-type of subset result + bool m_bFilled = false; }; - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/fontsubset/cff.cxx b/vcl/source/fontsubset/cff.cxx index 897287711dba..0df6b53db0c0 100644 --- a/vcl/source/fontsubset/cff.cxx +++ b/vcl/source/fontsubset/cff.cxx @@ -22,7 +22,9 @@ #include <vector> #include <assert.h> +#include <sft.hxx> #include <fontsubset.hxx> +#include <glyphid.hxx> #include <comphelper/flagguard.hxx> #include <o3tl/safeint.hxx> @@ -33,6 +35,7 @@ #include <strhelper.hxx> #include <sal/log.hxx> #include <tools/stream.hxx> +#include <unotools/tempfile.hxx> typedef sal_uInt8 U8; typedef sal_uInt16 U16; @@ -2604,22 +2607,38 @@ void CffSubsetterContext::emitAsType1( Type1Emitter& rEmitter, rFSInfo.m_aPSName = OUString( rEmitter.maSubsetName, strlen(rEmitter.maSubsetName), RTL_TEXTENCODING_UTF8 ); } -bool FontSubsetInfo::CreateFontSubsetFromCff() +namespace vcl { - CffSubsetterContext aCff( mpInFontBytes, mnInByteLength); +bool CreateCFFfontSubset(const unsigned char* pFontBytes, int nByteLength, + std::vector<sal_uInt8>& rOutBuffer, const sal_GlyphId* pGlyphIds, + const sal_uInt8* pEncoding, int nGlyphCount, FontSubsetInfo& rInfo) +{ + CffSubsetterContext aCff(pFontBytes, nByteLength); bool bRC = aCff.initialCffRead(); if (!bRC) return bRC; + utl::TempFileFast aTempFile; + SvStream* pStream = aTempFile.GetStream(StreamMode::READWRITE); + // emit Type1 subset from the CFF input // TODO: also support CFF->CFF subsetting (when PDF-export and PS-printing need it) - const bool bPfbSubset(mnReqFontTypeMask & FontType::TYPE1_PFB); - Type1Emitter aType1Emitter( mpOutFile, bPfbSubset); - aType1Emitter.setSubsetName( maReqFontName.getStr() ); - aCff.emitAsType1( aType1Emitter, - mpReqGlyphIds, mpReqEncodedIds, - mnReqGlyphCount, *this); + Type1Emitter aType1Emitter(pStream, true); + OString maReqFontName = rInfo.m_aPSName.toUtf8(); + aType1Emitter.setSubsetName(maReqFontName.getStr()); + aCff.emitAsType1(aType1Emitter, pGlyphIds, pEncoding, nGlyphCount, rInfo); + + rOutBuffer.resize(pStream->TellEnd()); + pStream->Seek(0); + auto nRead = pStream->ReadBytes(rOutBuffer.data(), rOutBuffer.size()); + if (nRead != rOutBuffer.size()) + { + rOutBuffer.clear(); + return false; + } + return true; } +} // namespace vcl /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/fontsubset/fontsubset.cxx b/vcl/source/fontsubset/fontsubset.cxx deleted file mode 100644 index 0fab8bfbf087..000000000000 --- a/vcl/source/fontsubset/fontsubset.cxx +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - - -#include <osl/diagnose.h> -#include <sal/log.hxx> - -#include <fontsubset.hxx> -#include <sft.hxx> - -FontSubsetInfo::FontSubsetInfo() - : m_nAscent( 0) - , m_nDescent( 0) - , m_nCapHeight( 0) - , m_nFontType( FontType::NO_FONT) - , m_bFilled(false) - , mpInFontBytes( nullptr) - , mnInByteLength( 0) - , meInFontType( FontType::NO_FONT) - , mnReqFontTypeMask( FontType::NO_FONT ) - , mpOutFile(nullptr) - , mpReqGlyphIds(nullptr) - , mpReqEncodedIds(nullptr) - , mnReqGlyphCount(0) -{ -} - -FontSubsetInfo::~FontSubsetInfo() -{ -} - -// prepare subsetting for fonts where the input font file is mapped -void FontSubsetInfo::LoadFont( - FontType eInFontType, - const unsigned char* pInFontBytes, int nInByteLength) -{ - meInFontType = eInFontType; - mpInFontBytes = pInFontBytes; - mnInByteLength = nInByteLength; -} - -bool FontSubsetInfo::CreateFontSubset( - FontType nReqFontTypeMask, - SvStream* pOutFile, - const sal_GlyphId* pReqGlyphIds, const sal_uInt8* pReqEncodedIds, int nReqGlyphCount) -{ - // prepare request details needed by all underlying subsetters - mnReqFontTypeMask = nReqFontTypeMask; - mpOutFile = pOutFile; - mpReqGlyphIds = pReqGlyphIds; - mpReqEncodedIds = pReqEncodedIds; - mnReqGlyphCount = nReqGlyphCount; - maReqFontName = m_aPSName.toUtf8(); - - // TODO: move the glyphid/encid/notdef reshuffling from the callers to here - - // dispatch to underlying subsetters - bool bOK = false; - - // TODO: better match available input-type to possible subset-types - switch( meInFontType) { - case FontType::CFF_FONT: - bOK = CreateFontSubsetFromCff(); - break; - default: - OSL_FAIL( "unhandled type in CreateFontSubset()"); - break; - } - - return bOK; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/fontsubset/sft.cxx b/vcl/source/fontsubset/sft.cxx index 16760fa97526..68f3e4a49dbf 100644 --- a/vcl/source/fontsubset/sft.cxx +++ b/vcl/source/fontsubset/sft.cxx @@ -705,35 +705,6 @@ SFErrCodes TrueTypeFont::open(sal_uInt32 facenum) return AbstractTrueTypeFont::initialize(); } - - -bool CreateCFFfontSubset(const unsigned char* pFontBytes, int nByteLength, - std::vector<sal_uInt8>& rOutBuffer, const sal_GlyphId* pGlyphIds, - const sal_uInt8* pEncoding, int nGlyphCount, FontSubsetInfo& rInfo) -{ - utl::TempFileFast aTempFile; - SvStream* pStream = aTempFile.GetStream(StreamMode::READWRITE); - - rInfo.LoadFont(FontType::CFF_FONT, pFontBytes, nByteLength); - bool bRet = rInfo.CreateFontSubset(FontType::TYPE1_PFB, pStream, pGlyphIds, pEncoding, - nGlyphCount); - - if (bRet) - { - rOutBuffer.resize(pStream->TellEnd()); - pStream->Seek(0); - auto nRead = pStream->ReadBytes(rOutBuffer.data(), rOutBuffer.size()); - if (nRead != rOutBuffer.size()) - { - rOutBuffer.clear(); - return false; - } - } - - return bRet; -} - - bool GetTTGlobalFontHeadInfo(const AbstractTrueTypeFont *ttf, int& xMin, int& yMin, int& xMax, int& yMax, sal_uInt16& macStyle) { sal_uInt32 table_size; commit 99c9cd8e40c0b0a08d297f9e021706acb0628589 Author: Khaled Hosny <[email protected]> AuthorDate: Tue Feb 17 22:10:53 2026 +0200 Commit: Khaled Hosny <[email protected]> CommitDate: Fri Feb 20 22:29:35 2026 +0100 Remove now unused CreateTTFromTTGlyphs() and related code Change-Id: I7b5f1bc473a091143f9be9584db9d3ce112f3aa4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199577 Tested-by: Jenkins Reviewed-by: Khaled Hosny <[email protected]> diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index e9acf2f397dc..7c8c30f10042 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -564,7 +564,6 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/fontsubset/cff \ vcl/source/fontsubset/fontsubset \ vcl/source/fontsubset/sft \ - vcl/source/fontsubset/ttcr \ vcl/source/pdf/COSWriter \ vcl/source/pdf/EncryptionHashTransporter \ vcl/source/pdf/ExternalPDFStreams \ diff --git a/vcl/inc/sft.hxx b/vcl/inc/sft.hxx index 3e4a6a695f71..1ff10a985846 100644 --- a/vcl/inc/sft.hxx +++ b/vcl/inc/sft.hxx @@ -47,14 +47,11 @@ #include <vcl/fontcharmap.hxx> #include <i18nlangtag/lang.h> -#include "fontsubset.hxx" #include "glyphid.hxx" #include <array> -#include <memory> #include <vector> - -#include "font/TTFStructure.hxx" +#include "fontsubset.hxx" class LanguageTag; @@ -119,26 +116,7 @@ namespace vcl OVERLAP_COMPOUND = 1<<10 }; -/** Structure used by GetTTSimpleCharMetrics() functions */ - typedef struct { - sal_uInt16 adv; /**< advance width or height */ - sal_Int16 sb; /**< left or top sidebearing */ - } TTSimpleGlyphMetrics; - -/** Structure used by the TrueType Creator and GetRawGlyphData() */ - - typedef struct { - sal_uInt32 glyphID; /**< glyph ID */ - sal_uInt16 nbytes; /**< number of bytes in glyph data */ - std::unique_ptr<sal_uInt8[]> ptr; /**< pointer to glyph data */ - sal_uInt16 aw; /**< advance width */ - sal_Int16 lsb; /**< left sidebearing */ - bool compflag; /**< false- if non-composite */ - sal_uInt16 npoints; /**< number of points */ - sal_uInt16 ncontours; /**< number of contours */ - /* */ - sal_uInt32 newID; /**< used internally by the TTCR */ - } GlyphData; + /** Structure used by the TrueType Creator and CreateTTFromTTGlyphs() */ struct NameRecord { @@ -183,15 +161,6 @@ namespace vcl sal_uInt16 fsSelection = 0; /**< OS/2 fsSelection */ } TTGlobalFontInfo; -/** ControlPoint structure used by GetTTGlyphPoints() */ - typedef struct { - sal_uInt32 flags; /**< 00000000 00000000 e0000000 bbbbbbbb */ - /**< b - byte flags from the glyf array */ - /**< e == 0 - regular point */ - /**< e == 1 - end contour */ - sal_Int16 x; /**< X coordinate in EmSquare units */ - sal_Int16 y; /**< Y coordinate in EmSquare units */ - } ControlPoint; /* @@ -495,88 +464,6 @@ class TrueTypeFont; */ void VCL_DLLPUBLIC CloseTTFont(TrueTypeFont *); -/** - * Extracts TrueType control points, and stores them in an allocated array pointed to - * by *pointArray. This function returns the number of extracted points. - * - * @param ttf pointer to the TrueTypeFont structure - * @param glyphID Glyph ID - * @param pointArray Return value - address of the pointer to the first element of the array - * of points allocated by the function - * @return Returns the number of points in *pointArray or -1 if glyphID is - * invalid. - * @ingroup sft - * - */ - int GetTTGlyphPoints(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, std::vector<ControlPoint>& pointArray); - -/** - * Extracts raw glyph data from the 'glyf' table and returns it in an allocated - * GlyphData structure. - * - * @param ttf pointer to the TrueTypeFont structure - * @param glyphID Glyph ID - * - * @return pointer to an allocated GlyphData structure or NULL if - * glyphID is not present in the font - * @ingroup sft - * - */ - std::unique_ptr<GlyphData> GetTTRawGlyphData(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID); - -/** - * For a specified glyph adds all component glyphs IDs to the list and - * return their number. If the glyph is a single glyph it has one component - * glyph (which is added to the list) and the function returns 1. - * For a composite glyphs it returns the number of component glyphs - * and adds all of them to the list. - * - * @param ttf pointer to the TrueTypeFont structure - * @param glyphID Glyph ID - * @param glyphlist list of glyphs - * - * @return number of component glyphs - * @ingroup sft - * - */ - int GetTTGlyphComponents(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, std::vector< sal_uInt32 >& glyphlist); - -/** - * Extracts all Name Records from the font and stores them in an allocated - * array of NameRecord structs - * - * @param ttf pointer to the TrueTypeFont struct - * @param nr reference to the vector of NameRecord structs - * - * @ingroup sft - */ - - void GetTTNameRecords(AbstractTrueTypeFont const *ttf, std::vector<NameRecord>& nr); - -/** - * Generates a new TrueType font and dumps it to <b>outf</b> file. - * This function substitutes glyph 0 for all glyphIDs that are not found in the font. - * @param ttf pointer to the TrueTypeFont structure - * @param fname file name for the output TrueType font file - * @param glyphArray pointer to an array of glyphs that are to be extracted from ttf. The first - * element of this array has to be glyph 0 (default glyph) - * @param encoding array of encoding values. encoding[i] specifies character code for - * the glyphID glyphArray[i]. Character code 0 usually points to a default - * glyph (glyphID 0) - * @param nGlyphs number of glyph IDs in glyphArray and encoding values in encoding - * @param flags or'ed TTCreationFlags - * @return return the value of SFErrCodes enum - * @see SFErrCodes - * @ingroup sft - * - */ - VCL_DLLPUBLIC SFErrCodes CreateTTFromTTGlyphs(AbstractTrueTypeFont *ttf, - std::vector<sal_uInt8>& rOutBuffer, - sal_uInt16 const *glyphArray, - sal_uInt8 const *encoding, - int nGlyphs); - - bool CreateCFFfontSubset(const unsigned char* pFontBytes, int nByteLength, std::vector<sal_uInt8>& rOutBuffer, const sal_GlyphId* pGlyphIds, diff --git a/vcl/source/fontsubset/sft.cxx b/vcl/source/fontsubset/sft.cxx index 322f250f9c88..16760fa97526 100644 --- a/vcl/source/fontsubset/sft.cxx +++ b/vcl/source/fontsubset/sft.cxx @@ -29,13 +29,13 @@ #include <stdlib.h> #include <string.h> #include <sft.hxx> +#include <font/TTFStructure.hxx> #include <impfontcharmap.hxx> #ifdef SYSTEM_LIBFIXMATH #include <libfixmath/fix16.hpp> #else #include <tools/fix16.hxx> #endif -#include "ttcr.hxx" #include <i18nlangtag/applelangid.hxx> #include <i18nlangtag/languagetag.hxx> #include <rtl/crc.h> @@ -50,8 +50,6 @@ #include <tools/UnixWrappers.h> #include <unotools/tempfile.hxx> #include <fontsubset.hxx> -#include <algorithm> -#include <memory> namespace vcl { @@ -60,15 +58,6 @@ namespace { /*- In horizontal writing mode right sidebearing is calculated using this formula *- rsb = aw - (lsb + xMax - xMin) -*/ -struct TTGlyphMetrics { - sal_Int16 xMin; - sal_Int16 yMin; - sal_Int16 xMax; - sal_Int16 yMax; - sal_uInt16 aw; /*- Advance Width (horizontal writing mode) */ - sal_Int16 lsb; /*- Left sidebearing (horizontal writing mode) */ - sal_uInt16 ah; /*- advance height (vertical writing mode) */ -}; } @@ -104,506 +93,6 @@ static sal_Int32 GetInt32(const sal_uInt8* ptr, size_t offset) return static_cast<sal_Int32>(GetUInt32(ptr, offset)); } -static F16Dot16 fixedMul(F16Dot16 a, F16Dot16 b) -{ - return fix16_mul(a, b); -} - -static F16Dot16 fixedDiv(F16Dot16 a, F16Dot16 b) -{ - return fix16_div(a, b); -} - -/*- returns a * b / c -*/ -/* XXX provide a real implementation that preserves accuracy */ -static F16Dot16 fixedMulDiv(F16Dot16 a, F16Dot16 b, F16Dot16 c) -{ - F16Dot16 res = fixedMul(a, b); - return fixedDiv(res, c); -} - -/* Outline Extraction functions */ - -/* fills the aw and lsb entries of the TTGlyphMetrics structure from hmtx table -*/ -static void GetMetrics(AbstractTrueTypeFont const *ttf, sal_uInt32 glyphID, TTGlyphMetrics *metrics) -{ - sal_uInt32 nSize; - const sal_uInt8* table = ttf->table(O_hmtx, nSize); - - metrics->aw = metrics->lsb = metrics->ah = 0; - if (!table || !ttf->horzMetricCount()) - return; - - if (glyphID < ttf->horzMetricCount()) - { - metrics->aw = GetUInt16(table, 4 * glyphID); - metrics->lsb = GetInt16(table, 4 * glyphID + 2); - } - else - { - metrics->aw = GetUInt16(table, 4 * (ttf->horzMetricCount() - 1)); - metrics->lsb = GetInt16(table + ttf->horzMetricCount() * 4, (glyphID - ttf->horzMetricCount()) * 2); - } - - table = ttf->table(O_vmtx, nSize); - if (!table || !ttf->vertMetricCount()) - return; - - if (glyphID < ttf->vertMetricCount()) - metrics->ah = GetUInt16(table, 4 * glyphID); - else - metrics->ah = GetUInt16(table, 4 * (ttf->vertMetricCount() - 1)); -} - -static int GetTTGlyphOutline(AbstractTrueTypeFont *, sal_uInt32 , std::vector<ControlPoint>&, TTGlyphMetrics *, std::vector< sal_uInt32 >* ); - -/* returns the number of control points, allocates the pointArray */ -static int GetSimpleTTOutline(AbstractTrueTypeFont const *ttf, sal_uInt32 glyphID, - std::vector<ControlPoint>& pointArray, TTGlyphMetrics *metrics) -{ - sal_uInt32 nTableSize; - const sal_uInt8* table = ttf->table(O_glyf, nTableSize); - sal_uInt8 n; - int i, j, z; - - pointArray.clear(); - - if (glyphID >= ttf->glyphCount()) - return 0; - - sal_uInt32 nGlyphOffset = ttf->glyphOffset(glyphID); - if (nGlyphOffset > nTableSize) - return 0; - - const sal_uInt8* ptr = table + nGlyphOffset; - const sal_uInt32 nMaxGlyphSize = nTableSize - nGlyphOffset; - constexpr sal_uInt32 nContourOffset = 10; - if (nMaxGlyphSize < nContourOffset) - return 0; - - const sal_Int16 numberOfContours = GetInt16(ptr, GLYF_numberOfContours_offset); - if( numberOfContours <= 0 ) /*- glyph is not simple */ - return 0; - - const sal_Int32 nMaxContours = (nMaxGlyphSize - nContourOffset)/2; - if (numberOfContours > nMaxContours) - return 0; - - if (metrics) { /*- GetCompoundTTOutline() calls this function with NULL metrics -*/ - metrics->xMin = GetInt16(ptr, GLYF_xMin_offset); - metrics->yMin = GetInt16(ptr, GLYF_yMin_offset); - metrics->xMax = GetInt16(ptr, GLYF_xMax_offset); - metrics->yMax = GetInt16(ptr, GLYF_yMax_offset); - GetMetrics(ttf, glyphID, metrics); - } - - /* determine the last point and be extra safe about it. But probably this code is not needed */ - sal_uInt16 lastPoint=0; - for (i=0; i<numberOfContours; i++) - { - const sal_uInt16 t = GetUInt16(ptr, nContourOffset + i * 2); - if (t > lastPoint) - lastPoint = t; - } - - sal_uInt32 nInstLenOffset = nContourOffset + numberOfContours * 2; - if (nInstLenOffset + 2 > nMaxGlyphSize) - return 0; - sal_uInt16 instLen = GetUInt16(ptr, nInstLenOffset); - - sal_uInt32 nOffset = nContourOffset + 2 * numberOfContours + 2 + instLen; - if (nOffset > nMaxGlyphSize) - return 0; - const sal_uInt8* p = ptr + nOffset; - - sal_uInt32 nBytesRemaining = nMaxGlyphSize - nOffset; - const sal_uInt32 palen = lastPoint+1; - - //at a minimum its one byte per entry - if (palen > nBytesRemaining || lastPoint > nBytesRemaining-1) - { - SAL_WARN("vcl.fonts", "Font " << OUString::createFromAscii(ttf->fileName()) << - "claimed a palen of " - << palen << " but max bytes remaining is " << nBytesRemaining); - return 0; - } - - std::vector<ControlPoint> pa(palen); - - i = 0; - while (i <= lastPoint) { - if (!nBytesRemaining) - { - SAL_WARN("vcl.fonts", "short read"); - break; - } - sal_uInt8 flag = *p++; - --nBytesRemaining; - pa[i++].flags = static_cast<sal_uInt32>(flag); - if (flag & 8) { /*- repeat flag */ - if (!nBytesRemaining) - { - SAL_WARN("vcl.fonts", "short read"); - break; - } - n = *p++; - --nBytesRemaining; - // coverity[tainted_data : FALSE] - i > lastPoint extra checks the n loop bound - for (j=0; j<n; j++) { - if (i > lastPoint) { /*- if the font is really broken */ - return 0; - } - pa[i++].flags = flag; - } - } - } - - /*- Process the X coordinate */ - z = 0; - for (i = 0; i <= lastPoint; i++) { - if (pa[i].flags & 0x02) { - if (!nBytesRemaining) - { - SAL_WARN("vcl.fonts", "short read"); - break; - } - if (pa[i].flags & 0x10) { - z += static_cast<int>(*p++); - } else { - z -= static_cast<int>(*p++); - } - --nBytesRemaining; - } else if ( !(pa[i].flags & 0x10)) { - if (nBytesRemaining < 2) - { - SAL_WARN("vcl.fonts", "short read"); - break; - } - z += GetInt16(p, 0); - p += 2; - nBytesRemaining -= 2; - } - pa[i].x = static_cast<sal_Int16>(z); - } - - /*- Process the Y coordinate */ - z = 0; - for (i = 0; i <= lastPoint; i++) { - if (pa[i].flags & 0x04) { - if (!nBytesRemaining) - { - SAL_WARN("vcl.fonts", "short read"); - break; - } - if (pa[i].flags & 0x20) { - z += *p++; - } else { - z -= *p++; - } - --nBytesRemaining; - } else if ( !(pa[i].flags & 0x20)) { - if (nBytesRemaining < 2) - { - SAL_WARN("vcl.fonts", "short read"); - break; - } - z += GetInt16(p, 0); - p += 2; - nBytesRemaining -= 2; - } - pa[i].y = static_cast<sal_Int16>(z); - } - - for (i=0; i<numberOfContours; i++) { - sal_uInt16 offset = GetUInt16(ptr, 10 + i * 2); - SAL_WARN_IF(offset >= palen, "vcl.fonts", "Font " << OUString::createFromAscii(ttf->fileName()) << - " contour " << i << " claimed an illegal offset of " - << offset << " but max offset is " << palen-1); - if (offset >= palen) - continue; - pa[offset].flags |= 0x00008000; /*- set the end contour flag */ - } - - pointArray = std::move(pa); - return lastPoint + 1; -} - -static F16Dot16 fromF2Dot14(sal_Int16 n) -{ - // Avoid undefined shift of negative values prior to C++2a: - return sal_uInt32(n) << 2; -} - -static int GetCompoundTTOutline(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, std::vector<ControlPoint>& pointArray, - TTGlyphMetrics *metrics, std::vector<sal_uInt32>& glyphlist) -{ - sal_uInt16 flags, index; - sal_Int16 e, f; - sal_uInt32 nTableSize; - const sal_uInt8* table = ttf->table(O_glyf, nTableSize); - std::vector<ControlPoint> myPoints; - std::vector<ControlPoint> nextComponent; - int i, np; - F16Dot16 a = 0x10000, b = 0, c = 0, d = 0x10000, m, n, abs1, abs2, abs3; - - pointArray.clear(); - - if (glyphID >= ttf->glyphCount()) - return 0; - - sal_uInt32 nGlyphOffset = ttf->glyphOffset(glyphID); - if (nGlyphOffset > nTableSize) - return 0; - - const sal_uInt8* ptr = table + nGlyphOffset; - sal_uInt32 nAvailableBytes = nTableSize - nGlyphOffset; - - if (GLYF_numberOfContours_offset + 2 > nAvailableBytes) - return 0; - - if (GetInt16(ptr, GLYF_numberOfContours_offset) != -1) /* number of contours - glyph is not compound */ - return 0; - - if (metrics) { - metrics->xMin = GetInt16(ptr, GLYF_xMin_offset); - metrics->yMin = GetInt16(ptr, GLYF_yMin_offset); - metrics->xMax = GetInt16(ptr, GLYF_xMax_offset); - metrics->yMax = GetInt16(ptr, GLYF_yMax_offset); - GetMetrics(ttf, glyphID, metrics); - } - - if (nAvailableBytes < 10) - { - SAL_WARN("vcl.fonts", "short read"); - return 0; - } - - ptr += 10; - nAvailableBytes -= 10; - - do { - - if (nAvailableBytes < 4) - { - SAL_WARN("vcl.fonts", "short read"); - return 0; - } - flags = GetUInt16(ptr, 0); - /* printf("flags: 0x%X ", flags); */ - index = GetUInt16(ptr, 2); - ptr += 4; - nAvailableBytes -= 4; - - if( std::find( glyphlist.begin(), glyphlist.end(), index ) != glyphlist.end() ) - { - SAL_WARN("vcl.fonts", "Endless loop found in a compound glyph."); - -#if OSL_DEBUG_LEVEL > 1 - std::ostringstream oss; - oss << index << " -> ["; - for( const auto& rGlyph : glyphlist ) - { - oss << (int) rGlyph << " "; - } - oss << "]"; - SAL_INFO("vcl.fonts", oss.str()); - /**/ -#endif - return 0; - } - - glyphlist.push_back( index ); - - np = GetTTGlyphOutline(ttf, index, nextComponent, nullptr, &glyphlist); - - if( ! glyphlist.empty() ) - glyphlist.pop_back(); - - if (np == 0) - { - /* XXX that probably indicates a corrupted font */ - SAL_WARN("vcl.fonts", "An empty compound!"); - /* assert(!"An empty compound"); */ - return 0; - } - - if ((flags & USE_MY_METRICS) && metrics) - GetMetrics(ttf, index, metrics); - - if (flags & ARG_1_AND_2_ARE_WORDS) { - if (nAvailableBytes < 4) - { - SAL_WARN("vcl.fonts", "short read"); - return 0; - } - e = GetInt16(ptr, 0); - f = GetInt16(ptr, 2); - /* printf("ARG_1_AND_2_ARE_WORDS: %d %d ", e & 0xFFFF, f & 0xFFFF); */ - ptr += 4; - nAvailableBytes -= 4; - } else { - if (nAvailableBytes < 2) - { - SAL_WARN("vcl.fonts", "short read"); - return 0; - } - if (flags & ARGS_ARE_XY_VALUES) { /* args are signed */ - e = static_cast<sal_Int8>(*ptr++); - f = static_cast<sal_Int8>(*ptr++); - /* printf("ARGS_ARE_XY_VALUES: %d %d ", e & 0xFF, f & 0xFF); */ - } else { /* args are unsigned */ - /* printf("!ARGS_ARE_XY_VALUES "); */ - e = *ptr++; - f = *ptr++; - } - nAvailableBytes -= 2; - } - - a = d = 0x10000; - b = c = 0; - - if (flags & WE_HAVE_A_SCALE) { - if (nAvailableBytes < 2) - { - SAL_WARN("vcl.fonts", "short read"); - return 0; - } - a = fromF2Dot14(GetInt16(ptr, 0)); - d = a; - ptr += 2; - nAvailableBytes -= 2; - } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) { - if (nAvailableBytes < 4) - { - SAL_WARN("vcl.fonts", "short read"); - return 0; - } - a = fromF2Dot14(GetInt16(ptr, 0)); - d = fromF2Dot14(GetInt16(ptr, 2)); - ptr += 4; - nAvailableBytes -= 4; - } else if (flags & WE_HAVE_A_TWO_BY_TWO) { - if (nAvailableBytes < 8) - { - SAL_WARN("vcl.fonts", "short read"); - return 0; - } - a = fromF2Dot14(GetInt16(ptr, 0)); - b = fromF2Dot14(GetInt16(ptr, 2)); - c = fromF2Dot14(GetInt16(ptr, 4)); - d = fromF2Dot14(GetInt16(ptr, 6)); - ptr += 8; - nAvailableBytes -= 8; - } - - abs1 = (a < 0) ? -a : a; - abs2 = (b < 0) ? -b : b; - m = std::max(abs1, abs2); - abs3 = abs1 - abs2; - if (abs3 < 0) abs3 = -abs3; - if (abs3 <= 33) m *= 2; - - abs1 = (c < 0) ? -c : c; - abs2 = (d < 0) ? -d : d; - n = std::max(abs1, abs2); - abs3 = abs1 - abs2; - if (abs3 < 0) abs3 = -abs3; - if (abs3 <= 33) n *= 2; - - SAL_WARN_IF(np && (!m || !n), "vcl.fonts", "Parsing error in " << OUString::createFromAscii(ttf->fileName()) << - ": divide by zero"); - - if (m != 0 && n != 0) { - for (i=0; i<np; i++) { - F16Dot16 t; - ControlPoint cp; - cp.flags = nextComponent[i].flags; - const sal_uInt16 x = nextComponent[i].x; - const sal_uInt16 y = nextComponent[i].y; - t = o3tl::saturating_add(o3tl::saturating_add(fixedMulDiv(a, x << 16, m), fixedMulDiv(c, y << 16, m)), sal_Int32(sal_uInt16(e) << 16)); - cp.x = static_cast<sal_Int16>(fixedMul(t, m) >> 16); - t = o3tl::saturating_add(o3tl::saturating_add(fixedMulDiv(b, x << 16, n), fixedMulDiv(d, y << 16, n)), sal_Int32(sal_uInt16(f) << 16)); - cp.y = static_cast<sal_Int16>(fixedMul(t, n) >> 16); - - myPoints.push_back( cp ); - } - } - - if (myPoints.size() > SAL_MAX_UINT16) { - SAL_WARN("vcl.fonts", "number of points has to be limited to max value GlyphData::npoints can contain, abandon effort"); - myPoints.clear(); - break; - } - - } while (flags & MORE_COMPONENTS); - - // #i123417# some fonts like IFAOGrec have no outline points in some compound glyphs - // so this unlikely but possible scenario should be handled gracefully - if( myPoints.empty() ) - return 0; - - np = myPoints.size(); - - pointArray = std::move(myPoints); - - return np; -} - -/* NOTE: GetTTGlyphOutline() returns -1 if the glyphID is incorrect, - * but Get{Simple|Compound}GlyphOutline returns 0 in such a case. - * - * NOTE: glyphlist is the stack of glyphs traversed while constructing - * a composite glyph. This is a safeguard against endless recursion - * in corrupted fonts. - */ -static int GetTTGlyphOutline(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, std::vector<ControlPoint>& pointArray, TTGlyphMetrics *metrics, std::vector< sal_uInt32 >* glyphlist) -{ - sal_uInt32 glyflength; - const sal_uInt8 *table = ttf->table(O_glyf, glyflength); - sal_Int16 numberOfContours; - int res; - pointArray.clear(); - - if (metrics) - memset(metrics, 0, sizeof(TTGlyphMetrics)); - - if (glyphID >= ttf->glyphCount()) - return -1; - - sal_uInt32 nNextOffset = ttf->glyphOffset(glyphID + 1); - if (nNextOffset > glyflength) - return -1; - - sal_uInt32 nOffset = ttf->glyphOffset(glyphID); - if (nOffset > nNextOffset) - return -1; - - int length = nNextOffset - nOffset; - if (length == 0) { /*- empty glyphs still have hmtx and vmtx metrics values */ - if (metrics) GetMetrics(ttf, glyphID, metrics); - return 0; - } - - const sal_uInt8* ptr = table + nOffset; - const sal_uInt32 nMaxGlyphSize = glyflength - nOffset; - - if (nMaxGlyphSize < 2) - return -1; - - numberOfContours = GetInt16(ptr, 0); - - if (numberOfContours >= 0) - { - res = GetSimpleTTOutline(ttf, glyphID, pointArray, metrics); - } - else - { - std::vector< sal_uInt32 > aPrivList { glyphID }; - res = GetCompoundTTOutline(ttf, glyphID, pointArray, metrics, glyphlist ? *glyphlist : aPrivList ); - } - - return res; -} /*- Extracts a string from the name table and allocates memory for it -*/ @@ -1216,197 +705,6 @@ SFErrCodes TrueTypeFont::open(sal_uInt32 facenum) return AbstractTrueTypeFont::initialize(); } -int GetTTGlyphPoints(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, std::vector<ControlPoint>& pointArray) -{ - return GetTTGlyphOutline(ttf, glyphID, pointArray, nullptr, nullptr); -} - -int GetTTGlyphComponents(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, std::vector< sal_uInt32 >& glyphlist) -{ - int n = 1; - - if (glyphID >= ttf->glyphCount()) - return 0; - - sal_uInt32 glyflength; - const sal_uInt8* glyf = ttf->table(O_glyf, glyflength); - - sal_uInt32 nNextOffset = ttf->glyphOffset(glyphID + 1); - if (nNextOffset > glyflength) - return 0; - - sal_uInt32 nOffset = ttf->glyphOffset(glyphID); - if (nOffset > nNextOffset) - return 0; - - if (std::find(glyphlist.begin(), glyphlist.end(), glyphID) != glyphlist.end()) - { - SAL_INFO("vcl.fonts", "Already have this glyph, don't need to get it again"); - return 0; - } - - glyphlist.push_back( glyphID ); - - // Empty glyph. - if (nOffset == nNextOffset) - return n; - - const auto* ptr = glyf + nOffset; - sal_uInt32 nRemainingData = glyflength - nOffset; - - if (nRemainingData >= 10 && GetInt16(ptr, 0) == -1) { - sal_uInt16 flags, index; - ptr += 10; - nRemainingData -= 10; - do { - if (nRemainingData < 4) - { - SAL_WARN("vcl.fonts", "short read"); - break; - } - flags = GetUInt16(ptr, 0); - index = GetUInt16(ptr, 2); - - ptr += 4; - nRemainingData -= 4; - n += GetTTGlyphComponents(ttf, index, glyphlist); - - sal_uInt32 nAdvance; - if (flags & ARG_1_AND_2_ARE_WORDS) { - nAdvance = 4; - } else { - nAdvance = 2; - } - - if (flags & WE_HAVE_A_SCALE) { - nAdvance += 2; - } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) { - nAdvance += 4; - } else if (flags & WE_HAVE_A_TWO_BY_TWO) { - nAdvance += 8; - } - if (nRemainingData < nAdvance) - { - SAL_WARN("vcl.fonts", "short read"); - break; - } - ptr += nAdvance; - nRemainingData -= nAdvance; - } while (flags & MORE_COMPONENTS); - } - - return n; -} - -SFErrCodes CreateTTFromTTGlyphs(AbstractTrueTypeFont *ttf, - std::vector<sal_uInt8>& rOutBuffer, - sal_uInt16 const *glyphArray, - sal_uInt8 const *encoding, - int nGlyphs) -{ - std::unique_ptr<TrueTypeTableGeneric> cvt, prep, fpgm, os2; - std::unique_ptr<TrueTypeTableName> name; - std::unique_ptr<TrueTypeTableMaxp> maxp; - std::unique_ptr<TrueTypeTableHhea> hhea; - std::unique_ptr<TrueTypeTableHead> head; - std::unique_ptr<TrueTypeTableGlyf> glyf; - std::unique_ptr<TrueTypeTableCmap> cmap; - std::unique_ptr<TrueTypeTablePost> post; - int i; - SFErrCodes res; - - TrueTypeCreator ttcr(T_true); - - /** name **/ - - std::vector<NameRecord> names; - GetTTNameRecords(ttf, names); - name.reset(new TrueTypeTableName(std::move(names))); - - /** maxp **/ - sal_uInt32 nTableSize; - const sal_uInt8* p = ttf->table(O_maxp, nTableSize); - maxp.reset(new TrueTypeTableMaxp(p, nTableSize)); - - /** hhea **/ - p = ttf->table(O_hhea, nTableSize); - if (p && nTableSize >= HHEA_caretSlopeRun_offset + 2) - hhea.reset(new TrueTypeTableHhea(GetInt16(p, HHEA_ascender_offset), GetInt16(p, HHEA_descender_offset), GetInt16(p, HHEA_lineGap_offset), GetInt16(p, HHEA_caretSlopeRise_offset), GetInt16(p, HHEA_caretSlopeRun_offset))); - else - hhea.reset(new TrueTypeTableHhea(0, 0, 0, 0, 0)); - - /** head **/ - - p = ttf->table(O_head, nTableSize); - assert(p != nullptr); - head.reset(new TrueTypeTableHead(GetInt32(p, HEAD_fontRevision_offset), - GetUInt16(p, HEAD_flags_offset), - GetUInt16(p, HEAD_unitsPerEm_offset), - p+HEAD_created_offset, - GetUInt16(p, HEAD_macStyle_offset), - GetUInt16(p, HEAD_lowestRecPPEM_offset), - GetInt16(p, HEAD_fontDirectionHint_offset))); - - /** glyf **/ - - glyf.reset(new TrueTypeTableGlyf()); - std::unique_ptr<sal_uInt32[]> gID(new sal_uInt32[nGlyphs]); - - for (i = 0; i < nGlyphs; i++) { - gID[i] = glyf->glyfAdd(GetTTRawGlyphData(ttf, glyphArray[i]), ttf); - } - - /** cmap **/ - cmap.reset(new TrueTypeTableCmap()); - - for (i=0; i < nGlyphs; i++) { - cmap->cmapAdd(0x010000, encoding[i], gID[i]); - } - - /** cvt **/ - if ((p = ttf->table(O_cvt, nTableSize)) != nullptr) - cvt.reset(new TrueTypeTableGeneric(T_cvt, nTableSize, p)); - - /** prep **/ - if ((p = ttf->table(O_prep, nTableSize)) != nullptr) - prep.reset(new TrueTypeTableGeneric(T_prep, nTableSize, p)); - - /** fpgm **/ - if ((p = ttf->table(O_fpgm, nTableSize)) != nullptr) - fpgm.reset(new TrueTypeTableGeneric(T_fpgm, nTableSize, p)); - - /** post **/ - if ((p = ttf->table(O_post, nTableSize)) != nullptr) - { - sal_Int32 nItalic = (POST_italicAngle_offset + 4 < nTableSize) ? - GetInt32(p, POST_italicAngle_offset) : 0; - sal_Int16 nPosition = (POST_underlinePosition_offset + 2 < nTableSize) ? - GetInt16(p, POST_underlinePosition_offset) : 0; - sal_Int16 nThickness = (POST_underlineThickness_offset + 2 < nTableSize) ? - GetInt16(p, POST_underlineThickness_offset) : 0; - sal_uInt32 nFixedPitch = (POST_isFixedPitch_offset + 4 < nTableSize) ? - GetUInt32(p, POST_isFixedPitch_offset) : 0; - - post.reset(new TrueTypeTablePost(0x00030000, - nItalic, nPosition, - nThickness, nFixedPitch)); - } - else - post.reset(new TrueTypeTablePost(0x00030000, 0, 0, 0, 0)); - - ttcr.AddTable(std::move(name)); ttcr.AddTable(std::move(maxp)); ttcr.AddTable(std::move(hhea)); - ttcr.AddTable(std::move(head)); ttcr.AddTable(std::move(glyf)); ttcr.AddTable(std::move(cmap)); - ttcr.AddTable(std::move(cvt)); ttcr.AddTable(std::move(prep)); ttcr.AddTable(std::move(fpgm)); - ttcr.AddTable(std::move(post)); ttcr.AddTable(std::move(os2)); - - res = ttcr.StreamToMemory(rOutBuffer); -#if OSL_DEBUG_LEVEL > 1 - SAL_WARN_IF(res != SFErrCodes::Ok, "vcl.fonts", "StreamToMemory: error code: " - << (int) res << "."); -#endif - - return res; -} bool CreateCFFfontSubset(const unsigned char* pFontBytes, int nByteLength, @@ -1505,97 +803,13 @@ void GetTTGlobalFontInfo(const AbstractTrueTypeFont *ttf, TTGlobalFontInfo *info } } -std::unique_ptr<GlyphData> GetTTRawGlyphData(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID) -{ - if (glyphID >= ttf->glyphCount()) - return nullptr; - - sal_uInt32 hmtxlength; - const sal_uInt8* hmtx = ttf->table(O_hmtx, hmtxlength); - - if (!hmtxlength) - return nullptr; - - sal_uInt32 glyflength; - const sal_uInt8* glyf = ttf->table(O_glyf, glyflength); - int n; - - /* #127161# check the glyph offsets */ - sal_uInt32 nNextOffset = ttf->glyphOffset(glyphID + 1); - if (nNextOffset > glyflength) - return nullptr; - - sal_uInt32 nOffset = ttf->glyphOffset(glyphID); - if (nOffset > nNextOffset) - return nullptr; - - sal_uInt32 length = nNextOffset - nOffset; - - std::unique_ptr<GlyphData> d(new GlyphData); - - if (length > 0) { - const sal_uInt8* srcptr = glyf + ttf->glyphOffset(glyphID); - const size_t nChunkLen = ((length + 1) & ~1); - d->ptr.reset(new sal_uInt8[nChunkLen]); - memcpy(d->ptr.get(), srcptr, length); - memset(d->ptr.get() + length, 0, nChunkLen - length); - d->compflag = (GetInt16( srcptr, 0 ) < 0); - } else { - d->ptr = nullptr; - d->compflag = false; - } - - d->glyphID = glyphID; - d->nbytes = static_cast<sal_uInt16>((length + 1) & ~1); - - /* now calculate npoints and ncontours */ - std::vector<ControlPoint> cp; - n = GetTTGlyphPoints(ttf, glyphID, cp); - if (n > 0) - { - int m = 0; - for (int i = 0; i < n; i++) - { - if (cp[i].flags & 0x8000) - m++; - } - d->npoints = static_cast<sal_uInt16>(n); - d->ncontours = static_cast<sal_uInt16>(m); - } else { - d->npoints = 0; - d->ncontours = 0; - } - /* get advance width and left sidebearing */ - sal_uInt32 nAwOffset; - sal_uInt32 nLsboffset; - if (glyphID < ttf->horzMetricCount()) { - nAwOffset = 4 * glyphID; - nLsboffset = 4 * glyphID + 2; - } else { - nAwOffset = 4 * (ttf->horzMetricCount() - 1); - nLsboffset = (ttf->horzMetricCount() * 4) + ((glyphID - ttf->horzMetricCount()) * 2); - } - if (nAwOffset + 2 <= hmtxlength) - d->aw = GetUInt16(hmtx, nAwOffset); - else - { - SAL_WARN("vcl.fonts", "hmtx offset " << nAwOffset << " not available"); - d->aw = 0; - } - if (nLsboffset + 2 <= hmtxlength) - d->lsb = GetInt16(hmtx, nLsboffset); - else - { - SAL_WARN("vcl.fonts", "hmtx offset " << nLsboffset << " not available"); - d->lsb = 0; - } - - return d; -} - -void GetTTNameRecords(AbstractTrueTypeFont const *ttf, std::vector<NameRecord>& nr) +/** + * Extracts all Name Records from the font and stores them in an allocated + * array of NameRecord structs + */ +static void GetTTNameRecords(AbstractTrueTypeFont const *ttf, std::vector<NameRecord>& nr) { sal_uInt32 nTableSize; const sal_uInt8* table = ttf->table(O_name, nTableSize); diff --git a/vcl/source/fontsubset/ttcr.cxx b/vcl/source/fontsubset/ttcr.cxx deleted file mode 100644 index e2095f987338..000000000000 --- a/vcl/source/fontsubset/ttcr.cxx +++ /dev/null @@ -1,1136 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -/* - * TrueTypeCreator method implementation - */ - -#include <iomanip> -#include <assert.h> - -#include <sal/log.hxx> - -#include "ttcr.hxx" -#include <string.h> - -namespace vcl -{ - -/* - * Private Data Types - */ - -struct TableEntry { - sal_uInt32 tag; - sal_uInt32 length; - sal_uInt8 *data; -}; - -/*- Data access macros for data stored in big-endian or little-endian format */ -static sal_Int16 GetInt16( const sal_uInt8* ptr, sal_uInt32 offset) -{ - assert(ptr != nullptr); - sal_Int16 t = (ptr+offset)[0] << 8 | (ptr+offset)[1]; - return t; -} - -static sal_uInt16 GetUInt16( const sal_uInt8* ptr, sal_uInt32 offset) -{ - assert(ptr != nullptr); - sal_uInt16 t = (ptr+offset)[0] << 8 | (ptr+offset)[1]; - return t; -} - -static void PutInt16(sal_Int16 val, sal_uInt8 *ptr, sal_uInt32 offset) -{ - assert(ptr != nullptr); - - ptr[offset] = static_cast<sal_uInt8>((val >> 8) & 0xFF); - ptr[offset+1] = static_cast<sal_uInt8>(val & 0xFF); -} - -static void PutUInt16(sal_uInt16 val, sal_uInt8 *ptr, sal_uInt32 offset) -{ - assert(ptr != nullptr); - - ptr[offset] = static_cast<sal_uInt8>((val >> 8) & 0xFF); - ptr[offset+1] = static_cast<sal_uInt8>(val & 0xFF); -} - -static void PutUInt32(sal_uInt32 val, sal_uInt8 *ptr, sal_uInt32 offset) -{ - assert(ptr != nullptr); - - ptr[offset] = static_cast<sal_uInt8>((val >> 24) & 0xFF); - ptr[offset+1] = static_cast<sal_uInt8>((val >> 16) & 0xFF); - ptr[offset+2] = static_cast<sal_uInt8>((val >> 8) & 0xFF); - ptr[offset+3] = static_cast<sal_uInt8>(val & 0xFF); -} - -static int TableEntryCompareF(const void *l, const void *r) -{ - sal_uInt32 const ltag(static_cast<TableEntry const*>(l)->tag); - sal_uInt32 const rtag(static_cast<TableEntry const*>(r)->tag); - return (ltag == rtag) ? 0 : (ltag < rtag) ? -1 : 1; -} - -namespace { -struct NameRecordCompareF -{ - bool operator()(const NameRecord& l, const NameRecord& r) const - { - if (l.platformID != r.platformID) { - return l.platformID < r.platformID; - } else if (l.encodingID != r.encodingID) { - return l.encodingID < r.encodingID; - } else if (l.languageID != r.languageID) { - return l.languageID < r.languageID; - } else if (l.nameID != r.nameID) { - return l.nameID < r.nameID; - } - return false; - } -}; -} - -static sal_uInt32 CheckSum(sal_uInt32 *ptr, sal_uInt32 length) -{ - sal_uInt32 sum = 0; - sal_uInt32 *endptr = ptr + ((length + 3) & sal_uInt32(~3)) / 4; - - while (ptr < endptr) sum += *ptr++; - - return sum; -} - -/* - * Public functions - */ - -TrueTypeCreator::TrueTypeCreator(sal_uInt32 _tag) -{ - this->m_tag = _tag; -} - -void TrueTypeCreator::AddTable(std::unique_ptr<TrueTypeTable> table) -{ - if (table != nullptr) { - this->m_tables.push_back(std::move(table)); - } -} - -void TrueTypeCreator::RemoveTable(sal_uInt32 tableTag) -{ - for (auto it = this->m_tables.begin(); it != this->m_tables.end(); ) - { - if ((*it)->m_tag == tableTag) - { - it = this->m_tables.erase(it); - } - else - ++it; - } -} - -SFErrCodes TrueTypeCreator::StreamToMemory(std::vector<sal_uInt8>& rOutBuffer) -{ - sal_uInt16 searchRange=1, entrySelector=0, rangeShift; - sal_uInt32 s, offset, checkSumAdjustment = 0; - sal_uInt32 *p; - sal_uInt8 *head = nullptr; /* saved pointer to the head table data for checkSumAdjustment calculation */ - - if (this->m_tables.empty()) - return SFErrCodes::TtFormat; - - ProcessTables(); - - /* ProcessTables() adds 'loca' and 'hmtx' */ - - sal_uInt16 numTables = this->m_tables.size(); - - std::unique_ptr<TableEntry[]> te(new TableEntry[numTables]); - - int teIdx = 0; - for (auto const & e : this->m_tables) - { - e->GetRawData(&te[teIdx]); - ++teIdx; - } - - qsort(te.get(), numTables, sizeof(TableEntry), TableEntryCompareF); - - do { - searchRange *= 2; - entrySelector++; - } while (searchRange <= numTables); - - searchRange *= 8; - entrySelector--; - rangeShift = numTables * 16 - searchRange; - - s = offset = 12 + 16 * numTables; - - for (int i = 0; i < numTables; ++i) { - s += (te[i].length + 3) & sal_uInt32(~3); - /* if ((te[i].length & 3) != 0) s += (4 - (te[i].length & 3)) & 3; */ - } - - rOutBuffer.resize(s); - sal_uInt8* ttf = rOutBuffer.data(); - - /* Offset Table */ - PutUInt32(this->m_tag, ttf, 0); - PutUInt16(numTables, ttf, 4); - PutUInt16(searchRange, ttf, 6); - PutUInt16(entrySelector, ttf, 8); - PutUInt16(rangeShift, ttf, 10); - - /* Table Directory */ - for (int i = 0; i < numTables; ++i) { - PutUInt32(te[i].tag, ttf + 12, 16 * i); - PutUInt32(CheckSum(reinterpret_cast<sal_uInt32 *>(te[i].data), te[i].length), ttf + 12, 16 * i + 4); - PutUInt32(offset, ttf + 12, 16 * i + 8); - PutUInt32(te[i].length, ttf + 12, 16 * i + 12); - - if (te[i].tag == T_head) { - head = ttf + offset; - } - - memcpy(ttf+offset, te[i].data, (te[i].length + 3) & sal_uInt32(~3) ); - offset += (te[i].length + 3) & sal_uInt32(~3); - /* if ((te[i].length & 3) != 0) offset += (4 - (te[i].length & 3)) & 3; */ - } - - te.reset(); - - p = reinterpret_cast<sal_uInt32 *>(ttf); - for (int i = 0; i < static_cast<int>(s) / 4; ++i) checkSumAdjustment += p[i]; - PutUInt32(0xB1B0AFBA - checkSumAdjustment, head, 8); - - return SFErrCodes::Ok; -} - -/* - * TrueTypeTable private methods - */ - -/* Table data points to - * -------------------------------------------- - * generic tdata_generic struct - * 'head' HEAD_Length bytes of memory - * 'hhea' HHEA_Length bytes of memory - * 'loca' tdata_loca struct - * 'maxp' MAXP_Version1Length bytes of memory - * 'glyf' list of GlyphData structs (defined in sft.h) - * 'name' list of NameRecord structs (defined in sft.h) - * 'post' tdata_post struct - * - */ - -#define CMAP_SUBTABLE_INIT 10 -#define CMAP_SUBTABLE_INCR 10 - -namespace { - -struct CmapSubTable { - sal_uInt32 id; /* subtable ID (platform/encoding ID) */ - std::vector<std::pair<sal_uInt32, sal_uInt32>> mappings; /* character to glyph mapping array */ -}; - -} - -struct table_cmap { - sal_uInt32 n; /* number of used CMAP sub-tables */ - sal_uInt32 m; /* number of allocated CMAP sub-tables */ - std::unique_ptr<CmapSubTable[]> s; /* sorted array of sub-tables */ -}; - -struct tdata_loca { - sal_uInt32 nbytes; /* number of bytes in loca table */ - std::unique_ptr<sal_uInt8[]> ptr; /* pointer to the data */ -}; - -/* allocate memory for a TT table */ -static std::unique_ptr<sal_uInt8[]> ttmalloc(sal_uInt32 nbytes) -{ - sal_uInt32 n = (nbytes + 3) & sal_uInt32(~3); - return std::make_unique<sal_uInt8[]>(n); -} - -TrueTypeTable::~TrueTypeTable() {} - -TrueTypeTableGeneric::~TrueTypeTableGeneric() -{ -} - -TrueTypeTableHead::~TrueTypeTableHead() -{ -} - -TrueTypeTableHhea::~TrueTypeTableHhea() -{ -} - -TrueTypeTableLoca::~TrueTypeTableLoca() -{ -} - -TrueTypeTableMaxp::~TrueTypeTableMaxp() -{ -} - -TrueTypeTableGlyf::~TrueTypeTableGlyf() -{ -} - -TrueTypeTableCmap::~TrueTypeTableCmap() -{ -} - -TrueTypeTableName::~TrueTypeTableName() -{ -} - -TrueTypeTablePost::~TrueTypeTablePost() -{ - if (m_format == 0x00030000) { - /* do nothing */ - } else { - SAL_WARN("vcl.fonts", "Unsupported format of a 'post' table: " - << std::setfill('0') - << std::setw(8) - << std::hex - << std::uppercase - << static_cast<int>(m_format) << "."); - } -} - - -int TrueTypeTableGeneric::GetRawData(TableEntry* te) -{ - te->data = this->m_ptr.get(); - te->length = this->m_nbytes; - te->tag = this->m_tag; - - return TTCR_OK; -} - -int TrueTypeTableHead::GetRawData(TableEntry* te) -{ - te->length = HEAD_Length; - te->data = this->m_head.get(); - te->tag = T_head; - - return TTCR_OK; -} - -int TrueTypeTableHhea::GetRawData(TableEntry* te) -{ - te->length = HHEA_Length; - te->data = this->m_hhea.get(); - te->tag = T_hhea; - - return TTCR_OK; -} - -int TrueTypeTableLoca::GetRawData(TableEntry* te) -{ - assert(this->m_loca != nullptr); - - if (m_loca->nbytes == 0) return TTCR_ZEROGLYPHS; - - te->data = m_loca->ptr.get(); - te->length = m_loca->nbytes; - te->tag = T_loca; - - return TTCR_OK; -} - -int TrueTypeTableMaxp::GetRawData(TableEntry* te) -{ - te->length = MAXP_Version1Length; - te->data = this->m_maxp.get(); - te->tag = T_maxp; - - return TTCR_OK; -} - -int TrueTypeTableGlyf::GetRawData(TableEntry* te) -{ - sal_uInt32 n, nbytes = 0; - /* sal_uInt16 curID = 0; */ /* to check if glyph IDs are sequential and start from zero */ - - te->data = nullptr; - te->length = 0; - te->tag = 0; - - if (m_list.empty()) return TTCR_ZEROGLYPHS; - - for (const std::unique_ptr<GlyphData>& pGlyph : m_list) - { - /* if (((GlyphData *) listCurrent(l))->glyphID != curID++) return TTCR_GLYPHSEQ; */ - nbytes += pGlyph->nbytes; - } - - m_rawdata = ttmalloc(nbytes); - - auto p = m_rawdata.get(); - for (const std::unique_ptr<GlyphData>& pGlyph : m_list) - { - n = pGlyph->nbytes; - if (n != 0) { - memcpy(p, pGlyph->ptr.get(), n); - p += n; - } - } - - te->length = nbytes; - te->data = m_rawdata.get(); - te->tag = T_glyf; - - return TTCR_OK; -} - -/* cmap packers */ -static std::unique_ptr<sal_uInt8[]> PackCmapType0(CmapSubTable const *s, sal_uInt32 *length) -{ - std::unique_ptr<sal_uInt8[]> ptr(new sal_uInt8[262]); - sal_uInt8 *p = ptr.get() + 6; - - PutUInt16(0, ptr.get(), 0); - PutUInt16(262, ptr.get(), 2); - PutUInt16(0, ptr.get(), 4); - - for (sal_uInt32 i = 0; i < 256; i++) { - sal_uInt16 g = 0; - for (const auto& [ch, glyph] : s->mappings) { - if (ch == i) { - g = static_cast<sal_uInt16>(glyph); - } - } - p[i] = static_cast<sal_uInt8>(g); - } - *length = 262; - return ptr; -} - -static std::unique_ptr<sal_uInt8[]> PackCmapType6(CmapSubTable const *s, sal_uInt32 *length) -{ - std::unique_ptr<sal_uInt8[]> ptr(new sal_uInt8[s->mappings.size()*2 + 10]); - sal_uInt8 *p = ptr.get() + 10; - - PutUInt16(6, ptr.get(), 0); - PutUInt16(static_cast<sal_uInt16>(s->mappings.size()*2+10), ptr.get(), 2); - PutUInt16(0, ptr.get(), 4); - PutUInt16(0, ptr.get(), 6); - PutUInt16(static_cast<sal_uInt16>(s->mappings.size()), ptr.get(), 8 ); - - for (size_t i = 0; i < s->mappings.size(); i++) { - sal_uInt16 g = 0; - for (const auto& [ch, glyph] : s->mappings) { - if (ch == i) { - g = static_cast<sal_uInt16>(glyph); - } - } - PutUInt16( g, p, 2*i ); - } - *length = s->mappings.size()*2+10; - return ptr; -} - -/* XXX it only handles Format 0 encoding tables */ -static std::unique_ptr<sal_uInt8[]> PackCmap(CmapSubTable const *s, sal_uInt32 *length) -{ - if (s->mappings.back().second > 0xff) - return PackCmapType6(s, length); - else - return PackCmapType0(s, length); -} - -int TrueTypeTableCmap::GetRawData(TableEntry* te) -{ - sal_uInt32 i; - sal_uInt32 tlen = 0; - sal_uInt32 l; - sal_uInt32 cmapsize; - sal_uInt8 *cmap; - sal_uInt32 coffset; - - assert(m_cmap); - assert(m_cmap->n != 0); - - std::unique_ptr<std::unique_ptr<sal_uInt8[]>[]> subtables(new std::unique_ptr<sal_uInt8[]>[m_cmap->n]); - std::unique_ptr<sal_uInt32[]> sizes(new sal_uInt32[m_cmap->n]); - - for (i = 0; i < m_cmap->n; i++) { - subtables[i] = PackCmap(m_cmap->s.get()+i, &l); - sizes[i] = l; - tlen += l; - } - - cmapsize = tlen + 4 + 8 * m_cmap->n; - this->m_rawdata = ttmalloc(cmapsize); - cmap = this->m_rawdata.get(); - - PutUInt16(0, cmap, 0); - PutUInt16(static_cast<sal_uInt16>(m_cmap->n), cmap, 2); - coffset = 4 + m_cmap->n * 8; - - for (i = 0; i < m_cmap->n; i++) { - PutUInt16(static_cast<sal_uInt16>(m_cmap->s[i].id >> 16), cmap + 4, i * 8); - PutUInt16(static_cast<sal_uInt16>(m_cmap->s[i].id & 0xFF), cmap + 4, 2 + i * 8); - PutUInt32(coffset, cmap + 4, 4 + i * 8); - memcpy(cmap + coffset, subtables[i].get(), sizes[i]); - subtables[i].reset(); - coffset += sizes[i]; - } - - subtables.reset(); - sizes.reset(); - - te->data = cmap; - te->length = cmapsize; - te->tag = T_cmap; - - return TTCR_OK; -} - -int TrueTypeTableName::GetRawData(TableEntry* te) -{ - sal_Int16 i=0, n; /* number of Name Records */ - int stringLen = 0; - sal_uInt8 *p1, *p2; - - te->data = nullptr; - te->length = 0; - te->tag = 0; - - if ((n = static_cast<sal_Int16>(m_list.size())) == 0) return TTCR_NONAMES; - - std::vector<NameRecord> nr = m_list; - - for (const NameRecord & rName : m_list) - stringLen += rName.sptr.size(); - - if (stringLen > 65535) { - return TTCR_NAMETOOLONG; - } - - std::sort(nr.begin(), nr.end(), NameRecordCompareF()); - - int nameLen = stringLen + 12 * n + 6; - std::unique_ptr<sal_uInt8[]> name = ttmalloc(nameLen); - - PutUInt16(0, name.get(), 0); - PutUInt16(n, name.get(), 2); - PutUInt16(static_cast<sal_uInt16>(6 + 12 * n), name.get(), 4); - - p1 = name.get() + 6; - p2 = p1 + 12 * n; - - for (i = 0; i < n; i++) { - PutUInt16(nr[i].platformID, p1, 0); - PutUInt16(nr[i].encodingID, p1, 2); - PutUInt16(static_cast<sal_uInt16>(nr[i].languageID), p1, 4); - PutUInt16(nr[i].nameID, p1, 6); - PutUInt16(nr[i].sptr.size(), p1, 8); - PutUInt16(static_cast<sal_uInt16>(p2 - (name.get() + 6 + 12 * n)), p1, 10); - if (nr[i].sptr.size()) { - memcpy(p2, nr[i].sptr.data(), nr[i].sptr.size()); - } - /* {int j; for(j=0; j<nr[i].slen; j++) printf("%c", nr[i].sptr[j]); printf(" "); }; */ - p2 += nr[i].sptr.size(); - p1 += 12; - } - - nr.clear(); - this->m_rawdata = std::move(name); - - te->data = this->m_rawdata.get(); - te->length = static_cast<sal_uInt16>(nameLen); - te->tag = T_name; - - /*{int j; for(j=0; j<nameLen; j++) printf("%c", name[j]); }; */ - - return TTCR_OK; -} - -int TrueTypeTablePost::GetRawData(TableEntry* te) -{ - std::unique_ptr<sal_uInt8[]> post; - sal_uInt32 postLen = 0; - int ret; - - this->m_rawdata.reset(); - - if (m_format == 0x00030000) { - postLen = 32; - post = ttmalloc(postLen); - PutUInt32(0x00030000, post.get(), 0); - PutUInt32(m_italicAngle, post.get(), 4); - PutUInt16(m_underlinePosition, post.get(), 8); - PutUInt16(m_underlineThickness, post.get(), 10); - PutUInt16(static_cast<sal_uInt16>(m_isFixedPitch), post.get(), 12); - ret = TTCR_OK; - } else { - SAL_WARN("vcl.fonts", "Unrecognized format of a post table: " - << std::setfill('0') - << std::setw(8) - << std::hex - << std::uppercase - << static_cast<int>(m_format) << "."); - ret = TTCR_POSTFORMAT; - } - - this->m_rawdata = std::move(post); - te->data = this->m_rawdata.get(); - te->length = postLen; - te->tag = T_post; - - return ret; -} - -/* - * TrueTypeTable public methods - */ - -/* Note: Type42 fonts only need these tables: - * head, hhea, loca, maxp, cvt, prep, glyf, hmtx, fpgm - * - * Microsoft required tables - * cmap, glyf, head, hhea, hmtx, loca, maxp, name, post, OS/2 - * - * Apple required tables - * cmap, glyf, head, hhea, hmtx, loca, maxp, name, post - * - */ - -TrueTypeTableGeneric::TrueTypeTableGeneric(sal_uInt32 tag, - sal_uInt32 nbytes, - const sal_uInt8* ptr) - : TrueTypeTable(tag), - m_nbytes(nbytes) -{ - if (nbytes) { - m_ptr = ttmalloc(nbytes); - memcpy(m_ptr.get(), ptr, nbytes); - } -} - -TrueTypeTableGeneric::TrueTypeTableGeneric(sal_uInt32 tag, - sal_uInt32 nbytes, - std::unique_ptr<sal_uInt8[]> ptr) - : TrueTypeTable(tag), - m_nbytes(nbytes) -{ - if (nbytes) { - m_ptr = std::move(ptr); - } -} - -TrueTypeTableHead::TrueTypeTableHead(sal_uInt32 fontRevision, - sal_uInt16 flags, - sal_uInt16 unitsPerEm, - const sal_uInt8* created, - sal_uInt16 macStyle, - sal_uInt16 lowestRecPPEM, - sal_Int16 fontDirectionHint) - : TrueTypeTable(T_head) - , m_head(ttmalloc(HEAD_Length)) -{ - assert(created != nullptr); - - sal_uInt8* ptr = m_head.get(); - - PutUInt32(0x00010000, ptr, 0); /* version */ - PutUInt32(fontRevision, ptr, 4); - PutUInt32(0x5F0F3CF5, ptr, 12); /* magic number */ - PutUInt16(flags, ptr, 16); - PutUInt16(unitsPerEm, ptr, 18); - memcpy(ptr+20, created, 8); /* Created Long Date */ - memset(ptr+28, 0, 8); /* Modified Long Date */ - PutUInt16(macStyle, ptr, 44); - PutUInt16(lowestRecPPEM, ptr, 46); - PutUInt16(fontDirectionHint, ptr, 48); - PutUInt16(0, ptr, 52); /* glyph data format: 0 */ -} - -TrueTypeTableHhea::TrueTypeTableHhea(sal_Int16 ascender, - sal_Int16 descender, - sal_Int16 linegap, - sal_Int16 caretSlopeRise, - sal_Int16 caretSlopeRun) - : TrueTypeTable(T_hhea), - m_hhea(ttmalloc(HHEA_Length)) -{ - sal_uInt8* ptr = m_hhea.get(); - - PutUInt32(0x00010000, ptr, 0); /* version */ - PutUInt16(ascender, ptr, 4); - PutUInt16(descender, ptr, 6); - PutUInt16(linegap, ptr, 8); - PutUInt16(caretSlopeRise, ptr, 18); - PutUInt16(caretSlopeRun, ptr, 20); - PutUInt16(0, ptr, 22); /* reserved 1 */ - PutUInt16(0, ptr, 24); /* reserved 2 */ - PutUInt16(0, ptr, 26); /* reserved 3 */ - PutUInt16(0, ptr, 28); /* reserved 4 */ - PutUInt16(0, ptr, 30); /* reserved 5 */ - PutUInt16(0, ptr, 32); /* metricDataFormat */ -} - -TrueTypeTableLoca::TrueTypeTableLoca() - : TrueTypeTable(T_loca), - m_loca(new tdata_loca) -{ - this->m_loca->nbytes = 0; - this->m_loca->ptr = nullptr; -} - -TrueTypeTableMaxp::TrueTypeTableMaxp( const sal_uInt8* maxp, int size) - : TrueTypeTable(T_maxp) -{ - this->m_maxp = ttmalloc(MAXP_Version1Length); - - if (maxp && size == MAXP_Version1Length) { - memcpy(this->m_maxp.get(), maxp, MAXP_Version1Length); - } -} - -TrueTypeTableGlyf::TrueTypeTableGlyf() - : TrueTypeTable(T_glyf) -{ -} - -TrueTypeTableCmap::TrueTypeTableCmap() - : TrueTypeTable(T_cmap) - , m_cmap(new table_cmap) -{ - m_cmap->n = 0; - m_cmap->m = CMAP_SUBTABLE_INIT; - m_cmap->s.reset(new CmapSubTable[CMAP_SUBTABLE_INIT]); -} - -TrueTypeTableName::TrueTypeTableName(std::vector<NameRecord> nr) - : TrueTypeTable(T_name) - , m_list(std::move(nr)) -{ -} - -TrueTypeTablePost::TrueTypeTablePost(sal_Int32 format, - sal_Int32 italicAngle, - sal_Int16 underlinePosition, - sal_Int16 underlineThickness, - sal_uInt32 isFixedPitch) - : TrueTypeTable(T_post) -{ - assert(format == 0x00030000); /* Only format 3.0 is supported at this time */ - - m_format = format; - m_italicAngle = italicAngle; - m_underlinePosition = underlinePosition; - m_underlineThickness = underlineThickness; - m_isFixedPitch = isFixedPitch; -} - -void TrueTypeTableCmap::cmapAdd(sal_uInt32 id, sal_uInt32 c, sal_uInt32 g) -{ - sal_uInt32 i, found; - CmapSubTable *s; - - assert(m_cmap); - s = m_cmap->s.get(); assert(s != nullptr); - - found = 0; - - for (i = 0; i < m_cmap->n; i++) { - if (s[i].id == id) { - found = 1; - break; - } - } - - if (!found) { - if (m_cmap->n == m_cmap->m) { - std::unique_ptr<CmapSubTable[]> tmp(new CmapSubTable[m_cmap->m + CMAP_SUBTABLE_INCR]); - for (sal_uInt32 j = 0; j != m_cmap->m; ++j) { - tmp[j] = std::move(s[j]); - } - m_cmap->m += CMAP_SUBTABLE_INCR; - s = tmp.get(); - m_cmap->s = std::move(tmp); - } - - for (i = 0; i < m_cmap->n; i++) { - if (s[i].id > id) break; - } - - if (i < m_cmap->n) { - for (sal_uInt32 j = m_cmap->n; j != i; --j) { - s[j + 1] = std::move(s[j]); - } - } - - m_cmap->n++; - - s[i].id = id; - } - - s[i].mappings.emplace_back(c, g); -} - -sal_uInt32 TrueTypeTableGlyf::glyfAdd(std::unique_ptr<GlyphData> glyphdata, AbstractTrueTypeFont *fnt) -{ - sal_uInt32 currentID; - int ret, n, ncomponents; - - if (!glyphdata) return sal_uInt32(~0); - - std::vector< sal_uInt32 > glyphlist; - - ncomponents = GetTTGlyphComponents(fnt, glyphdata->glyphID, glyphlist); - - if (m_list.size() > 0) { - ret = n = m_list.back()->newID + 1; - } else { - ret = n = 0; - } - glyphdata->newID = n++; - m_list.push_back(std::move(glyphdata)); - - if (ncomponents > 1 && glyphlist.size() > 1 ) - { - std::vector< sal_uInt32 >::const_iterator it = glyphlist.begin(); - ++it; - /* glyphData->glyphID is always the first glyph on the list */ - do - { - int found = 0; - currentID = *it; - /* XXX expensive! should be rewritten with sorted arrays! */ - for (const std::unique_ptr<GlyphData>& pGlyph : m_list) - { - if (pGlyph->glyphID == currentID) { - found = 1; - break; - } - } - - if (!found) { - std::unique_ptr<GlyphData> gd = GetTTRawGlyphData(fnt, currentID); - gd->newID = n++; - m_list.push_back(std::move(gd)); - } - } while( ++it != glyphlist.end() ); - } - - return ret; -} - -TrueTypeTable *TrueTypeCreator::FindTable(sal_uInt32 tableTag) -{ - for (const std::unique_ptr<TrueTypeTable>& p : this->m_tables) - if (p->m_tag == tableTag) { - return p.get(); - } - - return nullptr; -} - -/* This function processes all the tables and synchronizes them before creating - * the output TrueType stream. - * - * *** It adds two TrueType tables to the font: 'loca' and 'hmtx' *** - * - * It does: - * - * - Re-numbers glyph IDs and creates 'glyf', 'loca', and 'hmtx' tables. - * - Calculates xMin, yMin, xMax, and yMax and stores values in 'head' table. - * - Stores indexToLocFormat in 'head' - * - updates 'maxp' table - * - Calculates advanceWidthMax, minLSB, minRSB, xMaxExtent and numberOfHMetrics - * in 'hhea' table - * - */ -void TrueTypeCreator::ProcessTables() -{ - TrueTypeTableHhea *hhea = nullptr; - TrueTypeTableMaxp *maxp = nullptr; - TrueTypeTableHead *head = nullptr; - std::unique_ptr<TrueTypeTableLoca> loca; - TrueTypeTableGlyf *glyf = nullptr; - sal_uInt32 nGlyphs, locaLen = 0, glyfLen = 0; - sal_Int16 xMin = 0, yMin = 0, xMax = 0, yMax = 0; - sal_uInt32 i = 0; - sal_Int16 indexToLocFormat; - std::unique_ptr<sal_uInt8[]> hmtxPtr; - sal_uInt8 *hheaPtr; - sal_uInt32 hmtxSize; - sal_uInt8 *p1, *p2; - sal_uInt16 maxPoints = 0, maxContours = 0, maxCompositePoints = 0, maxCompositeContours = 0; - int nlsb = 0; - std::unique_ptr<sal_uInt32[]> gid; /* array of old glyphIDs */ - - glyf = static_cast<TrueTypeTableGlyf*>(FindTable(T_glyf)); - std::vector<std::unique_ptr<GlyphData>>& glyphlist = glyf->m_list; - nGlyphs = glyphlist.size(); - if (!nGlyphs) - { - SAL_WARN("vcl.fonts", "no glyphs found in ProcessTables"); - return; - } - gid.reset(new sal_uInt32[nGlyphs]); - - RemoveTable(T_loca); - RemoveTable(T_hmtx); - - /* XXX Need to make sure that composite glyphs do not break during glyph renumbering */ - - for (const std::unique_ptr<GlyphData>& gd : glyphlist) - { - glyfLen += gd->nbytes; - /* XXX if (gd->nbytes & 1) glyfLen++; */ - - assert(gd->newID == i); - gid[i++] = gd->glyphID; - /* gd->glyphID = i++; */ - - /* printf("IDs: %d %d. ", gd->glyphID, gd->newID); */ - - if (gd->nbytes >= 10) { - sal_Int16 z = GetInt16(gd->ptr.get(), 2); - if (z < xMin) xMin = z; - - z = GetInt16(gd->ptr.get(), 4); - if (z < yMin) yMin = z; - - z = GetInt16(gd->ptr.get(), 6); - if (z > xMax) xMax = z; - - z = GetInt16(gd->ptr.get(), 8); - if (z > yMax) yMax = z; - } - - if (!gd->compflag) { /* non-composite glyph */ - if (gd->npoints > maxPoints) maxPoints = gd->npoints; - if (gd->ncontours > maxContours) maxContours = gd->ncontours; - } else { /* composite glyph */ - if (gd->npoints > maxCompositePoints) maxCompositePoints = gd->npoints; - if (gd->ncontours > maxCompositeContours) maxCompositeContours = gd->ncontours; - } - - } - - indexToLocFormat = (glyfLen / 2 > 0xFFFF) ? 1 : 0; - locaLen = indexToLocFormat ? (nGlyphs + 1) << 2 : (nGlyphs + 1) << 1; - - std::unique_ptr<sal_uInt8[]> glyfPtr = ttmalloc(glyfLen); - std::unique_ptr<sal_uInt8[]> locaPtr = ttmalloc(locaLen); - std::unique_ptr<TTSimpleGlyphMetrics[]> met(new TTSimpleGlyphMetrics[nGlyphs]); - i = 0; - - p1 = glyfPtr.get(); - p2 = locaPtr.get(); - for (const std::unique_ptr<GlyphData>& gd : glyphlist) - { - if (gd->compflag && gd->nbytes > 10) { /* re-number all components */ - sal_uInt16 flags, index; - sal_uInt8 *ptr = gd->ptr.get() + 10; - size_t nRemaining = gd->nbytes - 10; - do { - if (nRemaining < 4) - { - SAL_WARN("vcl.fonts", "truncated font"); - break; - } - flags = GetUInt16(ptr, 0); - index = GetUInt16(ptr, 2); - - /* XXX use the sorted array of old to new glyphID mapping and do a binary search */ - sal_uInt32 j; - for (j = 0; j < nGlyphs; j++) { - if (gid[j] == index) { - break; - } - } - /* printf("X: %d -> %d. ", index, j); */ - - PutUInt16(static_cast<sal_uInt16>(j), ptr, 2); - - ptr += 4; - nRemaining -= 4; - - sal_uInt32 nAdvance = 0; - if (flags & ARG_1_AND_2_ARE_WORDS) { - nAdvance += 4; - } else { - nAdvance += 2; - } - - if (flags & WE_HAVE_A_SCALE) { - nAdvance += 2; - } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) { - nAdvance += 4; - } else if (flags & WE_HAVE_A_TWO_BY_TWO) { - nAdvance += 8; - } - - if (nRemaining < nAdvance) - { - SAL_WARN("vcl.fonts", "truncated font"); - break; - } - - ptr += nAdvance; - nRemaining -= nAdvance; - - } while (flags & MORE_COMPONENTS); - } - - if (gd->nbytes != 0) { - memcpy(p1, gd->ptr.get(), gd->nbytes); - } - if (indexToLocFormat == 1) { - PutUInt32(p1 - glyfPtr.get(), p2, 0); - p2 += 4; - } else { - PutUInt16(static_cast<sal_uInt16>((p1 - glyfPtr.get()) >> 1), p2, 0); - p2 += 2; - } - p1 += gd->nbytes; - - /* fill the array of metrics */ - met[i].adv = gd->aw; - met[i].sb = gd->lsb; - i++; - } - - gid.reset(); - - if (indexToLocFormat == 1) { - PutUInt32(p1 - glyfPtr.get(), p2, 0); - } else { - PutUInt16(static_cast<sal_uInt16>((p1 - glyfPtr.get()) >> 1), p2, 0); - } - - glyf->m_rawdata = std::move(glyfPtr); - - loca.reset(new TrueTypeTableLoca()); - loca->m_loca->ptr = std::move(locaPtr); - loca->m_loca->nbytes = locaLen; - - AddTable(std::move(loca)); - - head = static_cast<TrueTypeTableHead*>(FindTable(T_head)); - sal_uInt8* const pHeadData = head->m_head.get(); - PutInt16(xMin, pHeadData, HEAD_xMin_offset); - PutInt16(yMin, pHeadData, HEAD_yMin_offset); - PutInt16(xMax, pHeadData, HEAD_xMax_offset); - PutInt16(yMax, pHeadData, HEAD_yMax_offset); - PutInt16(indexToLocFormat, pHeadData, HEAD_indexToLocFormat_offset); - - maxp = static_cast<TrueTypeTableMaxp*>(FindTable(T_maxp)); - - sal_uInt8* const pMaxpData = maxp->m_maxp.get(); - PutUInt16(static_cast<sal_uInt16>(nGlyphs), pMaxpData, MAXP_numGlyphs_offset); - PutUInt16(maxPoints, pMaxpData, MAXP_maxPoints_offset); - PutUInt16(maxContours, pMaxpData, MAXP_maxContours_offset); - PutUInt16(maxCompositePoints, pMaxpData, MAXP_maxCompositePoints_offset); - PutUInt16(maxCompositeContours, pMaxpData, MAXP_maxCompositeContours_offset); - - /* - * Generate an htmx table and update hhea table - */ - hhea = static_cast<TrueTypeTableHhea*>(FindTable(T_hhea)); assert(hhea != nullptr); - hheaPtr = hhea->m_hhea.get(); - if (nGlyphs > 2) { - for (i = nGlyphs - 1; i > 0; i--) { - if (met[i].adv != met[i-1].adv) break; - } - nlsb = nGlyphs - 1 - i; - } - hmtxSize = (nGlyphs - nlsb) * 4 + nlsb * 2; - hmtxPtr = ttmalloc(hmtxSize); - p1 = hmtxPtr.get(); - - for (i = 0; i < nGlyphs; i++) { - if (i < nGlyphs - nlsb) { - PutUInt16(met[i].adv, p1, 0); - PutUInt16(met[i].sb, p1, 2); - p1 += 4; - } else { - PutUInt16(met[i].sb, p1, 0); - p1 += 2; - } - } - - AddTable(std::make_unique<TrueTypeTableGeneric>(T_hmtx, hmtxSize, std::move(hmtxPtr))); - PutUInt16(static_cast<sal_uInt16>(nGlyphs - nlsb), hheaPtr, 34); -} - -/** - * TrueTypeCreator destructor. It calls destructors for all TrueTypeTables added to it. - */ -TrueTypeCreator::~TrueTypeCreator() -{ -} - -} // namespace vcl - -#ifdef TEST_TTCR -static sal_uInt32 mkTag(sal_uInt8 a, sal_uInt8 b, sal_uInt8 c, sal_uInt8 d) { - return (a << 24) | (b << 16) | (c << 8) | d; -} - -int main() -{ - TrueTypeCreator *ttcr; - sal_uInt8 *t1, *t2, *t3, *t4, *t5, *t6; - - TrueTypeCreatorNewEmpty(mkTag('t','r','u','e'), &ttcr); - - t1 = malloc(1000); memset(t1, 'a', 1000); - t2 = malloc(2000); memset(t2, 'b', 2000); - t3 = malloc(3000); memset(t3, 'c', 3000); - t4 = malloc(4000); memset(t4, 'd', 4000); - t5 = malloc(5000); memset(t5, 'e', 5000); - t6 = malloc(6000); memset(t6, 'f', 6000); - - AddTable(ttcr, TrueTypeTableNew(T_maxp, 1000, t1)); - AddTable(ttcr, TrueTypeTableNew(T_OS2, 2000, t2)); - AddTable(ttcr, TrueTypeTableNew(T_cmap, 3000, t3)); - AddTable(ttcr, TrueTypeTableNew(T_loca, 4000, t4)); - AddTable(ttcr, TrueTypeTableNew(T_hhea, 5000, t5)); - AddTable(ttcr, TrueTypeTableNew(T_glyf, 6000, t6)); - - free(t1); - free(t2); - free(t3); - free(t4); - free(t5); - free(t6); - - StreamToFile(ttcr, "ttcrout.ttf"); - - TrueTypeCreatorDispose(ttcr); - return 0; -} -#endif - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/fontsubset/ttcr.hxx b/vcl/source/fontsubset/ttcr.hxx deleted file mode 100644 index 4dd78b05444f..000000000000 --- a/vcl/source/fontsubset/ttcr.hxx +++ /dev/null @@ -1,288 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -/** - * @file ttcr.hxx - * @brief TrueType font creator - */ - -#pragma once - -#include <sft.hxx> -#include <vector> - -namespace vcl -{ -class TrueTypeTable; -struct tdata_loca; -struct table_cmap; -struct TableEntry; - - -/* TrueType data types */ - typedef struct { - sal_uInt16 aw; - sal_Int16 lsb; - } longHorMetrics; - -/** Error codes for most functions */ - enum TTCRErrCodes { - TTCR_OK, /**< no error */ - TTCR_ZEROGLYPHS, /**< At least one glyph should be defined */ - TTCR_UNKNOWN, /**< Unknown TrueType table */ - TTCR_NONAMES, /**< 'name' table does not contain any names */ - TTCR_NAMETOOLONG, /**< 'name' table is too long (string data > 64K) */ - TTCR_POSTFORMAT /**< unsupported format of a 'post' table */ - }; - - class TrueTypeCreator { - public: - /** - * TrueTypeCreator constructor. - * Allocates all internal structures. - */ - TrueTypeCreator(sal_uInt32 tag); - ~TrueTypeCreator(); - /** - * Adds a TrueType table to the TrueType creator. - */ - void AddTable(std::unique_ptr<TrueTypeTable> table); - /** - * Removes a TrueType table from the TrueType creator if it is stored there. - * It also calls a TrueTypeTable destructor. - * Note: all generic tables (with tag 0) will be removed if this function is - * called with the second argument of 0. - * @return value of SFErrCodes type - */ - void RemoveTable(sal_uInt32 tag); - /** - * Writes a TrueType font generated by the TrueTypeCreator to a segment of - * memory that this method allocates. When it is not needed anymore the caller - * is supposed to call free() on it. - * @return value of SFErrCodes type - */ - SFErrCodes StreamToMemory(std::vector<sal_uInt8>& rOutBuffer); - - private: - TrueTypeTable *FindTable(sal_uInt32 tag); - void ProcessTables(); - - sal_uInt32 m_tag; /**< TrueType file tag */ - std::vector<std::unique_ptr<TrueTypeTable>> m_tables; /**< List of table tags and pointers */ - }; - - /* A generic base class for all TrueType tables */ - class TrueTypeTable { - protected: - TrueTypeTable(sal_uInt32 tag_) : m_tag(tag_) {} - - public: - virtual ~TrueTypeTable(); - - /** - * This function converts the data of a TrueType table to a raw array of bytes. - * It may allocates the memory for it and returns the size of the raw data in bytes. - * If memory is allocated it does not need to be freed by the caller of this function, - * since the pointer to it is stored in the TrueTypeTable and it is freed by the destructor - * @return TTCRErrCode - * - */ - virtual int GetRawData(TableEntry*) = 0; - - sal_uInt32 m_tag = 0; /* table tag */ - std::unique_ptr<sal_uInt8[]> m_rawdata; /* raw data allocated by GetRawData_*() */ - }; - - class TrueTypeTableGeneric : public TrueTypeTable - { - public: - /** - * - * Creates a new raw TrueType table. The difference between this constructor and - * TrueTypeTableNew_tag constructors is that the latter create structured tables - * while this constructor just copies memory pointed to by ptr to its buffer - * and stores its length. This constructor is suitable for data that is not - * supposed to be processed in any way, just written to the resulting TTF file. - */ - TrueTypeTableGeneric(sal_uInt32 tag, - sal_uInt32 nbytes, - const sal_uInt8* ptr); - TrueTypeTableGeneric(sal_uInt32 tag, - sal_uInt32 nbytes, - std::unique_ptr<sal_uInt8[]> ptr); - virtual ~TrueTypeTableGeneric() override; - virtual int GetRawData(TableEntry*) override; - private: - sal_uInt32 m_nbytes; - std::unique_ptr<sal_uInt8[]> m_ptr; - }; - -/** - * Creates a new 'head' table for a TrueType font. - * Allocates memory for it. Since a lot of values in the 'head' table depend on the - * rest of the tables in the TrueType font this table should be the last one added - * to the font. - */ - class TrueTypeTableHead : public TrueTypeTable - { - public: - TrueTypeTableHead(sal_uInt32 fontRevision, - sal_uInt16 flags, - sal_uInt16 unitsPerEm, - const sal_uInt8 *created, - sal_uInt16 macStyle, - sal_uInt16 lowestRecPPEM, - sal_Int16 fontDirectionHint); - virtual ~TrueTypeTableHead() override; - virtual int GetRawData(TableEntry*) override; - - std::unique_ptr<sal_uInt8[]> m_head; - }; - -/** - * Creates a new 'hhea' table for a TrueType font. - * Allocates memory for it and stores it in the hhea pointer. - */ - class TrueTypeTableHhea : public TrueTypeTable - { - public: - TrueTypeTableHhea(sal_Int16 ascender, - sal_Int16 descender, - sal_Int16 linegap, - sal_Int16 caretSlopeRise, - sal_Int16 caretSlopeRun); - virtual ~TrueTypeTableHhea() override; - virtual int GetRawData(TableEntry*) override; - - std::unique_ptr<sal_uInt8[]> m_hhea; - }; - -/** - * Creates a new empty 'loca' table for a TrueType font. - * - * INTERNAL: gets called only from ProcessTables(); - */ - class TrueTypeTableLoca : public TrueTypeTable - { - public: - TrueTypeTableLoca(); - virtual ~TrueTypeTableLoca() override; - virtual int GetRawData(TableEntry*) override; - - std::unique_ptr<tdata_loca> m_loca; - }; - -/** - * Creates a new 'maxp' table based on an existing maxp table. - * If maxp is 0, a new empty maxp table is created - * size specifies the size of existing maxp table for - * error-checking purposes - */ - class TrueTypeTableMaxp : public TrueTypeTable - { - public: - TrueTypeTableMaxp(const sal_uInt8* maxp, int size); - virtual ~TrueTypeTableMaxp() override; - virtual int GetRawData(TableEntry*) override; - - std::unique_ptr<sal_uInt8[]> m_maxp; - }; - -/** - * Creates a new empty 'glyf' table. - */ - class TrueTypeTableGlyf : public TrueTypeTable - { - public: - TrueTypeTableGlyf(); - virtual ~TrueTypeTableGlyf() override; - virtual int GetRawData(TableEntry*) override; - - /** - * Add a glyph to a glyf table. - * - * @return glyphID of the glyph in the new font - * - * NOTE: This function does not duplicate GlyphData, so memory will be - * deallocated in the table destructor - */ - sal_uInt32 glyfAdd(std::unique_ptr<GlyphData> glyphdata, AbstractTrueTypeFont *fnt); - - std::vector<std::unique_ptr<GlyphData>> m_list; - }; - -/** - * Creates a new empty 'cmap' table. - */ - class TrueTypeTableCmap : public TrueTypeTable - { - public: - TrueTypeTableCmap(); - virtual ~TrueTypeTableCmap() override; - virtual int GetRawData(TableEntry*) override; - - /** - * Add a character/glyph pair to a cmap table - */ - void cmapAdd(sal_uInt32 id, sal_uInt32 c, sal_uInt32 g); - - private: - std::unique_ptr<table_cmap> m_cmap; - }; - -/** - * Creates a new 'name' table. If n != 0 the table gets populated by - * the Name Records stored in the nr array. This function allocates - * memory for its own copy of NameRecords, so nr array has to - * be explicitly deallocated when it is not needed. - */ - class TrueTypeTableName : public TrueTypeTable - { - public: - TrueTypeTableName(std::vector<NameRecord> nr); - virtual ~TrueTypeTableName() override; - virtual int GetRawData(TableEntry*) override; - private: - std::vector<NameRecord> m_list; - }; - -/** - * Creates a new 'post' table of one of the supported formats - */ - class TrueTypeTablePost : public TrueTypeTable - { - public: - TrueTypeTablePost(sal_Int32 format, - sal_Int32 italicAngle, - sal_Int16 underlinePosition, - sal_Int16 underlineThickness, - sal_uInt32 isFixedPitch); - virtual ~TrueTypeTablePost() override; - virtual int GetRawData(TableEntry*) override; - private: - sal_uInt32 m_format; - sal_uInt32 m_italicAngle; - sal_Int16 m_underlinePosition; - sal_Int16 m_underlineThickness; - sal_uInt32 m_isFixedPitch; - }; - -} // namespace - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
