Font-FreeType

 view release on metacpan or  search on metacpan

FreeType.xs  view on Meta::CPAN

    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)
        QEFFT2_PUSH_DNUM((extra->cury + 2 * cy) / 3)
        QEFFT2_PUSH_DNUM((2 * cx + x) / 3)
        QEFFT2_PUSH_DNUM((2 * cy + y) / 3)
        QEFFT2_CALL(extra->cubic_to)
    }

    QEFFT2_CALL_TIDY

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

static int
handle_cubic_to (const FT_Vector *control1, const FT_Vector *control2, 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_PUSH_NUM(control1->x)
    QEFFT2_PUSH_NUM(control1->y)
    QEFFT2_PUSH_NUM(control2->x)
    QEFFT2_PUSH_NUM(control2->y)
    QEFFT2_CALL(extra->cubic_to)
    QEFFT2_CALL_TIDY

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

MODULE = Font::FreeType   PACKAGE = Font::FreeType   PREFIX = qefft2_library_

PROTOTYPES: DISABLE


void
qefft2_import (const char *target_pkg)
    PREINIT:
        HV *stash;
        size_t i;
    PPCODE:
        stash = gv_stashpv(target_pkg, 0);
        if (!stash)
            croak("the package I'm importing into doesn't seem to exist");
        for (i = 0; i < sizeof(qefft2_uv_const) / sizeof(QefFT2_Uv_Const); ++i) {
            const char* name = qefft2_uv_const[i].name;
            if ( !hv_exists(stash, name, strlen(name)) )
                 newCONSTSUB(stash, name,  newSVuv(qefft2_uv_const[i].value));
        }


Font_FreeType
qefft2_library_new (void)
    CODE:
        errchk(FT_Init_FreeType(&RETVAL),
               "opening freetype library");
    OUTPUT:
        RETVAL


void
qefft2_library_DESTROY (Font_FreeType library)
    CODE:
        if (FT_Done_FreeType(library))
            warn("error closing freetype library");


void
qefft2_library_version (Font_FreeType library)
    PREINIT:
        FT_Int major, minor, patch;
    PPCODE:
        major = minor = patch = -1;
        FT_Library_Version(library, &major, &minor, &patch);
        assert(major != -1);
        assert(minor != -1);
        assert(patch != -1);
        if (GIMME_V != G_ARRAY)
            PUSHs(sv_2mortal(newSVpvf("%d.%d.%d",
                                      (int) major, (int) minor, (int) patch)));
        else {
            EXTEND(SP, 3);
            PUSHs(sv_2mortal(newSViv(major)));
            PUSHs(sv_2mortal(newSViv(minor)));
            PUSHs(sv_2mortal(newSViv(patch)));
        }


Font_FreeType_Face
qefft2_face (Font_FreeType library, const char *filename, int faceidx, FT_Int32 glyph_load_flags)
    PREINIT:
        SV *library_sv;
        QefFT2_Face_Extra *extra;
    CODE:
        errchk(FT_New_Face(library, filename, faceidx, &RETVAL),
               "opening font face");
        library_sv = SvRV(ST(0));
        SvREFCNT_inc(library_sv);
        Newx(extra, 1, QefFT2_Face_Extra);
        extra->library_sv = library_sv;
        extra->loaded_glyph_idx = 0;
        extra->slot_valid = 0;
        extra->glyph_load_flags = glyph_load_flags;
        extra->glyph_ft = 0;
        RETVAL->generic.data = (void *) extra;
        /*
        set active charmap if we don't have one;  caused by regression:
        https://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=79e3789f81e14266578e71196ce71ecf5381d142
        http://lists.nongnu.org/archive/html/freetype/2017-10/msg00006.html
        */
#if (QEFFT2_FT_AT_LEAST(2,8,1))
        if (!RETVAL->charmap && RETVAL->num_charmaps) {
            RETVAL->charmap = RETVAL->charmaps[0];
        }
#endif

    OUTPUT:
        RETVAL


MODULE = Font::FreeType   PACKAGE = Font::FreeType::Face   PREFIX = qefft2_face_


FT_Int32
qefft2_face_load_flags (Font_FreeType_Face face, FT_Int32 val = NO_INIT )
    PREINIT:
        QefFT2_Face_Extra *extra;
    CODE:
        extra = face->generic.data;
        if( items > 1 )
        {
            extra->slot_valid = 0;

FreeType.xs  view on Meta::CPAN

    OUTPUT:
        RETVAL


long
qefft2_face_number_of_glyphs (Font_FreeType_Face face)
    CODE:
        RETVAL = face->num_glyphs;
    OUTPUT:
        RETVAL


SV *
qefft2_face_units_per_em (Font_FreeType_Face face)
    CODE:
        RETVAL = FT_IS_SCALABLE(face) ? newSVuv((UV) face->units_per_EM)
                                      : &PL_sv_undef;
    OUTPUT:
        RETVAL


void
qefft2_face_attach_file (Font_FreeType_Face face, const char *filename)
    CODE:
        errchk(FT_Attach_File(face, filename),
               "attaching file to freetype face");


void
qefft2_face_set_char_size (Font_FreeType_Face face, FT_F26Dot6 width, FT_F26Dot6 height, FT_UInt x_res, FT_UInt y_res)
    CODE:
        errchk(FT_Set_Char_Size(face, width, height, x_res, y_res),
               "setting char size of freetype face");
        ((QefFT2_Face_Extra *) face->generic.data)->slot_valid = 0;


void
qefft2_face_set_pixel_size (Font_FreeType_Face face, FT_UInt width, FT_UInt height)
    CODE:
        errchk(FT_Set_Pixel_Sizes(face, width, height),
               "setting pixel size of freetype face");
        ((QefFT2_Face_Extra *) face->generic.data)->slot_valid = 0;


SV *
qefft2_face_height (Font_FreeType_Face face)
    CODE:
        RETVAL = FT_IS_SCALABLE(face) ? newSViv(face->height)
                                      : &PL_sv_undef;
    OUTPUT:
        RETVAL


void
qefft2_face_fixed_sizes (Font_FreeType_Face face)
    PREINIT:
        int i;
        FT_Bitmap_Size *size;
        HV *hash;
        double pt = 0.0, ppem;
    PPCODE:
        if (GIMME_V != G_ARRAY) {
            PUSHs(sv_2mortal(newSViv((int) face->num_fixed_sizes)));
        }
        else {
            EXTEND(SP, face->num_fixed_sizes);
            for (i = 0; i < face->num_fixed_sizes; ++i) {
                size = &face->available_sizes[i];
                hash = newHV();
                if (size->height)
                    hv_store(hash, "height", 6, newSVuv(size->height), 0);
                if (size->width)
                    hv_store(hash, "width", 5, newSVuv(size->width), 0);
                /* The 'size', 'x_ppem', and 'y_ppem' fields were only added
                 * to the FT_Bitmap_Size structure in version 2.1.5.  */
#if QEFFT2_FT_AT_LEAST(2,1,5)
                if (size->size) {
                    pt = size->size / 64.0;
                    hv_store(hash, "size", 4, newSVnv(pt), 0);
                }
                if (size->x_ppem) {
                    ppem = size->x_ppem / 64.0;
                    hv_store(hash, "x_res_ppem", 10, newSVnv(ppem), 0);
                    if (size->size)
                        hv_store(hash, "x_res_dpi", 9,
                                 newSVnv((72 * ppem) / pt), 0);
                }
                if (size->y_ppem) {
                    ppem = size->y_ppem / 64.0;
                    hv_store(hash, "y_res_ppem", 10, newSVnv(ppem), 0);
                    if (size->size)
                        hv_store(hash, "y_res_dpi", 9,
                                 newSVnv((72 * ppem) / pt), 0);
                }
#endif
                PUSHs(sv_2mortal(newRV_inc((SV *) hash)));
            }
        }


SV *
qefft2_face_ascender (Font_FreeType_Face face)
    CODE:
        RETVAL = FT_IS_SCALABLE(face) ? newSViv(face->ascender)
                                      : &PL_sv_undef;
    OUTPUT:
        RETVAL


SV *
qefft2_face_descender (Font_FreeType_Face face)
    CODE:
        RETVAL = FT_IS_SCALABLE(face) ? newSViv(face->descender)
                                      : &PL_sv_undef;
    OUTPUT:
        RETVAL


SV *
qefft2_face_underline_position (Font_FreeType_Face face)
    CODE:

FreeType.xs  view on Meta::CPAN

        RETVAL

AV *
qefft2_face_charmaps (Font_FreeType_Face face)
    PREINIT:
        AV* array;
        int i;
        Font_FreeType_CharMap* ptr;
    CODE:
        array = newAV();
        ptr = face->charmaps;
        for(i = 0; i < face->num_charmaps; i++) {
            SV *sv = newSV(0);
            sv_setref_pv(sv, "Font::FreeType::CharMap", (void *) *ptr++);
            av_push(array, sv);
        }
        RETVAL = array;
    OUTPUT:
        RETVAL

Font_FreeType_BoundingBox
qefft2_face_bounding_box (Font_FreeType_Face face)
    CODE:
        if (!FT_IS_SCALABLE(face)) {
            XSRETURN_UNDEF;
        } else {
            RETVAL = &face->bbox;
        }
    OUTPUT:
        RETVAL

AV*
qefft2_face_namedinfos (Font_FreeType_Face face)
    PREINIT:
        AV* array;
        int i;
    CODE:
        if (!FT_IS_SCALABLE(face)) {
            XSRETURN_UNDEF;
        } else {
            array = newAV();
            int count = FT_Get_Sfnt_Name_Count(face);
            for(i = 0; i < count; i++) {
                SV *sv = newSV(0);
                FT_SfntName* sfnt;
                Newx(sfnt, 1, FT_SfntName);
                errchk(FT_Get_Sfnt_Name(face, i, sfnt),
                       "loading sfnt structure");
                sv_setref_pv(sv, "Font::FreeType::NamedInfo", (void *) sfnt);
                av_push(array, sv);
            }
            RETVAL = array;
        }
    OUTPUT:
        RETVAL

void
qefft2_face_kerning (Font_FreeType_Face face, FT_UInt left_glyph_idx, FT_UInt right_glyph_idx, UV kern_mode = FT_KERNING_DEFAULT)
    PREINIT:
        FT_Vector kerning;
    PPCODE:
        errchk(FT_Get_Kerning(face, left_glyph_idx, right_glyph_idx, kern_mode,
                              &kerning),
               "getting kerning from freetype face");
        if (GIMME_V != G_ARRAY) {
            PUSHs(sv_2mortal(newSVnv((double) kerning.x / 64.0)));
        }
        else {
            EXTEND(SP, 2);
            PUSHs(sv_2mortal(newSVnv((double) kerning.x / 64.0)));
            PUSHs(sv_2mortal(newSVnv((double) kerning.y / 64.0)));
        }


SV *
qefft2_face_glyph_from_char_code (Font_FreeType_Face face, FT_ULong char_code, int fallback = 0)
    PREINIT:
        FT_UInt glyph_idx;
    CODE:
        glyph_idx = FT_Get_Char_Index(face, char_code);
        if (glyph_idx || fallback)
            RETVAL = make_glyph(SvRV(ST(0)), char_code, 1, glyph_idx);
        else
            RETVAL = &PL_sv_undef;
    OUTPUT:
        RETVAL


SV *
qefft2_face_glyph_from_char (Font_FreeType_Face face, SV *sv, int fallback = 0)
    PREINIT:
        FT_UInt glyph_idx;
        const U8 *str;
        STRLEN len;
        UV char_code;
    CODE:
        if (!SvPOK(sv))
            croak("argument must be a string containing a character");
        str = (const U8*)SvPV(sv, len);
        if (!len)
            croak("string has no characters");
        if (!UTF8_IS_INVARIANT(*str)) {
            STRLEN s_len;
            char_code = utf8_to_uvchr_buf(str, str + len, &s_len);
            if (len != s_len) {
                croak("malformed string (looks as UTF-8, but isn't it)");
            }
        } else {
            char_code = *str;
        }
        glyph_idx = FT_Get_Char_Index(face, char_code);
        fallback = SvOK(ST(2)) ? SvIV(ST(2)) : 0;
        if (glyph_idx || fallback)
            RETVAL = make_glyph(SvRV(ST(0)), char_code, 1, glyph_idx);
        else
            RETVAL = &PL_sv_undef;
    OUTPUT:
        RETVAL

FT_UInt
qefft2_face_get_name_index (Font_FreeType_Face face, SV *sv)

FreeType.xs  view on Meta::CPAN

    PREINIT:
        FT_Face face;
        const FT_Glyph_Metrics *metrics;
    CODE:
        face = (FT_Face) SvIV(glyph->face_sv);
        metrics = &ensure_glyph_loaded(face, glyph)->metrics;
        RETVAL = metrics->horiAdvance - metrics->horiBearingX - metrics->width;
    OUTPUT:
        RETVAL


FT_F26Dot6
qefft2_glyph_horizontal_advance (Font_FreeType_Glyph glyph)
    PREINIT:
        FT_Face face;
    CODE:
        face = (FT_Face) SvIV(glyph->face_sv);
        RETVAL = ensure_glyph_loaded(face, glyph)->metrics.horiAdvance;
    OUTPUT:
        RETVAL


FT_F26Dot6
qefft2_glyph_vertical_advance (Font_FreeType_Glyph glyph)
    PREINIT:
        FT_Face face;
    CODE:
        face = (FT_Face) SvIV(glyph->face_sv);
        RETVAL = ensure_glyph_loaded(face, glyph)->metrics.vertAdvance;
    OUTPUT:
        RETVAL


void
qefft2_glyph_load (Font_FreeType_Glyph glyph)
    PREINIT:
        FT_Face face;
    CODE:
        face = (FT_Face) SvIV(glyph->face_sv);
        ensure_glyph_loaded(face, glyph);


bool
qefft2_glyph_has_outline (Font_FreeType_Glyph glyph)
    PREINIT:
        FT_Face face;
    CODE:
        face = (FT_Face) SvIV(glyph->face_sv);
        RETVAL = ensure_outline_loaded(face, glyph);
    OUTPUT:
        RETVAL


void
qefft2_glyph_outline_bbox (Font_FreeType_Glyph glyph)
    PREINIT:
        FT_Face face;
        QefFT2_Face_Extra *extra;
        FT_OutlineGlyph outline_glyph;
        FT_BBox bbox;
    PPCODE:
        face = (FT_Face) SvIV(glyph->face_sv);
        if (!ensure_outline_loaded(face, glyph))
            croak("glyph %lu does not have an outline",
                  (unsigned long) glyph->char_code);
        extra = face->generic.data;
        outline_glyph = (FT_OutlineGlyph) extra->glyph_ft;
        errchk(FT_Outline_Get_BBox(&outline_glyph->outline, &bbox),
               "getting glyph outline bounding box");
        EXTEND(SP, 4);
        PUSHs(sv_2mortal(newSVnv((double) bbox.xMin / 64.0)));
        PUSHs(sv_2mortal(newSVnv((double) bbox.yMin / 64.0)));
        PUSHs(sv_2mortal(newSVnv((double) bbox.xMax / 64.0)));
        PUSHs(sv_2mortal(newSVnv((double) bbox.yMax / 64.0)));


void
qefft2_glyph_outline_decompose_ (Font_FreeType_Glyph glyph, HV *args)
    PREINIT:
        FT_Face face;
        QefFT2_Face_Extra *extra;
        FT_OutlineGlyph outline_glyph;
        FT_Outline_Funcs handlers;
        struct QefFT2_Outline_Decompose_Extra_ decompose_extra;
        STRLEN len;
        HE *he;
        const char *key;
        SV *sv;
    CODE:
        face = (FT_Face) SvIV(glyph->face_sv);
        if (!ensure_outline_loaded(face, glyph))
            croak("glyph %lu does not have an outline",
                  (unsigned long) glyph->char_code);
        extra = face->generic.data;

        decompose_extra.move_to = 0;
        decompose_extra.line_to = 0;
        decompose_extra.conic_to = 0;
        decompose_extra.cubic_to = 0;
        hv_iterinit(args);
        while ((he = hv_iternext(args))) {
            key = HePV(he, len);
            sv = HeVAL(he);
            if (!strcmp(key, "move_to"))
                decompose_extra.move_to = sv;
            else if (!strcmp(key, "line_to"))
                decompose_extra.line_to = sv;
            else if (!strcmp(key, "conic_to"))
                decompose_extra.conic_to = sv;
            else if (!strcmp(key, "cubic_to"))
                decompose_extra.cubic_to = sv;
            else
                croak("hash key '%s' not the name of a known event", key);
        }

        if (!decompose_extra.move_to)
            croak("callback handler 'move_to' argument required");
        if (!decompose_extra.line_to)
            croak("callback handler 'line_to' argument required");
        if (!decompose_extra.cubic_to)
            croak("callback handler 'cubic_to' argument required");

        handlers.move_to = handle_move_to;
        handlers.line_to = handle_line_to;
        handlers.conic_to = handle_conic_to;
        handlers.cubic_to = handle_cubic_to;
        handlers.shift = 0;
        handlers.delta = 0;
        outline_glyph = (FT_OutlineGlyph) extra->glyph_ft;
        errchk(FT_Outline_Decompose(&outline_glyph->outline, &handlers,
                                    &decompose_extra),
               "decomposing FreeType outline");


void
qefft2_glyph_bitmap (Font_FreeType_Glyph glyph, UV render_mode = FT_RENDER_MODE_NORMAL)
    PREINIT:
        FT_Face face;
        FT_GlyphSlot glyph_ft;
        FT_Bitmap *bitmap;
        unsigned char *buf;
        int i, j;
        int bits = 0;
        AV *rows;
        unsigned char *row_buf;
    PPCODE:
        face = (FT_Face) SvIV(glyph->face_sv);
        /* XXX: For some reason I can't work out how to load the bitmap and
         * then load the outline later, but it works the other way round.
         * To ensure that a glyph object can be used for both, in either order,
         * I load the outline first even if it's not needed.  There's probably
         * a better way of doing this.  I'll ask on the mailing list.  */
        ensure_outline_loaded(face, glyph);
        glyph_ft = face->glyph;
        if (glyph_ft->format != FT_GLYPH_FORMAT_BITMAP) {
            errchk(FT_Render_Glyph(glyph_ft, render_mode), "rendering glyph");
        }
        bitmap = &glyph_ft->bitmap;
        assert(bitmap);

        rows = newAV();
        av_extend(rows, bitmap->rows - 1);
        buf = bitmap->buffer;
        Newx(row_buf, bitmap->width, unsigned char);

        if (bitmap->pixel_mode == FT_PIXEL_MODE_MONO) {
            for (i = 0; i < bitmap->rows; ++i) {
                for (j = 0; j < bitmap->width; ++j) {
                    if (j % 8 == 0)
                        bits = buf[j / 8];
                    row_buf[j] = bits & 0x80 ? 0xFF : 0x00;
                    bits <<= 1;
                }
                /* Not bothering to check that value was actually stored */
                av_store(rows, i, newSVpvn(row_buf, bitmap->width));
                buf += bitmap->pitch;
            }
        }
        else if (bitmap->pixel_mode == FT_PIXEL_MODE_GRAY) {
            for (i = 0; i < bitmap->rows; ++i) {
                for (j = 0; j < bitmap->width; ++j) {
                    row_buf[j] = buf[j];
                }
                /* Not bothering to check that value was actually stored */
                av_store(rows, i, newSVpvn(row_buf, bitmap->width));
                buf += bitmap->pitch;
            }
        }
        else {
            Safefree(row_buf);
            SvREFCNT_dec(rows);
            croak("unsupported pixel mode %d", (int) bitmap->pixel_mode);
        }

        Safefree(row_buf);
        EXTEND(SP, 3);
        PUSHs(sv_2mortal(newRV_inc((SV *) rows)));
        PUSHs(sv_2mortal(newSViv(glyph_ft->bitmap_left)));
        PUSHs(sv_2mortal(newSViv(glyph_ft->bitmap_top)));


MODULE = Font::FreeType   PACKAGE = Font::FreeType::CharMap   PREFIX = qefft2_charmap_

FT_Encoding
qefft2_charmap_encoding (Font_FreeType_CharMap charmap)
    CODE:



( run in 1.066 second using v1.01-cache-2.11-cpan-71847e10f99 )