freetype-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[ft-devel] Sample driver example


From: Ian Britten
Subject: [ft-devel] Sample driver example
Date: Tue, 10 Jun 2008 16:59:57 -0300
User-agent: Mozilla Thunderbird 1.0.2 (X11/20050322)

Werner LEMBERG wrote:

Can you post your driver to this list so that we can have a look at
it?  This is, remove all stuff which actually does something with your
proprietary data and leave the skeleton.  This probably helps more
than anything else.

Attached is a simple little driver that we have.
It models a totally in-memory font (No file), which only contains
a single glyph.
It is used as a final fallback for those rare cases when we can't
seem to find *any* font file on the system, and it at least lets
us draw rectangles for each of the characters of the text, rather
than crashing, triggering an error, etc, etc.

It may not be particularly useful, but serves as an example of
someone trying to write a driver from *outside* of FT.
[ Apologies that the code is a bit C++-ish... ]

We also have a second, more extensive driver that works with our
own file format, and obviously has a much more extensive
implementation for the various functions.  However, the FT
hooks are basically the same (Just more of the callbacks
are implemented, for kerning, etc)

The crux of the problem is that in order to do this, a couple of
the FT_INTERNAL header files need to be publicly available, or
at least some of the data structures they declare to be made
available, primarily FT_Driver_ClassRec and FT_CMap_ClassRec.

I'm not particularly attached to the code (It was written years
ago, by someone else), and if anyone has any suggestions,
improvements, alternative approaches, etc, please feel free to
speak up!

Thanks for any help, guidance, etc!
Ian
// Most error handling skipped, for clarity.
// Code comes from C++ and may not compile as C
// Code not actually compiled - Ignore any typos, etc.


// This (incomplete) function represents the starting point
void init(void)
{
        // Make the library
        FT_Library library;
        FT_Init_FreeType(&library);

        // Add the custom driver (as a new module)
        FT_Add_Module(library, getDefaultDriver());


        // Continue with remaining work...  (eg: cache, etc)


        return;
}

// These names are used when making the driver, and if/when a final
// fallback font (name) is needed
static const char FAILSAFE_DRIVER[] = "Fail safe driver";
static const std::string FAILSAFE_NAME("NO FONT");


// This function defines+creates the default driver, and returns a
// reference (handle) to it.  (AKA Singleton, Global, etc)
static const FT_Module_Class& getDefaultDriver(void)
{
        static const FT_Driver_ClassRec theDriver = {
                {
                        (ft_module_font_driver|ft_module_driver_scalable|0),
                        sizeof(FT_DriverRec),
                        FAILSAFE_DRIVER, // driver name
                        0x10000L, // driver version == 1.0
                        0x20000L, // driver requires FreeType 2.0 or above
                        0, // driver specific interface
                        NULL, // FT_Module_Constructor
                        NULL, // FT_Module_Destructor
                        NULL, // FT_Module_Requester
                },
                sizeof(FT_FaceRec),
                sizeof(FT_SizeRec),
                sizeof(FT_GlyphSlotRec),
                initDefaultFace, // FT_Face_InitFunc
                NULL, // FT_Face_DoneFunc
                NULL, // FT_Size_InitFunc
                NULL, // FT_Size_DoneFunc
                NULL, // FT_Slot_InitFunc
                NULL, // FT_Slot_DoneFunc
                NULL, // FT_Size_ResetPointsFunc
                NULL, // FT_Size_ResetPixelsFunc
                loadDefaultGlyph, // FT_Slot_LoadFunc
                NULL, // FT_Face_GetKerningFunc
                NULL, // FT_Face_AttachFunc
                NULL, // FT_Face_GetAdvancesFunc
                NULL, // FT_Size_RequestFunc
                NULL // FT_Size_SelectFunc
        };

        // Return it as a module (Easier for the caller)
        return reinterpret_cast<const FT_Module_Class&>(theDriver); 
}

