X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=src%2Fface.c;h=983228c13a07ca71fe264902f677502e3d08bfdc;hb=08e7cd818a87fafc460cc35dc3e62524def3fc94;hp=757c2456d96e8a17727ac50ef1477d712699c2b9;hpb=c4db091d2f7d1f005ba5c389134772b82408709d;p=m17n%2Fm17n-lib.git diff --git a/src/face.c b/src/face.c index 757c245..983228c 100644 --- a/src/face.c +++ b/src/face.c @@ -17,7 +17,7 @@ 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 @@ -164,7 +164,7 @@ get_box_create (MFaceBoxProp *prop) FACE. */ static MRealizedFace * -find_realized_face (MFrame *frame, MFace *face) +find_realized_face (MFrame *frame, MFace *face, MFont *font) { MPlist *plist; @@ -172,8 +172,11 @@ find_realized_face (MFrame *frame, MFace *face) { 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; @@ -240,7 +243,7 @@ serialize_face (void *val) MSymbol *key; MSymbol *type; MPlist *(*func) (MPlist *plist, void *val); - } serializer[MFACE_PROPERTY_MAX] + } serializer[MFACE_RATIO + 1] = { { &Mfoundry, &Msymbol }, { &Mfamily, &Msymbol }, { &Mweight, &Msymbol }, @@ -254,11 +257,9 @@ serialize_face (void *val) { &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); @@ -360,7 +361,7 @@ deserialize_face (MPlist *plist) 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 @@ -414,10 +415,12 @@ mface__init () 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"); @@ -439,7 +442,7 @@ mface__init () 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 }, @@ -453,10 +456,8 @@ mface__init () { &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. */ @@ -485,7 +486,7 @@ mface__init () 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; @@ -589,27 +590,31 @@ mface__fini () 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]) @@ -618,52 +623,142 @@ mface__realize (MFrame *frame, MFace **faces, int num, int size) 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, Municode_bmp); + spec.source = MFONT_SOURCE_FT; + font = mfont__select (frame, &spec, 0); + if (font) + rfont = mfont__open (frame, font, &spec); + if (! rfont) + { + 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) + { + 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].g.code = MCHAR_INVALID_CODE; + work_gstring.glyphs[0].g.measured = 0; + mfont__get_metric (&work_gstring, 0, 1); + rface->ascent = work_gstring.glyphs[0].g.ascent; + rface->descent = work_gstring.glyphs[0].g.descent; + work_gstring.glyphs[0].g.code + = mfont__encode_char (frame, (MFont *) rfont, NULL, ' '); + if (work_gstring.glyphs[0].g.code != MCHAR_INVALID_CODE) + { + work_gstring.glyphs[0].g.measured = 0; + mfont__get_metric (&work_gstring, 0, 1); + rface->space_width = work_gstring.glyphs[0].g.xadv; + } + else + rface->space_width = rfont->spec.size / 10; + if (rfont->average_width) + rface->average_width = rfont->average_width >> 6; + else + { + work_gstring.glyphs[0].g.code + = mfont__encode_char (frame, (MFont *) rfont, NULL, 'x'); + if (work_gstring.glyphs[0].g.code != MCHAR_INVALID_CODE) + { + work_gstring.glyphs[0].g.measured = 0; + mfont__get_metric (&work_gstring, 0, 1); + rface->average_width = work_gstring.glyphs[0].g.xadv; + } + else + rface->average_width = rface->space_width; + } } else { @@ -671,16 +766,16 @@ mface__realize (MFrame *frame, MFace **faces, int num, int size) 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]); @@ -704,13 +799,103 @@ MGlyph * 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->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 >> 6; + new->descent = rfont->descent >> 6; + } + for (; from_g < to_g && from_g->rface->font; from_g++) + { + from_g->rface = new; + if (new->layouter) + { + MFLT *flt = mflt_get (new->layouter); + MCharTable *coverage; + + if (! flt + || ((coverage = mflt_coverage (flt)) + && ! (from_g->g.code + = (unsigned) mchartable_lookup (coverage, + from_g->g.c)))) + { + from_g->rface = rface; + from_g->g.code = mfont__encode_char (rfont->frame, + (MFont *) rfont, + NULL, from_g->g.c); + } + } + else + from_g->g.code = mfont__encode_char (rfont->frame, + (MFont *) rfont, + NULL, from_g->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].g.c); + if (code == MCHAR_INVALID_CODE) + break; + from_g[i].g.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->g.code = MCHAR_INVALID_CODE; + num = 1; + rfont = NULL; + layouter = Mnil; + } to_g = from_g + num; while (from_g < to_g) @@ -719,24 +904,31 @@ mface__for_chars (MSymbol script, MSymbol language, MSymbol charset, 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) { - new->ascent = rfont->ascent; - new->descent = rfont->descent; + new->ascent = rfont->ascent >> 6; + new->descent = rfont->descent >> 6; } } while (g < from_g) @@ -755,6 +947,8 @@ mface__free_realized (MRealizedFace *rface) 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); } @@ -762,8 +956,9 @@ void 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; } @@ -1483,6 +1678,54 @@ mface_copy (MFace *face) /*=*/ /***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 @@ -1586,7 +1829,7 @@ mface_from_font (MFont *font) #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 ¤Ë°Í¸¤¹¤ë¡£¾åµ­¤Î¥­¡¼¤ÎÀâÌÀ¤ò»²¾È¤¹¤ë¤³¤È¡£ @@ -1595,7 +1838,7 @@ mface_from_font (MFont *font) /*** @seealso - mface_put_prop () + mface_put_prop (), mface_put_hook () @errors @c MERROR_FACE */ @@ -1606,13 +1849,37 @@ mface_get_prop (MFace *face, MSymbol key) 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 @@ -1667,22 +1934,32 @@ mface_put_prop (MFace *face, MSymbol key, void *val) 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) { @@ -1699,6 +1976,40 @@ mface_put_prop (MFace *face, MSymbol key, void *val) /*=*/ /***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 @@ -1713,7 +2024,7 @@ mface_put_prop (MFace *face, MSymbol key, void *val) void mface_update (MFrame *frame, MFace *face) { - MFaceHookFunc func = (MFaceHookFunc) face->property[MFACE_HOOK_FUNC]; + MFaceHookFunc func = face->hook; MPlist *rface_list; MRealizedFace *rface; @@ -1722,7 +2033,7 @@ mface_update (MFrame *frame, MFace *face) 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); }