desktop/inc/lib/init.hxx                     |    2 
 desktop/source/lib/init.cxx                  |   62 +++++++++++++++++++++++++++
 include/LibreOfficeKit/LibreOfficeKitEnums.h |   23 ++++++++++
 libreofficekit/source/gtk/lokdocview.cxx     |    1 
 4 files changed, 88 insertions(+)

New commits:
commit 0d7763e1c2676bcf7ccbaf6c632ca62b7c30ba79
Author:     Tor Lillqvist <t...@collabora.com>
AuthorDate: Wed Aug 24 15:40:16 2022 +0300
Commit:     Tor Lillqvist <t...@collabora.com>
CommitDate: Thu Aug 25 13:45:46 2022 +0200

    Tell LibreOfficeKit clients what fonts in a document are missing on the 
machine
    
    Use the OutputDevice::StartTrackingFontMappingUse() and
    OutputDevice::FinishTrackingFontMappingUse() functionality that was
    added last year.
    
    Add a new LibreOfficeKit document callback:
    LOK_CALLBACK_FONTS_MISSING.
    
    "Font" here means just the family name. We dont really know what style
    from the family is missing.
    
    Change-Id: Iec4349b5827e7d1dbdde7f8a9f8da92efde429e0
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138766
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Tor Lillqvist <t...@collabora.com>

diff --git a/desktop/inc/lib/init.hxx b/desktop/inc/lib/init.hxx
index 3ef6433ebea2..baa1b682de07 100644
--- a/desktop/inc/lib/init.hxx
+++ b/desktop/inc/lib/init.hxx
@@ -13,6 +13,7 @@
 #include <unordered_map>
 #include <memory>
 #include <mutex>
+#include <set>
 #include <string_view>
 
 #include <boost/property_tree/ptree.hpp>
