svx/source/inc/svdpdf.hxx    |    2 
 svx/source/svdraw/svdpdf.cxx |  139 +++++++++++++++++++++++++++++++++++++------
 2 files changed, 123 insertions(+), 18 deletions(-)

New commits:
commit e10deac930b7aa982f2ab921d57975d4028314db
Author:     Caolán McNamara <[email protected]>
AuthorDate: Tue Sep 30 11:55:33 2025 +0100
Commit:     Caolán McNamara <[email protected]>
CommitDate: Wed Oct 15 12:02:55 2025 +0200

    handle cid ranges, minimal pass through for now
    
    example has multiple subsets fonts all with the same cid ranges,
    but no actualy glyphs in them, so just pass through the declared
    ranges for now.
    
    Change-Id: Ie38cba1b44c1cae5e3e87576561e52a061bf6266
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191679
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Miklos Vajna <[email protected]>
    (cherry picked from commit c610e1b81ecdabc3bfb9ef9d369e323891791c66)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192355
    Reviewed-by: Caolán McNamara <[email protected]>
    Tested-by: Jenkins

diff --git a/svx/source/inc/svdpdf.hxx b/svx/source/inc/svdpdf.hxx
index c506f096b2c1..bb97c4b5ebf5 100644
--- a/svx/source/inc/svdpdf.hxx
+++ b/svx/source/inc/svdpdf.hxx
@@ -59,6 +59,8 @@ struct FontSubSet
     // What glyphs are in the subset and what characters those represent.
     std::map<sal_Int32, OString> glyphToChars;
     std::map<OString, sal_Int32> charsToGlyph;
+    // What glyphs ranges are in the subset
+    std::map<sal_Int32, Range> glyphRangesToChars;
     int nGlyphCount;
 };
 
diff --git a/svx/source/svdraw/svdpdf.cxx b/svx/source/svdraw/svdpdf.cxx
index cb8923a1e36a..8a460791c085 100644
--- a/svx/source/svdraw/svdpdf.cxx
+++ b/svx/source/svdraw/svdpdf.cxx
@@ -1186,6 +1186,14 @@ static bool toPfaCID(SubSetInfo& rSubSetInfo, const 
OUString& fileUrl,
     return true;
 }
 
+static void appendFourByteHex(OStringBuffer& rBuffer, sal_uInt32 nNumber)
+{
+    OString sCodePoint = OString::number(nNumber, 16);
+    for (sal_Int32 j = sCodePoint.getLength(); j < 4; ++j)
+        rBuffer.append('0');
+    rBuffer.append(sCodePoint);
+}
+
 static OString decomposeLegacyUnicodeLigature(UChar32 cUnicode)
 {
     UErrorCode eCode(U_ZERO_ERROR);
@@ -1206,12 +1214,7 @@ static OString decomposeLegacyUnicodeLigature(UChar32 
cUnicode)
             {
                 OStringBuffer aBuffer;
                 for (int32_t i = 0, nLen = sDecomposed.length(); i < nLen; ++i)
-                {
-                    OString sCodePoint = OString::number(sDecomposed[i], 16);
-                    for (sal_Int32 j = sCodePoint.getLength(); j < 4; ++j)
-                        aBuffer.append('0');
-                    aBuffer.append(sCodePoint);
-                }
+                    appendFourByteHex(aBuffer, sDecomposed[i]);
                 return aBuffer.toString();
             }
         }
