<commit_before>extern mod harfbuzz;

use font::Font;
use font_cache::FontCache;

use au = gfx::geometry;
use au::Au;
use geom::point::Point2D;
use glyph::{GlyphStore, GlyphIndex, GlyphData};
use libc::types::common::c99::int32_t;
use libc::{c_uint, c_int, c_void, c_char};
use ptr::{null, to_unsafe_ptr, offset};
use std::arc;
use text_run::TextRun;
use util::*;

use harfbuzz::{HB_MEMORY_MODE_READONLY,
                  HB_DIRECTION_LTR};
use harfbuzz::{hb_blob_t, hb_face_t, hb_font_t, hb_font_funcs_t, hb_buffer_t,
                  hb_codepoint_t, hb_bool_t, hb_glyph_position_t,
		  hb_glyph_info_t, hb_var_int_t, hb_position_t};
use harfbuzz::bindgen::{hb_blob_create, hb_blob_destroy,
                           hb_face_create, hb_face_destroy,
                           hb_font_create, hb_font_destroy,
                           hb_buffer_create, hb_buffer_destroy,
                           hb_buffer_add_utf8, hb_shape,
                           hb_buffer_get_glyph_infos,
                           hb_buffer_get_glyph_positions,
                           hb_font_set_ppem, hb_font_set_scale,
                           hb_buffer_set_direction,
                           hb_font_funcs_create, hb_font_funcs_destroy,
                           hb_font_set_funcs,
                           hb_font_funcs_set_glyph_h_advance_func,
                           hb_font_funcs_set_glyph_func,
                           hb_font_funcs_set_glyph_h_kerning_func};

fn float_to_fixed_hb(f: float) -> i32 {
    util::float_to_fixed(16, f)
}

fn fixed_to_float_hb(i: hb_position_t) -> float {
    util::fixed_to_float(16, i)
}

fn fixed_to_rounded_int_hb(f: hb_position_t) -> int {
    util::fixed_to_rounded_int(16, f)
}

pub struct HarfbuzzShaper {
    dummy: int
}

pub impl HarfbuzzShaper {
    static pub fn new() -> HarfbuzzShaper {
        HarfbuzzShaper { dummy: 42 }
    }
    
