How to prevent endless g_object_get_qdata loop when subclassing PangoFontMap?

36 Views Asked by At

I'm trying to subclass PangoFontMap to read fonts in a custom format from a custom directory (the TXF format which cannot be read by FreeType2, but by OSG). I have the following code:

PangoFontOSG.hxx

#ifndef PANGO_FONT_OSG_HXX
#define PANGO_FONT_OSG_HXX

#include <map>

#include <pango/pango-font.h>

#include <osgText/Font>

#include "PangoFontMapOSG.hxx"

struct FontOSG {
    PangoFont parent_instance;
    PangoFontMap* fontmap;
};
struct FontOSGClass {
    PangoFontClass class_instance;
};

class PangoFontOSG {
    public:
        PangoFontOSG(PangoFontMapOSG* fontmap);
        ~PangoFontOSG();
        static PangoFontOSG* getFont(PangoFont*);
        
        PangoFont* _font;
    private:
        static std::map<PangoFont*, PangoFontOSG*> _fontMap;
};

#endif // PANGO_FONT_MAP_OSG_HXX

PangoFontOSG.cxx

#include <glib-object.h>

#include "PangoFontMapOSG.hxx"
#include "PangoFontOSG.hxx"

G_DEFINE_TYPE(FontOSG, font_osg, PANGO_TYPE_FONT);
#define TYPE_FONT_OSG (font_osg_get_type())
#define FONT_OSG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_FONT_OSG, FontOSG))
#define IS_FONT_OSG(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), TYPE_FONT_OSG))

static GObjectClass* _pangoClass = 0;

void font_osg_init(FontOSG* priv) {
}

void font_osg_finalize(GObject* object) {
    // FontMap* priv = FONT_MAP(object);
    G_OBJECT_CLASS(_pangoClass)->finalize(object);
}

void font_osg_class_init(FontOSGClass* klass) {
    GObjectClass* object_class = G_OBJECT_CLASS(klass);
    object_class->finalize = font_osg_finalize;
    _pangoClass = static_cast<GObjectClass*>(g_type_class_peek_parent(klass));
}

std::map<PangoFont*, PangoFontOSG*> PangoFontOSG::_fontMap;

PangoFontOSG* PangoFontOSG::getFont(PangoFont* font) {
    if (_fontMap.count(font)) {
        return _fontMap[font];
    } else {
        return nullptr;
    }
}

PangoFontOSG::PangoFontOSG(PangoFontMapOSG* fontmap) {
    FontOSG* font = static_cast<FontOSG*>(g_object_new(TYPE_FONT_OSG, 0));
    font->fontmap = fontmap->_fontmap;
    _font = PANGO_FONT(font);
    _fontMap[_font] = this;
}

PangoFontOSG::~PangoFontOSG() {
    _fontMap.erase(_font);
}

PangoFontMapOSG.hxx

#ifndef PANGO_FONT_MAP_OSG_HXX
#define PANGO_FONT_MAP_OSG_HXX

#include <map>

#include <pango/pango-context.h>
#include <pango/pango-font.h>
#include <pango/pango-fontmap.h>

#include <osgText/Font>

struct FontMapOSG {
    PangoFontMap parent_instance;
};
struct FontMapOSGClass {
    PangoFontMapClass class_instance;
};

class PangoFontMapOSG {
    public:
        PangoFontMapOSG();
        ~PangoFontMapOSG();
        static PangoFontMapOSG* getFontMap(PangoFontMap*);

        static void c_list_families(PangoFontMap* fontmap, PangoFontFamily*** families, int* n_families) {
            PangoFontMapOSG* fontmapOSG = getFontMap(fontmap);
            if (!fontmapOSG) {
                return;
            }
            fontmapOSG->list_families(families, n_families);
        };
        static PangoFont* c_load_font(PangoFontMap* fontmap, PangoContext* context, const PangoFontDescription* desc) {
            PangoFontMapOSG* fontmapOSG = getFontMap(fontmap);
            if (!fontmapOSG) {
                return nullptr;
            }
            return fontmapOSG->load_font(context, desc);
        };
        static PangoFontset* c_load_fontset(PangoFontMap* fontmap, PangoContext* context, const PangoFontDescription* desc, PangoLanguage* language) {
            PangoFontMapOSG* fontmapOSG = getFontMap(fontmap);
            if (!fontmapOSG) {
                return nullptr;
            }
            return fontmapOSG->load_fontset(context, desc, language);
        };

        PangoFont* load_font(PangoContext* context, const PangoFontDescription* desc);
        PangoFontset* load_fontset(PangoContext* context, const PangoFontDescription* desc, PangoLanguage* language);
        void list_families(PangoFontFamily*** families, int* n_families);
        
        PangoFontMap* _fontmap;
    private:
        static std::map<PangoFontMap*, PangoFontMapOSG*> _fontmapMap;
};

#endif // PANGO_FONT_MAP_OSG_HXX

PangoFontMapOSG.cxx

#include <set>

#include <glib-object.h>
#include <pango/pango-fontmap.h>
#include <pango/pango-fontset-simple.h>

#include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/misc/ResourceManager.hxx>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include "PangoFontMapOSG.hxx"
#include "PangoFontOSG.hxx"

G_DEFINE_TYPE(FontMapOSG, font_map_osg, PANGO_TYPE_FONT_MAP);
#define TYPE_FONT_MAP_OSG (font_map_osg_get_type())
#define FONT_MAP_OSG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_FONT_MAP_OSG, FontMapOSG))
#define IS_FONT_MAP_OSG(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), TYPE_FONT_MAP_OSG))