@@ -1256,22 +1259,30 @@ static void buildCMapAndFeatures(const OUString& 
CMapUrl, const OUString& Featur
 
     SvMemoryStream aInCMap(const_cast<uint8_t*>(toUnicodeData.data()), 
toUnicodeData.size(),
                            StreamMode::READ);
-    OString sLine;
-    while (aInCMap.ReadLine(sLine))
-    {
-        if (sLine.endsWith("beginbfchar"))
-            break;
-    }
 
     std::vector<OString> bfcharlines;
+    std::vector<OString> bfcharranges;
 
-    if (sLine.endsWith("beginbfchar"))
+    OString sLine;
+    while (aInCMap.ReadLine(sLine))
     {
-        while (aInCMap.ReadLine(sLine))
+        if (sLine.endsWith("beginbfchar"))
         {
-            if (sLine.endsWith("endbfchar"))
-                break;
-            bfcharlines.push_back(sLine);
+            while (aInCMap.ReadLine(sLine))
+            {
+                if (sLine.endsWith("endbfchar"))
+                    break;
+                bfcharlines.push_back(sLine);
+            }
+        }
+        else if (sLine.endsWith("beginbfrange"))
+        {
+            while (aInCMap.ReadLine(sLine))
+            {
+                if (sLine.endsWith("endbfrange"))
+                    break;
+                bfcharranges.push_back(sLine);
+            }
         }
     }
 
@@ -1282,6 +1293,51 @@ static void buildCMapAndFeatures(const OUString& 
CMapUrl, const OUString& Featur
     std::map<sal_Int32, OString> ligatureGlyphToChars;
     std::vector<sal_Int32> glyphs;
 
+    if (!bfcharranges.empty())
+    {
+        assert(!bNameKeyed);
+        OString beginline = OString::number(bfcharranges.size()) + " 
begincidrange";
+        CMap.WriteLine(beginline);
+        for (const auto& charrange : bfcharranges)
+        {
+            assert(charrange[0] == '<');
+            sal_Int32 nEnd = charrange.indexOf('>', 1);
+            assert(charrange[nEnd] == '>');
+            sal_Int32 nGlyphRangeStart = o3tl::toInt32(charrange.subView(1, 
nEnd - 1), 16);
+
+            OString remainder(o3tl::trim(charrange.subView(nEnd + 1)));
+            assert(remainder[0] == '<');
+            nEnd = remainder.indexOf('>', 1);
+            assert(remainder[nEnd] == '>');
+            sal_Int32 nGlyphRangeEnd = o3tl::toInt32(remainder.subView(1, nEnd 
- 1), 16);
+
+            sal_Int32 nGlyphRangeLen = nGlyphRangeEnd - nGlyphRangeStart;
+
+            assert(nGlyphRangeLen > 0);
+
+            OString sChars(o3tl::trim(remainder.subView(nEnd + 1)));
+            assert(sChars[0] == '<' && sChars[sChars.getLength() - 1] == '>');
+            OString sContents = sChars.copy(1, sChars.getLength() - 2);
+            //TODO, it might be that there are cases of ligatures here too in
+            //which case I presume that it can only be with a range of a single
+            //glyph(?). If that's how it works, then we could push the entry
+            //instead into bfcharlines.
+            assert(sContents.getLength() == 4);
+            sal_Int32 nCharRangeStart = o3tl::toInt32(sContents, 16);
+            OStringBuffer aBuffer("<");
+            appendFourByteHex(aBuffer, nCharRangeStart);
+            aBuffer.append("> <");
+            sal_Int32 nCharRangeEnd = nCharRangeStart + nGlyphRangeLen;
+            appendFourByteHex(aBuffer, nCharRangeEnd);
+            aBuffer.append("> "_ostr + OString::number(nGlyphRangeStart));
+            OString cidrangeline = aBuffer.toString();
+            rSubSetInfo.aComponents.back().glyphRangesToChars[nGlyphRangeStart]
+                = Range(nCharRangeStart, nCharRangeEnd);
+            CMap.WriteLine(cidrangeline);
+        }
+        CMap.WriteLine("endcidrange");
+    }
+
     if (!bfcharlines.empty())
     {
         OString beginline = OString::number(bfcharlines.size()) + " 
begincidchar";
@@ -1427,13 +1483,60 @@ static EmbeddedFontInfo mergeFontSubsets(const 
OUString& mergedFontUrl,
 
     mergedCMap.WriteBytes(cmapprefix, std::size(cmapprefix) - 1);
 
-    sal_Int32 cidcharcount(0);
+    sal_Int32 cidcharcount(0), cidrangecount(0);
+    bool differentcidranges(false);
     for (const auto& component : rSubSetInfo.aComponents)
         cidcharcount += component.glyphToChars.size();
 
+    for (size_t i = 0, size = rSubSetInfo.aComponents.size(); i < size; ++i)
+    {
+        const auto& component = rSubSetInfo.aComponents[i];
+        if (i == 0)
+        {
+            cidrangecount += component.glyphRangesToChars.size();
+            continue;
+        }
+
+        if (component.glyphRangesToChars != rSubSetInfo.aComponents[i - 
1].glyphRangesToChars)
+        {
+            cidrangecount += component.glyphRangesToChars.size();
+            differentcidranges = true;
+        }
+    }
+
+    assert(!differentcidranges && "TODO: deal with this when an example 
arises");
+    if (differentcidranges)
+        return EmbeddedFontInfo();
+
     std::map<sal_Int32, OString> ligatureGlyphToChars;
     std::map<OString, sal_Int32> charsToGlyph;
 
+    if (cidrangecount)
+    {
+        OString beginline = OString::number(cidrangecount) + " begincidrange";
+        mergedCMap.WriteLine(beginline);
+
+        const auto& component = rSubSetInfo.aComponents[0];
+        for (const auto& entry : component.glyphRangesToChars)
+        {
+            sal_Int32 glyphrangebegin = entry.first;
+            sal_Int32 charrangebegin = entry.second.Min();
+            sal_Int32 charrangeend = entry.second.Max();
+
+            OStringBuffer aBuffer("<");
+            appendFourByteHex(aBuffer, charrangebegin);
+            aBuffer.append("> <");
+            appendFourByteHex(aBuffer, charrangeend);
+            aBuffer.append("> "_ostr + OString::number(glyphrangebegin));
+            OString cidrangeline = aBuffer.toString();
+
+            mergedCMap.WriteLine(cidrangeline);
+        }
+
+        // glyphoffset += component.nGlyphCount;
+        mergedCMap.WriteLine("endcidrange");
+    }
+
     if (cidcharcount)
     {
         sal_Int32 glyphoffset(0);

Reply via email to