/* * textarea.c -- portable gui library text area, platform independent */ #include "gui.h" static void reflow_from(struct gui_ta *doc, unsigned int c, unsigned int w, gui_window_id window_id, unsigned int x_offset, unsigned int y_offset, int newline); #ifdef DEBUG static int document_ok(const struct gui_ta *doc); #endif /* * gui_ta -- return a new document with the specified width */ struct gui_ta *gui_ta(unsigned long width) { struct gui_ta *doc = malloc(sizeof(struct gui_ta)); #ifdef DEBUG printf("gui_ta: width = %li\n", width); fflush(stdout); #endif if (doc == NULL) return NULL; doc->width = width; doc->height = doc->contents = doc->styles = 0; doc->content = malloc(0); doc->style = malloc(0); if (doc->content == NULL || doc->style == NULL) return NULL; assert(document_ok(doc)); #ifdef DEBUG printf("gui_ta: doc = %p\n", doc); fflush(stdout); #endif return doc; } /* * gui_ta_add_space -- add a space of the specified height to the document * and return success */ long gui_ta_add_space(struct gui_ta *doc, unsigned long height) { struct gui_ta_content *con = malloc(sizeof(struct gui_ta_content)); struct gui_ta_content *(*new_content)[]; #ifdef DEBUG printf("gui_ta_add_space: doc = %p, height = %li\n", doc, height); fflush(stdout); #endif assert(document_ok(doc)); new_content = realloc(doc->content, (doc->contents + 1) * sizeof(struct gui_ta_content *)); if (con == NULL || new_content == NULL) return 0; con->type = CONTENT_SPACE; con->y0 = doc->height; con->y1 = doc->height + height; (*new_content)[doc->contents] = con; doc->content = new_content; doc->height += height; doc->contents++; assert(document_ok(doc)); return 1; } /* * gui_ta_add_paragraph -- add a paragraph of text */ int gui_ta_add_paragraph(struct gui_ta *doc, unsigned long leading, unsigned long base, wchar_t *text, unsigned long style, unsigned long align) { unsigned int words = 1; /* number of words added */ unsigned int w; /* word number */ wchar_t *text_pos = text; /* current position in text */ struct gui_ta_content *con = malloc(sizeof(struct gui_ta_content)); struct gui_ta_content *(*new_content)[]; struct gui_ta_word *word; /* current word structure */ unsigned int len; /* length of current word */ wchar_t *space; /* position of next space */ #ifdef DEBUG printf("gui_ta_add_paragraph: doc = %p, leading = %li, base = %li, style = %li\n", doc, leading, base, style); fflush(stdout); #endif assert(document_ok(doc)); new_content = realloc(doc->content, (doc->contents + 1) * sizeof(struct gui_ta_content *)); if (con == NULL || new_content == NULL) return 0; /* set up new paragraph */ con->type = CONTENT_PARAGRAPH; con->y0 = doc->height; con->leading = leading; con->base = base; con->align = align; /* count words and allocate space */ while (*text_pos) if (*text_pos++ == ' ') words++; con->words = words; con->word = calloc(words, sizeof(struct gui_ta_word *)); if (con->word == NULL) return 0; /* add the words */ text_pos = text; for (w = 0; w < words; w++) { space = wcschr(text_pos, ' '); len = (space ? space - text_pos : wcslen(text_pos)); word = malloc(gui_SIZEOF_GUI_TA_WORD(len + 1)); if (word == NULL) return 0; wcsncpy(word->text, text_pos, len); word->text[len] = 0; word->width = gui_ta_text_width(doc, word->text, style); word->style = style; (*con->word)[w] = word; text_pos += len + 1; } doc->height = gui_ta_reformat_paragraph(doc, con, doc->height, doc->width, 0, 0); /* add paragraph to document */ (*new_content)[doc->contents] = con; doc->content = new_content; doc->contents++; assert(document_ok(doc)); return 1; } /* * gui_ta_get_style -- get a style number, creating a new style if required */ unsigned long gui_ta_get_style(struct gui_ta *doc, unsigned long xsize, unsigned long ysize, unsigned long fcolour, unsigned long bcolour, char *font) { unsigned int s; /* style number */ struct gui_ta_style *style; /* current style structure */ struct gui_ta_style *(*new_style)[]; /* new style pointer list */ wchar_t const space[] = { 0x0020, 0 }; #ifdef DEBUG printf("gui_ta_get_style: doc = %p, font = '%s'\n", doc, font); fflush(stdout); #endif assert(document_ok(doc)); /* search for existing style */ for (s = 0; s < doc->styles; s++) { style = (*doc->style)[s]; if (style->xsize == xsize && style->ysize == ysize && style->fcolour == fcolour && style->bcolour == bcolour && strcmp(style->font, font) == 0) return s; } /* create a new style */ style = malloc(gui_SIZEOF_GUI_TA_STYLE(strlen(font) + 1)); if (style == NULL) return 0; new_style = realloc(doc->style, (doc->styles + 1) * sizeof(struct gui_ta_style *)); if (new_style == NULL) return 0; style->xsize = xsize; style->ysize = ysize; style->fcolour = fcolour; style->bcolour = bcolour; strcpy(style->font, font); gui_ta_fill_style(style); (*new_style)[doc->styles] = style; doc->style = new_style; doc->styles++; style->space = gui_ta_text_width(doc, space, doc->styles - 1); assert(document_ok(doc)); return doc->styles - 1; } /* * gui_ta_render -- render document to the screen */ void gui_ta_render(struct gui_ta *doc, unsigned long x, unsigned long y, unsigned int invalid[], struct gui_ta_selection *sel) { unsigned int c; unsigned int w; unsigned int base; const signed int x0 = (invalid[0] < x ? 0 : invalid[0] - x); const unsigned int y0 = (invalid[1] < y ? 0 : invalid[1] - y); const signed int x1 = (invalid[2] < x ? 0 : invalid[2] - x); const unsigned int y1 = (invalid[3] < y ? 0 : invalid[3] - y); struct gui_ta_content *con; struct gui_ta_word *word; #ifdef DEBUG printf("gui_ta_render: doc = %p\n", doc); fflush(stdout); #endif assert(document_ok(doc)); /* loop through document contents */ for (c = 0; c < doc->contents; c++) { con = (*doc->content)[c]; /* render content if it lies in invalid area */ if (!(con->y0 > y1 || con->y1 < y0)) { switch (con->type) { case CONTENT_SPACE: break; case CONTENT_PARAGRAPH: base = con->base; /* loop through paragraph words */ for (w = 0; w < con->words; w++) { word = (*con->word)[w];; /* continue if word is above or to right of invalid area */ if (word->y < y0 || word->box_x0 > x1) continue; /* exit if word is below invalid area */ if (word->y - con->leading > y1) return; assert((w < con->words - 1) || ((w == con->words - 1) && word->end)); /* render word if it lies in invalid area */ if (word->box_x1 >= x0) gui_ta_render_text(doc, word->text, word->style, x + word->x, y + word->y - base, x + word->box_x0, y + word->y - con->leading, x + word->box_x1, y + word->y, sel && (c > sel->start.content || (c == sel->start.content && w >= sel->start.word)) && (c < sel->end.content || (c == sel->end.content && w <= sel->end.word))); } break; } } } } /* * gui_ta_position_xy -- update position from coordinates */ void gui_ta_position_xy(struct gui_ta *doc, struct gui_ta_position *pos, signed long x, unsigned long y) { unsigned int c = 0; /* content number */ unsigned int w = 0; /* word number */ unsigned int word_y; /* y position of word */ struct gui_ta_content *con; /* current content structure */ #ifdef DEBUG printf("gui_ta_position_xy: doc = %p\n", doc); fflush(stdout); #endif assert(document_ok(doc)); if (doc->contents == 0) return; if (y > doc->height) c = doc->contents - 1; else while (y > (*doc->content)[c]->y1) c++; if (x < 0) x = 0; pos->content = c; con = (*doc->content)[c]; switch (con->type) { case CONTENT_SPACE: pos->word = pos->offset = pos->x = pos->y = 0xffffffffu; break; case CONTENT_PARAGRAPH: word_y = con->y0 + con->leading; while (y > word_y) word_y += con->leading; if (word_y > con->y1) word_y = con->y1; while ((*con->word)[w]->y != word_y) w++; while (x > (signed long) ((*con->word)[w]->x + (*con->word)[w]->width)) { if (w == con->words - 1 || (*con->word)[w + 1]->y != word_y) { pos->word = w; pos->offset = wcslen((*con->word)[w]->text); pos->x = (*con->word)[w]->x + (*con->word)[w]->width; pos->y = word_y; return; } w++; } pos->word = w; pos->y = word_y; x -= (*con->word)[w]->x; pos->offset = gui_ta_position_x(doc, (*con->word)[w]->text, (*con->word)[w]->style, &x); pos->x = (*con->word)[w]->x + x; break; } } /* * gui_ta_reformat -- change the width of the document */ void gui_ta_reformat(struct gui_ta *doc, unsigned long width) { unsigned int c; /* content number */ unsigned int y = 0; /* current y coordinate */ unsigned int h; /* height of space */ struct gui_ta_content *con; /* current content structure */ #ifdef DEBUG printf("gui_ta_reformat: doc = %p\n", doc); fflush(stdout); #endif for (c = 0; c < doc->contents; c++) { con = (*doc->content)[c]; switch (con->type) { case CONTENT_SPACE: h = con->y1 - con->y0; con->y0 = y; con->y1 = y = y + h; break; case CONTENT_PARAGRAPH: y = gui_ta_reformat_paragraph(doc, con, y, width, 0, 0); break; } } doc->width = width; doc->height = y; assert(document_ok(doc)); } /* * gui_ta_reformat_paragraph */ unsigned int gui_ta_reformat_paragraph(struct gui_ta *doc, struct gui_ta_content *con, unsigned long y, unsigned long width, unsigned long *y0_ret, unsigned long *y1_ret) { unsigned int x = 0; /* current x coordinate */ unsigned int x1 = 0; /* current x coordinate excluding last space */ unsigned int w; /* word number */ unsigned int w_start = 0; /* word at start of line */ unsigned int w_align; /* word when aligning */ unsigned int space; unsigned int y0, y1; unsigned int change = 0; struct gui_ta_word *word; /* current word structure */ struct gui_ta_word *next_word; if (y0_ret) y0 = *y0_ret; if (y1_ret) y1 = *y1_ret; con->y0 = y; y += con->leading; for (w = 0; w < con->words; w++) { word = (*con->word)[w]; if ((x + word->width > width) && (x != 0)) { space = width - x1; switch (con->align) { case ALIGN_LEFT: for (w_align = w_start; w_align < w; w_align++) (*con->word)[w_align]->x = (*con->word)[w_align]->lx; break; case ALIGN_CENTRE: space /= 2; case ALIGN_RIGHT: for (w_align = w_start; w_align < w; w_align++) (*con->word)[w_align]->x = (*con->word)[w_align]->lx + space; break; case ALIGN_FULL: (*con->word)[w_start]->x = (*con->word)[w_start]->lx; for (w_align = 1; w_align < w - w_start; w_align++) (*con->word)[w_start + w_align]->x = (*con->word)[w_start + w_align]->lx + w_align * space / (w - w_start - 1); break; } (*con->word)[w_start]->start = 1; (*con->word)[w - 1]->end = 1; x = x1 = 0; y += con->leading; w_start = w; } if (change == 0 && (x != word->lx || y != word->y)) { if (y < word->y) { y0 = y - con->leading; y1 = word->y; } else { y0 = word->y - con->leading; y1 = y; } change = 1; } else if (change == 1 && (x != word->lx || y != word->y)) y1 = y < word->y ? word->y : y; else if (change == 1 && x == word->lx && y == word->y) change = 2; word->lx = x; word->y = y; word->start = word->end = 0; x1 = x + word->width; x = x1 + (*doc->style)[word->style]->space; } space = width - x1; switch (con->align) { case ALIGN_LEFT: case ALIGN_FULL: for (w_align = w_start; w_align < con->words; w_align++) (*con->word)[w_align]->x = (*con->word)[w_align]->lx; break; case ALIGN_CENTRE: space /= 2; case ALIGN_RIGHT: for (w_align = w_start; w_align < con->words; w_align++) (*con->word)[w_align]->x = (*con->word)[w_align]->lx + space; break; } (*con->word)[w_start]->start = 1; word->end = 1; next_word = (*con->word)[0]; for (w = 0; w < con->words; w++) { word = next_word; next_word = (*con->word)[w + 1]; word->box_x0 = word->start ? 0 : word->x; word->box_x1 = word->end ? width : next_word->x; } con->y1 = y; if (y0_ret) *y0_ret = y0 < *y0_ret ? y0 : *y0_ret; if (y1_ret) *y1_ret = y1 < *y1_ret ? *y1_ret : y1; return y; } /* * gui_ta_insert_char -- insert a character at the specified position */ void gui_ta_insert_char(struct gui_ta *doc, struct gui_ta_position *pos, wchar_t text, gui_window_id window_id, unsigned long x_offset, unsigned long y_offset) { struct gui_ta_content *con = (*doc->content)[pos->content]; struct gui_ta_word *word = (*con->word)[pos->word]; #ifdef DEBUG printf("gui_ta_insert_char: doc = %p, char = %04x\n", doc, text); fflush(stdout); #endif assert(document_ok(doc)); word = realloc(word, gui_SIZEOF_GUI_TA_WORD(wcslen(word->text) + 2)); if (word == NULL) return; memmove(word->text + pos->offset + 1, word->text + pos->offset, (wcslen(word->text + pos->offset) + 1) * sizeof(wchar_t)); word->text[pos->offset] = text; word->width = gui_ta_text_width(doc, word->text, word->style); (*con->word)[pos->word] = word; reflow_from(doc, pos->content, pos->word, window_id, x_offset, y_offset, 0); } /* * gui_ta_insert_split -- split a word into two words at the specified position */ void gui_ta_insert_split(struct gui_ta *doc, struct gui_ta_position *pos, gui_window_id window_id, unsigned long x_offset, unsigned long y_offset) { struct gui_ta_content *con = (*doc->content)[pos->content]; struct gui_ta_word *word = (*con->word)[pos->word]; struct gui_ta_word *left = malloc(gui_SIZEOF_GUI_TA_WORD(pos->offset + 1)); struct gui_ta_word *right = malloc(gui_SIZEOF_GUI_TA_WORD(wcslen(word->text) - pos->offset + 1)); struct gui_ta_word *(*new_word)[] = malloc((con->words + 1) * sizeof(struct gui_ta_word *)); #ifdef DEBUG printf("gui_ta_insert_split: doc = %p\n", doc); fflush(stdout); #endif assert(document_ok(doc)); if (new_word == NULL || left == NULL || right == NULL) return; memcpy(*new_word, *con->word, pos->word * sizeof(struct gui_ta_word *)); (*new_word)[pos->word] = left; (*new_word)[pos->word + 1] = right; memcpy(*new_word + pos->word + 2, *con->word + pos->word + 1, (con->words - pos->word - 1) * sizeof(struct gui_ta_word *)); wcsncpy(left->text, word->text, pos->offset); left->text[pos->offset] = 0; left->style = word->style; left->width = gui_ta_text_width(doc, left->text, left->style); left->x = word->x; left->lx = word->lx; left->y = word->y; wcscpy(right->text, word->text + pos->offset); right->style = word->style; right->width = gui_ta_text_width(doc, right->text, right->style); right->x = right->y = 0; left->lx = 0; free(word); free(con->word); con->word = new_word; con->words++; if (pos->word && (*con->word)[pos->word - 1]->y != left->y) { left->x = left->y = 0; reflow_from(doc, pos->content, pos->word - 1, window_id, x_offset, y_offset, 0); } else reflow_from(doc, pos->content, pos->word, window_id, x_offset, y_offset, 0); } /* * gui_ta_insert_newline -- split a paragraph into two paragraphs at the specified position */ void gui_ta_insert_newline(struct gui_ta *doc, struct gui_ta_position *pos, gui_window_id window_id, unsigned long x_offset, unsigned long y_offset) { struct gui_ta_content *con = (*doc->content)[pos->content]; struct gui_ta_content *new_con = malloc(sizeof(struct gui_ta_content)); struct gui_ta_word *word = (*con->word)[pos->word]; struct gui_ta_word *left = malloc(gui_SIZEOF_GUI_TA_WORD(pos->offset + 1)); struct gui_ta_word *right = malloc(gui_SIZEOF_GUI_TA_WORD(wcslen(word->text) - pos->offset + 1)); struct gui_ta_word *(*new_word)[] = malloc((con->words - pos->word) * sizeof(struct gui_ta_word *)); struct gui_ta_content *(*content)[]; #ifdef DEBUG printf("gui_ta_insert_newline: doc = %p\n", doc); fflush(stdout); #endif assert(document_ok(doc)); content = realloc(doc->content, (doc->contents + 1) * sizeof(struct gui_ta_content *)); if (new_con == NULL || new_word == NULL || left == NULL || right == NULL || content == NULL) return; doc->content = content; new_con->type = con->type; new_con->y0 = 0; new_con->y1 = con->y1; new_con->leading = con->leading; new_con->base = con->base; new_con->align = con->align; new_con->words = con->words - pos->word; new_con->word = new_word; (*new_word)[0] = right; memcpy(*new_word + 1, *con->word + pos->word + 1, (con->words - pos->word - 1) * sizeof(struct gui_ta_word *)); wcsncpy(left->text, word->text, pos->offset); left->text[pos->offset] = 0; left->style = word->style; left->width = gui_ta_text_width(doc, left->text, left->style); left->x = word->x; left->y = word->y; wcscpy(right->text, word->text + pos->offset); right->style = word->style; right->width = gui_ta_text_width(doc, right->text, right->style); right->x = right->y = 0; free(word); (*con->word)[pos->word] = left; con->words = pos->word + 1; memmove(*doc->content + pos->content + 2, *doc->content + pos->content + 1, (doc->contents - pos->content - 1) * sizeof(struct gui_ta_content *)); (*doc->content)[pos->content + 1] = new_con; doc->contents++; if (pos->word && (*con->word)[pos->word - 1]->y != left->y) { left->x = left->lx = left->y = 0; reflow_from(doc, pos->content, pos->word - 1, window_id, x_offset, y_offset, 1); } else reflow_from(doc, pos->content, pos->word, window_id, x_offset, y_offset, 1); } /* * reflow_from -- helper function to reflow document after insertion / deletion */ void reflow_from(struct gui_ta *doc, unsigned int c0, unsigned int w0, gui_window_id window_id, unsigned int x_offset, unsigned int y_offset, int newline) { unsigned int y; unsigned long y0, y1; unsigned int old_y1; unsigned int c, w; struct gui_ta_content *con = (*doc->content)[c0]; y0 = (*con->word)[w0]->y - con->leading; y1 = (*con->word)[w0]->y; old_y1 = con->y1; y = gui_ta_reformat_paragraph(doc, con, con->y0, doc->width, &y0, &y1); if (y == old_y1 && !newline) { assert(document_ok(doc)); gui_refresh_box(window_id, x_offset, y_offset + y0, x_offset + doc->width, y_offset + y1); return; } if (c0 + 1 < doc->contents) { con = (*doc->content)[c0 + 1]; if (newline) { y = gui_ta_reformat_paragraph(doc, con, y, doc->width, 0, &y1); if (c0 + 2 == doc->contents) { doc->height = y; assert(document_ok(doc)); gui_refresh_box(window_id, x_offset, y_offset + y0, x_offset + doc->width, y_offset + y1); #ifdef DEBUG printf("reflow_from: last content\n"); fflush(stdout); #endif return; } con = (*doc->content)[c0 + 2]; } if (y != con->y0) { signed int move = y - con->y0; gui_move_box(window_id, x_offset, y_offset + con->y0, x_offset + doc->width, y_offset + doc->height, x_offset, y_offset + y); for (c = c0 + 1 + newline; c < doc->contents; c++) { con = (*doc->content)[c]; con->y0 += move; con->y1 += move; switch (con->type) { case CONTENT_SPACE: break; case CONTENT_PARAGRAPH: for (w = 0; w < con->words; w++) (*con->word)[w]->y += move; break; } } doc->height += move; } } else { doc->height = y; } assert(document_ok(doc)); gui_refresh_box(window_id, x_offset, y_offset + y0, x_offset + doc->width, y_offset + y1); #ifdef DEBUG printf("reflow_from: full\n"); fflush(stdout); #endif } /* * gui_ta_position_cwo -- update position from content, word, offset */ void gui_ta_position_cwo(struct gui_ta *doc, struct gui_ta_position *pos) { struct gui_ta_word *word = (*(*doc->content)[pos->content]->word)[pos->word]; #ifdef DEBUG printf("gui_ta_position_cwo: doc = %p\n", doc); fflush(stdout); #endif assert(document_ok(doc)); pos->x = word->x + gui_ta_position_o(doc, word->text, word->style, pos->offset); pos->y = word->y; } /* * gui_ta_delete -- delete a block of text * * There are two possible cases: * * 1. The block to be deleted lies within one word * => remove those characters * 2. The block is between different words * => remove intervening words, and merge words */ void gui_ta_delete(struct gui_ta *doc, struct gui_ta_position *start, struct gui_ta_position *end, gui_window_id window_id, unsigned long x_offset, unsigned long y_offset) { unsigned int c = start->content; unsigned int w = start->word; // struct gui_ta_content *con = (*doc->content)[c]; struct gui_ta_content *start_con = (*doc->content)[c]; struct gui_ta_word *start_word = (*start_con->word)[w]; struct gui_ta_content *end_con = (*doc->content)[end->content]; struct gui_ta_word *end_word = (*end_con->word)[end->word]; void *mem; assert(end->content > start->content || (end->content == start->content && (end->word > start->word || (end->word == start->word && end->offset > start->offset)))); /* case 1 */ if (start_word == end_word) { wcscpy(start_word->text + start->offset, end_word->text + end->offset); start_word->width = gui_ta_text_width(doc, start_word->text, start_word->style); reflow_from(doc, start->content, start->word, window_id, x_offset, y_offset, 0); return; } /* case 2 */ mem = realloc(start_word, gui_SIZEOF_GUI_TA_WORD(start->offset + wcslen(end_word->text + end->offset) + 1)); if (mem == NULL) return; start_word = (*start_con->word)[start->word] = mem; if (start_con != end_con) { mem = realloc(start_con->word, (start->word + end_con->words - end->word) * sizeof(struct gui_ta_word *)); if (mem == NULL) return; start_con->word = mem; } wcscpy(start_word->text + start->offset, end_word->text + end->offset); start_word->width = gui_ta_text_width(doc, start_word->text, start_word->style); memcpy(*start_con->word + start->word + 1, *end_con->word + end->word + 1, (end_con->words - end->word - 1) * sizeof(struct gui_ta_word *)); start_con->words = start->word + end_con->words - end->word; if (start_con == end_con) { reflow_from(doc, start->content, start->word, window_id, x_offset, y_offset, 0); return; } start_con->y1 = end_con->y1; free(end_con->word); free(end_con); memcpy(*doc->content + start->content + 1, *doc->content + end->content + 1, (doc->contents - end->content - 1) * sizeof(struct gui_ta_content *)); doc->contents = start->content + doc->contents - end->content; mem = realloc(doc->content, doc->contents * sizeof(struct gui_ta_content *)); if (mem) doc->content = mem; reflow_from(doc, start->content, start->word, window_id, x_offset, y_offset, 0); } /* while (c < end->content || w < end->word) { w++; if (w == con->words) { if (c > start->content && c < end->content) { free(con->word); free(con); } c++; w = 0; con = (*doc->content)[c]; } free((*con->word)[w]); } */ /* * gui_ta_remove -- free up resources associated with a document */ extern void gui_ta_remove(struct gui_ta *doc) { unsigned int c, w, s; struct gui_ta_content *con; for (c = 0; c < doc->contents; c++) { con = (*doc->content)[c]; switch (con->type) { case CONTENT_PARAGRAPH: { for (w = 0; w < con->words; w++) free((*con->word)[w]); break; } case CONTENT_SPACE: ; } free(con); } for (s = 0; s < doc->styles; s++) { gui_ta_empty_style((*doc->style)[s]); free((*doc->style)[s]); } } /* * gui_ta_align */ void gui_ta_align(struct gui_ta *doc, unsigned int content, unsigned int align, gui_window_id window_id, unsigned int x_offset, unsigned int y_offset) { struct gui_ta_content *con = (*doc->content)[content]; con->align = align; gui_ta_reformat_paragraph(doc, con, con->y0, doc->width, 0, 0); gui_refresh_box(window_id, x_offset, y_offset + con->y0, x_offset + doc->width, y_offset + con->y1); } /* * gui_ta_export -- export a document */ void gui_ta_export(struct gui_ta *doc, const char *path) { unsigned int c, w, s; FILE *fp = fopen(path, "w"); struct gui_ta_style *style; struct gui_ta_content *con; struct gui_ta_word *word; wfputc(0x74785457, fp); wfputc(doc->contents, fp); for (c = 0; c < doc->contents; c++) { con = (*doc->content)[c]; switch (con->type) { case CONTENT_SPACE: wfputc(0x63617053, fp); break; case CONTENT_PARAGRAPH: { wfputc(0x61726150, fp); wfputc(con->leading, fp); wfputc(con->base, fp); for (w = 0; w < con->words; w++) { word = (*con->word)[w]; if ((w == 0) || (word->style != s)) { /* style = (*doc->style)[s]; */ /* fprintf(fp, " %s\n", style->font); */ /* fprintf(fp, " %d\n", style->xsize); */ /* fprintf(fp, " %d\n", style->ysize); */ /* fprintf(fp, " %x\n", style->fcolour); */ /* fprintf(fp, " %x\n", style->bcolour); */ wfputc(word->style, fp); } s = word->style; wfputs(word->text, fp); } break; } } } fclose(fp); } #ifdef DEBUG /* * document_ok -- check document integrity */ int document_ok(const struct gui_ta *doc) { unsigned int c; unsigned int w; const struct gui_ta_content *con; const struct gui_ta_word *word; /* printf("%p [width %i, height %i, contents %i, styles %i]\n", */ /* doc, doc->width, doc->height, doc->contents, doc->styles); */ for (c = 0; c < doc->contents; c++) { con = (*doc->content)[c]; /* printf("%i %p\n", c, con); */ if (c && con->y0 != (*doc->content)[c - 1]->y1) { printf("content y coordinates don't match %i %li, %i %li\n", c - 1, (*doc->content)[c - 1]->y1, c, con->y0); fflush(stdout); return 0; } if (con->y1 > doc->height) { printf("con->y1 %li greater than doc->height %li\n", con->y1, doc->height); fflush(stdout); return 0; } switch (con->type) { case CONTENT_SPACE: /* printf("\n", */ /* con->y0, con->y1); */ break; case CONTENT_PARAGRAPH: /* printf("\n", */ /* con->y0, con->y1, con->leading, con->words); */ for (w = 0; w < con->words; w++) { word = (*con->word)[w]; /* printf(" \n", */ /* word->x, word->y, word->width, word->style, word->box_x0, word->box_x1); */ if (word->x > doc->width) { printf("word->x %li greater than doc->width %li\n", word->x, doc->width); fflush(stdout); return 0; } if ((word->x != 0) && (word->x + word->width > doc->width)) { printf("word->x %li + word->width %li greater than doc->width %li\n", word->x, word->width, doc->width); fflush(stdout); return 0; } if (word->y < con->y0 || word->y > con->y1) { printf("word->y %li not within content y %li %li\n", word->y, con->y0, con->y1); fflush(stdout); return 0; } if (word->style >= doc->styles) { printf("word->style %li greater than doc->styles %li\n", word->style, doc->styles); fflush(stdout); return 0; } } break; default: printf("unknown document content type %li %li\n", c, con->type); fflush(stdout); return 0; } } return 1; } #endif