Font-FreeType

 view release on metacpan or  search on metacpan

FreeType.xs  view on Meta::CPAN

/* Perl binding for the FreeType font rendering library.
 *
 * Copyright 2004, Geoff Richards.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the same terms as Perl itself.
 */

#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif

#include <ft2build.h>
#include FT_SFNT_NAMES_H
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_OUTLINE_H
#include FT_BBOX_H
#include FT_TYPE1_TABLES_H

#undef assert
#include <assert.h>

/* utf8_to_uvchr is deprecated in 5.16, but
 * utf8_to_uvchr_buf is not available before 5.16
 * If I need to get fancier, I should look at Dumper.xs
 * in Data::Dumper
 */
#if PERL_VERSION <= 15 && ! defined(utf8_to_uvchr_buf)
#define utf8_to_uvchr_buf(s, send, p_length) (utf8_to_uvchr(s, p_length))
#endif

/* Macro for testing whether we have at least a certain version of
 * Freetype available.  */
#define QEFFT2_FT_AT_LEAST(major, minor, patch) \
    FREETYPE_MAJOR > major || \
        (FREETYPE_MAJOR == major && \
            (FREETYPE_MINOR > minor || \
                (FREETYPE_MINOR == minor && FREETYPE_PATCH >= patch)))

/* Define the newer names for constants in terms of the old names if we're
 * compiling against an old version of the library.  These uppercase
 * constants, which are defined in enums, were added in Freetype 2.1.3.  */
#if !(QEFFT2_FT_AT_LEAST(2,1,3))
#define FT_GLYPH_FORMAT_NONE ft_glyph_format_none
#define FT_GLYPH_FORMAT_COMPOSITE ft_glyph_format_composite
#define FT_GLYPH_FORMAT_BITMAP ft_glyph_format_bitmap
#define FT_GLYPH_FORMAT_OUTLINE ft_glyph_format_outline
#define FT_GLYPH_FORMAT_PLOTTER ft_glyph_format_plotter
#define FT_RENDER_MODE_NORMAL ft_render_mode_normal
#define FT_RENDER_MODE_MONO ft_render_mode_mono
#define FT_PIXEL_MODE_NONE ft_pixel_mode_none
#define FT_PIXEL_MODE_MONO ft_pixel_mode_mono
#define FT_PIXEL_MODE_GRAY ft_pixel_mode_grays
#define FT_PIXEL_MODE_GRAY2 ft_pixel_mode_pal2
#define FT_PIXEL_MODE_GRAY4 ft_pixel_mode_pal4
#define FT_KERNING_DEFAULT ft_kerning_default
#define FT_KERNING_UNFITTED ft_kerning_unfitted
#define FT_KERNING_UNSCALED ft_kerning_unscaled
#endif

#define QEF_BUF_SZ 256

/* Scary macrology follows, stolen from fterrors.h
 * This stuff sets up a table mapping error codes to descriptive strings.
 * I find the whole idea of 'callback macros' rather distasteful though.
 */
#undef __FTERRORS_H__
#define FT_ERRORDEF( e, v, s )  { e, s },
#define FT_ERROR_START_LIST {
#define FT_ERROR_END_LIST { 0, 0 } };
struct QefFT2_Errstr_
{
  int num;
  const char *message;
};
typedef struct QefFT2_Errstr_ QefFT2_Errstr;
QefFT2_Errstr qefft2_errstr[] = /* rest filled in by the header */
#include FT_ERRORS_H

#define ftnum_to_nv(num) newSVnv((double) (num) / 1.0)

struct QefFT2_Glyph_
{
    SV *face_sv;
    FT_ULong char_code;     /* 0 if not yet known */
    bool has_char_code;
    FT_UInt index;
    char *name;
};
struct QefFT2_Face_Extra_
{
    SV *library_sv;

FreeType.xs  view on Meta::CPAN

        }
        ++errmap;
    }

    croak("error %s: unknown error code", desc);
}

