Skip to content

Instantly share code, notes, and snippets.

@roxlu
Last active August 29, 2015 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save roxlu/da3251cb2045823922fa to your computer and use it in GitHub Desktop.
Save roxlu/da3251cb2045823922fa to your computer and use it in GitHub Desktop.
Test code for caret offset calculation using Harfbuzz, Icu and Freetype.
#include <stdio.h>
#include <stdlib.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <harfbuzz/hb.h>
#include <harfbuzz/hb-ft.h>
#include <unicode/uchriter.h>
#include <unicode/schriter.h>
#include <unicode/ustring.h>
#include <unicode/ustdio.h>
#include <unicode/brkiter.h>
#include <string>
/* ------------------------------------------------------------- */
struct Font {
FT_Face face;
hb_font_t* hb_font;
hb_buffer_t* hb_buffer;
hb_glyph_info_t* glyph_info;
hb_glyph_position_t* glyph_pos;
unsigned int glyph_count;
};
FT_Library library = NULL;
/* ------------------------------------------------------------- */
int main() {
/* Harfbuzz + Freetype vars. */
std::string test_string = "Af̀fiZ";
std::string fontfile;
int r = 0;
unsigned int i = 0;
FT_Error err;
Font font;
/* ICU */
UBreakIterator* bi = NULL;
int32_t p = 0;
UErrorCode icu_err = U_ZERO_ERROR;
UnicodeString ts(test_string.c_str());
const UChar* ts_ptr = ts.getTerminatedBuffer();
printf("\n\n");
printf("Testing caret offset calculation with Freetype + Harfbuzz.\n");
printf("\n\n");
/* Initialize + load. */
font.face = NULL;
font.hb_font = NULL;
font.hb_buffer = NULL;
font.glyph_info = NULL;
font.glyph_pos = NULL;
font.glyph_count = 0;
err = FT_Init_FreeType(&library);
if (FT_Err_Ok != err) {
printf("Failed to initialize Freetype.");
return -1;
}
fontfile = "data/Clarendon.ttf";
err = FT_New_Face(library, fontfile.c_str(), 0, &font.face);
if (FT_Err_Ok != err) {
printf("Failed to create a new ft face.");
r = -1;
goto error;
}
font.hb_font = hb_ft_font_create(font.face, 0);
if (NULL == font.hb_font) {
printf("Failed to create harfbuzz font context.");
r = -2;
goto error;
}
font.hb_buffer = hb_buffer_create();
if (NULL == font.hb_buffer) {
printf("Failed to create the harfbuzz buffer.");
r = -3;
goto error;
}
/* Write some content. */
hb_buffer_set_direction(font.hb_buffer, HB_DIRECTION_LTR);
hb_buffer_set_script(font.hb_buffer, HB_SCRIPT_UNKNOWN);
hb_buffer_add_utf8(font.hb_buffer, test_string.c_str(), test_string.size(), 0, test_string.size());
hb_shape(font.hb_font, font.hb_buffer, NULL, 0);
font.glyph_count = hb_buffer_get_length(font.hb_buffer);
font.glyph_info = hb_buffer_get_glyph_infos(font.hb_buffer, NULL);
font.glyph_pos = hb_buffer_get_glyph_positions(font.hb_buffer, NULL);
/* Iterate over HB glyphs */
for (i = 0; i < font.glyph_count; ++i) {
printf("Glyph: %u, cluster: %d\n", i, font.glyph_info[i].cluster);
}
/* Interate over graphmemes. */
bi = ubrk_open(UBRK_CHARACTER, 0, ts_ptr, u_strlen(ts_ptr), &icu_err);
if (U_FAILURE(icu_err)) {
printf("Error: failed to create a break iterator.");
r = -4;
goto error;
}
p = ubrk_first(bi);
printf("\n");
while (p != UBRK_DONE) {
printf("Graphmeme offset: %u\n", p);
p = ubrk_next(bi);
}
ubrk_close(bi);
printf("\n\n");
error:
if (NULL != font.hb_buffer) {
hb_buffer_destroy(font.hb_buffer);
font.hb_buffer = NULL;
}
if (NULL != font.hb_font) {
hb_font_destroy(font.hb_font);
font.hb_font = NULL;
}
if (NULL != font.face) {
err = FT_Done_Face(font.face);
if (FT_Err_Ok != err) {
printf("Failed FT_Done_Face.");
}
font.face = NULL;
}
return r;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment