#include #include #include "xwchar.h" #include "text.h" #include "miniframe.h" #ifndef MAX #define MAX(a,b) (((a)>(b))?(a):(b)) #endif MiniFrame * miniframe_new(Display *dpy, Window win, FontFaceTableList fftl, FontNameList fnl, int fonttype, double factor, u_int width) { MiniFrame *p; if ((p = malloc(sizeof(*p))) == NULL) { perror("frame_new"); exit(1); } p->dpy = dpy; p->win = win; p->width = width; p->oc = oc_new(fftl, fnl, fonttype, factor); p->obj = p->line = NULL; p->wstr = NULL; { XWindowAttributes attr; XGetWindowAttributes(p->dpy, p->win, &attr); p->foreground = BlackPixelOfScreen(attr.screen); p->gc = XCreateGC(p->dpy, p->win, 0, NULL); XSetGraphicsExposures(p->dpy, p->gc, False); } return p; } static void miniframe_clean(MiniFrame *fm) { htmlobjlist_delete(fm->obj); fm->obj = NULL; } static void miniframe_init_params(MiniFrame *mf) { mf->after_lf = 1; mf->cur_x = mf->cur_y = 0; mf->formatted_width = mf->formatted_height = 0; mf->max_ascent = mf->max_descent = 0; mf->obj = mf->line = htmlobj_new(); } void miniframe_delete(MiniFrame *mf) { if (mf) { htmlobjlist_delete(mf->obj); XFreeGC(mf->dpy, mf->gc); oc_delete(mf->oc); if (mf->wstr) free(mf->wstr); free(mf); } } static void miniframe_add_obj(MiniFrame *mf, HTMLObj *obj) { obj->x = mf->cur_x; obj->y = mf->cur_y; mf->max_ascent = MAX(mf->max_ascent, obj->ascent); mf->max_descent = MAX(mf->max_descent, obj->descent); mf->cur_x += obj->width; mf->formatted_width = MAX(mf->formatted_width, obj->x + obj->rbearing); obj->next = mf->obj; obj->prev = mf->obj->prev; mf->obj->prev->next = obj; mf->obj->prev = obj; } static void miniframe_add_lf(MiniFrame *mf) { HTMLObj *o; o = mf->line->next; while (o != mf->obj) { o->y += mf->max_ascent; o = o->next; } mf->line = mf->obj->prev; mf->cur_y += (mf->max_descent + mf->max_ascent + 10); mf->cur_x = 0; mf->max_ascent = 0; mf->max_descent = 0; mf->after_lf = 1; } static void miniframe_add_string(MiniFrame *mf, wchar_t *str, size_t len) { XCharStruct all; HTMLObj *obj; HTMLTextObj *t; if (len == 0) return; obj = htmlobj_new(); t = htmltextobj_new(); obj->type = HTMLOBJ_TEXT; obj->data = t; obj->pixel = mf->foreground; t->oc = mf->oc; t->str = str; t->len = len; WcExtents(mf->oc, str, len, &all); obj->lbearing = all.lbearing; obj->rbearing = all.rbearing; obj->width = all.width; obj->height = all.ascent + all.descent; obj->ascent = all.ascent; obj->descent = all.descent; miniframe_add_obj(mf,obj); } static void miniframe_parse_string(MiniFrame *mf, wchar_t wstr[]) { XCharStruct all; wchar_t *start, *wp, *p; /* normal string */ start = wp = p = wstr; while (*start) { p = start; word: /* 単語の切り出し */ while (*p && *p != ' ' && !IS_MB(*p)) p++; if (*p && (*p == ' ' || wp == p)) p++; WcExtents(mf->oc, start, p - start, &all); if (mf->cur_x + all.rbearing < mf->width) { mf->after_lf = 0; /* 途中で終了 */ if (!*p) { miniframe_add_string(mf, start, p - start); break; } wp = p; goto word; } /* 改行直後は禁則を無視 */ if (mf->after_lf) { miniframe_add_string(mf, start, p - start); miniframe_add_lf(mf); wp = start = p; continue; } /* 行末禁則処理 (2文字まで) */ if (wp-1 >= start && gyomatsu_kinsoku(*(wp-1))) { wp--; if (wp-1 >= start && gyomatsu_kinsoku(*(wp-1))) wp--; } if (wp == start) { miniframe_add_lf(mf); continue; } /* 行頭禁則処理 (2文字まで) */ if (*wp && gyoto_kinsoku(*wp)) { wp++; if (*wp && gyoto_kinsoku(*wp)) wp++; } miniframe_add_string(mf, start, wp - start); start = wp; miniframe_add_lf(mf); continue; } } void miniframe_open(MiniFrame *mf, char *str) { int len = strlen(str); miniframe_clean(mf); miniframe_init_params(mf); if (mf->wstr) free(mf->wstr); if ((mf->wstr = malloc((sizeof(*mf->wstr) * len + 1)))) { mbstate_t state; mbrtowc(NULL, NULL, 0, &state); len = mbsrtowcs(mf->wstr, str, len, &state); mf->wstr[len] = '\0'; miniframe_parse_string(mf, mf->wstr); if (!mf->after_lf) miniframe_add_lf(mf); mf->formatted_height = mf->cur_y; } } void miniframe_expose_region(MiniFrame *mf, int off_x, int off_y, Region reg) { HTMLObj *obj = mf->obj->next; while (obj != mf->obj) { htmlobj_draw(mf->dpy, mf->win, mf->gc, off_x, off_y, obj, 0,0,0,0); obj = obj->next; } }