You should have received a copy of the GNU Lesser General Public
License along with the m17n library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
02111-1307, USA. */
/***en
FACE. */
static MRealizedFace *
-find_realized_face (MFrame *frame, MFace *face)
+find_realized_face (MFrame *frame, MFace *face, MFont *font)
{
MPlist *plist;
{
MRealizedFace *rface = MPLIST_VAL (plist);
- if (memcmp (rface->face.property, face->property, sizeof face->property)
- == 0)
+ if (memcmp (rface->face.property, face->property,
+ sizeof face->property) == 0
+ && (rface->font
+ ? (font && ! memcmp (rface->font, font, sizeof (MFont)))
+ : ! font))
return rface;
}
return NULL;
MSymbol *key;
MSymbol *type;
MPlist *(*func) (MPlist *plist, void *val);
- } serializer[MFACE_PROPERTY_MAX]
+ } serializer[MFACE_RATIO + 1]
= { { &Mfoundry, &Msymbol },
{ &Mfamily, &Msymbol },
{ &Mweight, &Msymbol },
{ &Mhline, NULL },
{ &Mbox, NULL },
{ &Mvideomode, &Msymbol },
- { NULL, NULL}, /* MFACE_HOOK_FUNC */
- { NULL, NULL}, /* MFACE_HOOK_ARG */
{ &Mratio, &Minteger } };
- for (i = 0; i < MFACE_PROPERTY_MAX; i++)
+ for (i = 0; i <= MFACE_RATIO; i++)
if (face->property[i] && serializer[i].key)
{
pl = mplist_add (pl, Msymbol, *serializer[i].key);
plist = MPLIST_NEXT (plist);
if (MPLIST_TAIL_P (plist))
break;
- if (index < 0 || index >= MFACE_PROPERTY_MAX)
+ if (index < 0 || index > MFACE_RATIO)
continue;
if (key == Mfoundry || key == Mfamily || key == Mweight || key == Mstyle
|| key == Mstretch || key == Madstyle
MFaceHLineProp *hline;
MFaceBoxProp *box;
- face_table.count = 0;
+ M17N_OBJECT_ADD_ARRAY (face_table, "Face");
Mface = msymbol_as_managing_key ("face");
- msymbol_put (Mface, Mtext_prop_serializer, (void *) serialize_face);
- msymbol_put (Mface, Mtext_prop_deserializer, (void *) deserialize_face);
+ msymbol_put_func (Mface, Mtext_prop_serializer,
+ M17N_FUNC (serialize_face));
+ msymbol_put_func (Mface, Mtext_prop_deserializer,
+ M17N_FUNC (deserialize_face));
Mforeground = msymbol ("foreground");
Mbackground = msymbol ("background");
MSymbol *key;
/* Index (enum face_property) of the face property. */
int index;
- } mface_prop_data[MFACE_PROPERTY_MAX] =
+ } mface_prop_data[MFACE_HOOK_ARG + 1] =
{ { &Mfoundry, MFACE_FOUNDRY },
{ &Mfamily, MFACE_FAMILY },
{ &Mweight, MFACE_WEIGHT },
{ &Mhline, MFACE_HLINE },
{ &Mbox, MFACE_BOX },
{ &Mvideomode, MFACE_VIDEOMODE },
- { &Mhook_func, MFACE_HOOK_FUNC },
- { &Mhook_arg, MFACE_HOOK_ARG },
{ &Mratio, MFACE_RATIO },
- };
+ { &Mhook_arg, MFACE_HOOK_ARG } };
for (i = 0; i < MFACE_PROPERTY_MAX; i++)
/* We add one to distinguish it from no-property. */
mface__default->property[MFACE_HLINE] = hline;
mface__default->property[MFACE_BOX] = box;
mface__default->property[MFACE_VIDEOMODE] = Mnormal;
- mface__default->property[MFACE_HOOK_FUNC] = (void *) noop_hook;
+ mface__default->hook = noop_hook;
mface_normal_video = mface ();
mface_normal_video->property[MFACE_VIDEOMODE] = (void *) Mnormal;
M17N_OBJECT_UNREF (box_prop_list);
free (work_gstring.glyphs);
-
- mdebug__report_object ("Face", &face_table);
}
-/** Return a realized face for ASCII characters from NUM number of
- base faces pointed by FACES on the frame FRAME. */
+/** Return a face realized from NUM number of base faces pointed by
+ FACES on the frame FRAME. If SIZE is nonzero, it specifies the
+ maximum font size. */
MRealizedFace *
-mface__realize (MFrame *frame, MFace **faces, int num, int size)
+mface__realize (MFrame *frame, MFace **faces, int num, int size, MFont *font)
{
MRealizedFace *rface;
MRealizedFont *rfont;
MFace merged_face = *(frame->face);
- void **props;
int i, j;
- MGlyph g;
MFaceHookFunc func;
+ MFont spec;
- if (num == 0 && frame->rface)
+ if (num == 0 && frame->rface && ! font)
return frame->rface;
+ if (! mplist_find_by_value (frame->face->frame_list, frame))
+ mplist_push (frame->face->frame_list, Mt, frame);
+ for (i = 0; i < num; i++)
+ if (! mplist_find_by_value (faces[i]->frame_list, frame))
+ mplist_push (faces[i]->frame_list, Mt, frame);
+
for (i = 0; i < MFACE_PROPERTY_MAX; i++)
for (j = num - 1; j >= 0; j--)
if (faces[j]->property[i])
break;
}
- if (! mplist_find_by_value (frame->face->frame_list, frame))
- mplist_push (frame->face->frame_list, Mt, frame);
- for (i = 0; i < num; i++)
- if (! mplist_find_by_value (faces[i]->frame_list, frame))
- mplist_push (faces[i]->frame_list, Mt, frame);
+ if (font)
+ {
+ if (font->type != MFONT_TYPE_REALIZED)
+ font = mfont_copy (font);
+ for (i = 0; i <= MFACE_ADSTYLE; i++)
+ if (font->property[i])
+ merged_face.property[i] = FONT_PROPERTY (font, i);
+ if (font->size)
+ {
+ int font_size;
- if (merged_face.property[MFACE_RATIO])
+ if (font->size < 0)
+ font->size = ((double) (- font->size)) * frame->dpi / 72.27 + 0.5;
+ font_size = font->size;
+ merged_face.property[MFACE_SIZE] = (void *) font_size;
+ merged_face.property[MFACE_RATIO] = (void *) 0;
+ }
+ }
+
+ if (! font || ! font->size)
{
- int font_size = (int) merged_face.property[MFACE_SIZE];
+ double font_size = (int) merged_face.property[MFACE_SIZE];
+ int ifont_size;
- font_size *= (int) merged_face.property[MFACE_RATIO];
- font_size /= 100;
- merged_face.property[MFACE_SIZE] = (void *) font_size;
- merged_face.property[MFACE_RATIO] = 0;
+ if (font_size < 0)
+ font_size = - font_size * frame->dpi / 72.27;
+ if (merged_face.property[MFACE_RATIO]
+ && (int) merged_face.property[MFACE_RATIO] != 100)
+ {
+ font_size *= (int) merged_face.property[MFACE_RATIO];
+ font_size /= 100;
+ }
+ ifont_size = font_size + 0.5;
+ merged_face.property[MFACE_SIZE] = (void *) ifont_size;
+ merged_face.property[MFACE_RATIO] = (void *) 0;
}
- rface = find_realized_face (frame, &merged_face);
+ merged_face.property[MFACE_FOUNDRY] = Mnil;
+ rface = find_realized_face (frame, &merged_face, font);
if (rface)
- return rface;
+ {
+ if (font && font->type != MFONT_TYPE_REALIZED)
+ free (font);
+ return rface;
+ }
MSTRUCT_CALLOC (rface, MERROR_FACE);
mplist_push (frame->realized_face_list, Mt, rface);
rface->frame = frame;
rface->face = merged_face;
- props = rface->face.property;
- rface->rfontset = mfont__realize_fontset (frame,
- (MFontset *) props[MFACE_FONTSET],
- &merged_face);
- g.type = GLYPH_SPACE;
- g.c = ' ';
- num = 1;
- rfont = mfont__lookup_fontset (rface->rfontset, &g, &num,
- Mlatin, Mnil, Mnil, size);
+ rface->font = font;
+
+ if (font)
+ {
+ if (font->type == MFONT_TYPE_SPEC)
+ rfont = (MRealizedFont *) mfont_find (frame, font, NULL, 0);
+ else if (font->type == MFONT_TYPE_OBJECT)
+ {
+ MFONT_INIT (&spec);
+ spec.size = (int) merged_face.property[MFONT_SIZE];
+ if (font->property[MFONT_REGISTRY])
+ spec.property[MFONT_REGISTRY] = font->property[MFONT_REGISTRY];
+ else
+ mfont_put_prop (&spec, Mregistry,
+ (font->source == MFONT_SOURCE_X
+ ? Miso8859_1 : Municode_bmp));
+ rfont = mfont__open (frame, font, &spec);
+ }
+ else
+ rfont = (MRealizedFont *) font;
+ }
+ else
+ {
+ MFontset *fontset = (MFontset *) merged_face.property[MFACE_FONTSET];
+
+ rface->rfontset = mfont__realize_fontset (frame, fontset, &merged_face,
+ font);
+ rfont = NULL;
+ mfont__set_spec_from_face (&spec, &merged_face);
+ mfont_put_prop (&spec, Mregistry, Miso8859_1);
+ spec.source = MFONT_SOURCE_X;
+ font = mfont__select (frame, &spec, 0);
+ if (font)
+ rfont = mfont__open (frame, font, &spec);
+ if (! rfont)
+ {
+ mfont_put_prop (&spec, Mregistry, Municode_bmp);
+ spec.source = MFONT_SOURCE_FT;
+ font = mfont__select (frame, &spec, 0);
+ if (font)
+ rfont = mfont__open (frame, font, &spec);
+ }
+ if (! rfont)
+ {
+ num = 0;
+ rfont = mfont__lookup_fontset (rface->rfontset, NULL, &num,
+ Mlatin, Mnil, Mnil, size, 0);
+ }
+ }
+
if (rfont)
{
rface->rfont = rfont;
- g.otf_encoded = 0;
- work_gstring.frame = frame;
- work_gstring.glyphs[0] = g;
+ rface->layouter = rfont->layouter;
+ rfont->layouter = Mnil;
work_gstring.glyphs[0].rface = rface;
- work_gstring.glyphs[1].code = MCHAR_INVALID_CODE;
- work_gstring.glyphs[1].rface = rface;
- mfont__get_metric (&work_gstring, 0, 2);
- rface->space_width = work_gstring.glyphs[0].width;
- rface->ascent = work_gstring.glyphs[1].ascent;
- rface->descent = work_gstring.glyphs[1].descent;
+ work_gstring.glyphs[0].code = MCHAR_INVALID_CODE;
+ mfont__get_metric (&work_gstring, 0, 1);
+ rface->ascent = work_gstring.glyphs[0].ascent;
+ rface->descent = work_gstring.glyphs[0].descent;
+ work_gstring.glyphs[0].code
+ = mfont__encode_char (frame, (MFont *) rfont, NULL, ' ');
+ if (work_gstring.glyphs[0].code != MCHAR_INVALID_CODE)
+ {
+ mfont__get_metric (&work_gstring, 0, 1);
+ rface->space_width = work_gstring.glyphs[0].width;
+ }
+ else
+ rface->space_width = rfont->spec.size / 10;
+ if (rfont->average_width)
+ rface->average_width = rfont->average_width;
+ else
+ {
+ work_gstring.glyphs[0].code
+ = mfont__encode_char (frame, (MFont *) rfont, NULL, 'x');
+ if (work_gstring.glyphs[0].code != MCHAR_INVALID_CODE)
+ {
+ mfont__get_metric (&work_gstring, 0, 1);
+ rface->average_width = work_gstring.glyphs[0].width;
+ }
+ else
+ rface->average_width = rface->space_width;
+ }
}
else
{
rface->space_width = frame->space_width;
}
- rface->hline = (MFaceHLineProp *) props[MFACE_HLINE];
+ rface->hline = (MFaceHLineProp *) merged_face.property[MFACE_HLINE];
if (rface->hline && rface->hline->width == 0)
rface->hline = NULL;
- rface->box = (MFaceBoxProp *) props[MFACE_BOX];
+ rface->box = (MFaceBoxProp *) merged_face.property[MFACE_BOX];
if (rface->box && rface->box->width == 0)
rface->box = NULL;
rface->ascii_rface = rface;
(*frame->driver->realize_face) (rface);
- func = (MFaceHookFunc) rface->face.property[MFACE_HOOK_FUNC];
+ func = rface->face.hook;
if (func && func != noop_hook)
(func) (&(rface->face), rface->info, rface->face.property[MFACE_HOOK_ARG]);
mface__for_chars (MSymbol script, MSymbol language, MSymbol charset,
MGlyph *from_g, MGlyph *to_g, int size)
{
- MRealizedFont *rfont;
+ MRealizedFont *rfont = from_g->rface->rfont;
+ MSymbol layouter;
int num = to_g - from_g;
+ int i;
+
+ if (from_g->rface->font)
+ {
+ MRealizedFace *rface = from_g->rface, *new;
+
+ if (! rfont)
+ rfont = mfontset__get_font (rface->frame,
+ rface->face.property[MFACE_FONTSET],
+ script, language,
+ rface->font, NULL);
+ else if (script != Mlatin)
+ rfont = mfontset__get_font (rface->frame,
+ rface->face.property[MFACE_FONTSET],
+ script, language,
+ (MFont *) rfont, NULL);
+ if (! rfont)
+ {
+ for (; from_g < to_g && from_g->rface->font; from_g++)
+ from_g->code = MCHAR_INVALID_CODE;
+ }
+ else
+ {
+ if (rface->rfont == rfont && rfont->layouter == Mnil)
+ new = rface;
+ else
+ {
+ MSTRUCT_MALLOC (new, MERROR_FACE);
+ mplist_push (rface->non_ascii_list, Mt, new);
+ *new = *rface;
+ new->rfont = rfont;
+ new->layouter = rfont->layouter;
+ rfont->layouter = Mnil;
+ new->non_ascii_list = NULL;
+ new->ascent = rfont->ascent;
+ new->descent = rfont->descent;
+ }
+ for (; from_g < to_g && from_g->rface->font; from_g++)
+ {
+ from_g->rface = new;
+ if (new->layouter)
+ {
+ from_g->code = mfont__flt_encode_char (new->layouter,
+ from_g->c);
+ if (from_g->code == MCHAR_INVALID_CODE)
+ {
+ from_g->rface = rface;
+ from_g->code = mfont__encode_char (rfont->frame,
+ (MFont *) rfont,
+ NULL, from_g->c);
+ }
+ }
+ else
+ from_g->code = mfont__encode_char (rfont->frame,
+ (MFont *) rfont,
+ NULL, from_g->c);
+ }
+ }
+ return from_g;
+ }
+
+ if (rfont && script == Mlatin)
+ {
+ for (i = 0; i < num; i++)
+ {
+ unsigned code = mfont__encode_char (rfont->frame, (MFont *) rfont,
+ NULL, from_g[i].c);
+ if (code == MCHAR_INVALID_CODE)
+ break;
+ from_g[i].code = code;
+ }
+ if (i == num || from_g[i].rface->font)
+ return from_g + i;
+ }
rfont = mfont__lookup_fontset (from_g->rface->rfontset, from_g, &num,
- script, language, charset, size);
- if (! rfont)
- num = 1;
+ script, language, charset, size, 0);
+ if (rfont)
+ {
+ layouter = rfont->layouter;
+ rfont->layouter = Mnil;
+ }
+ else
+ {
+ from_g->code = MCHAR_INVALID_CODE;
+ num = 1;
+ rfont = NULL;
+ layouter = Mnil;
+ }
to_g = from_g + num;
while (from_g < to_g)
MRealizedFace *rface = from_g++->rface;
while (from_g < to_g && rface == from_g->rface) from_g++;
- if (rface->rfont != rfont)
+ if (rface->rfont != rfont
+ || rface->layouter != layouter)
{
MPlist *plist = mplist_find_by_value (rface->non_ascii_list, rfont);
- MRealizedFace *new;
+ MRealizedFace *new = NULL;
- if (plist)
- new = MPLIST_VAL (plist);
- else
+ while (plist)
+ {
+ new = MPLIST_VAL (plist);
+ if (new->layouter == layouter)
+ break;
+ plist = mplist_find_by_value (MPLIST_NEXT (plist), rfont);
+ }
+ if (! plist)
{
MSTRUCT_MALLOC (new, MERROR_FACE);
mplist_push (rface->non_ascii_list, Mt, new);
*new = *rface;
new->rfont = rfont;
+ new->layouter = layouter;
new->non_ascii_list = NULL;
if (rfont)
{
MPLIST_DO (plist, rface->non_ascii_list)
free (MPLIST_VAL (plist));
M17N_OBJECT_UNREF (rface->non_ascii_list);
+ if (rface->font && rface->font->type != MFONT_TYPE_REALIZED)
+ free (rface->font);
free (rface);
}
mface__update_frame_face (MFrame *frame)
{
frame->rface = NULL;
- frame->rface = mface__realize (frame, NULL, 0, 0);
+ frame->rface = mface__realize (frame, NULL, 0, 0, NULL);
frame->space_width = frame->rface->space_width;
+ frame->average_width = frame->rface->average_width;
frame->ascent = frame->rface->ascent;
frame->descent = frame->rface->descent;
}
/*=*/
/***en
+ @brief Compare faces.
+
+ The mface_equal () function compares faces $FACE1 and $FACE2.
+
+ @return If two faces have the same property values, return 1.
+ Otherwise return 0. */
+
+int
+mface_equal (MFace *face1, MFace *face2)
+{
+ MFaceHLineProp *hline1, *hline2;
+ MFaceBoxProp *box1, *box2;
+ int i;
+
+ if (face1 == face2)
+ return 1;
+ if (memcmp (face1->property, face2->property, sizeof face1->property) == 0)
+ return 1;
+ for (i = MFACE_FOUNDRY; i <= MFACE_BACKGROUND; i++)
+ if (face1->property[i] != face2->property[i])
+ return 0;
+ for (i = MFACE_VIDEOMODE; i <= MFACE_RATIO; i++)
+ if (face1->property[i] != face2->property[i])
+ return 0;
+ hline1 = (MFaceHLineProp *) face1->property[MFACE_HLINE];
+ hline2 = (MFaceHLineProp *) face2->property[MFACE_HLINE];
+ if (hline1 != hline2)
+ {
+ if (! hline1 || ! hline2)
+ return 0;
+ if (memcmp (hline1, hline2, sizeof (MFaceHLineProp)) != 0)
+ return 0;
+ }
+ box1 = (MFaceBoxProp *) face1->property[MFACE_BOX];
+ box2 = (MFaceBoxProp *) face2->property[MFACE_BOX];
+ if (box1 != box2)
+ {
+ if (! box1 || ! box2)
+ return 0;
+ if (memcmp (box1, box2, sizeof (MFaceBoxProp)) != 0)
+ return 0;
+ }
+ return 1;
+}
+
+
+/*=*/
+/***en
@brief Merge faces.
The mface_merge () functions merges the properties of face $SRC
#Mforeground, #Mbackground, #Mvideomode, #Mhline, #Mbox,
#Mfoundry, #Mfamily, #Mweight, #Mstyle, #Mstretch, #Madstyle,
- #Msize, #Mfontset, #Mratio, #Mhook_func, #Mhook_arg
+ #Msize, #Mfontset, #Mratio, #Mhook_arg
@return
Ìá¤êÃͤη¿¤Ï $KEY ¤Ë°Í¸¤¹¤ë¡£¾åµ¤Î¥¡¼¤ÎÀâÌÀ¤ò»²¾È¤¹¤ë¤³¤È¡£
/***
@seealso
- mface_put_prop ()
+ mface_put_prop (), mface_put_hook ()
@errors
@c MERROR_FACE */
int index = (int) msymbol_get (key, M_face_prop_index) - 1;
if (index < 0)
- MERROR (MERROR_FACE, NULL);
+ {
+ if (key == Mhook_func)
+ /* This unsafe code is for backward compatiblity. */
+ return *(void **) &face->hook;
+ MERROR (MERROR_FACE, NULL);
+ }
return face->property[index];
}
/*=*/
/***en
+ @brief Get the hook function of a face.
+
+ The mface_get_hook () function returns the hook function of face
+ $FACE. */
+
+/***ja
+ @brief ¥Õ¥§¡¼¥¹¤Î¥Õ¥Ã¥¯´Ø¿ô¤òÆÀ¤ë.
+
+ ´Ø¿ô mface_get_hook () ¤Ï¥Õ¥§¡¼¥¹ $FACE ¤Î¥Õ¥Ã¥¯´Ø¿ô¤òÊÖ¤¹¡£ */
+
+MFaceHookFunc
+mface_get_hook (MFace *face)
+{
+ return face->hook;
+}
+
+/*=*/
+
+/***en
@brief Set a value of a face property.
The mface_put_prop () function assigns $VAL to the property whose
int index = (int) msymbol_get (key, M_face_prop_index) - 1;
MPlist *plist;
- if (index < 0)
- MERROR (MERROR_FACE, -1);
- if (key == Mfontset)
+ if (key == Mhook_func)
{
- if (face->property[index])
- M17N_OBJECT_UNREF (face->property[index]);
- M17N_OBJECT_REF (val);
+ /* This unsafe code is for backward compatiblity. */
+ if (*(void **) &face->hook == val)
+ return 0;
+ *(void **) &face->hook = val;
}
- else if (key == Mhline)
- val = get_hline_create (val);
- else if (key == Mbox)
- val = get_box_create (val);
+ else
+ {
+ if (index < 0)
+ MERROR (MERROR_FACE, -1);
+ if (key == Mfontset)
+ {
+ if (face->property[index])
+ M17N_OBJECT_UNREF (face->property[index]);
+ M17N_OBJECT_REF (val);
+ }
+ else if (key == Mhline)
+ val = get_hline_create (val);
+ else if (key == Mbox)
+ val = get_box_create (val);
- if (face->property[index] == val)
- return 0;
- face->property[index] = val;
+ if (face->property[index] == val)
+ return 0;
+ face->property[index] = val;
+ }
MPLIST_DO (plist, face->frame_list)
{
/*=*/
/***en
+ @brief Set a hook function to a face.
+
+ The mface_set_hook () function sets the hook function of face
+ $FACE to $FUNC. */
+
+/***ja
+ @brief ¥Õ¥§¡¼¥¹¤Î¥Õ¥Ã¥¯´Ø¿ô¤òÀßÄꤹ¤ë.
+
+ ´Ø¿ô mface_set_hook () ¤Ï¡¢¥Õ¥§¡¼¥¹ $FACE ¤Î¥Õ¥Ã¥¯´Ø¿ô¤ò$FUNC ¤ËÀß
+ Äꤹ¤ë¡£ */
+
+int
+mface_put_hook (MFace *face, MFaceHookFunc func)
+{
+ if (face->hook != func)
+ {
+ MPlist *plist;
+ face->hook = func;
+
+ MPLIST_DO (plist, face->frame_list)
+ {
+ MFrame *frame = MPLIST_VAL (plist);
+
+ frame->tick++;
+ if (face == frame->face)
+ mface__update_frame_face (frame);
+ }
+ }
+ return 0;
+}
+
+/*=*/
+
+/***en
@brief Update a face.
The mface_update () function update face $FACE on frame $FRAME by
void
mface_update (MFrame *frame, MFace *face)
{
- MFaceHookFunc func = (MFaceHookFunc) face->property[MFACE_HOOK_FUNC];
+ MFaceHookFunc func = face->hook;
MPlist *rface_list;
MRealizedFace *rface;
MPLIST_DO (rface_list, frame->realized_face_list)
{
rface = MPLIST_VAL (rface_list);
- if ((MFaceHookFunc) rface->face.property[MFACE_HOOK_FUNC] == func)
+ if (rface->face.hook == func)
(func) (&(rface->face), rface->face.property[MFACE_HOOK_ARG],
rface->info);
}