// Initialize the given face (As per FT_Face_InitFunc)
// This face only contains one glyph (A filled rectangle), used to draw
// any/all characters with.
static FT_Error initDefaultFace(
        FT_Stream stream,
        FT_Face face,
        FT_Int face_index,
        FT_Int /*num_params*/,
        FT_Parameter* /*params*/
        )
{
        // Validate the input
        const std::string *keyPtr =
                reinterpret_cast<std::string*>(stream->base);
        if ((keyPtr == NULL) || (*keyPtr != FAILSAFE_NAME))
                return FT_Err_Unknown_File_Format;

        // 1)   The number of faces.
        //      Only 1 for this face. 
        face->num_faces = 1;

        // 2)   The index of the face in its resource. 
        face->face_index = face_index;

        // 3) A set of bit flags that give important information
        // about the face.
        face->face_flags =
                (FT_FACE_FLAG_SCALABLE | FT_FACE_FLAG_HORIZONTAL);

        // 4) A set of bit flags indicating the style of the face 
        //     (i.e., italic, bold, underline, etc).
        face->style_flags = 0;

        // 5) The total number of glyphs in the face.
        face->num_glyphs = 1;

        // 6) The face's family name.
        face->family_name = NULL;

        // 7)  The face's style name. 
        face->style_name = NULL;  

        // 8)  The fixed sizes available in this face.
        //     Not relevant for scalable fonts.
        face->num_fixed_sizes = 0;
        face->available_sizes = NULL;

        // 9) Setup the charmap
        //    Adding the new charmap will automatically set the number
        //    of charmaps to 1
        FT_CharMapRec charmap;
        charmap.face        = FT_FACE(face);
        charmap.platform_id = 3;
        charmap.encoding_id = 1;
        charmap.encoding    = FT_ENCODING_UNICODE;
        FT_CMap_New( &getCharMap(), NULL, &charmap, NULL );

        // 11) Client data, not used
        face->generic.data = NULL;
        face->generic.finalizer = NULL;


        // 12) The font bounding box.
        const FT_Short xMin = 0;
        const FT_Short xMax = 17000;
        const FT_Short yMin = 0;
        const FT_Short yMax = 32000;
        face->bbox.xMin = xMin;
        face->bbox.yMin = yMin; 
        face->bbox.xMax = xMax; 
        face->bbox.yMax = yMax; 

        // 13) The size of the Em square
        face->units_per_EM = 32000;

        // 14)  Should be the vertical distance from the baseline to 
        //      the topmost point of any glyph in the face.
        //      This field's value is positive, expressed in font units.
        face->ascender = yMax;

        // 15)  Should be the vertical distance from the baseline to 
        //      the bottommost point of any glyph in the face. 
        //      This field's value is positive, expressed in font units.
        face->descender = -yMin;

        // 16)  The face's height is the vertical distance from one baseline
        //      to the next when writing several lines of text. 
        //      Its value is always positive, expressed in font units.
        // 20% seems to be a reasonable value.
        const FT_Short lineGap = static_cast<FT_Short>(0.2 * (yMax - yMin));
        face->height = static_cast<FT_Short>(
                face->ascender + face->descender + lineGap);

        // 17)  The maximal advance width, in font units, for all glyphs 
        //      in this face. This can be used to make word wrapping 
        //      computations faster.
        face->max_advance_width = xMax - xMin;

        // 18)  The maximal advance height, in font units, for all glyphs
        //      in this face. This is only relevant for vertical layouts,
        //      and should be set to the `height' for fonts that do not
        //      provide vertical metrics.
        face->max_advance_height = face->height;

        // 19)  The position, in font units, of the underline line for this 
        //      face. It's the center of the underlining stem.
        face->underline_position = yMin;

        // 20)  The thickness, in font units, of the underline for this face. 
        //      We will use an arbitrary value of 1.
        face->underline_thickness = 1;

        return 0;
}