static SV *
make_glyph (SV *face_sv, FT_ULong char_code, bool has_cc, FT_UInt index)
{
    Font_FreeType_Glyph glyph;
    SV *sv;
    Newx(glyph, 1, struct QefFT2_Glyph_);

    glyph->face_sv = face_sv;
    SvREFCNT_inc(face_sv);

    glyph->char_code = char_code;
    glyph->has_char_code = has_cc;
    glyph->index = index;
    glyph->name = 0;

    sv = newSV(0);
    sv_setref_pv(sv, "Font::FreeType::Glyph", (void *) glyph);
    return sv;
}

static FT_GlyphSlot
ensure_glyph_loaded (FT_Face face, Font_FreeType_Glyph glyph)
{
    QefFT2_Face_Extra *extra = face->generic.data;

    if (extra->loaded_glyph_idx != glyph->index || !extra->slot_valid) {
        if (extra->glyph_ft) {
            FT_Done_Glyph(extra->glyph_ft);
            extra->glyph_ft = 0;
        }
        errchk(FT_Load_Glyph(face, glyph->index, extra->glyph_load_flags),
               "loading freetype glyph");
        extra->loaded_glyph_idx = glyph->index;
        extra->slot_valid = 1;
    }

    return face->glyph;
}

static bool
ensure_outline_loaded (FT_Face face, Font_FreeType_Glyph glyph)
{
    QefFT2_Face_Extra *extra;
    ensure_glyph_loaded(face, glyph);

    extra = face->generic.data;
    if (!extra->glyph_ft)
        errchk(FT_Get_Glyph(face->glyph, &extra->glyph_ft),
               "getting glyph object from freetype");

    return extra->glyph_ft->format == FT_GLYPH_FORMAT_OUTLINE;
}

/* Macros to help the outline event handlers call Perl code */
#define QEFFT2_CALL_PREP  dSP; ENTER; SAVETMPS; PUSHMARK(SP);
#define QEFFT2_NUM(num)  ((double) (num) / 64.0)
#define QEFFT2_PUSH_NUM(num)  XPUSHs(sv_2mortal(newSVnv((double) num / 64.0)));
#define QEFFT2_PUSH_DNUM(num)  XPUSHs(sv_2mortal(newSVnv(num)));
#define QEFFT2_CALL(code)  PUTBACK; call_sv(code, G_DISCARD);
#define QEFFT2_CALL_TIDY  FREETMPS; LEAVE;

static int
handle_move_to (const FT_Vector *to, void *data)
{
    struct QefFT2_Outline_Decompose_Extra_ *extra = data;
    double x = QEFFT2_NUM(to->x), y = QEFFT2_NUM(to->y);

    QEFFT2_CALL_PREP
    QEFFT2_PUSH_DNUM(x)
    QEFFT2_PUSH_DNUM(y)
    QEFFT2_CALL(extra->move_to)
    QEFFT2_CALL_TIDY

    extra->curx = x;
    extra->cury = y;
    return 0;
}

static int
handle_line_to (const FT_Vector *to, void *data)
{
    struct QefFT2_Outline_Decompose_Extra_ *extra = data;
    double x = QEFFT2_NUM(to->x), y = QEFFT2_NUM(to->y);

    QEFFT2_CALL_PREP
    QEFFT2_PUSH_DNUM(x)
    QEFFT2_PUSH_DNUM(y)
    QEFFT2_CALL(extra->line_to)
    QEFFT2_CALL_TIDY

    extra->curx = x;
    extra->cury = y;
    return 0;
}

static int
handle_conic_to (const FT_Vector *control, const FT_Vector *to, void *data)
{
    struct QefFT2_Outline_Decompose_Extra_ *extra = data;
    double x = QEFFT2_NUM(to->x), y = QEFFT2_NUM(to->y);
    double cx = QEFFT2_NUM(control->x), cy = QEFFT2_NUM(control->y);

    QEFFT2_CALL_PREP
    QEFFT2_PUSH_DNUM(x)
    QEFFT2_PUSH_DNUM(y)

    /* If there's no conic callback, simulate an equivalent cubic one */
    if (extra->conic_to) {
        QEFFT2_PUSH_DNUM(cx)
        QEFFT2_PUSH_DNUM(cy)
        QEFFT2_CALL(extra->conic_to)
    }
    else {
        QEFFT2_PUSH_DNUM((extra->curx + 2 * cx) / 3)



( run in 1.189 second using v1.01-cache-2.11-cpan-483215c6ad5 )