@@ -240,6 +241,7 @@ namespace desktop {
         std::shared_ptr< LibreOfficeKitDocumentClass > m_pDocumentClass;
         std::map<size_t, std::shared_ptr<CallbackFlushHandler>> 
mpCallbackFlushHandlers;
         const int mnDocumentId;
+        std::set<OUString> maFontsMissing;
 
         explicit LibLODocument_Impl(const 
css::uno::Reference<css::lang::XComponent>& xComponent,
                                     int nDocumentId);
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index ada68c426d61..23807a7f1403 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -2590,6 +2590,8 @@ static LibreOfficeKitDocument* 
lo_documentLoadWithOptions(LibreOfficeKit* pThis,
         aFilterOptions[3].Value <<= nUpdateDoc;
         */
 
+        OutputDevice::StartTrackingFontMappingUse();
+
         const int nThisDocumentId = nDocumentIdCounter++;
         SfxViewShell::SetCurrentDocId(ViewShellDocId(nThisDocumentId));
         uno::Reference<lang::XComponent> xComponent = 
xComponentLoader->loadComponentFromURL(
@@ -2613,6 +2615,49 @@ static LibreOfficeKitDocument* 
lo_documentLoadWithOptions(LibreOfficeKit* pThis,
             int nState = doc_getSignatureState(pDocument);
             pLib->mpCallback(LOK_CALLBACK_SIGNATURE_STATUS, 
OString::number(nState).getStr(), pLib->mpCallbackData);
         }
+
+        auto aFontMappingUseData = 
OutputDevice::FinishTrackingFontMappingUse();
+
+        // Filter out font substitutions that actually aren't any 
substitutions, like "Liberation
+        // Serif" -> "Liberation Serif/Regular". If even one of the 
"substitutions" of a font is to
+        // the same font, don't count that as a missing font.
+
+        for (std::size_t i = 0; i < aFontMappingUseData.size();)
+        {
+            // If the original font had an empty style and one of its 
replacement fonts has the same
+            // family name, we assume the font is present. The root problem 
here is that the code
+            // that collects font substitutions tends to get just empty styles 
for the font that is
+            // being substituded, as vcl::Font::GetStyleName() tents to return 
an empty string.
+            // (Italicness is instead indicated by what vcl::Font::GetItalic() 
returns and boldness
+            // by what vcl::Font::GetWeight() returns.)
+            if (aFontMappingUseData[i].mOriginalFont.indexOf('/') == -1)
+            {
+                bool bSubstitutedByTheSame = false;
+                for (const auto &j : aFontMappingUseData[i].mUsedFonts)
+                {
+                    if 
(j.startsWith(OUStringConcatenation(aFontMappingUseData[i].mOriginalFont + 
"/")))
+                    {
+                        bSubstitutedByTheSame = true;
+                        break;
+                    }
+                }
+
+                if (bSubstitutedByTheSame)
+                    aFontMappingUseData.erase(aFontMappingUseData.begin() + i);
+                else
+                    i++;
+            }
+            else
+            {
+                i++;
+            }
+        }
+
+        for (std::size_t i = 0; i < aFontMappingUseData.size(); ++i)
+        {
+            
pDocument->maFontsMissing.insert(aFontMappingUseData[i].mOriginalFont);
+        }
+
         return pDocument;
     }
     catch (const uno::Exception& exception)
@@ -3808,6 +3853,23 @@ static void doc_registerCallback(LibreOfficeKitDocument* 
pThis,
             
pDocument->mpCallbackFlushHandlers[nView]->setViewId(pViewShell->GetViewShellId().get());
             
pViewShell->setLibreOfficeKitViewCallback(pDocument->mpCallbackFlushHandlers[nView].get());
         }
+
+        if (pDocument->maFontsMissing.size() != 0)
+        {
+            std::string sPayload = "{ \"fontsmissing\": [ ";
+            bool bFirst = true;
+            for (const auto &f : pDocument->maFontsMissing)
+            {
+                if (bFirst)
+                    bFirst = false;
+                else
+                    sPayload += ", ";
+                sPayload += "\"" + std::string(f.toUtf8().getStr()) + "\"";
+            }
+            sPayload += " ] }";
+            pCallback(LOK_CALLBACK_FONTS_MISSING, sPayload.c_str(), pData);
+            pDocument->maFontsMissing.clear();
+        }
     }
     else
     {
diff --git a/include/LibreOfficeKit/LibreOfficeKitEnums.h 
b/include/LibreOfficeKit/LibreOfficeKitEnums.h
index 22577a193e52..0e86a654a464 100644
--- a/include/LibreOfficeKit/LibreOfficeKitEnums.h
+++ b/include/LibreOfficeKit/LibreOfficeKitEnums.h
@@ -860,6 +860,27 @@ typedef enum
      * [<startColumn>, <startRow>, <endColumn>, <endRow>]
      */
     LOK_CALLBACK_PRINT_RANGES = 56,
+
+    /**
+     * Informs the LibreOfficeKit client that a font specified in the
+     * document is missing.
+     *
+     * This callback is emitted right after the document has been loaded.
+     *
+     * Payload example:
+     * {
+     *     "fontsmissing": [
+     *         "Some Random Font",
+     *         "Another Font"
+     *     ]
+     * }
+     *
+     * The names are those of the font family. Sadly it is currently
+     * not possible to know the name of the font style that is
+     * missing.
+     *
+     */
+    LOK_CALLBACK_FONTS_MISSING = 57,
 }
 LibreOfficeKitCallbackType;
 
@@ -1002,6 +1023,8 @@ static inline const char* lokCallbackTypeToString(int 
nType)
         return "LOK_CALLBACK_CONTENT_CONTROL";
     case LOK_CALLBACK_PRINT_RANGES:
         return "LOK_CALLBACK_PRINT_RANGES";
+    case LOK_CALLBACK_FONTS_MISSING:
+        return "LOK_CALLBACK_FONTS_MISSING";
     }
 
     assert(!"Unknown LibreOfficeKitCallbackType type.");
diff --git a/libreofficekit/source/gtk/lokdocview.cxx 
b/libreofficekit/source/gtk/lokdocview.cxx
index 0c6874660aef..051970538a08 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -1465,6 +1465,7 @@ callback (gpointer pData)
     case LOK_COMMAND_BLOCKED:
     case LOK_CALLBACK_SC_FOLLOW_JUMP:
     case LOK_CALLBACK_PRINT_RANGES:
+    case LOK_CALLBACK_FONTS_MISSING:
     {
         // TODO: Implement me
         break;

Reply via email to