    /**
    Calculate the layout metrics associated with a some given text
    when rendered in a specific font.
    */
    pub fn shape_textrun(run: &TextRun) {
        debug!("shaping text '%s'", run.text);

        // TODO: harfbuzz fonts and faces should be cached on the Font object.
        // TODO: font tables should be stored in Font object and cached by FontCache (Issue #92)
        let face_blob: *hb_blob_t = vec::as_imm_buf(*(run.font).fontbuf, |buf: *u8, len: uint| {
            hb_blob_create(buf as *c_char,
                           len as c_uint,
                           HB_MEMORY_MODE_READONLY,
                           null(),
                           null())
        });

        let hb_face: *hb_face_t = hb_face_create(face_blob, 0 as c_uint);
        let hb_font: *hb_font_t = hb_font_create(hb_face);

        // TODO: set font size here, based on Font's size
        // Set points-per-em. if zero, performs no hinting in that direction.
        hb_font_set_ppem(hb_font, 21 as c_uint, 21 as c_uint);
        // Set scaling. Note that this takes 16.16 fixed point.
        hb_font_set_scale(hb_font, float_to_fixed_hb(21f) as c_int, float_to_fixed_hb(21f) as c_int);

        let funcs: *hb_font_funcs_t = hb_font_funcs_create();
        hb_font_funcs_set_glyph_func(funcs, glyph_func, null(), null());
        hb_font_funcs_set_glyph_h_advance_func(funcs, glyph_h_advance_func, null(), null());

        unsafe {
            let font_data: *c_void = core::ptr::addr_of(run.font) as *c_void;
            hb_font_set_funcs(hb_font, funcs, font_data, null());
        };

        let hb_buffer: *hb_buffer_t = hb_buffer_create();
        hb_buffer_set_direction(hb_buffer, HB_DIRECTION_LTR);

        // Using as_buf because it never does a copy - we don't need the trailing null
        str::as_buf(run.text, |ctext: *u8, _l: uint| {
            hb_buffer_add_utf8(hb_buffer, 
                               ctext as *c_char,
                               run.text.len() as c_int,
                               0 as c_uint,
                               run.text.len() as c_int);
        });<commit_msg>Shaper now uses actual font point size. Closes #162.<commit_after>extern mod harfbuzz;

use font::Font;
use font_cache::FontCache;

use au = gfx::geometry;
use au::Au;
use geom::point::Point2D;
use glyph::{GlyphStore, GlyphIndex, GlyphData};
use libc::types::common::c99::int32_t;
use libc::{c_uint, c_int, c_void, c_char};
use ptr::{null, to_unsafe_ptr, offset};
use std::arc;
use text_run::TextRun;
use util::*;

use harfbuzz::{HB_MEMORY_MODE_READONLY,
                  HB_DIRECTION_LTR};
use harfbuzz::{hb_blob_t, hb_face_t, hb_font_t, hb_font_funcs_t, hb_buffer_t,
                  hb_codepoint_t, hb_bool_t, hb_glyph_position_t,
		  hb_glyph_info_t, hb_var_int_t, hb_position_t};
use harfbuzz::bindgen::{hb_blob_create, hb_blob_destroy,
                           hb_face_create, hb_face_destroy,
                           hb_font_create, hb_font_destroy,
                           hb_buffer_create, hb_buffer_destroy,
                           hb_buffer_add_utf8, hb_shape,
                           hb_buffer_get_glyph_infos,
                           hb_buffer_get_glyph_positions,
                           hb_font_set_ppem, hb_font_set_scale,
                           hb_buffer_set_direction,
                           hb_font_funcs_create, hb_font_funcs_destroy,
                           hb_font_set_funcs,
                           hb_font_funcs_set_glyph_h_advance_func,
                           hb_font_funcs_set_glyph_func,
                           hb_font_funcs_set_glyph_h_kerning_func};

fn float_to_fixed_hb(f: float) -> i32 {
    util::float_to_fixed(16, f)
}

fn fixed_to_float_hb(i: hb_position_t) -> float {
    util::fixed_to_float(16, i)
}

fn fixed_to_rounded_int_hb(f: hb_position_t) -> int {
    util::fixed_to_rounded_int(16, f)
}

pub struct HarfbuzzShaper {
    dummy: int
}

pub impl HarfbuzzShaper {
    static pub fn new() -> HarfbuzzShaper {
        HarfbuzzShaper { dummy: 42 }
    }
    
    /**
    Calculate the layout metrics associated with a some given text
    when rendered in a specific font.
    */
    pub fn shape_textrun(run: &TextRun) {
        debug!("shaping text '%s'", run.text);

        // TODO(Issue #94): harfbuzz fonts and faces should be cached on the 
        // Shaper object, which is owned by the Font instance.
        // TODO(Issue #92): font tables should be stored in Font object and cached per-task
        let face_blob: *hb_blob_t = vec::as_imm_buf(*(run.font).fontbuf, |buf: *u8, len: uint| {
            hb_blob_create(buf as *c_char,
                           len as c_uint,
                           HB_MEMORY_MODE_READONLY,
                           null(),
                           null())
        });

        let hb_face: *hb_face_t = hb_face_create(face_blob, 0 as c_uint);
        let hb_font: *hb_font_t = hb_font_create(hb_face);

        // Set points-per-em. if zero, performs no hinting in that direction.
        let pt_size = run.font.style.pt_size;
        hb_font_set_ppem(hb_font, pt_size as c_uint, pt_size as c_uint);
        // Set scaling. Note that this takes 16.16 fixed point.
        hb_font_set_scale(hb_font, float_to_fixed_hb(pt_size) as c_int, float_to_fixed_hb(pt_size) as c_int);

        let funcs: *hb_font_funcs_t = hb_font_funcs_create();
        hb_font_funcs_set_glyph_func(funcs, glyph_func, null(), null());
        hb_font_funcs_set_glyph_h_advance_func(funcs, glyph_h_advance_func, null(), null());

        unsafe {
            let font_data: *c_void = core::ptr::addr_of(run.font) as *c_void;
            hb_font_set_funcs(hb_font, funcs, font_data, null());
        };

        let hb_buffer: *hb_buffer_t = hb_buffer_create();
        hb_buffer_set_direction(hb_buffer, HB_DIRECTION_LTR);

        // Using as_buf because it never does a copy - we don't need the trailing null
        str::as_buf(run.text, |ctext: *u8, _l: uint| {
            hb_buffer_add_utf8(hb_buffer, 
                               ctext as *c_char,
                               run.text.len() as c_int,
                               0 as c_uint,
                               run.text.len() as c_int);
        });
{'fraction_non_alphanumeric': 0.09012980651481754, 'fraction_numerical': 0.008204751408278227, 'mean_word_length': 2.149633629001157, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7639252', 'n_tokens_mistral': 2958, 'n_tokens_neox': 2787, 'n_words': 584}