/* Font support for Haiku windowing Copyright (C) 2021 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see . */ #include #include "lisp.h" #include "dispextern.h" #include "composite.h" #include "blockinput.h" #include "charset.h" #include "frame.h" #include "window.h" #include "fontset.h" #include "haikuterm.h" #include "character.h" #include "font.h" #include "termchar.h" #include "pdumper.h" #include "haiku_support.h" #include #include static Lisp_Object haikufont_get_fallback_entity (void) { Lisp_Object ent = font_make_entity (); ASET (ent, FONT_TYPE_INDEX, Qhaiku); ASET (ent, FONT_FOUNDRY_INDEX, Qhaiku); ASET (ent, FONT_FAMILY_INDEX, Qnil); ASET (ent, FONT_ADSTYLE_INDEX, Qnil); ASET (ent, FONT_REGISTRY_INDEX, Qiso10646_1); 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_SET_STYLE (ent, FONT_WIDTH_INDEX, Qnil); FONT_SET_STYLE (ent, FONT_WEIGHT_INDEX, Qnil); FONT_SET_STYLE (ent, FONT_SLANT_INDEX, Qnil); return ent; } static Lisp_Object haikufont_get_cache (struct frame *frame) { return x_display_list->name_list_element; } static Lisp_Object haikufont_weight_to_lisp (int weight) { switch (weight) { case HAIKU_THIN: return Qthin; case HAIKU_ULTRALIGHT: return Qultra_light; case HAIKU_EXTRALIGHT: return Qextra_light; case HAIKU_LIGHT: return Qlight; case HAIKU_SEMI_LIGHT: return Qsemi_light; case HAIKU_REGULAR: return Qnormal; case HAIKU_SEMI_BOLD: return Qsemi_bold; case HAIKU_BOLD: return Qbold; case HAIKU_EXTRA_BOLD: return Qextra_bold; case HAIKU_ULTRA_BOLD: return Qultra_bold; } emacs_abort (); } static int haikufont_lisp_to_weight (Lisp_Object weight) { if (EQ (weight, Qthin)) return HAIKU_THIN; if (EQ (weight, Qultra_light)) return HAIKU_ULTRALIGHT; if (EQ (weight, Qextra_light)) return HAIKU_EXTRALIGHT; if (EQ (weight, Qlight)) return HAIKU_LIGHT; if (EQ (weight, Qsemi_light)) return HAIKU_SEMI_LIGHT; if (EQ (weight, Qnormal)) return HAIKU_REGULAR; if (EQ (weight, Qsemi_bold)) return HAIKU_SEMI_BOLD; if (EQ (weight, Qbold)) return HAIKU_BOLD; if (EQ (weight, Qextra_bold)) return HAIKU_EXTRA_BOLD; if (EQ (weight, Qultra_bold)) return HAIKU_ULTRA_BOLD; emacs_abort (); } static Lisp_Object haikufont_slant_to_lisp (enum haiku_font_slant slant) { switch (slant) { case NO_SLANT: emacs_abort (); case SLANT_ITALIC: return Qitalic; case SLANT_REGULAR: return Qnormal; case SLANT_OBLIQUE: return Qoblique; } emacs_abort (); } static enum haiku_font_slant haikufont_lisp_to_slant (Lisp_Object slant) { if (EQ (slant, Qitalic) || EQ (slant, Qreverse_italic)) return SLANT_ITALIC; if (EQ (slant, Qoblique) || EQ (slant, Qreverse_oblique)) return SLANT_OBLIQUE; if (EQ (slant, Qnormal)) return SLANT_REGULAR; emacs_abort (); } static Lisp_Object haikufont_width_to_lisp (enum haiku_font_width width) { switch (width) { case NO_WIDTH: emacs_abort (); case ULTRA_CONDENSED: return Qultra_condensed; case EXTRA_CONDENSED: return Qextra_condensed; case CONDENSED: return Qcondensed; case SEMI_CONDENSED: return Qsemi_condensed; case NORMAL_WIDTH: return Qnormal; case SEMI_EXPANDED: return Qsemi_expanded; case EXPANDED: return Qexpanded; case EXTRA_EXPANDED: return Qextra_expanded; case ULTRA_EXPANDED: return Qultra_expanded; } emacs_abort (); } static enum haiku_font_width haikufont_lisp_to_width (Lisp_Object lisp) { if (EQ (lisp, Qultra_condensed)) return ULTRA_CONDENSED; if (EQ (lisp, Qextra_condensed)) return EXTRA_CONDENSED; if (EQ (lisp, Qcondensed)) return CONDENSED; if (EQ (lisp, Qsemi_condensed)) return SEMI_CONDENSED; if (EQ (lisp, Qnormal)) return NORMAL_WIDTH; if (EQ (lisp, Qexpanded)) return EXPANDED; if (EQ (lisp, Qextra_expanded)) return EXTRA_EXPANDED; if (EQ (lisp, Qultra_expanded)) return ULTRA_EXPANDED; emacs_abort (); } static int haikufont_maybe_handle_special_family (Lisp_Object family, struct haiku_font_pattern *ptn) { CHECK_SYMBOL (family); if (EQ (family, Qmonospace) || EQ (family, Qfixed) || EQ (family, Qdefault)) { BFont_populate_fixed_family (ptn); return 1; } else if (EQ (family, intern ("Sans Serif"))) { BFont_populate_plain_family (ptn); return 1; } return 0; } static Lisp_Object haikufont_pattern_to_entity (struct haiku_font_pattern *ptn) { Lisp_Object ent = font_make_entity (); ASET (ent, FONT_TYPE_INDEX, Qhaiku); ASET (ent, FONT_FOUNDRY_INDEX, Qhaiku); ASET (ent, FONT_FAMILY_INDEX, Qdefault); ASET (ent, FONT_ADSTYLE_INDEX, Qnil); ASET (ent, FONT_REGISTRY_INDEX, Qiso10646_1); 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_SET_STYLE (ent, FONT_WIDTH_INDEX, Qnormal); FONT_SET_STYLE (ent, FONT_WEIGHT_INDEX, Qnormal); FONT_SET_STYLE (ent, FONT_SLANT_INDEX, Qnormal); if (ptn->specified & FSPEC_FAMILY) ASET (ent, FONT_FAMILY_INDEX, intern (ptn->family)); else ASET (ent, FONT_FAMILY_INDEX, Qdefault); if (ptn->specified & FSPEC_STYLE) ASET (ent, FONT_ADSTYLE_INDEX, intern (ptn->style)); else { if (ptn->specified & FSPEC_WEIGHT) FONT_SET_STYLE (ent, FONT_WEIGHT_INDEX, haikufont_weight_to_lisp (ptn->weight)); if (ptn->specified & FSPEC_SLANT) FONT_SET_STYLE (ent, FONT_SLANT_INDEX, haikufont_slant_to_lisp (ptn->slant)); if (ptn->specified & FSPEC_WIDTH) FONT_SET_STYLE (ent, FONT_WIDTH_INDEX, haikufont_width_to_lisp (ptn->width)); } if (ptn->specified & FSPEC_SPACING) ASET (ent, FONT_SPACING_INDEX, make_fixnum (ptn->mono_spacing_p ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); return ent; } static void haikufont_spec_or_entity_to_pattern (Lisp_Object ent, int list_p, struct haiku_font_pattern *ptn) { Lisp_Object tem; ptn->specified = 0; tem = AREF (ent, FONT_ADSTYLE_INDEX); if (!NILP (tem)) { ptn->specified |= FSPEC_STYLE; strncpy ((char *) &ptn->style, SSDATA (SYMBOL_NAME (tem)), sizeof ptn->style - 1); } tem = FONT_SLANT_SYMBOLIC (ent); if (!NILP (tem)) { ptn->specified |= FSPEC_SLANT; ptn->slant = haikufont_lisp_to_slant (tem); } tem = FONT_WEIGHT_SYMBOLIC (ent); if (!NILP (tem)) { ptn->specified |= FSPEC_WEIGHT; ptn->weight = haikufont_lisp_to_weight (tem); } tem = FONT_WIDTH_SYMBOLIC (ent); if (!NILP (tem)) { ptn->specified |= FSPEC_WIDTH; ptn->width = haikufont_lisp_to_width (tem); } tem = AREF (ent, FONT_SPACING_INDEX); if (FIXNUMP (tem)) { ptn->specified |= FSPEC_SPACING; ptn->mono_spacing_p = XFIXNUM (tem) != FONT_SPACING_PROPORTIONAL; } tem = AREF (ent, FONT_FAMILY_INDEX); if (!NILP (tem) && (list_p && !haikufont_maybe_handle_special_family (tem, ptn))) { ptn->specified |= FSPEC_FAMILY; strncpy ((char *) &ptn->family, SSDATA (SYMBOL_NAME (tem)), sizeof ptn->family - 1); } tem = assq_no_quit (QCscript, AREF (ent, FONT_EXTRA_INDEX)); if (!NILP (tem)) { tem = assq_no_quit (XCDR (tem), Vscript_representative_chars); if (CONSP (tem) && VECTORP (XCDR (tem))) { tem = XCDR (tem); int count = 0; for (int j = 0; j < ASIZE (tem); ++j) if (TYPE_RANGED_FIXNUMP (uint32_t, AREF (tem, j))) ++count; if (count) { ptn->specified |= FSPEC_NEED_ONE_OF; ptn->need_one_of_len = count; ptn->need_one_of = xmalloc (count * sizeof *ptn->need_one_of); count = 0; for (int j = 0; j < ASIZE (tem); ++j) if (TYPE_RANGED_FIXNUMP (uint32_t, AREF (tem, j))) { ptn->need_one_of[j] = XFIXNAT (AREF (tem, j)); ++count; } } } else if (CONSP (tem) && CONSP (XCDR (tem))) { int count = 0; for (Lisp_Object it = XCDR (tem); CONSP (it); it = XCDR (it)) if (TYPE_RANGED_FIXNUMP (uint32_t, XCAR (it))) ++count; if (count) { ptn->specified |= FSPEC_WANTED; ptn->want_chars_len = count; ptn->wanted_chars = xmalloc (count * sizeof *ptn->wanted_chars); count = 0; for (tem = XCDR (tem); CONSP (tem); tem = XCDR (tem)) if (TYPE_RANGED_FIXNUMP (uint32_t, XCAR (tem))) { ptn->wanted_chars[count] = XFIXNAT (XCAR (tem)); ++count; } } } } tem = assq_no_quit (QClang, AREF (ent, FONT_EXTRA_INDEX)); if (CONSP (tem)) { tem = XCDR (tem); if (EQ (tem, Qzh)) { ptn->specified |= FSPEC_LANGUAGE; ptn->language = LANGUAGE_CN; } else if (EQ (tem, Qko)) { ptn->specified |= FSPEC_LANGUAGE; ptn->language = LANGUAGE_KO; } else if (EQ (tem, Qjp)) { ptn->specified |= FSPEC_LANGUAGE; ptn->language = LANGUAGE_JP; } } } static void haikufont_done_with_query_pattern (struct haiku_font_pattern *ptn) { if (ptn->specified & FSPEC_WANTED) xfree (ptn->wanted_chars); if (ptn->specified & FSPEC_NEED_ONE_OF) xfree (ptn->need_one_of); } static Lisp_Object haikufont_match (struct frame *f, Lisp_Object font_spec) { block_input (); Lisp_Object tem = Qnil; struct haiku_font_pattern ptn; haikufont_spec_or_entity_to_pattern (font_spec, 0, &ptn); ptn.specified &= ~FSPEC_FAMILY; struct haiku_font_pattern *found = BFont_find (&ptn); haikufont_done_with_query_pattern (&ptn); if (found) { tem = haikufont_pattern_to_entity (found); haiku_font_pattern_free (found); } unblock_input (); return !NILP (tem) ? tem : haikufont_get_fallback_entity (); } static Lisp_Object haikufont_list (struct frame *f, Lisp_Object font_spec) { block_input (); Lisp_Object lst = Qnil; struct haiku_font_pattern ptn; haikufont_spec_or_entity_to_pattern (font_spec, 1, &ptn); struct haiku_font_pattern *found = BFont_find (&ptn); haikufont_done_with_query_pattern (&ptn); if (found) { for (struct haiku_font_pattern *pt = found; pt; pt = pt->next) lst = Fcons (haikufont_pattern_to_entity (pt), lst); haiku_font_pattern_free (found); } unblock_input (); return lst; } static unsigned int haikufont_encode_char (struct font *font, int c) { struct haikufont_info *info = (struct haikufont_info *) font; if (c < HAVE_CHAR_CACHE_MAX && c < info->charc_size && info->have_char_cache[c]) return info->have_char_cache[c] < 0 ? FONT_INVALID_CODE : c; if (c < HAVE_CHAR_CACHE_MAX) { int min_size = c + 1; if (info->charc_size < min_size) { ptrdiff_t current = info->charc_size; info->charc_size = min_size + min_size % 256; info->met_cache = xrealloc (info->met_cache, info->charc_size * sizeof *info->met_cache); info->have_char_cache = xrealloc (info->have_char_cache, info->charc_size * sizeof *info->have_char_cache); memset (&info->have_char_cache[current], 0, sizeof *info->have_char_cache * (info->charc_size - current)); memset (&info->met_cache[current], 0, sizeof *info->met_cache * (info->charc_size - current)); } info->have_char_cache[c] = -1; } if (!BFont_have_char_p (((struct haikufont_info *) font)->be_font, c)) { if (c < HAVE_CHAR_CACHE_MAX) { info->have_char_cache[c] = -1; } return FONT_INVALID_CODE; } if (c < HAVE_CHAR_CACHE_MAX) info->have_char_cache[c] = 1; return c; } static int haikufont_have_char (Lisp_Object font, int c) { if (FONT_ENTITY_P (font)) return -1; return haikufont_encode_char (XFONT_OBJECT (font), c) != FONT_INVALID_CODE; } static Lisp_Object haikufont_open (struct frame *f, Lisp_Object font_entity, int x) { struct haikufont_info *font_info; struct haiku_font_pattern ptn; struct font *font; void *be_font; Lisp_Object font_object; Lisp_Object tem; block_input (); if (x <= 0) { /* Get pixel size from frame instead */ tem = get_frame_param (f, Qfontsize); x = NILP (tem) ? 0 : XFIXNAT (tem); } 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); font_object = font_make_object (VECSIZE (struct haikufont_info), font_entity, x); ASET (font_object, FONT_TYPE_INDEX, Qhaiku); font_info = (struct haikufont_info *) XFONT_OBJECT (font_object); font = (struct font *) font_info; font_info->charc_size = 256; font_info->met_cache = xmalloc (font_info->charc_size * sizeof *font_info->met_cache); font_info->have_char_cache = xmalloc (font_info->charc_size * sizeof *font_info->met_cache); memset (font_info->met_cache, 0, font_info->charc_size * sizeof *font_info->met_cache); memset (font_info->have_char_cache, 0, font_info->charc_size * sizeof *font_info->met_cache); if (!font) { unblock_input (); return Qnil; } font_info->be_font = be_font; font->pixel_size = 0; font->driver = &haikufont_driver; font->encoding_charset = -1; font->repertory_charset = -1; font->default_ascent = 0; font->vertical_centering = 0; font->baseline_offset = 0; font->relative_compose = 0; font->props[FONT_FULLNAME_INDEX] = build_unibyte_string ("fixed"); int px_size, min_width, max_width, avg_width, height, space_width, ascent, descent, underline_pos, underline_thickness; BFont_dat (be_font, &px_size, &min_width, &max_width, &avg_width, &height, &space_width, &ascent, &descent, &underline_pos, &underline_thickness); font->pixel_size = px_size; font->min_width = min_width; font->max_width = max_width; font->average_width = avg_width; font->height = height; font->space_width = space_width; font->ascent = ascent; font->descent = descent; font->default_ascent = ascent; font->underline_position = underline_pos; font->underline_thickness = underline_thickness; font->vertical_centering = 0; font->baseline_offset = 0; font->relative_compose = 0; font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil); unblock_input (); return font_object; } static void haikufont_close (struct font *font) { if (font_data_structures_may_be_ill_formed ()) return; struct haikufont_info *info = (struct haikufont_info *) font; block_input (); if (info && info->be_font) BFont_close (info->be_font); unblock_input (); } static void haikufont_prepare_face (struct frame *f, struct face *face) { } static void haikufont_glyph_extents (struct font *font, unsigned code, struct font_metrics *metrics) { struct haikufont_info *info = (struct haikufont_info *) font; if (code < HAVE_CHAR_CACHE_MAX && info->met_cache[code].ascent != 0) { int min_size = code + 1; if (info->charc_size < min_size) { info->charc_size = min_size + min_size % 256; ptrdiff_t current = info->charc_size; info->charc_size = min_size + min_size % 256; info->met_cache = xrealloc (info->met_cache, info->charc_size * sizeof *info->met_cache); info->have_char_cache = xrealloc (info->have_char_cache, info->charc_size * sizeof *info->have_char_cache); memset (&info->have_char_cache[current], 0, sizeof *info->have_char_cache * (info->charc_size - current)); memset (&info->met_cache[current], 0, sizeof *info->met_cache * (info->charc_size - current)); } *metrics = info->met_cache[code]; return; } unsigned char utf8[MAX_MULTIBYTE_LENGTH]; memset (utf8, 0, MAX_MULTIBYTE_LENGTH); CHAR_STRING (code, utf8); int advance, lb, rb; BFont_char_bounds (info->be_font, (const char *) utf8, &advance, &lb, &rb); metrics->lbearing = lb; metrics->rbearing = rb; metrics->width = advance; metrics->ascent = font->ascent; metrics->descent = font->descent; if (code < HAVE_CHAR_CACHE_MAX) { int min_size = code + 1; if (info->charc_size < min_size) { ptrdiff_t current = info->charc_size; info->charc_size = min_size + min_size % 256; info->met_cache = xrealloc (info->met_cache, info->charc_size * sizeof *info->met_cache); info->have_char_cache = xrealloc (info->have_char_cache, info->charc_size * sizeof *info->have_char_cache); memset (&info->have_char_cache[current], 0, sizeof *info->have_char_cache * (info->charc_size - current)); memset (&info->met_cache[current], 0, sizeof *info->met_cache * (info->charc_size - current)); } info->met_cache[code] = *metrics; } } static void haikufont_text_extents (struct font *font, const unsigned int *code, int nglyphs, struct font_metrics *metrics) { int totalwidth = 0; memset (metrics, 0, sizeof (struct font_metrics)); block_input (); for (int i = 0; i < nglyphs; i++) { struct font_metrics m; haikufont_glyph_extents (font, code[i], &m); if (metrics) { if (totalwidth + m.lbearing < metrics->lbearing) metrics->lbearing = totalwidth + m.lbearing; if (totalwidth + m.rbearing > metrics->rbearing) metrics->rbearing = totalwidth + m.rbearing; if (m.ascent > metrics->ascent) metrics->ascent = m.ascent; if (m.descent > metrics->descent) metrics->descent = m.descent; } totalwidth += m.width; } unblock_input (); if (metrics) metrics->width = totalwidth; } static Lisp_Object haikufont_shape (Lisp_Object lgstring, Lisp_Object direction) { struct haikufont_info *font = (struct haikufont_info *) CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring)); int *advance, *lb, *rb; ptrdiff_t glyph_len, len, i, b_len; Lisp_Object tem; char *b; uint32_t *mb_buf; glyph_len = LGSTRING_GLYPH_LEN (lgstring); for (i = 0; i < glyph_len; ++i) { tem = LGSTRING_GLYPH (lgstring, i); if (NILP (tem)) break; } len = i; if (INT_MAX / 2 < len) memory_full (SIZE_MAX); block_input (); b_len = 0; b = xmalloc (b_len); mb_buf = alloca (len * sizeof *mb_buf); for (i = b_len; i < len; ++i) { uint32_t c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i)); mb_buf[i] = c; unsigned char mb[MAX_MULTIBYTE_LENGTH]; int slen = CHAR_STRING (c, mb); b = xrealloc (b, b_len = (b_len + slen)); if (len == 1) b[b_len - slen] = mb[0]; else memcpy (b + b_len - slen, mb, slen); } advance = alloca (len * sizeof *advance); lb = alloca (len * sizeof *lb); rb = alloca (len * sizeof *rb); eassert (font->be_font); BFont_nchar_bounds (font->be_font, b, advance, lb, rb, len); xfree (b); for (i = 0; i < len; ++i) { tem = LGSTRING_GLYPH (lgstring, i); if (NILP (tem)) { tem = LGLYPH_NEW (); LGSTRING_SET_GLYPH (lgstring, i, tem); } LGLYPH_SET_FROM (tem, i); LGLYPH_SET_TO (tem, i); LGLYPH_SET_CHAR (tem, mb_buf[i]); LGLYPH_SET_CODE (tem, mb_buf[i]); LGLYPH_SET_WIDTH (tem, advance[i]); LGLYPH_SET_LBEARING (tem, lb[i]); LGLYPH_SET_RBEARING (tem, rb[i]); LGLYPH_SET_ASCENT (tem, font->font.ascent); LGLYPH_SET_DESCENT (tem, font->font.descent); } unblock_input (); return make_fixnum (len); } static int haikufont_draw (struct glyph_string *s, int from, int to, int x, int y, bool with_background) { struct frame *f = s->f; struct face *face = s->face; struct font_info *info = (struct font_info *) s->font; unsigned char mb[MAX_MULTIBYTE_LENGTH]; void *view = FRAME_HAIKU_VIEW (f); if (s->hl == DRAW_MOUSE_FACE) face = FACE_FROM_ID_OR_NULL (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id); if (!face) face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); block_input (); prepare_face_for_display (s->f, face); BView_draw_lock (view); BView_StartClip (view); if (with_background && !s->background_filled_p) { int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f); int vx, vy, width, height; vx = s->x; vy = s->y; width = s->width; height = FONT_HEIGHT (face->font); if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p) vx += max (s->face->box_vertical_line_width, 0); int mbox_line_width = max (s->face->box_vertical_line_width, 0); if (s->row->full_width_p) { if (vx <= fibw + 1 + mbox_line_width) { width += vx - mbox_line_width; vx = mbox_line_width; } if (FRAME_PIXEL_WIDTH (s->f) - (vx + width) <= fibw+1) width += fibw; } if (s->face->box == FACE_NO_BOX) { /* Expand unboxed top row over internal border. */ if (vy <= fibw + 1 + mbox_line_width) { height += vy; vy = 0; } } else { int correction = abs (s->face->box_horizontal_line_width) + 1; vy += correction; height -= 2 * correction; correction = abs (s->face->box_vertical_line_width) + 1; vx += correction; width -= 2 * correction; } BView_SetHighColor (view, s->hl == DRAW_CURSOR ? FRAME_CURSOR_COLOR (s->f).pixel : face->background); BView_FillRectangle (view, vx, vy, width, height); s->background_filled_p = 1; } if (s->left_overhang && s->clip_head && !s->for_overlaps) { /* XXX: Why is this neccessary? */ BView_ClipToRect (view, s->clip_head->x, 0, FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f)); } if (s->hl == DRAW_CURSOR) BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg); else BView_SetHighColor (view, face->foreground); BView_MovePenTo (view, x, y); BView_SetFont (view, ((struct haikufont_info *) info)->be_font); if (from == to) { int len = CHAR_STRING (s->char2b[from], mb); BView_DrawString (view, (char *) mb, len); } else { ptrdiff_t b_len = 0; char *b = xmalloc (b_len); for (int idx = from; idx < to; ++idx) { int len = CHAR_STRING (s->char2b[idx], mb); b = xrealloc (b, b_len = (b_len + len)); if (len == 1) b[b_len - len] = mb[0]; else memcpy (b + b_len - len, mb, len); } BView_DrawString (view, b, b_len); xfree (b); } BView_EndClip (view); BView_draw_unlock (view); unblock_input (); return 1; } struct font_driver const haikufont_driver = { .type = LISPSYM_INITIALLY (Qhaiku), .case_sensitive = true, .get_cache = haikufont_get_cache, .has_char = haikufont_have_char, .list = haikufont_list, .match = haikufont_match, .draw = haikufont_draw, .open_font = haikufont_open, .close_font = haikufont_close, .prepare_face = haikufont_prepare_face, .encode_char = haikufont_encode_char, .text_extents = haikufont_text_extents, .shape = haikufont_shape }; void syms_of_haikufont (void) { DEFSYM (Qfontsize, "fontsize"); DEFSYM (Qfixed, "fixed"); DEFSYM (Qplain, "plain"); DEFSYM (Qultra_light, "ultra-light"); DEFSYM (Qthin, "thin"); DEFSYM (Qreverse_italic, "reverse-italic"); DEFSYM (Qreverse_oblique, "reverse-oblique"); DEFSYM (Qmonospace, "monospace"); DEFSYM (Qultra_condensed, "ultra-condensed"); DEFSYM (Qextra_condensed, "extra-condensed"); DEFSYM (Qcondensed, "condensed"); DEFSYM (Qsemi_condensed, "semi-condensed"); DEFSYM (Qsemi_expanded, "semi-expanded"); DEFSYM (Qexpanded, "expanded"); DEFSYM (Qextra_expanded, "extra-expanded"); DEFSYM (Qultra_expanded, "ultra-expanded"); DEFSYM (Qzh, "zh"); DEFSYM (Qko, "ko"); DEFSYM (Qjp, "jp"); }