1474 lines
38 KiB
C
1474 lines
38 KiB
C
/* Font support for Haiku windowing
|
|
|
|
Copyright (C) 2021-2024 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 <https://www.gnu.org/licenses/>. */
|
|
|
|
#include <config.h>
|
|
|
|
#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 "coding.h"
|
|
#include "font.h"
|
|
#include "termchar.h"
|
|
#include "pdumper.h"
|
|
#include "haiku_support.h"
|
|
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
|
|
static Lisp_Object font_cache;
|
|
|
|
#define METRICS_NCOLS_PER_ROW (128)
|
|
|
|
enum metrics_status
|
|
{
|
|
METRICS_INVALID = -1, /* metrics entry is invalid */
|
|
};
|
|
|
|
#define METRICS_STATUS(metrics) ((metrics)->ascent + (metrics)->descent)
|
|
#define METRICS_SET_STATUS(metrics, status) \
|
|
((metrics)->ascent = 0, (metrics)->descent = (status))
|
|
|
|
static struct
|
|
{
|
|
/* registry name */
|
|
const char *name;
|
|
/* characters to distinguish the charset from the others */
|
|
int uniquifier[6];
|
|
/* additional constraint by language */
|
|
const char *lang;
|
|
} em_charset_table[] =
|
|
{ { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
|
|
{ "iso8859-2", { 0x00A0, 0x010E }},
|
|
{ "iso8859-3", { 0x00A0, 0x0108 }},
|
|
{ "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
|
|
{ "iso8859-5", { 0x00A0, 0x0401 }},
|
|
{ "iso8859-6", { 0x00A0, 0x060C }},
|
|
{ "iso8859-7", { 0x00A0, 0x0384 }},
|
|
{ "iso8859-8", { 0x00A0, 0x05D0 }},
|
|
{ "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
|
|
{ "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
|
|
{ "iso8859-11", { 0x00A0, 0x0E01 }},
|
|
{ "iso8859-13", { 0x00A0, 0x201C }},
|
|
{ "iso8859-14", { 0x00A0, 0x0174 }},
|
|
{ "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
|
|
{ "iso8859-16", { 0x00A0, 0x0218}},
|
|
{ "gb2312.1980-0", { 0x4E13 }, "zh-cn"},
|
|
{ "big5-0", { 0x9C21 }, "zh-tw" },
|
|
{ "jisx0208.1983-0", { 0x4E55 }, "ja"},
|
|
{ "ksc5601.1985-0", { 0xAC00 }, "ko"},
|
|
{ "cns11643.1992-1", { 0xFE32 }, "zh-tw"},
|
|
{ "cns11643.1992-2", { 0x4E33, 0x7934 }},
|
|
{ "cns11643.1992-3", { 0x201A9 }},
|
|
{ "cns11643.1992-4", { 0x20057 }},
|
|
{ "cns11643.1992-5", { 0x20000 }},
|
|
{ "cns11643.1992-6", { 0x20003 }},
|
|
{ "cns11643.1992-7", { 0x20055 }},
|
|
{ "gbk-0", { 0x4E06 }, "zh-cn"},
|
|
{ "jisx0212.1990-0", { 0x4E44 }},
|
|
{ "jisx0213.2000-1", { 0xFA10 }, "ja"},
|
|
{ "jisx0213.2000-2", { 0xFA49 }},
|
|
{ "jisx0213.2004-1", { 0x20B9F }},
|
|
{ "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, "vi"},
|
|
{ "tis620.2529-1", { 0x0E01 }, "th"},
|
|
{ "microsoft-cp1251", { 0x0401, 0x0490 }, "ru"},
|
|
{ "koi8-r", { 0x0401, 0x2219 }, "ru"},
|
|
{ "mulelao-1", { 0x0E81 }, "lo"},
|
|
{ "unicode-sip", { 0x20000 }},
|
|
{ "mulearabic-0", { 0x628 }},
|
|
{ "mulearabic-1", { 0x628 }},
|
|
{ "mulearabic-2", { 0x628 }},
|
|
{ NULL }
|
|
};
|
|
|
|
static void
|
|
haikufont_apply_registry (struct haiku_font_pattern *pattern,
|
|
Lisp_Object registry)
|
|
{
|
|
char *str = SSDATA (SYMBOL_NAME (registry));
|
|
USE_SAFE_ALLOCA;
|
|
char *re = SAFE_ALLOCA (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
|
|
int i, j;
|
|
|
|
for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
|
|
{
|
|
if (str[i] == '.')
|
|
re[j++] = '\\';
|
|
else if (str[i] == '*')
|
|
re[j++] = '.';
|
|
re[j] = str[i];
|
|
if (re[j] == '?')
|
|
re[j] = '.';
|
|
}
|
|
re[j] = '\0';
|
|
AUTO_STRING_WITH_LEN (regexp, re, j);
|
|
for (i = 0; em_charset_table[i].name; i++)
|
|
if (fast_c_string_match_ignore_case
|
|
(regexp, em_charset_table[i].name,
|
|
strlen (em_charset_table[i].name)) >= 0)
|
|
break;
|
|
SAFE_FREE ();
|
|
if (!em_charset_table[i].name)
|
|
return;
|
|
int *uniquifier = em_charset_table[i].uniquifier;
|
|
int l;
|
|
|
|
for (l = 0; uniquifier[l]; ++l);
|
|
|
|
int *a = xmalloc (l * sizeof *a);
|
|
for (l = 0; uniquifier[l]; ++l)
|
|
a[l] = uniquifier[l];
|
|
|
|
if (pattern->specified & FSPEC_WANTED)
|
|
{
|
|
int old_l = l;
|
|
l += pattern->want_chars_len;
|
|
a = xrealloc (a, l * sizeof *a);
|
|
memcpy (&a[old_l], pattern->wanted_chars, (l - old_l) * sizeof *a);
|
|
xfree (pattern->wanted_chars);
|
|
}
|
|
|
|
pattern->specified |= FSPEC_WANTED;
|
|
pattern->want_chars_len = l;
|
|
pattern->wanted_chars = a;
|
|
|
|
if (em_charset_table[i].lang)
|
|
{
|
|
if (!strncmp (em_charset_table[i].lang, "zh", 2))
|
|
{
|
|
pattern->specified |= FSPEC_LANGUAGE;
|
|
pattern->language = LANGUAGE_CN;
|
|
}
|
|
else if (!strncmp (em_charset_table[i].lang, "ko", 2))
|
|
{
|
|
pattern->specified |= FSPEC_LANGUAGE;
|
|
pattern->language = LANGUAGE_KO;
|
|
}
|
|
else if (!strncmp (em_charset_table[i].lang, "ja", 2))
|
|
{
|
|
pattern->specified |= FSPEC_LANGUAGE;
|
|
pattern->language = LANGUAGE_JP;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
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 font_cache;
|
|
}
|
|
|
|
static Lisp_Object
|
|
haikufont_weight_to_lisp (int weight)
|
|
{
|
|
switch (weight)
|
|
{
|
|
case HAIKU_THIN:
|
|
return Qthin;
|
|
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_BOOK:
|
|
return Qbook;
|
|
case HAIKU_HEAVY:
|
|
return Qheavy;
|
|
case HAIKU_ULTRA_HEAVY:
|
|
return Qultra_heavy;
|
|
case HAIKU_BLACK:
|
|
return Qblack;
|
|
case HAIKU_MEDIUM:
|
|
return Qmedium;
|
|
}
|
|
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_EXTRALIGHT;
|
|
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) || EQ (weight, Qregular))
|
|
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_EXTRA_BOLD;
|
|
if (EQ (weight, Qbook))
|
|
return HAIKU_BOOK;
|
|
if (EQ (weight, Qheavy))
|
|
return HAIKU_HEAVY;
|
|
if (EQ (weight, Qultra_heavy))
|
|
return HAIKU_ULTRA_HEAVY;
|
|
if (EQ (weight, Qblack))
|
|
return HAIKU_BLACK;
|
|
if (EQ (weight, Qmedium))
|
|
return HAIKU_MEDIUM;
|
|
|
|
return HAIKU_REGULAR;
|
|
}
|
|
|
|
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) || EQ (slant, Qregular))
|
|
return SLANT_REGULAR;
|
|
|
|
return SLANT_REGULAR;
|
|
}
|
|
|
|
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) || EQ (lisp, Qregular))
|
|
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;
|
|
|
|
return NORMAL_WIDTH;
|
|
}
|
|
|
|
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, QSans_Serif))
|
|
{
|
|
BFont_populate_plain_family (ptn);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static Lisp_Object
|
|
haikufont_pattern_to_entity (struct haiku_font_pattern *ptn)
|
|
{
|
|
Lisp_Object entity, extras;
|
|
|
|
entity = font_make_entity ();
|
|
extras = Qnil;
|
|
|
|
ASET (entity, FONT_TYPE_INDEX, Qhaiku);
|
|
ASET (entity, FONT_FOUNDRY_INDEX, Qhaiku);
|
|
ASET (entity, FONT_FAMILY_INDEX, Qdefault);
|
|
ASET (entity, FONT_ADSTYLE_INDEX, Qnil);
|
|
ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
|
|
ASET (entity, FONT_SIZE_INDEX, make_fixnum (0));
|
|
ASET (entity, FONT_AVGWIDTH_INDEX, make_fixnum (0));
|
|
ASET (entity, FONT_SPACING_INDEX, make_fixnum (FONT_SPACING_MONO));
|
|
|
|
/* FONT_EXTRA_INDEX in a font entity can contain a cons of two
|
|
numbers (STYLE . IDX) under the key :indices that tell Emacs how
|
|
to open a font. */
|
|
if (ptn->specified & FSPEC_INDICES)
|
|
extras = Fcons (Fcons (QCindices,
|
|
Fcons (make_fixnum (ptn->family_index),
|
|
make_fixnum (ptn->style_index))),
|
|
extras);
|
|
|
|
if (ptn->specified & FSPEC_ANTIALIAS)
|
|
extras = Fcons (Fcons (QCantialias,
|
|
ptn->use_antialiasing ? Qt : Qnil),
|
|
extras);
|
|
|
|
ASET (entity, FONT_EXTRA_INDEX, extras);
|
|
|
|
FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, Qnormal);
|
|
FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX, Qnormal);
|
|
FONT_SET_STYLE (entity, FONT_SLANT_INDEX, Qnormal);
|
|
|
|
if (ptn->specified & FSPEC_FAMILY)
|
|
ASET (entity, FONT_FAMILY_INDEX, intern (ptn->family));
|
|
else
|
|
ASET (entity, FONT_FAMILY_INDEX, Qdefault);
|
|
|
|
if (ptn->specified & FSPEC_STYLE)
|
|
ASET (entity, FONT_ADSTYLE_INDEX, intern (ptn->style));
|
|
else
|
|
{
|
|
if (ptn->specified & FSPEC_WEIGHT)
|
|
FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
|
|
haikufont_weight_to_lisp (ptn->weight));
|
|
if (ptn->specified & FSPEC_SLANT)
|
|
FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
|
|
haikufont_slant_to_lisp (ptn->slant));
|
|
if (ptn->specified & FSPEC_WIDTH)
|
|
FONT_SET_STYLE (entity, FONT_WIDTH_INDEX,
|
|
haikufont_width_to_lisp (ptn->width));
|
|
}
|
|
|
|
if (ptn->specified & FSPEC_SPACING)
|
|
ASET (entity, FONT_SPACING_INDEX,
|
|
make_fixnum (ptn->mono_spacing_p
|
|
? FONT_SPACING_MONO
|
|
: FONT_SPACING_PROPORTIONAL));
|
|
|
|
return entity;
|
|
}
|
|
|
|
static void
|
|
haikufont_pattern_from_object (struct haiku_font_pattern *pattern,
|
|
Lisp_Object font_object)
|
|
{
|
|
Lisp_Object val;
|
|
|
|
pattern->specified = 0;
|
|
|
|
val = AREF (font_object, FONT_FAMILY_INDEX);
|
|
if (!NILP (val))
|
|
{
|
|
pattern->specified |= FSPEC_FAMILY;
|
|
strncpy ((char *) &pattern->family,
|
|
SSDATA (SYMBOL_NAME (val)),
|
|
sizeof pattern->family - 1);
|
|
pattern->family[sizeof pattern->family - 1] = '\0';
|
|
}
|
|
|
|
val = AREF (font_object, FONT_ADSTYLE_INDEX);
|
|
if (!NILP (val))
|
|
{
|
|
pattern->specified |= FSPEC_STYLE;
|
|
strncpy ((char *) &pattern->style,
|
|
SSDATA (SYMBOL_NAME (val)),
|
|
sizeof pattern->style - 1);
|
|
pattern->style[sizeof pattern->style - 1] = '\0';
|
|
}
|
|
|
|
val = FONT_WEIGHT_FOR_FACE (font_object);
|
|
if (!NILP (val) && !EQ (val, Qunspecified))
|
|
{
|
|
pattern->specified |= FSPEC_WEIGHT;
|
|
pattern->weight = haikufont_lisp_to_weight (val);
|
|
}
|
|
|
|
val = FONT_SLANT_FOR_FACE (font_object);
|
|
if (!NILP (val) && !EQ (val, Qunspecified))
|
|
{
|
|
pattern->specified |= FSPEC_SLANT;
|
|
pattern->slant = haikufont_lisp_to_slant (val);
|
|
}
|
|
|
|
val = FONT_WIDTH_FOR_FACE (font_object);
|
|
if (!NILP (val) && !EQ (val, Qunspecified))
|
|
{
|
|
pattern->specified |= FSPEC_WIDTH;
|
|
pattern->width = haikufont_lisp_to_width (val);
|
|
}
|
|
|
|
val = assq_no_quit (QCantialias,
|
|
AREF (font_object, FONT_EXTRA_INDEX));
|
|
if (CONSP (val))
|
|
{
|
|
pattern->specified |= FSPEC_ANTIALIAS;
|
|
pattern->use_antialiasing = !NILP (XCDR (val));
|
|
}
|
|
}
|
|
|
|
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);
|
|
ptn->style[sizeof ptn->style - 1] = '\0';
|
|
}
|
|
|
|
tem = FONT_SLANT_SYMBOLIC (ent);
|
|
if (!NILP (tem) && !EQ (tem, Qunspecified))
|
|
{
|
|
ptn->specified |= FSPEC_SLANT;
|
|
ptn->slant = haikufont_lisp_to_slant (tem);
|
|
}
|
|
|
|
tem = FONT_WEIGHT_SYMBOLIC (ent);
|
|
if (!NILP (tem) && !EQ (tem, Qunspecified))
|
|
{
|
|
ptn->specified |= FSPEC_WEIGHT;
|
|
ptn->weight = haikufont_lisp_to_weight (tem);
|
|
}
|
|
|
|
tem = FONT_WIDTH_SYMBOLIC (ent);
|
|
if (!NILP (tem) && !EQ (tem, Qunspecified))
|
|
{
|
|
ptn->specified |= FSPEC_WIDTH;
|
|
ptn->width = haikufont_lisp_to_width (tem);
|
|
}
|
|
|
|
tem = AREF (ent, FONT_SPACING_INDEX);
|
|
if (!NILP (tem) && !EQ (tem, Qunspecified))
|
|
{
|
|
ptn->specified |= FSPEC_SPACING;
|
|
ptn->mono_spacing_p = XFIXNUM (tem) != FONT_SPACING_PROPORTIONAL;
|
|
}
|
|
|
|
tem = AREF (ent, FONT_FAMILY_INDEX);
|
|
if (!NILP (tem) && !EQ (tem, Qunspecified)
|
|
&& (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);
|
|
ptn->family[sizeof ptn->family - 1] = '\0';
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
tem = assq_no_quit (QCantialias, AREF (ent, FONT_EXTRA_INDEX));
|
|
if (CONSP (tem))
|
|
{
|
|
ptn->specified |= FSPEC_ANTIALIAS;
|
|
ptn->use_antialiasing = !NILP (XCDR (tem));
|
|
}
|
|
|
|
tem = AREF (ent, FONT_REGISTRY_INDEX);
|
|
if (SYMBOLP (tem))
|
|
haikufont_apply_registry (ptn, tem);
|
|
}
|
|
|
|
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)
|
|
{
|
|
Lisp_Object lst, tem;
|
|
struct haiku_font_pattern ptn, *found, *pt;
|
|
|
|
lst = Qnil;
|
|
|
|
block_input ();
|
|
/* Returning irrelevant results on receiving an OTF form will cause
|
|
fontset.c to loop over and over, making displaying some
|
|
characters very slow. */
|
|
tem = assq_no_quit (QCotf, AREF (font_spec, FONT_EXTRA_INDEX));
|
|
|
|
if (CONSP (tem) && !NILP (XCDR (tem)))
|
|
{
|
|
unblock_input ();
|
|
return Qnil;
|
|
}
|
|
|
|
haikufont_spec_or_entity_to_pattern (font_spec, 1, &ptn);
|
|
found = BFont_find (&ptn);
|
|
haikufont_done_with_query_pattern (&ptn);
|
|
if (found)
|
|
{
|
|
for (pt = found; pt; pt = pt->next)
|
|
lst = Fcons (haikufont_pattern_to_entity (pt), lst);
|
|
haiku_font_pattern_free (found);
|
|
}
|
|
unblock_input ();
|
|
return lst;
|
|
}
|
|
|
|
static void
|
|
haiku_bulk_encode (struct haikufont_info *font_info, int block)
|
|
{
|
|
unsigned short *unichars = xmalloc (0x101 * sizeof (*unichars));
|
|
unsigned int i, idx;
|
|
|
|
block_input ();
|
|
|
|
font_info->glyphs[block] = unichars;
|
|
if (!unichars)
|
|
emacs_abort ();
|
|
|
|
for (idx = block << 8, i = 0; i < 0x100; idx++, i++)
|
|
unichars[i] = idx;
|
|
unichars[0x100] = 0;
|
|
|
|
|
|
/* If the font contains the entire block, just store it. */
|
|
if (!BFont_have_char_block (font_info->be_font,
|
|
unichars[0], unichars[0xff]))
|
|
{
|
|
for (int i = 0; i < 0x100; ++i)
|
|
if (!BFont_have_char_p (font_info->be_font, unichars[i]))
|
|
unichars[i] = 0xFFFF;
|
|
}
|
|
|
|
unblock_input ();
|
|
}
|
|
|
|
static unsigned int
|
|
haikufont_encode_char (struct font *font, int c)
|
|
{
|
|
struct haikufont_info *font_info = (struct haikufont_info *) font;
|
|
unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
|
|
unsigned short g;
|
|
|
|
if (c > 0xFFFF)
|
|
return FONT_INVALID_CODE;
|
|
|
|
if (!font_info->glyphs[high])
|
|
haiku_bulk_encode (font_info, high);
|
|
g = font_info->glyphs[high][low];
|
|
return g == 0xFFFF ? FONT_INVALID_CODE : g;
|
|
}
|
|
|
|
static Lisp_Object
|
|
haikufont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
|
|
{
|
|
struct haikufont_info *font_info;
|
|
struct haiku_font_pattern ptn;
|
|
struct font *font;
|
|
void *be_font;
|
|
Lisp_Object font_object, extra, indices, antialias;
|
|
int px_size, min_width, max_width;
|
|
int avg_width, height, space_width, ascent;
|
|
int descent, underline_pos, underline_thickness;
|
|
|
|
if (XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX)) != 0)
|
|
pixel_size = XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX));
|
|
else if (pixel_size == 0)
|
|
{
|
|
/* Try to resolve a suitable size for the font, if the font size
|
|
has not already been specified. First, if FRAME_FONT is set,
|
|
use its size. Otherwise, use 12, which is the default on
|
|
Haiku. */
|
|
|
|
if (FRAME_FONT (f))
|
|
pixel_size = FRAME_FONT (f)->pixel_size;
|
|
else
|
|
pixel_size = 12;
|
|
}
|
|
|
|
extra = AREF (font_entity, FONT_EXTRA_INDEX);
|
|
|
|
indices = assq_no_quit (QCindices, extra);
|
|
antialias = assq_no_quit (QCantialias, extra);
|
|
|
|
if (CONSP (indices))
|
|
indices = XCDR (indices);
|
|
|
|
/* If the font's indices is already available, open the font using
|
|
those instead. */
|
|
|
|
if (CONSP (indices) && FIXNUMP (XCAR (indices))
|
|
&& FIXNUMP (XCDR (indices)))
|
|
{
|
|
block_input ();
|
|
be_font = be_open_font_at_index (XFIXNUM (XCAR (indices)),
|
|
XFIXNUM (XCDR (indices)),
|
|
pixel_size);
|
|
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, pixel_size))
|
|
{
|
|
haikufont_done_with_query_pattern (&ptn);
|
|
unblock_input ();
|
|
return Qnil;
|
|
}
|
|
|
|
haikufont_done_with_query_pattern (&ptn);
|
|
unblock_input ();
|
|
}
|
|
|
|
block_input ();
|
|
|
|
font_object = font_make_object (VECSIZE (struct haikufont_info),
|
|
font_entity, pixel_size);
|
|
|
|
ASET (font_object, FONT_TYPE_INDEX, Qhaiku);
|
|
font_info = (struct haikufont_info *) XFONT_OBJECT (font_object);
|
|
font = (struct font *) font_info;
|
|
|
|
if (!font)
|
|
{
|
|
unblock_input ();
|
|
return Qnil;
|
|
}
|
|
|
|
font_info->be_font = be_font;
|
|
font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
|
|
|
|
if (CONSP (antialias))
|
|
be_set_font_antialiasing (be_font, !NILP (XCDR (antialias)));
|
|
|
|
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_info->metrics = NULL;
|
|
font_info->metrics_nrows = 0;
|
|
|
|
BFont_metrics (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, Qt);
|
|
|
|
unblock_input ();
|
|
return font_object;
|
|
}
|
|
|
|
static void
|
|
haikufont_close (struct font *font)
|
|
{
|
|
struct haikufont_info *info = (struct haikufont_info *) font;
|
|
int i;
|
|
|
|
if (font_data_structures_may_be_ill_formed ())
|
|
return;
|
|
|
|
block_input ();
|
|
if (info && info->be_font)
|
|
BFont_close (info->be_font);
|
|
|
|
for (i = 0; i < info->metrics_nrows; i++)
|
|
{
|
|
if (info->metrics[i])
|
|
xfree (info->metrics[i]);
|
|
}
|
|
|
|
if (info->metrics)
|
|
xfree (info->metrics);
|
|
|
|
for (i = 0; i < 0x100; ++i)
|
|
{
|
|
if (info->glyphs[i])
|
|
xfree (info->glyphs[i]);
|
|
}
|
|
|
|
xfree (info->glyphs);
|
|
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;
|
|
|
|
struct font_metrics *cache;
|
|
int row, col;
|
|
|
|
row = code / METRICS_NCOLS_PER_ROW;
|
|
col = code % METRICS_NCOLS_PER_ROW;
|
|
if (row >= info->metrics_nrows)
|
|
{
|
|
info->metrics =
|
|
xrealloc (info->metrics,
|
|
sizeof (struct font_metrics *) * (row + 1));
|
|
memset (info->metrics + info->metrics_nrows, 0,
|
|
(sizeof (struct font_metrics *)
|
|
* (row + 1 - info->metrics_nrows)));
|
|
info->metrics_nrows = row + 1;
|
|
}
|
|
|
|
if (info->metrics[row] == NULL)
|
|
{
|
|
struct font_metrics *new;
|
|
int i;
|
|
|
|
new = xmalloc (sizeof (struct font_metrics) * METRICS_NCOLS_PER_ROW);
|
|
for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
|
|
METRICS_SET_STATUS (new + i, METRICS_INVALID);
|
|
info->metrics[row] = new;
|
|
}
|
|
cache = info->metrics[row] + col;
|
|
|
|
if (METRICS_STATUS (cache) == METRICS_INVALID)
|
|
{
|
|
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);
|
|
|
|
cache->lbearing = lb;
|
|
cache->rbearing = rb;
|
|
cache->width = advance;
|
|
cache->ascent = font->ascent;
|
|
cache->descent = font->descent;
|
|
}
|
|
|
|
if (metrics)
|
|
*metrics = *cache;
|
|
}
|
|
|
|
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);
|
|
unsigned long foreground, background;
|
|
|
|
block_input ();
|
|
prepare_face_for_display (s->f, face);
|
|
|
|
if (s->hl != DRAW_CURSOR)
|
|
{
|
|
foreground = s->face->foreground;
|
|
background = s->face->background;
|
|
}
|
|
else
|
|
haiku_merge_cursor_foreground (s, &foreground, &background);
|
|
|
|
/* Presumably the draw lock is already held by
|
|
haiku_draw_glyph_string; */
|
|
if (with_background)
|
|
{
|
|
int height = FONT_HEIGHT (s->font), ascent = FONT_BASE (s->font);
|
|
|
|
/* Font's global height and ascent values might be
|
|
preposterously large for some fonts. We fix here the case
|
|
when those fonts are used for display of glyphless
|
|
characters, because drawing background with font dimensions
|
|
in those cases makes the display illegible. There's only one
|
|
more call to the draw method with with_background set to
|
|
true, and that's in x_draw_glyph_string_foreground, when
|
|
drawing the cursor, where we have no such heuristics
|
|
available. FIXME. */
|
|
if (s->first_glyph->type == GLYPHLESS_GLYPH
|
|
&& (s->first_glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE
|
|
|| s->first_glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM))
|
|
height = ascent =
|
|
s->first_glyph->slice.glyphless.lower_yoff
|
|
- s->first_glyph->slice.glyphless.upper_yoff;
|
|
|
|
haiku_draw_background_rect (s, s->face, x, y - ascent,
|
|
s->width, height);
|
|
}
|
|
|
|
BView_SetHighColor (view, 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 = alloca ((to - from + 1) * MAX_MULTIBYTE_LENGTH);
|
|
|
|
for (int idx = from; idx < to; ++idx)
|
|
{
|
|
int len = CHAR_STRING (s->char2b[idx], mb);
|
|
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);
|
|
}
|
|
|
|
unblock_input ();
|
|
return 1;
|
|
}
|
|
|
|
static Lisp_Object
|
|
haikufont_list_family (struct frame *f)
|
|
{
|
|
Lisp_Object list = Qnil;
|
|
size_t length;
|
|
ptrdiff_t idx;
|
|
haiku_font_family_or_style *styles;
|
|
|
|
block_input ();
|
|
styles = be_list_font_families (&length);
|
|
unblock_input ();
|
|
|
|
if (!styles)
|
|
return list;
|
|
|
|
block_input ();
|
|
for (idx = 0; idx < length; ++idx)
|
|
{
|
|
if (styles[idx][0])
|
|
list = Fcons (intern ((char *) &styles[idx]), list);
|
|
}
|
|
|
|
free (styles);
|
|
unblock_input ();
|
|
|
|
return list;
|
|
}
|
|
|
|
/* List of boolean properties in font names accepted by this font
|
|
driver. */
|
|
static const char *const haikufont_booleans[] =
|
|
{
|
|
":antialias",
|
|
NULL,
|
|
};
|
|
|
|
/* List of non-boolean properties. Currently empty. */
|
|
static const char *const haikufont_non_booleans[1];
|
|
|
|
static void
|
|
haikufont_filter_properties (Lisp_Object font, Lisp_Object alist)
|
|
{
|
|
font_filter_properties (font, alist, haikufont_booleans,
|
|
haikufont_non_booleans);
|
|
}
|
|
|
|
struct font_driver const haikufont_driver =
|
|
{
|
|
.type = LISPSYM_INITIALLY (Qhaiku),
|
|
.case_sensitive = true,
|
|
.get_cache = haikufont_get_cache,
|
|
.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,
|
|
.list_family = haikufont_list_family,
|
|
.filter_properties = haikufont_filter_properties,
|
|
};
|
|
|
|
static bool
|
|
haikufont_should_quit_popup (void)
|
|
{
|
|
return !NILP (Vquit_flag);
|
|
}
|
|
|
|
DEFUN ("x-select-font", Fx_select_font, Sx_select_font, 0, 2, 0,
|
|
doc: /* Read a font using a native dialog.
|
|
Return a font spec describing the font chosen by the user.
|
|
|
|
FRAME is the frame on which to pop up the font chooser. If omitted or
|
|
nil, it defaults to the selected frame.
|
|
If EXCLUDE-PROPORTIONAL is non-nil, exclude proportional fonts
|
|
in the font selection dialog. */)
|
|
(Lisp_Object frame, Lisp_Object exclude_proportional)
|
|
{
|
|
struct frame *f;
|
|
struct font *font;
|
|
Lisp_Object font_object;
|
|
haiku_font_family_or_style family, style;
|
|
int rc, size, initial_family, initial_style, initial_size;
|
|
struct haiku_font_pattern pattern;
|
|
Lisp_Object lfamily, lweight, lslant, lwidth, ladstyle, lsize;
|
|
bool disable_antialiasing, initial_antialias;
|
|
|
|
f = decode_window_system_frame (frame);
|
|
|
|
if (popup_activated_p)
|
|
error ("Trying to use a menu from within a menu-entry");
|
|
|
|
initial_style = -1;
|
|
initial_family = -1;
|
|
initial_size = -1;
|
|
initial_antialias = true;
|
|
|
|
font = FRAME_FONT (f);
|
|
|
|
if (font)
|
|
{
|
|
XSETFONT (font_object, font);
|
|
|
|
haikufont_pattern_from_object (&pattern, font_object);
|
|
be_find_font_indices (&pattern, &initial_family,
|
|
&initial_style);
|
|
haikufont_done_with_query_pattern (&pattern);
|
|
|
|
initial_size = font->pixel_size;
|
|
|
|
/* This field is safe to access even after
|
|
haikufont_done_with_query_pattern. */
|
|
if (pattern.specified & FSPEC_ANTIALIAS)
|
|
initial_antialias = pattern.use_antialiasing;
|
|
}
|
|
|
|
popup_activated_p++;
|
|
unrequest_sigio ();
|
|
rc = be_select_font (process_pending_signals,
|
|
haikufont_should_quit_popup,
|
|
&family, &style, &size,
|
|
!NILP (exclude_proportional),
|
|
initial_family, initial_style,
|
|
initial_size, initial_antialias,
|
|
&disable_antialiasing);
|
|
request_sigio ();
|
|
popup_activated_p--;
|
|
|
|
if (!rc)
|
|
quit ();
|
|
|
|
be_font_style_to_flags (style, &pattern);
|
|
|
|
lfamily = build_string_from_utf8 (family);
|
|
lweight = (pattern.specified & FSPEC_WEIGHT
|
|
? haikufont_weight_to_lisp (pattern.weight) : Qnil);
|
|
lslant = (pattern.specified & FSPEC_SLANT
|
|
? haikufont_slant_to_lisp (pattern.slant) : Qnil);
|
|
lwidth = (pattern.specified & FSPEC_WIDTH
|
|
? haikufont_width_to_lisp (pattern.width) : Qnil);
|
|
ladstyle = (pattern.specified & FSPEC_STYLE
|
|
? intern (pattern.style) : Qnil);
|
|
lsize = (size >= 0 ? make_fixnum (size) : Qnil);
|
|
|
|
if (disable_antialiasing)
|
|
return CALLN (Ffont_spec, QCfamily, lfamily,
|
|
QCweight, lweight, QCslant, lslant,
|
|
QCwidth, lwidth, QCadstyle, ladstyle,
|
|
QCsize, lsize, QCantialias, Qnil);
|
|
|
|
return CALLN (Ffont_spec, QCfamily, lfamily,
|
|
QCweight, lweight, QCslant, lslant,
|
|
QCwidth, lwidth, QCadstyle, ladstyle,
|
|
QCsize, lsize);
|
|
}
|
|
|
|
DEFUN ("font-get-system-normal-font", Ffont_get_system_normal_font,
|
|
Sfont_get_system_normal_font, 0, 0, 0,
|
|
doc: /* SKIP: real doc in xsettings.c. */)
|
|
(void)
|
|
{
|
|
Lisp_Object value;
|
|
const char *name, *style;
|
|
struct haiku_font_pattern pattern;
|
|
Lisp_Object lfamily, lweight, lslant, lwidth, ladstyle;
|
|
int size;
|
|
|
|
if (!be_lock_font_defaults ())
|
|
return Qnil;
|
|
|
|
name = be_get_font_default (DEFAULT_FAMILY);
|
|
style = be_get_font_default (DEFAULT_STYLE);
|
|
size = be_get_font_size (DEFAULT_FAMILY);
|
|
|
|
be_font_style_to_flags (style, &pattern);
|
|
|
|
lfamily = build_string_from_utf8 (name);
|
|
lweight = (pattern.specified & FSPEC_WEIGHT
|
|
? haikufont_weight_to_lisp (pattern.weight) : Qnil);
|
|
lslant = (pattern.specified & FSPEC_SLANT
|
|
? haikufont_slant_to_lisp (pattern.slant) : Qnil);
|
|
lwidth = (pattern.specified & FSPEC_WIDTH
|
|
? haikufont_width_to_lisp (pattern.width) : Qnil);
|
|
ladstyle = (pattern.specified & FSPEC_STYLE
|
|
? intern (pattern.style) : Qnil);
|
|
|
|
value = CALLN (Ffont_spec, QCfamily, lfamily,
|
|
QCweight, lweight, QCslant, lslant,
|
|
QCwidth, lwidth, QCadstyle, ladstyle,
|
|
QCsize, make_fixnum (size));
|
|
be_unlock_font_defaults ();
|
|
|
|
return value;
|
|
}
|
|
|
|
DEFUN ("font-get-system-font", Ffont_get_system_font,
|
|
Sfont_get_system_font, 0, 0, 0,
|
|
doc: /* SKIP: real doc in xsettings.c. */)
|
|
(void)
|
|
{
|
|
Lisp_Object value;
|
|
const char *name, *style;
|
|
struct haiku_font_pattern pattern;
|
|
Lisp_Object lfamily, lweight, lslant, lwidth, ladstyle;
|
|
int size;
|
|
|
|
if (!be_lock_font_defaults ())
|
|
return Qnil;
|
|
|
|
name = be_get_font_default (FIXED_FAMILY);
|
|
style = be_get_font_default (FIXED_STYLE);
|
|
size = be_get_font_size (FIXED_FAMILY);
|
|
|
|
be_font_style_to_flags (style, &pattern);
|
|
|
|
lfamily = build_string_from_utf8 (name);
|
|
lweight = (pattern.specified & FSPEC_WEIGHT
|
|
? haikufont_weight_to_lisp (pattern.weight) : Qnil);
|
|
lslant = (pattern.specified & FSPEC_SLANT
|
|
? haikufont_slant_to_lisp (pattern.slant) : Qnil);
|
|
lwidth = (pattern.specified & FSPEC_WIDTH
|
|
? haikufont_width_to_lisp (pattern.width) : Qnil);
|
|
ladstyle = (pattern.specified & FSPEC_STYLE
|
|
? intern (pattern.style) : Qnil);
|
|
|
|
value = CALLN (Ffont_spec, QCfamily, lfamily,
|
|
QCweight, lweight, QCslant, lslant,
|
|
QCwidth, lwidth, QCadstyle, ladstyle,
|
|
QCsize, make_fixnum (size));
|
|
be_unlock_font_defaults ();
|
|
|
|
return value;
|
|
}
|
|
|
|
void
|
|
haiku_handle_font_change_event (struct haiku_font_change_event *event,
|
|
struct input_event *ie)
|
|
{
|
|
ie->kind = CONFIG_CHANGED_EVENT;
|
|
|
|
/* This is the name of the display. */
|
|
ie->frame_or_window = XCAR (x_display_list->name_list_element);
|
|
|
|
/* And this is the font that changed. */
|
|
ie->arg = (event->what == FIXED_FAMILY
|
|
? Qmonospace_font_name : Qfont_name);
|
|
}
|
|
|
|
static void
|
|
syms_of_haikufont_for_pdumper (void)
|
|
{
|
|
register_font_driver (&haikufont_driver, NULL);
|
|
}
|
|
|
|
void
|
|
syms_of_haikufont (void)
|
|
{
|
|
DEFSYM (QSans_Serif, "Sans Serif");
|
|
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 (Qregular, "regular");
|
|
DEFSYM (Qzh, "zh");
|
|
DEFSYM (Qko, "ko");
|
|
DEFSYM (Qjp, "jp");
|
|
|
|
DEFSYM (QCindices, ":indices");
|
|
|
|
DEFSYM (Qmonospace_font_name, "monospace-font-name");
|
|
DEFSYM (Qfont_name, "font-name");
|
|
DEFSYM (Qdynamic_setting, "dynamic-setting");
|
|
|
|
DEFVAR_BOOL ("font-use-system-font", use_system_font,
|
|
doc: /* SKIP: real doc in xsettings.c. */);
|
|
use_system_font = false;
|
|
|
|
#ifdef USE_BE_CAIRO
|
|
Fput (Qhaiku, Qfont_driver_superseded_by, Qftcr);
|
|
#endif
|
|
pdumper_do_now_and_after_load (syms_of_haikufont_for_pdumper);
|
|
|
|
font_cache = list (Qnil);
|
|
staticpro (&font_cache);
|
|
|
|
defsubr (&Sx_select_font);
|
|
defsubr (&Sfont_get_system_normal_font);
|
|
defsubr (&Sfont_get_system_font);
|
|
|
|
be_init_font_data ();
|
|
|
|
/* This tells loadup to load dynamic-setting.el, which handles
|
|
config-changed events. */
|
|
Fprovide (Qdynamic_setting, Qnil);
|
|
}
|