static GObjectClass* _pangoClass = 0;

void font_map_osg_init(FontMapOSG* priv) {
}

void font_map_osg_finalize(GObject* object) {
    G_OBJECT_CLASS(_pangoClass)->finalize(object);
}

void font_map_osg_class_init(FontMapOSGClass* klass) {
    GObjectClass* object_class = G_OBJECT_CLASS(klass);
    object_class->finalize = font_map_osg_finalize;
    PangoFontMapClass* font_map_class = PANGO_FONT_MAP_CLASS(klass);
    _pangoClass = static_cast<GObjectClass*>(g_type_class_peek_parent(klass));
    font_map_class->list_families = &PangoFontMapOSG::c_list_families;
    font_map_class->load_font = &PangoFontMapOSG::c_load_font;
    font_map_class->load_fontset = &PangoFontMapOSG::c_load_fontset;
    font_map_class->shape_engine_type = "PangoRendererCanvas";
}

std::map<PangoFontMap*, PangoFontMapOSG*> PangoFontMapOSG::_fontmapMap;

PangoFontMapOSG* PangoFontMapOSG::getFontMap(PangoFontMap* fontmap) {
    if (_fontmapMap.count(fontmap)) {
        return _fontmapMap[fontmap];
    } else {
        return nullptr;
    }
}

PangoFontMapOSG::PangoFontMapOSG() {
    _fontmap = PANGO_FONT_MAP(static_cast<FontMapOSG*>(g_object_new(TYPE_FONT_MAP_OSG, 0)));
    _fontmapMap[_fontmap] = this;
}

PangoFontMapOSG::~PangoFontMapOSG() {
    _fontmapMap.erase(_fontmap);
}

PangoFont* PangoFontMapOSG::load_font(PangoContext* context, const PangoFontDescription* desc) {
    SG_LOG(SG_GENERAL, SG_ALERT, "PangoFontMapOSG::load_font family=" << pango_font_description_get_family(desc));
    PangoFont* font = PangoFontOSG(this)._font;
    return font;
}

PangoFontset* PangoFontMapOSG::load_fontset(PangoContext* context, const PangoFontDescription* desc, PangoLanguage* language) {
    SG_LOG(SG_GENERAL, SG_ALERT, "PangoFontMapOSG::load_fontset family=" << pango_font_description_get_family(desc));
    PangoFontsetSimple* fontset = pango_fontset_simple_new(language);
    PangoFontDescription* tmp_desc = pango_font_description_copy_static(desc);

    const char* family = pango_font_description_get_family(desc);
    char** families = g_strsplit(family ? family : "", ",", -1);

    for (int i = 0; families[i]; i++) {
        char **aliases;
        int n_aliases;
        PangoFont *font;


        pango_font_description_set_family_static((PangoFontDescription*)desc, family);
        font = load_font(context, desc);
        if (font) {
            pango_fontset_simple_append(fontset, font);
        }
    }
    g_strfreev (families);

    return PANGO_FONTSET(fontset);
}

void PangoFontMapOSG::list_families(PangoFontFamily*** families, int* n_families) {
    const SGPath fontmapXMLPath = simgear::ResourceManager::instance()->findPath("Fonts/fontmap.xml");
    if (fontmapXMLPath.isNull()) {
        simgear::reportFailure(
            simgear::LoadFailure::NotFound,
            simgear::ErrorCode::LoadingTexture,
            "PangoFontMapOSG couldn't find fontmap file 'Fonts/fontmap.xml'"
        );
        return;
    }

    SGPropertyNode* fontmapXML = new SGPropertyNode();
    readProperties(fontmapXMLPath, fontmapXML);
    if (!fontmapXML) {
        SG_LOG(SG_IO, SG_ALERT, "Failed loading fontmap from '" << fontmapXMLPath.utf8Str() << "'");
        return;
    }

    simgear::PropertyList fonts = fontmapXML->getChildren("font");
    std::set<std::string> familyNames;
    for (simgear::PropertyList::iterator it = fonts.begin(); it != fonts.end(); it++) {
        familyNames.insert((*it)->getStringValue("family", ""));
    }
    SG_LOG(SG_GENERAL, SG_ALERT, "families " << (*familyNames.begin()));
}

In the main function of my program PangoRenderer, I have:

            PangoContex* context = pango_context_new();
            PangoFontMapOSG fmap = PangoFontMapOSG();
            pango_context_set_font_map(_context, (PangoFontMap*)fmap._fontmap);

            PangoLayout* layout = pango_layout_new(_context);

When I then call layout->set_markup(…), I get the following console output repeating forever:

(process:1250236): GLib-GObject-CRITICAL **: 17:57:30.114: g_object_get_qdata: assertion 'G_IS_OBJECT (object)' failed

(process:1250236): GLib-GObject-CRITICAL **: 17:57:30.114: g_object_replace_qdata: assertion 'G_IS_OBJECT (object)' failed

The last function before g_object_get_qdata I could identify in gdb is pango_renderer_draw_layout.

The most important thing is, if I don't override the load_fontset function of PangoFont, the console messages are not printed - instead, it says that All font fallbacks failed!!! even though I am returning a non-null font from load_font.

Now, the question: Where is the small mistake I made that causes either of the issues ? Am I missing a function that has to be implemented in FontOSG ?

0

There are 0 best solutions below