Make Noto Color Emoji font work on Linux

Noto Color Emoji is a bitmap color font, Cairo knows how to scale such
fonts and FontConfig will identify them as scalable but not outline
fonts, so change the FontConfig checks to checks for scalability.

Make sft.cxx:doOpenTTFont() accept non-outline fonts, the text will not
show in PDF but that is not worse than the status quo.

Change-Id: I756c718296d2c43e3165cd2f07b11bbb981318d3
Reviewed-on: https://gerrit.libreoffice.org/78218
Tested-by: Jenkins
Reviewed-by: Khaled Hosny <khaledhosny@eglug.org>
(cherry picked from commit dcf7792da2aa2a1ef774a124f7b21f68fff0fd15)
Reviewed-on: https://gerrit.libreoffice.org/78589
diff --git a/vcl/source/font/fontmetric.cxx b/vcl/source/font/fontmetric.cxx
index 4e6c648..a9325fd 100644
--- a/vcl/source/font/fontmetric.cxx
+++ b/vcl/source/font/fontmetric.cxx
@@ -485,8 +485,8 @@
    if (mnAscent || mnDescent)
        mnIntLeading = mnAscent + mnDescent - mnHeight;

    SAL_INFO("vcl.gdi.fontmetric",
                  "fsSelection: "   << rInfo.fsSelection
    SAL_INFO("vcl.gdi.fontmetric", GetFamilyName()
             << ": fsSelection: "   << rInfo.fsSelection
             << ", typoAscender: "  << rInfo.typoAscender
             << ", typoDescender: " << rInfo.typoDescender
             << ", typoLineGap: "   << rInfo.typoLineGap
diff --git a/vcl/source/fontsubset/sft.cxx b/vcl/source/fontsubset/sft.cxx
index 2ad4169..979783a 100644
--- a/vcl/source/fontsubset/sft.cxx
+++ b/vcl/source/fontsubset/sft.cxx
@@ -1668,7 +1668,10 @@
        /* TODO: implement to get subsetting */
        assert(t->goffsets != nullptr);
    } else {
        return SFErrCodes::TtFormat;
        // Bitmap font, accept for now.
        t->goffsets = static_cast<sal_uInt32 *>(calloc(1+t->nglyphs, sizeof(sal_uInt32)));
        /* TODO: implement to get subsetting */
        assert(t->goffsets != nullptr);
    }

    table = getTable(t, O_hhea);
diff --git a/vcl/unx/generic/fontmanager/fontconfig.cxx b/vcl/unx/generic/fontmanager/fontconfig.cxx
index e13eb0a..8e3e916 100644
--- a/vcl/unx/generic/fontmanager/fontconfig.cxx
+++ b/vcl/unx/generic/fontmanager/fontconfig.cxx
@@ -65,7 +65,7 @@

class FontCfgWrapper
{
    FcFontSet* m_pOutlineSet;
    FcFontSet* m_pFontSet;

    void addFontSet( FcSetName );

@@ -93,17 +93,14 @@
};

FontCfgWrapper::FontCfgWrapper()
    : m_pOutlineSet( nullptr )
    : m_pFontSet( nullptr )
{
    FcInit();
}

void FontCfgWrapper::addFontSet( FcSetName eSetName )
{
    /*
      add only acceptable outlined fonts to our config,
      for future fontconfig use
    */
    // Add only acceptable fonts to our config, for future fontconfig use.
    FcFontSet* pOrig = FcConfigGetFonts( FcConfigGetCurrent(), eSetName );
    if( !pOrig )
        return;
@@ -112,10 +109,12 @@
    for( int i = 0; i < pOrig->nfont; ++i )
    {
        FcPattern* pPattern = pOrig->fonts[i];
        // #i115131# ignore non-outline fonts
        FcBool bOutline = FcFalse;
        FcResult eOutRes = FcPatternGetBool( pPattern, FC_OUTLINE, 0, &bOutline );
        if( (eOutRes != FcResultMatch) || (bOutline == FcFalse) )
        // #i115131# ignore non-scalable fonts
        // Scalable fonts are usually outline fonts, but some bitmaps fonts
        // (like Noto Color Emoji) are also scalable.
        FcBool bScalable = FcFalse;
        FcResult eScalableRes = FcPatternGetBool(pPattern, FC_SCALABLE, 0, &bScalable);
        if ((eScalableRes != FcResultMatch) || (bScalable == FcFalse))
            continue;

        // Ignore Type 1 fonts, too.
@@ -125,7 +124,7 @@
            continue;

        FcPatternReference( pPattern );
        FcFontSetAdd( m_pOutlineSet, pPattern );
        FcFontSetAdd( m_pFontSet, pPattern );
    }

    // TODO?: FcFontSetDestroy( pOrig );
@@ -216,16 +215,16 @@

FcFontSet* FontCfgWrapper::getFontSet()
{
    if( !m_pOutlineSet )
    if( !m_pFontSet )
    {
        m_pOutlineSet = FcFontSetCreate();
        m_pFontSet = FcFontSetCreate();
        addFontSet( FcSetSystem );
        addFontSet( FcSetApplication );

        ::std::sort(m_pOutlineSet->fonts,m_pOutlineSet->fonts+m_pOutlineSet->nfont,SortFont());
        ::std::sort(m_pFontSet->fonts,m_pFontSet->fonts+m_pFontSet->nfont,SortFont());
    }

    return m_pOutlineSet;
    return m_pFontSet;
}

FontCfgWrapper::~FontCfgWrapper()
@@ -370,10 +369,10 @@
{
    m_aFontNameToLocalized.clear();
    m_aLocalizedToCanonical.clear();
    if( m_pOutlineSet )
    if( m_pFontSet )
    {
        FcFontSetDestroy( m_pOutlineSet );
        m_pOutlineSet = nullptr;
        FcFontSetDestroy( m_pFontSet );
        m_pFontSet = nullptr;
    }
    m_pLanguageTag.reset();
}
@@ -504,7 +503,7 @@
            int width = 0;
            int spacing = 0;
            int nEntryId = -1;
            FcBool outline = false;
            FcBool scalable = false;

            FcResult eFileRes         = FcPatternGetString(pFSet->fonts[i], FC_FILE, 0, &file);
            FcResult eFamilyRes       = rWrapper.LocalizedElementFromPattern( pFSet->fonts[i], &family, FC_FAMILY, FC_FAMILYLANG );
@@ -515,11 +514,11 @@
            FcResult eWeightRes       = FcPatternGetInteger(pFSet->fonts[i], FC_WEIGHT, 0, &weight);
            FcResult eWidthRes        = FcPatternGetInteger(pFSet->fonts[i], FC_WIDTH, 0, &width);
            FcResult eSpacRes         = FcPatternGetInteger(pFSet->fonts[i], FC_SPACING, 0, &spacing);
            FcResult eOutRes          = FcPatternGetBool(pFSet->fonts[i], FC_OUTLINE, 0, &outline);
            FcResult eScalableRes     = FcPatternGetBool(pFSet->fonts[i], FC_SCALABLE, 0, &scalable);
            FcResult eIndexRes        = FcPatternGetInteger(pFSet->fonts[i], FC_INDEX, 0, &nEntryId);
            FcResult eFormatRes       = FcPatternGetString(pFSet->fonts[i], FC_FONTFORMAT, 0, &format);

            if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eOutRes != FcResultMatch )
            if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eScalableRes != FcResultMatch )
                continue;

            SAL_INFO(
@@ -529,15 +528,15 @@
                << (eSpacRes == FcResultMatch ? slant : -1) << ", style = \""
                << (eStyleRes == FcResultMatch ? reinterpret_cast<const char*>(style) : "<nil>")
                << "\",  width = " << (eWeightRes == FcResultMatch ? width : -1) << ", spacing = "
                << (eSpacRes == FcResultMatch ? spacing : -1) << ", outline = "
                << (eOutRes == FcResultMatch ? outline : -1) << ", format "
                << (eSpacRes == FcResultMatch ? spacing : -1) << ", scalable = "
                << (eScalableRes == FcResultMatch ? scalable : -1) << ", format "
                << (eFormatRes == FcResultMatch
                    ? reinterpret_cast<const char*>(format) : "<unknown>"));

//            OSL_ASSERT(eOutRes != FcResultMatch || outline);
//            OSL_ASSERT(eScalableRes != FcResultMatch || scalable);

            // only outline fonts are usable to psprint anyway
            if( eOutRes == FcResultMatch && ! outline )
            // only scalable fonts are usable to psprint anyway
            if( eScalableRes == FcResultMatch && ! scalable )
                continue;

            if (isPreviouslyDuplicateOrObsoleted(pFSet, i))
diff --git a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
index 4e3a834..396c937 100644
--- a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
+++ b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
@@ -436,9 +436,9 @@

    FT_New_Size( maFaceFT, &maSizeFT );
    FT_Activate_Size( maSizeFT );
    FT_Error rc = FT_Set_Pixel_Sizes( maFaceFT, mnWidth, rFSD.mnHeight );
    if( rc != FT_Err_Ok )
        return;
    /* This might fail for color bitmap fonts, but that is fine since we will
     * not need any glyph data from FreeType in this case */
    /*FT_Error rc = */ FT_Set_Pixel_Sizes( maFaceFT, mnWidth, rFSD.mnHeight );

    FT_Select_Charmap(maFaceFT, FT_ENCODING_UNICODE);