From 1468eef301a59346adc47ef19a740f4e2c3737a2 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Thu, 5 May 2022 09:46:05 +0000 Subject: [PATCH] Speed up opening fonts on Haiku * src/font.h (font_property_index): Note that some font drivers use the extra data in a font entity to store driver-specific information. * src/haiku_font_support.cc (BFont_find): Set font indices. (be_open_font_at_index): New function. (BFont_open_pattern): Clean up coding style. * src/haiku_support.h (enum haiku_font_specification) (struct haiku_font_pattern): New fields and specifications for indices. * src/haikufont.c (haikufont_pattern_to_entity, haikufont_open): Use indices to open fonts if available in the extra data. --- src/font.h | 5 +- src/haiku_font_support.cc | 118 +++++++++++++++++++++++++++++--------- src/haiku_support.h | 48 ++++++++++++++-- src/haikufont.c | 59 +++++++++++++++---- 4 files changed, 183 insertions(+), 47 deletions(-) diff --git a/src/font.h b/src/font.h index 424616a4a1e..06bd297ccb2 100644 --- a/src/font.h +++ b/src/font.h @@ -155,8 +155,9 @@ enum font_property_index /* In a font-spec, the value is an alist of extra information of a font such as name, OpenType features, and language coverage. In addition, in a font-entity, the value may contain a pair - (font-entity . INFO) where INFO is extra information to identify - a font (font-driver dependent). */ + (font-entity . INFO) where INFO is extra information to + identify a font (font-driver dependent). In a font-entity, + this holds font driver-specific information. */ FONT_EXTRA_INDEX, /* alist alist */ /* This value is the length of font-spec vector. */ diff --git a/src/haiku_font_support.cc b/src/haiku_font_support.cc index 339634f01be..ca6aaf71204 100644 --- a/src/haiku_font_support.cc +++ b/src/haiku_font_support.cc @@ -574,18 +574,21 @@ BFont_find (struct haiku_font_pattern *pt) font_family name; font_style sname; uint32 flags; - int sty_count; - int fam_count = count_font_families (); + int sty_count, fam_count, si, fi; + struct haiku_font_pattern *p, *head, *n; + bool oblique_seen_p; - for (int fi = 0; fi < fam_count; ++fi) + fam_count = count_font_families (); + + for (fi = 0; fi < fam_count; ++fi) { if (get_font_family (fi, &name, &flags) == B_OK) { sty_count = count_font_styles (name); - if (!sty_count && - font_family_style_matches_p (name, NULL, flags, pt)) + if (!sty_count + && font_family_style_matches_p (name, NULL, flags, pt)) { - struct haiku_font_pattern *p = new struct haiku_font_pattern; + p = new struct haiku_font_pattern; p->specified = 0; p->oblique_seen_p = 1; haiku_font_fill_pattern (p, name, NULL, flags); @@ -598,11 +601,11 @@ BFont_find (struct haiku_font_pattern *pt) } else if (sty_count) { - for (int si = 0; si < sty_count; ++si) + for (si = 0; si < sty_count; ++si) { - int oblique_seen_p = 0; - struct haiku_font_pattern *head = r; - struct haiku_font_pattern *p = NULL; + oblique_seen_p = 0; + head = r; + p = NULL; if (get_font_style (name, si, &sname, &flags) == B_OK) { @@ -611,8 +614,18 @@ BFont_find (struct haiku_font_pattern *pt) p = new struct haiku_font_pattern; p->specified = 0; haiku_font_fill_pattern (p, name, (char *) &sname, flags); - if (p->specified & FSPEC_SLANT && - ((p->slant == SLANT_OBLIQUE) || (p->slant == SLANT_ITALIC))) + + /* Add the indices to this font now so we + won't have to loop over each font in + order to open it later. */ + + p->specified |= FSPEC_INDICES; + p->family_index = fi; + p->style_index = si; + + if (p->specified & FSPEC_SLANT + && (p->slant == SLANT_OBLIQUE + || p->slant == SLANT_ITALIC)) oblique_seen_p = 1; p->next = r; @@ -627,9 +640,7 @@ BFont_find (struct haiku_font_pattern *pt) p->last = NULL; for (; head; head = head->last) - { - head->oblique_seen_p = oblique_seen_p; - } + head->oblique_seen_p = oblique_seen_p; } } } @@ -642,13 +653,18 @@ BFont_find (struct haiku_font_pattern *pt) if (!(pt->specified & FSPEC_SLANT)) { /* r->last is invalid from here onwards. */ - for (struct haiku_font_pattern *p = r; p;) + for (p = r; p;) { if (!p->oblique_seen_p) { - struct haiku_font_pattern *n = new haiku_font_pattern; + n = new haiku_font_pattern; *n = *p; + n->slant = SLANT_OBLIQUE; + + /* Opening a font by its indices doesn't provide enough + information to synthesize the oblique font later. */ + n->specified &= ~FSPEC_INDICES; p->next = n; p = p->next_family; } @@ -660,26 +676,68 @@ BFont_find (struct haiku_font_pattern *pt) return r; } +/* Find and open a font with the family at FAMILY and the style at + STYLE, and set its size to SIZE. Value is NULL if opening the font + failed. */ +void * +be_open_font_at_index (int family, int style, float size) +{ + font_family family_name; + font_style style_name; + uint32 flags; + status_t rc; + BFont *font; + + rc = get_font_family (family, &family_name, &flags); + + if (rc != B_OK) + return NULL; + + rc = get_font_style (family_name, style, &style_name, &flags); + + if (rc != B_OK) + return NULL; + + font = new BFont; + + rc = font->SetFamilyAndStyle (family_name, style_name); + + if (rc != B_OK) + { + delete font; + return NULL; + } + + font->SetSize (size); + font->SetEncoding (B_UNICODE_UTF8); + font->SetSpacing (B_BITMAP_SPACING); + return font; +} + /* Find and open a font matching the pattern PAT, which must have its family set. */ int BFont_open_pattern (struct haiku_font_pattern *pat, void **font, float size) { - int sty_count; + int sty_count, si, code; font_family name; font_style sname; + BFont *ft; uint32 flags = 0; + struct haiku_font_pattern copy; + if (!(pat->specified & FSPEC_FAMILY)) return 1; + strncpy (name, pat->family, sizeof name - 1); name[sizeof name - 1] = '\0'; sty_count = count_font_styles (name); - if (!sty_count && - font_family_style_matches_p (name, NULL, flags, pat, 1)) + if (!sty_count + && font_family_style_matches_p (name, NULL, flags, pat, 1)) { - BFont *ft = new BFont; + ft = new BFont; ft->SetSize (size); ft->SetEncoding (B_UNICODE_UTF8); ft->SetSpacing (B_BITMAP_SPACING); @@ -694,12 +752,13 @@ BFont_open_pattern (struct haiku_font_pattern *pat, void **font, float size) } else if (sty_count) { - for (int si = 0; si < sty_count; ++si) + for (si = 0; si < sty_count; ++si) { - if (get_font_style (name, si, &sname, &flags) == B_OK && - font_family_style_matches_p (name, (char *) &sname, flags, pat)) + if (get_font_style (name, si, &sname, &flags) == B_OK + && font_family_style_matches_p (name, (char *) &sname, + flags, pat)) { - BFont *ft = new BFont; + ft = new BFont; ft->SetSize (size); ft->SetEncoding (B_UNICODE_UTF8); ft->SetSpacing (B_BITMAP_SPACING); @@ -709,6 +768,7 @@ BFont_open_pattern (struct haiku_font_pattern *pat, void **font, float size) delete ft; return 1; } + *font = (void *) ft; return 0; } @@ -717,12 +777,14 @@ BFont_open_pattern (struct haiku_font_pattern *pat, void **font, float size) if (pat->specified & FSPEC_SLANT && pat->slant == SLANT_OBLIQUE) { - struct haiku_font_pattern copy = *pat; + copy = *pat; copy.slant = SLANT_REGULAR; - int code = BFont_open_pattern (©, font, size); + code = BFont_open_pattern (©, font, size); + if (code) return code; - BFont *ft = (BFont *) *font; + + ft = (BFont *) *font; /* XXX Font measurements don't respect shear. Haiku bug? This apparently worked in BeOS. ft->SetShear (100.0); */ diff --git a/src/haiku_support.h b/src/haiku_support.h index 63ba7260506..0fe2af3329a 100644 --- a/src/haiku_support.h +++ b/src/haiku_support.h @@ -246,6 +246,7 @@ enum haiku_font_specification FSPEC_NEED_ONE_OF = 1 << 6, FSPEC_WIDTH = 1 << 7, FSPEC_LANGUAGE = 1 << 8, + FSPEC_INDICES = 1 << 9, }; typedef char haiku_font_family_or_style[64]; @@ -300,25 +301,61 @@ enum haiku_font_weight struct haiku_font_pattern { + /* Bitmask indicating which fields are set. */ int specified; + + /* The next font in this list. */ struct haiku_font_pattern *next; - /* The next two fields are only temporarily used during the font - discovery process! Do not rely on them being correct outside - BFont_find. */ + + /* The last font in the list during font lookup. */ struct haiku_font_pattern *last; + + /* The next font in the list whose family differs from this one. + Only valid during font lookup. */ struct haiku_font_pattern *next_family; + + /* The family of the font. */ haiku_font_family_or_style family; + + /* The style of the font. */ haiku_font_family_or_style style; + + /* Whether or the font is monospace. */ int mono_spacing_p; - int want_chars_len; - int need_one_of_len; + + /* The slant of the font. */ enum haiku_font_slant slant; + + /* The width of the font. */ enum haiku_font_width width; + + /* The language of the font. Used during font lookup. */ enum haiku_font_language language; + + /* The weight of the font. */ enum haiku_font_weight weight; + + /* List of characters that must be present in the font for the match + to succeed. */ int *wanted_chars; + + /* The number of characters in `wanted_chars'. */ + int want_chars_len; + + /* List of characters. The font must fullfill at least one of + them for the match to succeed. */ int *need_one_of; + /* The number of characters in `need_one_of'. */ + int need_one_of_len; + + /* The index of the family of the font this pattern represents. */ + int family_index; + + /* The index of the style of the font this pattern represents. */ + int style_index; + + /* Temporary field used during font enumeration. */ int oblique_seen_p; }; @@ -635,6 +672,7 @@ extern bool be_use_subpixel_antialiasing (void); extern const char *be_find_setting (const char *); extern haiku_font_family_or_style *be_list_font_families (size_t *); extern void be_font_style_to_flags (char *, struct haiku_font_pattern *); +extern void *be_open_font_at_index (int, int, float); extern int be_get_ui_color (const char *, uint32_t *); extern void BMessage_delete (void *); diff --git a/src/haikufont.c b/src/haikufont.c index d18c1a393a0..f8cf45284d0 100644 --- a/src/haikufont.c +++ b/src/haikufont.c @@ -381,7 +381,9 @@ haikufont_maybe_handle_special_family (Lisp_Object family, static Lisp_Object haikufont_pattern_to_entity (struct haiku_font_pattern *ptn) { - Lisp_Object ent = font_make_entity (); + Lisp_Object ent; + + ent = font_make_entity (); ASET (ent, FONT_TYPE_INDEX, Qhaiku); ASET (ent, FONT_FOUNDRY_INDEX, Qhaiku); ASET (ent, FONT_FAMILY_INDEX, Qdefault); @@ -390,6 +392,14 @@ haikufont_pattern_to_entity (struct haiku_font_pattern *ptn) ASET (ent, FONT_SIZE_INDEX, make_fixnum (0)); ASET (ent, FONT_AVGWIDTH_INDEX, make_fixnum (0)); ASET (ent, FONT_SPACING_INDEX, make_fixnum (FONT_SPACING_MONO)); + + /* FONT_EXTRA_INDEX in a font entity can be a cons of two numbers + (STYLE . IDX) that tell Emacs how to open a font. */ + if (ptn->specified & FSPEC_INDICES) + ASET (ent, FONT_EXTRA_INDEX, + Fcons (make_fixnum (ptn->family_index), + make_fixnum (ptn->style_index))); + FONT_SET_STYLE (ent, FONT_WIDTH_INDEX, Qnormal); FONT_SET_STYLE (ent, FONT_WEIGHT_INDEX, Qnormal); FONT_SET_STYLE (ent, FONT_SLANT_INDEX, Qnormal); @@ -722,10 +732,11 @@ haikufont_open (struct frame *f, Lisp_Object font_entity, int x) struct haiku_font_pattern ptn; struct font *font; void *be_font; - Lisp_Object font_object; - Lisp_Object tem; + Lisp_Object font_object, tem, extra; + int px_size, min_width, max_width, + avg_width, height, space_width, ascent, + descent, underline_pos, underline_thickness; - block_input (); if (x <= 0) { /* Get pixel size from frame instead. */ @@ -733,19 +744,47 @@ haikufont_open (struct frame *f, Lisp_Object font_entity, int x) x = NILP (tem) ? 0 : XFIXNAT (tem); } - haikufont_spec_or_entity_to_pattern (font_entity, 1, &ptn); + extra = AREF (font_entity, FONT_EXTRA_INDEX); - if (BFont_open_pattern (&ptn, &be_font, x)) + /* If the font's indices is already available, open the font using + those instead. */ + + if (CONSP (extra) && FIXNUMP (XCAR (extra)) + && FIXNUMP (XCDR (extra))) { + block_input (); + be_font = be_open_font_at_index (XFIXNUM (XCAR (extra)), + XFIXNUM (XCDR (extra)), x); + unblock_input (); + + if (!be_font) + return Qnil; + } + else + { + block_input (); + haikufont_spec_or_entity_to_pattern (font_entity, 1, &ptn); + + if (BFont_open_pattern (&ptn, &be_font, x)) + { + haikufont_done_with_query_pattern (&ptn); + unblock_input (); + return Qnil; + } + haikufont_done_with_query_pattern (&ptn); unblock_input (); - return Qnil; } - haikufont_done_with_query_pattern (&ptn); + block_input (); + /* `font_make_object' tries to treat the extra data as an alist. + There is never any real data here, so clear that field. */ + + ASET (font_entity, FONT_EXTRA_INDEX, Qnil); font_object = font_make_object (VECSIZE (struct haikufont_info), font_entity, x); + ASET (font_entity, FONT_EXTRA_INDEX, extra); ASET (font_object, FONT_TYPE_INDEX, Qhaiku); font_info = (struct haikufont_info *) XFONT_OBJECT (font_object); @@ -772,10 +811,6 @@ haikufont_open (struct frame *f, Lisp_Object font_entity, int x) font_info->metrics = NULL; font_info->metrics_nrows = 0; - int px_size, min_width, max_width, - avg_width, height, space_width, ascent, - descent, underline_pos, underline_thickness; - BFont_metrics (be_font, &px_size, &min_width, &max_width, &avg_width, &height, &space_width, &ascent, &descent,