// Load the glyph (As per FT_Slot_LoadFunc)
// Because this driver/font only contains a single, in-memory glyph,
// it's just a matter of making the box at the requested size.
static FT_Error loadDefaultGlyph( 
        FT_GlyphSlot slot,
        FT_Size size,
        FT_UInt /*glyph_index*/,
        FT_Int32 /*load_flags*/ 
        )
{
        FT_GlyphLoader loader = FT_FACE_DRIVER(slot->face)->glyph_loader;
        FT_GlyphLoader_CheckPoints(loader,numPoints,1);
        FT_GlyphLoader_Rewind( loader );

        //The square will have 5 points and one contour. 
        loader->current.outline.n_points = 5;
        loader->current.outline.n_contours = 1;


        // Get the scaling to go from font units to 26.6 units.
        // The the scaling value is being held in 16.16 units so we
        // need to divide it.
        const double xScale =
                size->metrics.x_scale / static_cast<double>(0x10000);
        const double yScale =
                size->metrics.y_scale / static_cast<double>(0x10000);
        const double spacing = 5000;

        // Draw the box as (5000,0), (27000, 32000)
        const FT_Pos xMin = static_cast<FT_Pos>(xScale * 5000);
        const FT_Pos yMin = static_cast<FT_Pos>(yScale * 0);
        const FT_Pos xMax = static_cast<FT_Pos>(xScale * 27000);
        const FT_Pos yMax = static_cast<FT_Pos>(yScale * 32000);

        //Input the five points of the square.
        FT_Vector curPoint;
        curPoint.x = xMin;
        curPoint.y = yMin;
        loader->current.outline.points[0] = curPoint;
        curPoint.x = xMin;
        curPoint.y = yMax;
        loader->current.outline.points[1] = curPoint;
        curPoint.x = xMax;
        curPoint.y = yMax;
        loader->current.outline.points[2] = curPoint;
        curPoint.x = xMax;
        curPoint.y = yMin;
        loader->current.outline.points[3] = curPoint;
        curPoint.x = xMin;
        curPoint.y = yMin;
        loader->current.outline.points[4] = curPoint;
        loader->current.outline.tags[0] = 1;
        loader->current.outline.tags[1] = 1;
        loader->current.outline.tags[2] = 1;
        loader->current.outline.tags[3] = 1;
        loader->current.outline.tags[4] = 1;
        loader->current.outline.contours[0] = 4;

        FT_GlyphLoader_Add(loader);
        FT_Error error = FT_GlyphLoader_CopyPoints(
                slot->internal->loader, loader);
        if (error)
                return error;

        slot->format = ft_glyph_format_outline; 
        slot->outline = slot->internal->loader->base.outline;

        //Calculate glyph metrics.
        slot->metrics.width = xMax - xMin;
        slot->metrics.height = yMax - yMin;
        slot->metrics.horiBearingX = xMin;
        slot->metrics.horiBearingY = yMax;
        slot->metrics.vertBearingX = xMin;
        slot->metrics.vertBearingY = yMax;
        //This will put a small space between each square.
        slot->metrics.horiAdvance = (xMax - xMin) +
                static_cast<FT_Pos>(xScale * spacing);
        slot->metrics.vertAdvance = 0;
        slot->linearHoriAdvance = 0;
        slot->linearVertAdvance = 0;
        slot->advance.x = 0;
        slot->advance.y = 0;
        slot->bitmap_left = 0;
        slot->bitmap_top = 0;
        slot->num_subglyphs = 0;
        slot->subglyphs = 0; 
        slot->control_data = NULL;
        slot->control_len = 0;
        slot->other = NULL;

        return 0;
}



// This function defines+creates the charmap for the default driver,
// and returns a reference (handle) to it.  (AKA Singleton, Global, etc)
static const FT_CMap_ClassRec& getCharMap(void)
{
        static const FT_CMap_ClassRec charmap = {
                sizeof(FT_CMapRec),
                NULL, // FT_CMap_InitFunc
                NULL, // FT_CMap_DoneFunc
                cmapCharIndexCB, // FT_CMap_CharIndexFunc
                NULL // FT_CMap_CharNextFunc
        };

        return charmap; 
}

// As per FT_CMap_CharIndexFunc
// This function always returns zero, since the font/driver this is
// part of only has one glyph.
static FT_UInt cmapCharIndexCB(
        FT_CMap /*cmap*/,
        FT_UInt32  /*char_code*/
        )
{
        // Always returns 0
        return 0;
}


reply via email to

[Prev in Thread] Current Thread [Next in Thread]