/* 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");
}