/* Test al_ustr_get on invalid sequences. */ static void t22(void) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *us; /* Empty string. */ al_set_errno(0); CHECK(al_ustr_get(al_ustr_empty_string(), 0) < 0); CHECK(al_get_errno() == ERANGE); /* 5-byte sequence. */ us = al_ref_cstr(&info, "\xf8\x88\x80\x80\x80"); al_set_errno(0); CHECK(al_ustr_get(us, 0) < 0); CHECK(al_get_errno() == EILSEQ); /* Start in trail byte. */ us = al_ref_cstr(&info, "ð"); al_set_errno(0); CHECK(al_ustr_get(us, 1) < 0); CHECK(al_get_errno() == EILSEQ); /* Truncated 3-byte sequence. */ us = al_ref_cstr(&info, "\xEF\xBF"); al_set_errno(0); CHECK(al_ustr_get(us, 0) < 0); CHECK(al_get_errno() == EILSEQ); }
/* Test al_ustr_find_replace, al_ustr_find_replace_cstr. */ static void t49(void) { ALLEGRO_USTR *us; ALLEGRO_USTR_INFO findi; ALLEGRO_USTR_INFO repli; const ALLEGRO_USTR *find; const ALLEGRO_USTR *repl; us = al_ustr_new("aábdðeéfghiíaábdðeéfghií"); find = al_ref_cstr(&findi, "ðeéf"); repl = al_ref_cstr(&repli, "deef"); CHECK(al_ustr_find_replace(us, 0, find, repl)); CHECK(0 == strcmp(al_cstr(us), "aábddeefghiíaábddeefghií")); find = al_ref_cstr(&findi, "aá"); repl = al_ref_cstr(&repli, "AÁ"); CHECK(al_ustr_find_replace(us, 14, find, repl)); CHECK(0 == strcmp(al_cstr(us), "aábddeefghiíAÁbddeefghií")); CHECK(al_ustr_find_replace_cstr(us, 0, "dd", "đ")); CHECK(0 == strcmp(al_cstr(us), "aábđeefghiíAÁbđeefghií")); /* Not allowed */ find = al_ustr_empty_string(); CHECK(! al_ustr_find_replace(us, 0, find, repl)); CHECK(0 == strcmp(al_cstr(us), "aábđeefghiíAÁbđeefghií")); al_ustr_free(us); }
/* Function: al_ustr_find_replace_cstr */ bool al_ustr_find_replace_cstr(ALLEGRO_USTR *us, int start_pos, const char *find, const char *replace) { ALLEGRO_USTR_INFO find_info; ALLEGRO_USTR_INFO repl_info; ALLEGRO_USTR *find_us = al_ref_cstr(&find_info, find); ALLEGRO_USTR *repl_us = al_ref_cstr(&repl_info, replace); return al_ustr_find_replace(us, start_pos, find_us, repl_us); }
/* No memory needs to be freed. */ static void t3(void) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *us = al_ref_cstr(&info, "A static string."); CHECK(0 == strcmp(al_cstr(us), "A static string.")); }
/* Function: al_ustr_has_suffix_cstr */ bool al_ustr_has_suffix_cstr(const ALLEGRO_USTR *us1, const char *s2) { ALLEGRO_USTR_INFO info; ALLEGRO_USTR *us2 = al_ref_cstr(&info, s2); return al_ustr_has_suffix(us1, us2); }
//splits a string by a character static int _split_string_by_char(const char *str, int ch, ALLEGRO_USTR *result[], int result_len) { //start from the string beginning int pos = 0, next_pos; //count of sub-strings found int count = 0; //temp allegro string ALLEGRO_USTR_INFO temp_info; ALLEGRO_USTR *temp = al_ref_cstr(&temp_info, str); //iterate until the end of string for(;;) { //find the character next_pos = al_ustr_find_chr(temp, pos, ch); //if not found, end if (next_pos == -1) break; //add a string; if no more strings can be added, return if (!_add_substring(temp, pos, next_pos, result, result_len, &count)) goto END; //continue after the character pos = next_pos + al_utf8_width(ch); } //set the remainder of the string to be the last string in the array _add_substring(temp, pos, al_ustr_size(temp), result, result_len, &count); END: return count; }
//returns the filepath of a resource static ALLEGRO_USTR *_get_resource_filepath(const ALLEGRO_USTR *skin_filepath, const char *resource_filename) { ALLEGRO_USTR *result; int pos, end_pos; ALLEGRO_USTR *temp; ALLEGRO_USTR_INFO temp_info; //duplicate the resource filepath in order to replace '\' by '/' result = al_ustr_dup(skin_filepath); //replace '\' with '/' al_ustr_find_replace_cstr(result, 0, "\\", "/"); //find the end of the string end_pos = al_ustr_size(result); //find the last occurrence of '/' pos = al_ustr_rfind_chr(result, end_pos, '/'); //find the position after the '/' pos += al_utf8_width('/'); //the replace function needs a ustr temp = al_ref_cstr(&temp_info, resource_filename); //replace the string after the '/' with the resource filename al_ustr_replace_range(result, pos, end_pos, temp); return result; }
/* Function: al_ustr_find_set_cstr */ int al_ustr_find_set_cstr(const ALLEGRO_USTR *us, int start_pos, const char *accept) { ALLEGRO_USTR_INFO info; ALLEGRO_USTR *accept_us = al_ref_cstr(&info, accept); return al_ustr_find_set(us, start_pos, accept_us); }
/* Function: al_ustr_rfind_cstr */ int al_ustr_rfind_cstr(const ALLEGRO_USTR *haystack, int end_pos, const char *needle) { ALLEGRO_USTR_INFO info; ALLEGRO_USTR *needle_us = al_ref_cstr(&info, needle); return al_ustr_rfind_str(haystack, end_pos, needle_us); }
/* Function: al_ustr_find_cset_cstr */ int al_ustr_find_cset_cstr(const ALLEGRO_USTR *us, int start_pos, const char *reject) { ALLEGRO_USTR_INFO info; ALLEGRO_USTR *reject_us = al_ref_cstr(&info, reject); return al_ustr_find_cset(us, start_pos, reject_us); }
/* Test al_ustr_get. */ static void t21(void) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *us; us = al_ref_buffer(&info, "", 1); CHECK(al_ustr_get(us, 0) == 0); us = al_ref_cstr(&info, "\x7f"); CHECK(al_ustr_get(us, 0) == 0x7f); us = al_ref_cstr(&info, "\xC2\x80"); CHECK(al_ustr_get(us, 0) == 0x80); us = al_ref_cstr(&info, "\xDF\xBf"); CHECK(al_ustr_get(us, 0) == 0x7ff); us = al_ref_cstr(&info, "\xE0\xA0\x80"); CHECK(al_ustr_get(us, 0) == 0x800); us = al_ref_cstr(&info, "\xEF\xBF\xBF"); CHECK(al_ustr_get(us, 0) == 0xffff); us = al_ref_cstr(&info, "\xF0\x90\x80\x80"); CHECK(al_ustr_get(us, 0) == 0x010000); us = al_ref_cstr(&info, "\xF4\x8F\xBF\xBF"); CHECK(al_ustr_get(us, 0) == 0x10ffff); }
/* Test al_ustr_has_prefix, al_ustr_has_suffix. */ static void t48(void) { ALLEGRO_USTR_INFO i1; const ALLEGRO_USTR *us1 = al_ref_cstr(&i1, "Thú mỏ vịt"); /* The _cstr versions are simple wrappers around the real functions so its * okay to test them only. */ CHECK(al_ustr_has_prefix_cstr(us1, "")); CHECK(al_ustr_has_prefix_cstr(us1, "Thú")); CHECK(! al_ustr_has_prefix_cstr(us1, "Thú mỏ vịt.")); CHECK(al_ustr_has_suffix_cstr(us1, "")); CHECK(al_ustr_has_suffix_cstr(us1, "vịt")); CHECK(! al_ustr_has_suffix_cstr(us1, "Thú mỏ vịt.")); }
//locates a resource by name static _RESOURCE *_find_resource_by_name(const char *name) { ALGUI_LIST_NODE *node; _RESOURCE *res; ALLEGRO_USTR_INFO info; ALLEGRO_USTR *name_ustr; //create a temporary name ustr to use in comparison name_ustr = al_ref_cstr(&info, name); //iterate the resources for(node = algui_get_first_list_node(&_resources); node; node = algui_get_next_list_node(node)) { //get the resource res = (_RESOURCE *)algui_get_list_node_data(node); //compare the strings if (al_ustr_equal(res->name, name_ustr)) return res; } //not found return NULL; }
/* Print some text with a shadow. */ static void print(int x, int y, bool vertical, char const *format, ...) { va_list list; char message[1024]; ALLEGRO_COLOR color; int h; int j; va_start(list, format); vsnprintf(message, sizeof message, format, list); va_end(list); al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); h = al_get_font_line_height(ex.myfont); for (j = 0; j < 2; j++) { if (j == 0) color = al_map_rgb(0, 0, 0); else color = al_map_rgb(255, 255, 255); if (vertical) { int i; ALLEGRO_USTR_INFO ui; const ALLEGRO_USTR *us = al_ref_cstr(&ui, message); for (i = 0; i < (int)al_ustr_length(us); i++) { ALLEGRO_USTR_INFO letter; al_draw_ustr(ex.myfont, color, x + 1 - j, y + 1 - j + h * i, 0, al_ref_ustr(&letter, us, al_ustr_offset(us, i), al_ustr_offset(us, i + 1))); } } else { al_draw_text(ex.myfont, color, x + 1 - j, y + 1 - j, 0, message); } } }
/* parse_path_string: * * Parse a path string according to the following grammar. The last * component, if it is not followed by a directory separator, is interpreted * as the filename component, unless it is "." or "..". * * GRAMMAR * * path ::= "//" c+ "/" nonlast [Windows only] * | c ":" nonlast [Windows only] * | nonlast * * nonlast ::= c* "/" nonlast * | last * * last ::= "." * | ".." * | filename * * filename ::= c* [but not "." and ".."] * * c ::= any character but '/' */ static bool parse_path_string(const ALLEGRO_USTR *str, ALLEGRO_PATH *path) { ALLEGRO_USTR_INFO dot_info; ALLEGRO_USTR_INFO dotdot_info; const ALLEGRO_USTR * dot = al_ref_cstr(&dot_info, "."); const ALLEGRO_USTR * dotdot = al_ref_cstr(&dotdot_info, ".."); ALLEGRO_USTR *piece = al_ustr_new(""); int pos = 0; bool on_windows; /* We compile the drive handling code on non-Windows platforms to prevent * it becoming broken. */ #ifdef ALLEGRO_WINDOWS on_windows = true; #else on_windows = false; #endif if (on_windows) { /* UNC \\server\share name */ if (al_ustr_has_prefix_cstr(str, "//")) { int slash = al_ustr_find_chr(str, 2, '/'); if (slash == -1 || slash == 2) { /* Missing slash or server component is empty. */ goto Error; } al_ustr_assign_substr(path->drive, str, pos, slash); pos = slash + 1; } else { /* Drive letter. */ int colon = al_ustr_offset(str, 1); if (colon > -1 && al_ustr_get(str, colon) == ':') { /* Include the colon in the drive string. */ al_ustr_assign_substr(path->drive, str, 0, colon + 1); pos = colon + 1; } } } for (;;) { int slash = al_ustr_find_chr(str, pos, '/'); if (slash == -1) { /* Last component. */ al_ustr_assign_substr(piece, str, pos, al_ustr_size(str)); if (al_ustr_equal(piece, dot) || al_ustr_equal(piece, dotdot)) { al_append_path_component(path, al_cstr(piece)); } else { /* This might be an empty string, but that's okay. */ al_ustr_assign(path->filename, piece); } break; } /* Non-last component. */ al_ustr_assign_substr(piece, str, pos, slash); al_append_path_component(path, al_cstr(piece)); pos = slash + 1; } al_ustr_free(piece); return true; Error: al_ustr_free(piece); return false; }
/* Get more ideas for tests from * http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt */ static void t23(void) { ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *us; /* Examples of an overlong ASCII character */ us = al_ref_cstr(&info, "\xc0\xaf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xe0\x80\xaf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf0\x80\x80\xaf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf8\x80\x80\x80\xaf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xfc\x80\x80\x80\x80\xaf"); CHECK(al_ustr_get(us, 0) < 0); /* Maximum overlong sequences */ us = al_ref_cstr(&info, "\xc1\xbf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xe0\x9f\xbf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf0\x8f\xbf\xbf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf8\x87\xbf\xbf\xbf"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xfc\x83\xbf\xbf\xbf\xbf"); CHECK(al_ustr_get(us, 0) < 0); /* Overlong representation of the NUL character */ us = al_ref_cstr(&info, "\xc0\x80"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xe0\x80\x80"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf0\x80\x80"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xf8\x80\x80\x80"); CHECK(al_ustr_get(us, 0) < 0); us = al_ref_cstr(&info, "\xfc\x80\x80\x80\x80"); CHECK(al_ustr_get(us, 0) < 0); }
static void render(void) { ALLEGRO_COLOR white = al_map_rgba_f(1, 1, 1, 1); ALLEGRO_COLOR black = al_map_rgba_f(0, 0, 0, 1); ALLEGRO_COLOR red = al_map_rgba_f(1, 0, 0, 1); ALLEGRO_COLOR green = al_map_rgba_f(0, 0.5, 0, 1); ALLEGRO_COLOR blue = al_map_rgba_f(0.1, 0.2, 1, 1); int x, y, w, h, as, de, xpos, ypos; int target_w, target_h; ALLEGRO_USTR_INFO info, sub_info; const ALLEGRO_USTR *u; al_clear_to_color(white); al_hold_bitmap_drawing(true); al_draw_textf(ex.f1, black, 50, 50, 0, "Tulip (kerning)"); al_draw_textf(ex.f2, black, 50, 100, 0, "Tulip (no kerning)"); al_draw_textf(ex.f3, black, 50, 200, 0, "This font has a size of 12 pixels, " "the one above has 48 pixels."); al_hold_bitmap_drawing(false); al_hold_bitmap_drawing(true); al_draw_textf(ex.f3, red, 50, 220, 0, "The color can simply be changed."); al_hold_bitmap_drawing(false); al_hold_bitmap_drawing(true); al_draw_textf(ex.f3, green, 50, 240, 0, "Some unicode symbols:"); al_draw_textf(ex.f3, green, 50, 260, 0, "%s", get_string("symbols1")); al_draw_textf(ex.f3, green, 50, 280, 0, "%s", get_string("symbols2")); al_draw_textf(ex.f3, green, 50, 300, 0, "%s", get_string("symbols3")); #define OFF(x) al_ustr_offset(u, x) #define SUB(x, y) al_ref_ustr(&sub_info, u, OFF(x), OFF(y)) u = al_ref_cstr(&info, get_string("substr1")); al_draw_ustr(ex.f3, green, 50, 320, 0, SUB(0, 6)); u = al_ref_cstr(&info, get_string("substr2")); al_draw_ustr(ex.f3, green, 50, 340, 0, SUB(7, 11)); u = al_ref_cstr(&info, get_string("substr3")); al_draw_ustr(ex.f3, green, 50, 360, 0, SUB(4, 11)); u = al_ref_cstr(&info, get_string("substr4")); al_draw_ustr(ex.f3, green, 50, 380, 0, SUB(0, 11)); al_draw_textf(ex.f5, black, 50, 420, 0, "forced monochrome"); al_hold_bitmap_drawing(false); target_w = al_get_bitmap_width(al_get_target_bitmap()); target_h = al_get_bitmap_height(al_get_target_bitmap()); xpos = target_w - 10; ypos = target_h - 10; al_get_text_dimensions(ex.f4, "Allegro", &x, &y, &w, &h); as = al_get_font_ascent(ex.f4); de = al_get_font_descent(ex.f4); xpos -= w; ypos -= h; x += xpos; y += ypos; al_draw_rectangle(x, y, x + w, y + h, black, 0); al_draw_line(x, y + as, x + w, y + as, black, 0); al_draw_line(x, y + as + de, x + w, y + as + de, black, 0); al_hold_bitmap_drawing(true); al_draw_textf(ex.f4, blue, xpos, ypos, 0, "Allegro"); al_hold_bitmap_drawing(false); al_hold_bitmap_drawing(true); al_draw_textf(ex.f3, black, target_w, 0, ALLEGRO_ALIGN_RIGHT, "%.1f FPS", ex.fps); al_hold_bitmap_drawing(false); }
/* _al_xwin_keyboard_handler: * Keyboard "interrupt" handler. */ void _al_xwin_keyboard_handler(XKeyEvent *event, ALLEGRO_DISPLAY *display) { int keycode; if (!xkeyboard_installed) return; keycode = keycode_to_scancode[event->keycode]; if (keycode == -1) keycode = find_unknown_key_assignment(event->keycode); update_shifts(event); /* Special case the pause key. */ if (keycode == ALLEGRO_KEY_PAUSE) { /* Allegro ignore's releasing of the pause key. */ if (event->type == KeyRelease) return; if (pause_key) { event->type = KeyRelease; pause_key = 0; } else { pause_key = 1; } } if (event->type == KeyPress) { /* Key pressed. */ int len; char buffer[16]; int unicode = 0; int filtered = 0; #if defined (ALLEGRO_XWINDOWS_WITH_XIM) && defined(X_HAVE_UTF8_STRING) if (xic) { len = Xutf8LookupString(xic, event, buffer, sizeof buffer, NULL, NULL); } else #endif { /* XLookupString is supposed to only use ASCII. */ len = XLookupString(event, buffer, sizeof buffer, NULL, NULL); } buffer[len] = '\0'; ALLEGRO_USTR_INFO info; const ALLEGRO_USTR *ustr = al_ref_cstr(&info, buffer); unicode = al_ustr_get(ustr, 0); if (unicode < 0) unicode = 0; #ifdef ALLEGRO_XWINDOWS_WITH_XIM ALLEGRO_DISPLAY_XGLX *glx = (void *)display; filtered = XFilterEvent((XEvent *)event, glx->window); #endif if (keycode || unicode) { handle_key_press(keycode, unicode, filtered, _key_shifts, display); } } else { /* Key release. */ /* HACK: * Detect key repeat by looking forward to see if this release is * followed by a press event, in which case we assume that this release * event was generated in response to that key press event. Events are * simultaneous if they are separated by less than 4 ms (a value that * worked well on one machine where this hack was needed). * * This is unnecessary on systems where XkbSetDetectableAutorepeat works. */ if (XPending(event->display) > 0) { ALLEGRO_KEY_REPEAT_DATA d; XEvent dummy; d.event = event; d.found = false; XCheckIfEvent(event->display, &dummy, check_for_repeat, (XPointer)&d); if (d.found) { return; } } handle_key_release(keycode, display); } }
/* Function: al_ustr_insert_cstr */ bool al_ustr_insert_cstr(ALLEGRO_USTR *us, int pos, const char *s) { ALLEGRO_USTR_INFO info; return al_ustr_insert(us, pos, al_ref_cstr(&info, s)); }
static void render(void) { ALLEGRO_COLOR white = al_map_rgba_f(1, 1, 1, 1); ALLEGRO_COLOR black = al_map_rgba_f(0, 0, 0, 1); ALLEGRO_COLOR red = al_map_rgba_f(1, 0, 0, 1); ALLEGRO_COLOR green = al_map_rgba_f(0, 0.5, 0, 1); ALLEGRO_COLOR blue = al_map_rgba_f(0.1, 0.2, 1, 1); ALLEGRO_COLOR purple = al_map_rgba_f(0.3, 0.1, 0.2, 1); int x, y, w, h, as, de, xpos, ypos; unsigned int index; int target_w, target_h; ALLEGRO_USTR_INFO info, sub_info; const ALLEGRO_USTR *u; ALLEGRO_USTR *tulip = al_ustr_new("Tulip"); ALLEGRO_USTR *dimension_text = al_ustr_new("Tulip"); ALLEGRO_USTR *vertical_text = al_ustr_new("Rose."); al_clear_to_color(white); al_hold_bitmap_drawing(true); al_draw_textf(ex.f1, black, 50, 20, 0, "Tulip (kerning)"); al_draw_textf(ex.f2, black, 50, 80, 0, "Tulip (no kerning)"); x = 50; y = 140; for (index = 0; index < al_ustr_length(dimension_text); index ++) { int cp = ustr_at(dimension_text, index); int bbx, bby, bbw, bbh; al_get_glyph_dimensions(ex.f2, cp, &bbx, &bby, &bbw, &bbh); al_draw_rectangle(x + bbx + 0.5, y + bby + 0.5, x + bbx + bbw - 0.5, y + bby + bbh - 0.5, blue, 1); al_draw_rectangle(x + 0.5, y + 0.5, x + bbx + bbw - 0.5, y + bby + bbh - 0.5, green, 1); al_draw_glyph(ex.f2, purple, x, y, cp); x += al_get_glyph_advance(ex.f2, cp, ALLEGRO_NO_KERNING); } al_draw_line(50.5, y+0.5, x+0.5, y+0.5, red, 1); al_draw_textf(ex.f2, black, x + 10, y, 0, "(dimensions)"); al_draw_textf(ex.f3, black, 50, 200, 0, "This font has a size of 12 pixels, " "the one above has 48 pixels."); al_hold_bitmap_drawing(false); al_hold_bitmap_drawing(true); al_draw_textf(ex.f3, red, 50, 220, 0, "The color can simply be changed.🐊← fallback glyph"); al_hold_bitmap_drawing(false); al_hold_bitmap_drawing(true); al_draw_textf(ex.f3, green, 50, 240, 0, "Some unicode symbols:"); al_draw_textf(ex.f3, green, 50, 260, 0, "%s", get_string("symbols1")); al_draw_textf(ex.f3, green, 50, 280, 0, "%s", get_string("symbols2")); al_draw_textf(ex.f3, green, 50, 300, 0, "%s", get_string("symbols3")); #define OFF(x) al_ustr_offset(u, x) #define SUB(x, y) al_ref_ustr(&sub_info, u, OFF(x), OFF(y)) u = al_ref_cstr(&info, get_string("substr1")); al_draw_ustr(ex.f3, green, 50, 320, 0, SUB(0, 6)); u = al_ref_cstr(&info, get_string("substr2")); al_draw_ustr(ex.f3, green, 50, 340, 0, SUB(7, 11)); u = al_ref_cstr(&info, get_string("substr3")); al_draw_ustr(ex.f3, green, 50, 360, 0, SUB(4, 11)); u = al_ref_cstr(&info, get_string("substr4")); al_draw_ustr(ex.f3, green, 50, 380, 0, SUB(0, 11)); al_draw_textf(ex.f5, black, 50, 395, 0, "forced monochrome"); /* Glyph rendering tests. */ al_draw_textf(ex.f3, red, 50, 410, 0, "Glyph adv Tu: %d, draw: ", al_get_glyph_advance(ex.f3, 'T', 'u')); x = 50; y = 425; for (index = 0; index < al_ustr_length(tulip); index ++) { int cp = ustr_at(tulip, index); /* Use al_get_glyph_advance for the stride, with no kerning. */ al_draw_glyph(ex.f3, red, x, y, cp); x += al_get_glyph_advance(ex.f3, cp, ALLEGRO_NO_KERNING); } x = 50; y = 440; /* First draw a red string using al_draw_text, that should be hidden * completely by the same text drawing in green per glyph * using al_draw_glyph and al_get_glyph_advance below. */ al_draw_ustr(ex.f3, red, x, y, 0, tulip); for (index = 0; index < al_ustr_length(tulip); index ++) { int cp = ustr_at(tulip, index); int ncp = (index < (al_ustr_length(tulip) - 1)) ? ustr_at(tulip, index + 1) : ALLEGRO_NO_KERNING; /* Use al_get_glyph_advance for the stride and apply kerning. */ al_draw_glyph(ex.f3, green, x, y, cp); x += al_get_glyph_advance(ex.f3, cp, ncp); } x = 50; y = 466; al_draw_ustr(ex.f3, red, x, y, 0, tulip); for (index = 0; index < al_ustr_length(tulip); index ++) { int cp = ustr_at(tulip, index); int bbx, bby, bbw, bbh; al_get_glyph_dimensions(ex.f3, cp, &bbx, &bby, &bbw, &bbh); al_draw_glyph(ex.f3, blue, x, y, cp); x += bbx + bbw; } x = 10; y = 30; for (index = 0; index < al_ustr_length(vertical_text); index ++) { int bbx, bby, bbw, bbh; int cp = ustr_at(vertical_text, index); /* Use al_get_glyph_dimensions for the height to apply. */ al_get_glyph_dimensions(ex.f3, cp, &bbx, &bby, &bbw, &bbh); al_draw_glyph(ex.f3, green, x, y, cp); y += bby; y += bbh; } x = 30; y = 30; for (index = 0; index < al_ustr_length(vertical_text); index ++) { int bbx, bby, bbw, bbh; int cp = ustr_at(vertical_text, index); /* Use al_get_glyph_dimensions for the height to apply, here bby is * omited for the wrong result. */ al_get_glyph_dimensions(ex.f3, cp, &bbx, &bby, &bbw, &bbh); al_draw_glyph(ex.f3, red, x, y, cp); y += bbh; } al_hold_bitmap_drawing(false); target_w = al_get_bitmap_width(al_get_target_bitmap()); target_h = al_get_bitmap_height(al_get_target_bitmap()); xpos = target_w - 10; ypos = target_h - 10; al_get_text_dimensions(ex.f4, "Allegro", &x, &y, &w, &h); as = al_get_font_ascent(ex.f4); de = al_get_font_descent(ex.f4); xpos -= w; ypos -= h; x += xpos; y += ypos; al_draw_rectangle(x, y, x + w - 0.5, y + h - 0.5, black, 0); al_draw_line(x+0.5, y + as + 0.5, x + w - 0.5, y + as + 0.5, black, 0); al_draw_line(x + 0.5, y + as + de + 0.5, x + w - 0.5, y + as + de + 0.5, black, 0); al_hold_bitmap_drawing(true); al_draw_textf(ex.f4, blue, xpos, ypos, 0, "Allegro"); al_hold_bitmap_drawing(false); al_hold_bitmap_drawing(true); al_draw_textf(ex.f3, black, target_w, 0, ALLEGRO_ALIGN_RIGHT, "%.1f FPS", ex.fps); al_draw_textf(ex.f3, black, 0, 0, 0, "%s: %d unicode ranges", font_file, ex.ranges_count); al_hold_bitmap_drawing(false); }
/* Test al_ustr_compare, al_ustr_ncompare. */ static void t47(void) { ALLEGRO_USTR_INFO i1; ALLEGRO_USTR_INFO i2; CHECK(al_ustr_compare( al_ref_cstr(&i1, "Thú mỏ vịt"), al_ref_cstr(&i2, "Thú mỏ vịt")) == 0); CHECK(al_ustr_compare( al_ref_cstr(&i1, "Thú mỏ vị"), al_ref_cstr(&i2, "Thú mỏ vịt")) < 0); CHECK(al_ustr_compare( al_ref_cstr(&i1, "Thú mỏ vịt"), al_ref_cstr(&i2, "Thú mỏ vit")) > 0); CHECK(al_ustr_compare( al_ref_cstr(&i1, "abc"), al_ref_cstr(&i2, "abc\001")) < 0); CHECK(al_ustr_compare( al_ref_cstr(&i1, "abc\001"), al_ref_cstr(&i2, "abc")) > 0); CHECK(al_ustr_ncompare( al_ref_cstr(&i1, "Thú mỏ vịt"), al_ref_cstr(&i2, "Thú mỏ vit"), 8) == 0); CHECK(al_ustr_ncompare( al_ref_cstr(&i1, "Thú mỏ vịt"), al_ref_cstr(&i2, "Thú mỏ vit"), 9) > 0); CHECK(al_ustr_ncompare( al_ref_cstr(&i1, "Thú mỏ vịt"), al_ref_cstr(&i2, "platypus"), 0) == 0); CHECK(al_ustr_ncompare( al_ref_cstr(&i1, "abc"), al_ref_cstr(&i2, "abc\001"), 4) < 0); CHECK(al_ustr_ncompare( al_ref_cstr(&i1, "abc\001"), al_ref_cstr(&i2, "abc"), 4) > 0); }