From 4b8638cfa35ecacf7418ec8933f971577652bb79 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 2 Sep 2014 20:39:21 +0200 Subject: html: Add scaffolding. --- source/html/handler.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 source/html/handler.c (limited to 'source/html') diff --git a/source/html/handler.c b/source/html/handler.c new file mode 100644 index 00000000..39d5e9c9 --- /dev/null +++ b/source/html/handler.c @@ -0,0 +1,127 @@ +#include "mupdf/html.h" + +struct html_document_s +{ + fz_document super; + fz_context *ctx; + fz_xml *root; +}; + +struct html_page_s +{ +}; + +void +html_close_document(html_document *doc) +{ + fz_context *ctx = doc->ctx; + fz_free(ctx, doc); +} + +int +html_count_pages(html_document *doc) +{ + return 1; +} + +html_page * +html_load_page(html_document *doc, int number) +{ + printf("html: load page %d\n", number); + return NULL; +} + +void +html_free_page(html_document *doc, html_page *page) +{ +} + +fz_rect * +html_bound_page(html_document *doc, html_page *page, fz_rect *bbox) +{ + printf("html: bound page\n"); + bbox->x0 = bbox->y0 = 0; + bbox->x1 = 400; + bbox->y1 = 600; + return bbox; +} + +void +html_run_page(html_document *doc, html_page *page, fz_device *dev, const fz_matrix *ctm, fz_cookie *cookie) +{ + printf("html: run page\n"); +} + +html_document * +html_open_document_with_stream(fz_context *ctx, fz_stream *file) +{ + html_document *doc; + fz_buffer *buf; + fz_xml *root; + + buf = fz_read_all(file, 0); + root = fz_parse_xml(ctx, buf->data, buf->len, 1); + fz_drop_buffer(ctx, buf); + + doc = fz_malloc_struct(ctx, html_document); + doc->ctx = ctx; + doc->root = root; + + doc->super.close = (void*)html_close_document; + doc->super.count_pages = (void*)html_count_pages; + doc->super.load_page = (void*)html_load_page; + doc->super.bound_page = (void*)html_bound_page; + doc->super.run_page_contents = (void*)html_run_page; + doc->super.free_page = (void*)html_free_page; + + return doc; +} + +html_document * +html_open_document(fz_context *ctx, const char *filename) +{ + fz_stream *file; + html_document *doc; + + file = fz_open_file(ctx, filename); + if (!file) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", filename, strerror(errno)); + + fz_try(ctx) + { + doc = html_open_document_with_stream(ctx, file); + } + fz_always(ctx) + { + fz_close(file); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } + + return doc; +} + +static int +html_recognize(fz_context *doc, const char *magic) +{ + char *ext = strrchr(magic, '.'); + + if (ext) + { + if (!fz_strcasecmp(ext, ".xhtml") || !fz_strcasecmp(ext, ".html")) + return 100; + } + if (!strcmp(magic, "application/html+xml") || !strcmp(magic, "application/xml") || !strcmp(magic, "text/xml")) + return 100; + + return 0; +} + +fz_document_handler html_document_handler = +{ + (fz_document_recognize_fn *)&html_recognize, + (fz_document_open_fn *)&html_open_document, + (fz_document_open_with_stream_fn *)&html_open_document_with_stream +}; -- cgit v1.2.3 From 9d1482bc78d72ba330c2130170b49b4e18702623 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Mon, 8 Sep 2014 15:49:59 +0200 Subject: html: CSS lexer and parser. --- source/html/css-apply.c | 875 ++++++++++++++++++++++++++++++++++++++++++++++++ source/html/css-parse.c | 734 ++++++++++++++++++++++++++++++++++++++++ source/html/handler.c | 11 +- source/html/layout.c | 153 +++++++++ 4 files changed, 1765 insertions(+), 8 deletions(-) create mode 100644 source/html/css-apply.c create mode 100644 source/html/css-parse.c create mode 100644 source/html/layout.c (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c new file mode 100644 index 00000000..7f3028a9 --- /dev/null +++ b/source/html/css-apply.c @@ -0,0 +1,875 @@ +#include "mupdf/html.h" + +static void add_property(struct style *style, const char *name, struct value *value, int spec); + +struct rule * +new_rule(struct selector *selector, struct property *declaration) +{ + struct rule *rule; + + rule = malloc(sizeof(struct rule)); + rule->selector = selector; + rule->declaration = declaration; + rule->next = NULL; + + return rule; +} + +struct selector * +new_selector(const char *name) +{ + struct selector *sel; + + sel = malloc(sizeof(struct selector)); + sel->name = name ? strdup(name) : NULL; + sel->combine = 0; + sel->cond = NULL; + sel->left = NULL; + sel->right = NULL; + sel->next = NULL; + + return sel; +} + +struct condition * +new_condition(int type, const char *key, const char *val) +{ + struct condition *cond; + + cond = malloc(sizeof(struct condition)); + cond->type = type; + cond->key = key ? strdup(key) : NULL; + cond->val = val ? strdup(val) : NULL; + cond->next = NULL; + + return cond; +} + +struct property * +new_property(const char *name, struct value *value, int spec) +{ + struct property *prop; + + prop = malloc(sizeof(struct property)); + prop->name = strdup(name); + prop->value = value; + prop->spec = spec; + prop->next = NULL; + + return prop; +} + +struct value * +new_value(int type, const char *data) +{ + struct value *val; + + val = malloc(sizeof(struct value)); + val->type = type; + val->data = strdup(data); + val->args = NULL; + val->next = NULL; + + return val; +} + +/* + * Compute specificity + */ + +static int +count_condition_ids(struct condition *cond) +{ + int n = 0; + while (cond) + { + if (cond->type == '#') + n ++; + cond = cond->next; + } + return n; +} + +static int +count_selector_ids(struct selector *sel) +{ + int n = count_condition_ids(sel->cond); + if (sel->left && sel->right) + { + n += count_selector_ids(sel->left); + n += count_selector_ids(sel->right); + } + return n; +} + +static int +count_condition_atts(struct condition *cond) +{ + int n = 0; + while (cond) + { + if (cond->type != '#' && cond->type != ':') + n ++; + cond = cond->next; + } + return n; +} + +static int +count_selector_atts(struct selector *sel) +{ + int n = count_condition_atts(sel->cond); + if (sel->left && sel->right) + { + n += count_selector_atts(sel->left); + n += count_selector_atts(sel->right); + } + return n; +} + +static int +count_condition_names(struct condition *cond) +{ + int n = 0; + while (cond) + { + if (cond->type == ':') + n ++; + cond = cond->next; + } + return n; +} + +static int +count_selector_names(struct selector *sel) +{ + int n = count_condition_names(sel->cond); + if (sel->left && sel->right) + { + n += count_selector_names(sel->left); + n += count_selector_names(sel->right); + } + else if (sel->name) + { + n ++; + } + return n; +} + +int +selector_specificity(struct selector *sel) +{ + int b = count_selector_ids(sel); + int c = count_selector_atts(sel); + int d = count_selector_names(sel); + return b * 100 + c * 10 + d; +} + +/* + * Pretty printing + */ + +void +print_value(struct value *val) +{ + printf("%s", val->data); + if (val->args) + { + printf("("); + print_value(val->args); + printf(")"); + } + if (val->next) + { + printf(" "); + print_value(val->next); + } +} + +void +print_property(struct property *prop) +{ + printf("\t%s: ", prop->name); + print_value(prop->value); + printf(" !%d;\n", prop->spec); +} + +void +print_condition(struct condition *cond) +{ + if (cond->type == '=') + printf("[%s=%s]", cond->key, cond->val); + else if (cond->type == '[') + printf("[%s]", cond->key); + else + printf("%c%s", cond->type, cond->val); + if (cond->next) + print_condition(cond->next); +} + +void +print_selector(struct selector *sel) +{ + if (sel->combine) + { +putchar('('); + print_selector(sel->left); + if (sel->combine == ' ') + printf(" "); + else + printf(" %c ", sel->combine); + print_selector(sel->right); +putchar(')'); + } + else if (sel->name) + printf("%s", sel->name); + else + printf("*"); + if (sel->cond) + { + print_condition(sel->cond); + } +} + +void +print_rule(struct rule *rule) +{ + struct selector *sel; + struct property *prop; + + for (sel = rule->selector; sel; sel = sel->next) + { + print_selector(sel); + printf(" !%d", selector_specificity(sel)); + if (sel->next) + printf(", "); + } + + printf("\n{\n"); + for (prop = rule->declaration; prop; prop = prop->next) + { + print_property(prop); + } + printf("}\n"); +} + +void +print_rules(struct rule *rule) +{ + while (rule) + { + print_rule(rule); + rule = rule->next; + } +} + +/* + * Selector matching + */ + +int +match_id_condition(fz_xml *node, const char *p) +{ + const char *s = fz_xml_att(node, "id"); + if (s && !strcmp(s, p)) + return 1; + return 0; +} + +int +match_class_condition(fz_xml *node, const char *p) +{ + const char *s = fz_xml_att(node, "class"); + char buf[1024]; + if (s) { + strcpy(buf, s); + s = strtok(buf, " "); + while (s) { + if (!strcmp(s, p)) + return 1; + s = strtok(NULL, " "); + } + } + return 0; +} + +int +match_condition(struct condition *cond, fz_xml *node) +{ + if (!cond) + return 1; + + switch (cond->type) { + default: return 0; + case ':': return 0; /* don't support pseudo-classes */ + case '#': if (!match_id_condition(node, cond->val)) return 0; break; + case '.': if (!match_class_condition(node, cond->val)) return 0; break; + } + + return match_condition(cond->next, node); +} + +int +match_selector(struct selector *sel, fz_xml *node) +{ + if (!node) + return 0; + + if (sel->combine) + { + /* descendant */ + if (sel->combine == ' ') + { + fz_xml *parent = fz_xml_up(node); + while (parent) + { + if (match_selector(sel->left, parent)) + if (match_selector(sel->right, node)) + return 1; + parent = fz_xml_up(parent); + } + return 0; + } + + /* child */ + if (sel->combine == '>') + { + fz_xml *parent = fz_xml_up(node); + if (!parent) + return 0; + if (!match_selector(sel->left, parent)) + return 0; + if (!match_selector(sel->right, node)) + return 0; + } + + /* adjacent */ + if (sel->combine == '+') + { + fz_xml *prev = fz_xml_prev(node); + while (prev && !fz_xml_tag(prev) && fz_xml_prev(prev)) + prev = fz_xml_prev(prev); + if (!prev) + return 0; + if (!fz_xml_tag(prev)) + return 0; + if (!match_selector(sel->left, prev)) + return 0; + if (!match_selector(sel->right, node)) + return 0; + } + } + + if (sel->name) + { + if (strcmp(sel->name, fz_xml_tag(node))) + return 0; + } + + if (sel->cond) + { + if (!match_condition(sel->cond, node)) + return 0; + } + + return 1; +} + +/* + * Annotating nodes with properties and expanding shorthand forms. + */ + +static int +count_values(struct value *value) +{ + int n = 0; + while (value) + { + n++; + value = value->next; + } + return n; +} + +static void +add_shorthand_margin(struct style *style, struct value *value, int spec) +{ + int n = count_values(value); + + if (n == 1) + { + add_property(style, "margin-top", value, spec); + add_property(style, "margin-right", value, spec); + add_property(style, "margin-bottom", value, spec); + add_property(style, "margin-left", value, spec); + } + + if (n == 2) + { + struct value *a = new_value(value->type, value->data); + struct value *b = new_value(value->next->type, value->next->data); + + add_property(style, "margin-top", a, spec); + add_property(style, "margin-right", b, spec); + add_property(style, "margin-bottom", a, spec); + add_property(style, "margin-left", b, spec); + } + + if (n == 3) + { + struct value *a = new_value(value->type, value->data); + struct value *b = new_value(value->next->type, value->next->data); + struct value *c = new_value(value->next->next->type, value->next->next->data); + + add_property(style, "margin-top", a, spec); + add_property(style, "margin-right", b, spec); + add_property(style, "margin-bottom", c, spec); + add_property(style, "margin-left", b, spec); + } + + if (n == 4) + { + struct value *a = new_value(value->type, value->data); + struct value *b = new_value(value->next->type, value->next->data); + struct value *c = new_value(value->next->next->type, value->next->next->data); + struct value *d = new_value(value->next->next->next->type, value->next->next->next->data); + + add_property(style, "margin-top", a, spec); + add_property(style, "margin-right", b, spec); + add_property(style, "margin-bottom", c, spec); + add_property(style, "margin-left", d, spec); + } +} + +static void +add_shorthand_padding(struct style *style, struct value *value, int spec) +{ + int n = count_values(value); + + if (n == 1) + { + add_property(style, "padding-top", value, spec); + add_property(style, "padding-right", value, spec); + add_property(style, "padding-bottom", value, spec); + add_property(style, "padding-left", value, spec); + } + + if (n == 2) + { + struct value *a = new_value(value->type, value->data); + struct value *b = new_value(value->next->type, value->next->data); + + add_property(style, "padding-top", a, spec); + add_property(style, "padding-right", b, spec); + add_property(style, "padding-bottom", a, spec); + add_property(style, "padding-left", b, spec); + } + + if (n == 3) + { + struct value *a = new_value(value->type, value->data); + struct value *b = new_value(value->next->type, value->next->data); + struct value *c = new_value(value->next->next->type, value->next->next->data); + + add_property(style, "padding-top", a, spec); + add_property(style, "padding-right", b, spec); + add_property(style, "padding-bottom", c, spec); + add_property(style, "padding-left", b, spec); + } + + if (n == 4) + { + struct value *a = new_value(value->type, value->data); + struct value *b = new_value(value->next->type, value->next->data); + struct value *c = new_value(value->next->next->type, value->next->next->data); + struct value *d = new_value(value->next->next->next->type, value->next->next->next->data); + + add_property(style, "padding-top", a, spec); + add_property(style, "padding-right", b, spec); + add_property(style, "padding-bottom", c, spec); + add_property(style, "padding-left", d, spec); + } +} + +static void +add_shorthand_border_width(struct style *style, struct value *value, int spec) +{ + int n = count_values(value); + + if (n == 1) + { + add_property(style, "border-top-width", value, spec); + add_property(style, "border-right-width", value, spec); + add_property(style, "border-bottom-width", value, spec); + add_property(style, "border-left-width", value, spec); + } + + if (n == 2) + { + struct value *a = new_value(value->type, value->data); + struct value *b = new_value(value->next->type, value->next->data); + + add_property(style, "border-top-width", a, spec); + add_property(style, "border-right-width", b, spec); + add_property(style, "border-bottom-width", a, spec); + add_property(style, "border-left-width", b, spec); + } + + if (n == 3) + { + struct value *a = new_value(value->type, value->data); + struct value *b = new_value(value->next->type, value->next->data); + struct value *c = new_value(value->next->next->type, value->next->next->data); + + add_property(style, "border-top-width", a, spec); + add_property(style, "border-right-width", b, spec); + add_property(style, "border-bottom-width", c, spec); + add_property(style, "border-left-width", b, spec); + } + + if (n == 4) + { + struct value *a = new_value(value->type, value->data); + struct value *b = new_value(value->next->type, value->next->data); + struct value *c = new_value(value->next->next->type, value->next->next->data); + struct value *d = new_value(value->next->next->next->type, value->next->next->next->data); + + add_property(style, "border-top-width", a, spec); + add_property(style, "border-right-width", b, spec); + add_property(style, "border-bottom-width", c, spec); + add_property(style, "border-left-width", d, spec); + } +} + +static void +add_property(struct style *style, const char *name, struct value *value, int spec) +{ + int i; + + if (!strcmp(name, "margin")) + { + add_shorthand_margin(style, value, spec); + return; + } + if (!strcmp(name, "padding")) + { + add_shorthand_padding(style, value, spec); + return; + } + if (!strcmp(name, "border-width")) + { + add_shorthand_border_width(style, value, spec); + return; + } + + /* TODO: border-color */ + /* TODO: border-style */ + /* TODO: border */ + /* TODO: font */ + /* TODO: list-style */ + /* TODO: background */ + + for (i = 0; i < style->count; ++i) + { + if (!strcmp(style->prop[i].name, name)) + { + if (style->prop[i].spec <= spec) + { + style->prop[i].value = value; + style->prop[i].spec = spec; + } + return; + } + } + + if (style->count + 1 >= nelem(style->prop)) + { + // fz_warn(ctx, "too many css properties"); + return; + } + + style->prop[style->count].name = name; + style->prop[style->count].value = value; + style->prop[style->count].spec = spec; + ++style->count; +} + +void +apply_styles(struct rule *rule, struct style *style, fz_xml *node) +{ + struct selector *sel; + struct property *prop; + + while (rule) + { + sel = rule->selector; + while (sel) + { + if (match_selector(sel, node)) + { + for (prop = rule->declaration; prop; prop = prop->next) + add_property(style, prop->name, prop->value, selector_specificity(sel)); + break; + } + sel = sel->next; + } + rule = rule->next; + } +} + +static const char *inherit_list[] = { + "color", "direction", + "font-family", "font-size", "font-style", "font-variant", "font-weight", + "letter-spacing", "line-height", + "list-style-image", "list-style-position", "list-style-type", + "orphans", "quotes", "text-align", "text-indent", "text-transform", + "visibility", "white-space", "widows", "word-spacing", + + /* this is not supposed to be inherited: */ + "vertical-align", +}; + +static struct value * +get_raw_property(struct style *node, const char *name) +{ + int i; + for (i = 0; i < node->count; ++i) + if (!strcmp(node->prop[i].name, name)) + return node->prop[i].value; + return NULL; +} + +static int +should_inherit_property(const char *name) +{ + int l = 0; + int r = nelem(inherit_list) - 1; + while (l <= r) + { + int m = (l + r) >> 1; + int c = strcmp(name, inherit_list[m]); + if (c < 0) + r = m - 1; + else if (c > 0) + l = m + 1; + else + return 1; + } + return 0; +} + +static struct value * +get_style_property(struct style *node, const char *name) +{ + struct value *value; + + value = get_raw_property(node, name); + if (node->up) + { + if (value && !strcmp(value->data, "inherit")) + return get_style_property(node->up, name); + if (!value && should_inherit_property(name)) + return get_style_property(node->up, name); + } + return value; +} + +static const char * +get_style_property_string(struct style *node, const char *name, const char *initial) +{ + struct value *value; + value = get_style_property(node, name); + if (!value) + return initial; + return value->data; +} + +static int +compute_number(struct value *value, int em, int hundred, int scale, int initial) +{ + char *p; + + if (!value) + return initial; + + if (value->type == CSS_PERCENT) + return strtof(value->data, &p) * hundred / 100; + + if (value->type == CSS_NUMBER) + return strtof(value->data, &p) * scale; + + if (value->type == CSS_LENGTH) + { + float x = strtof(value->data, &p); + + if (p[0] == 'e' && p[1] == 'm') + return x * em; + if (p[0] == 'e' && p[1] == 'x') + return x * em / 2; + + if (p[0] == 'i' && p[1] == 'n') + return x * 72; + if (p[0] == 'c' && p[1] == 'm') + return x * 72 / 2.54; + if (p[0] == 'm' && p[1] == 'm') + return x * 72 / 25.4; + if (p[0] == 'p' && p[1] == 'c') + return x * 12; + + if (p[0] == 'p' && p[1] == 't') + return x; + if (p[0] == 'p' && p[1] == 'x') + return x; + + return x; + } + + return initial; +} + +void +compute_style(struct computed_style *style, struct style *node) +{ + struct value *value; + int em = 12; + int hundred = 100; + + memset(style, 0, sizeof *style); + + style->display = INLINE; + style->position = STATIC; + style->text_align = LEFT; + style->font_size = 12; + + value = get_style_property(node, "display"); + if (value) + { + if (!strcmp(value->data, "none")) + style->display = NONE; + if (!strcmp(value->data, "inline")) + style->display = INLINE; + if (!strcmp(value->data, "block")) + style->display = BLOCK; + if (!strcmp(value->data, "list-item")) + style->display = LIST_ITEM; + } + + value = get_style_property(node, "position"); + if (value) + { + if (!strcmp(value->data, "static")) + style->position = STATIC; + if (!strcmp(value->data, "relative")) + style->position = RELATIVE; + if (!strcmp(value->data, "absolute")) + style->position = ABSOLUTE; + if (!strcmp(value->data, "fixed")) + style->position = FIXED; + } + + value = get_style_property(node, "text-align"); + if (value) + { + if (!strcmp(value->data, "left")) + style->text_align = LEFT; + if (!strcmp(value->data, "right")) + style->text_align = RIGHT; + if (!strcmp(value->data, "center")) + style->text_align = CENTER; + if (!strcmp(value->data, "justify")) + style->text_align = JUSTIFY; + } + + value = get_style_property(node, "vertical-align"); + if (value) + { + if (!strcmp(value->data, "super")) + style->vertical_align = 1; + if (!strcmp(value->data, "sub")) + style->vertical_align = -1; + } + + value = get_style_property(node, "font-size"); + if (value) { + if (!strcmp(value->data, "xx-large")) style->font_size = 20; + else if (!strcmp(value->data, "x-large")) style->font_size = 16; + else if (!strcmp(value->data, "large")) style->font_size = 14; + else if (!strcmp(value->data, "medium")) style->font_size = 12; + else if (!strcmp(value->data, "small")) style->font_size = 10; + else if (!strcmp(value->data, "x-small")) style->font_size = 8; + else if (!strcmp(value->data, "xx-small")) style->font_size = 6; + else if (!strcmp(value->data, "larger")) style->font_size = em + 2; + else if (!strcmp(value->data, "smaller")) style->font_size = em - 2; + else style->font_size = compute_number(value, em, em, 1, 12); + } else { + style->font_size = 12; + } + em = style->font_size; + + value = get_style_property(node, "line-height"); + style->line_height = compute_number(value, em, em, em, 1.2 * em); + + value = get_style_property(node, "text-indent"); + style->text_indent = compute_number(value, em, hundred, 1, 0); + + value = get_style_property(node, "margin-top"); + style->margin[0] = compute_number(value, em, hundred, 1, 0); + value = get_style_property(node, "margin-right"); + style->margin[1] = compute_number(value, em, hundred, 1, 0); + value = get_style_property(node, "margin-bottom"); + style->margin[2] = compute_number(value, em, hundred, 1, 0); + value = get_style_property(node, "margin-left"); + style->margin[3] = compute_number(value, em, hundred, 1, 0); + + value = get_style_property(node, "padding-top"); + style->padding[0] = compute_number(value, em, hundred, 1, 0); + value = get_style_property(node, "padding-right"); + style->padding[1] = compute_number(value, em, hundred, 1, 0); + value = get_style_property(node, "padding-bottom"); + style->padding[2] = compute_number(value, em, hundred, 1, 0); + value = get_style_property(node, "padding-left"); + style->padding[3] = compute_number(value, em, hundred, 1, 0); + + { + const char *font_family = get_style_property_string(node, "font-family", "serif"); + const char *font_variant = get_style_property_string(node, "font-variant", "normal"); + const char *font_style = get_style_property_string(node, "font-style", "normal"); + const char *font_weight = get_style_property_string(node, "font-weight", "normal"); + + style->font_family = font_family; + + style->smallcaps = 0; + if (!strcmp(font_variant, "small-caps")) + style->smallcaps = 1; + + style->italic = 0; + if (!strcmp(font_style, "italic") || !strcmp(font_style, "oblique")) + style->italic = 1; + + style->bold = 0; + if (!strcmp(font_weight, "bold") || !strcmp(font_weight, "bolder") || atoi(font_weight) > 400) + style->bold = 1; + } +} + +void +print_style(struct computed_style *style) +{ + printf("style {\n"); + printf("\tdisplay = %d;\n", style->display); + printf("\tposition = %d;\n", style->position); + printf("\ttext-align = %d;\n", style->text_align); + printf("\tfont-family = %s;\n", style->font_family); + printf("\tfont-weight = %s;\n", style->bold ? "bold" : "normal"); + printf("\tfont-style = %s;\n", style->italic ? "italic" : "normal"); + printf("\tfont-variant = %s;\n", style->smallcaps ? "small-caps" : "normal"); + printf("\tfont-size = %d;\n", style->font_size); + printf("\tline-height = %d;\n", style->line_height); + printf("\ttext-indent = %d;\n", style->text_indent); + printf("\tvertical-align = %d;\n", style->vertical_align); + printf("\tmargin = %d %d %d %d;\n", + style->margin[0], style->margin[1], style->margin[2], style->margin[3]); + printf("\tpadding = %d %d %d %d;\n", + style->padding[0], style->padding[1], style->padding[2], style->padding[3]); + printf("}\n"); +} diff --git a/source/html/css-parse.c b/source/html/css-parse.c new file mode 100644 index 00000000..5f7fd254 --- /dev/null +++ b/source/html/css-parse.c @@ -0,0 +1,734 @@ +#include "mupdf/fitz.h" +#include "mupdf/html.h" + +struct lexbuf +{ + fz_context *ctx; + const char *s; + int lookahead; + int c; + int color; + int string_len; + char string[1024]; +}; + +static void css_lex_next(struct lexbuf *buf) +{ + // buf->s += fz_chartorune(&buf->c, buf->s); + buf->c = *(buf->s++); +} + +static void css_lex_init(fz_context *ctx, struct lexbuf *buf, const char *s) +{ + buf->ctx = ctx; + buf->s = s; + buf->c = 0; + css_lex_next(buf); + + buf->color = 0; + buf->string_len = 0; +} + +static int iswhite(int c) +{ + return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f'; +} + +static int isnmstart(int c) +{ + return c == '\\' || c == '_' || (c >= 'a' && c <= 'z') || + (c >= 128 && c <= 255); +} + +static int isnmchar(int c) +{ + return c == '\\' || c == '_' || (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || c == '-' || (c >= 128 && c <= 255); +} + +static void css_push_char(struct lexbuf *buf, int c) +{ + if (buf->string_len + 1 >= nelem(buf->string)) + fz_throw(buf->ctx, FZ_ERROR_GENERIC, "token too long"); + buf->string[buf->string_len++] = c; +} + +static int css_lex_accept(struct lexbuf *buf, int t) +{ + if (buf->c == t) + { + css_lex_next(buf); + return 1; + } + return 0; +} + +static void css_lex_expect(struct lexbuf *buf, int t) +{ + if (!css_lex_accept(buf, t)) + fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected '%c'", t); +} + +static int ishex(int c, int *v) +{ + if (c >= '0' && c <= '9') + { + *v = c - '0'; + return 1; + } + if (c >= 'A' && c <= 'F') + { + *v = c - 'A' + 0xA; + return 1; + } + if (c >= 'a' && c <= 'f') + { + *v = c - 'a' + 0xA; + return 1; + } + return 0; +} + +static int css_lex_accept_hex(struct lexbuf *buf, int *v) +{ + if (ishex(buf->c, v)) + { + css_lex_next(buf); + return 1; + } + return 0; +} + +static int css_lex_number(struct lexbuf *buf) +{ + while (buf->c >= '0' && buf->c <= '9') + { + css_push_char(buf, buf->c); + css_lex_next(buf); + } + + if (css_lex_accept(buf, '.')) + { + css_push_char(buf, '.'); + while (buf->c >= '0' && buf->c <= '9') + { + css_push_char(buf, buf->c); + css_lex_next(buf); + } + } + + if (css_lex_accept(buf, '%')) + { + css_push_char(buf, '%'); + css_push_char(buf, 0); + return CSS_PERCENT; + } + + if (isnmstart(buf->c)) + { + css_push_char(buf, buf->c); + css_lex_next(buf); + while (isnmchar(buf->c)) + { + css_push_char(buf, buf->c); + css_lex_next(buf); + } + css_push_char(buf, 0); + return CSS_LENGTH; + } + + css_push_char(buf, 0); + return CSS_NUMBER; +} + +static int css_lex_keyword(struct lexbuf *buf) +{ + while (isnmchar(buf->c)) + { + css_push_char(buf, buf->c); + css_lex_next(buf); + } + css_push_char(buf, 0); + return CSS_KEYWORD; +} + +static int css_lex_string(struct lexbuf *buf, int q) +{ + while (buf->c && buf->c != q) + { + if (css_lex_accept(buf, '\\')) + { + if (css_lex_accept(buf, 'n')) + css_push_char(buf, '\n'); + else if (css_lex_accept(buf, 'r')) + css_push_char(buf, '\r'); + else if (css_lex_accept(buf, 'f')) + css_push_char(buf, '\f'); + else if (css_lex_accept(buf, '\f')) + /* line continuation */ ; + else if (css_lex_accept(buf, '\n')) + /* line continuation */ ; + else if (css_lex_accept(buf, '\r')) + css_lex_accept(buf, '\n'); + else + { + css_push_char(buf, buf->c); + css_lex_next(buf); + } + } + else + { + css_push_char(buf, buf->c); + css_lex_next(buf); + } + } + css_lex_expect(buf, q); + css_push_char(buf, 0); + return CSS_STRING; +} + +static int css_lex(struct lexbuf *buf) +{ + int t; + + // TODO: keyword escape sequences + + buf->string_len = 0; + + while (buf->c) + { + while (iswhite(buf->c)) + css_lex_next(buf); + + if (buf->c == 0) + break; + + if (css_lex_accept(buf, '/')) + { + if (css_lex_accept(buf, '*')) + { + while (buf->c) + { + if (css_lex_accept(buf, '*')) + { + while (buf->c == '*') + css_lex_next(buf); + if (css_lex_accept(buf, '/')) + continue; + } + css_lex_next(buf); + } + fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: unterminated comment"); + } + return '/'; + } + + if (css_lex_accept(buf, '<')) + { + if (css_lex_accept(buf, '!')) + { + css_lex_expect(buf, '-'); + css_lex_expect(buf, '-'); + continue; /* ignore CDO */ + } + return '<'; + } + + if (css_lex_accept(buf, '-')) + { + if (css_lex_accept(buf, '-')) + { + css_lex_expect(buf, '>'); + continue; /* ignore CDC */ + } + if (buf->c >= '0' && buf->c <= '9') + { + css_push_char(buf, '-'); + return css_lex_number(buf); + } + if (isnmstart(buf->c)) + { + css_push_char(buf, '-'); + css_push_char(buf, buf->c); + css_lex_next(buf); + return css_lex_keyword(buf); + } + return '-'; + } + + if (css_lex_accept(buf, '.')) + { + if (buf->c >= '0' && buf->c <= '9') + { + css_push_char(buf, '.'); + return css_lex_number(buf); + } + return '.'; + } + + if (css_lex_accept(buf, '#')) + { + int a, b, c, d, e, f; + if (!css_lex_accept_hex(buf, &a)) goto colorerror; + if (!css_lex_accept_hex(buf, &b)) goto colorerror; + if (!css_lex_accept_hex(buf, &c)) goto colorerror; + if (css_lex_accept_hex(buf, &d)) + { + if (!css_lex_accept_hex(buf, &e)) goto colorerror; + if (!css_lex_accept_hex(buf, &f)) goto colorerror; + buf->color = (a << 20) | (b << 16) | (c << 12) | (d << 8) | (e << 4) | f; + } + else + { + buf->color = (a << 20) | (b << 12) | (c << 4); + } + sprintf(buf->string, "%06x", buf->color); // XXX + return CSS_COLOR; +colorerror: + fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error in color"); + } + + if (css_lex_accept(buf, '"')) + return css_lex_string(buf, '"'); + if (css_lex_accept(buf, '\'')) + return css_lex_string(buf, '\''); + + if (buf->c >= '0' && buf->c <= '9') + return css_lex_number(buf); + + if (css_lex_accept(buf, 'u')) + { + if (css_lex_accept(buf, 'r')) + { + if (css_lex_accept(buf, 'l')) + { + if (css_lex_accept(buf, '(')) + { + // string or url + css_lex_expect(buf, ')'); + return CSS_URI; + } + css_push_char(buf, 'u'); + css_push_char(buf, 'r'); + css_push_char(buf, 'l'); + return css_lex_keyword(buf); + } + css_push_char(buf, 'u'); + css_push_char(buf, 'r'); + return css_lex_keyword(buf); + } + css_push_char(buf, 'u'); + return css_lex_keyword(buf); + } + + if (isnmstart(buf->c)) + { + css_push_char(buf, buf->c); + css_lex_next(buf); + return css_lex_keyword(buf); + } + + t = buf->c; + css_lex_next(buf); + return t; + } + return EOF; +} + +static void next(struct lexbuf *buf) +{ + buf->lookahead = css_lex(buf); +} + +static int accept(struct lexbuf *buf, int t) +{ + if (buf->lookahead == t) + { + next(buf); + return 1; + } + return 0; +} + +static void expect(struct lexbuf *buf, int t) +{ + if (accept(buf, t)) + return; + if (t < 256) + fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected '%c'", t); + else + fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: unexpected token"); +} + +static int iscond(int t) +{ + return t == ':' || t == '.' || t == '#' || t == '['; +} + +static struct value *parse_value_list(struct lexbuf *buf); + +static struct value *parse_value(struct lexbuf *buf) +{ + struct value *v; + + if (buf->lookahead == CSS_KEYWORD) + { + v = new_value(CSS_KEYWORD, buf->string); + next(buf); + + if (accept(buf, '(')) + { + v->type = '('; + v->args = parse_value_list(buf); + expect(buf, ')'); + } + + return v; + } + + switch (buf->lookahead) + { + case CSS_NUMBER: + case CSS_LENGTH: + case CSS_PERCENT: + case CSS_STRING: + case CSS_COLOR: + case CSS_URI: + v = new_value(buf->lookahead, buf->string); + next(buf); + return v; + } + + if (accept(buf, ',')) + return new_value(',', ","); + if (accept(buf, '/')) + return new_value('/', "/"); + + fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected value"); +} + +static struct value *parse_value_list(struct lexbuf *buf) +{ + struct value *v, *vv; + + vv = NULL; + + while (buf->lookahead != '}' && buf->lookahead != ';' && buf->lookahead != '!' && + buf->lookahead != ')' && buf->lookahead != EOF) + { + v = parse_value(buf); + v->next = vv; + vv = v; + } + + return vv; +} + +static struct property *parse_declaration(struct lexbuf *buf) +{ + struct property *p; + + if (buf->lookahead != CSS_KEYWORD) + fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected keyword in property"); + p = new_property(buf->string, NULL, 0); + next(buf); + + expect(buf, ':'); + + p->value = parse_value_list(buf); + + /* !important */ + if (accept(buf, '!')) + expect(buf, CSS_KEYWORD); + + return p; +} + +static struct property *parse_declaration_list(struct lexbuf *buf) +{ + struct property *p, *pp; + + if (buf->lookahead == '}') + return NULL; + + pp = parse_declaration(buf); + + while (accept(buf, ';')) + { + if (buf->lookahead != '}' && buf->lookahead != ';') + { + p = parse_declaration(buf); + p->next = pp; + pp = p; + } + } + + return pp; +} + +static const char *parse_attrib_value(struct lexbuf *buf) +{ + const char *s; + + if (buf->lookahead == CSS_KEYWORD || buf->lookahead == CSS_STRING) + { + s = strdup(buf->string); + next(buf); + return s; + } + + fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected attribute value"); +} + +static struct condition *parse_condition(struct lexbuf *buf) +{ + struct condition *c; + + if (accept(buf, ':')) + { + if (buf->lookahead != CSS_KEYWORD) + fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected keyword after ':'"); + c = new_condition(':', "pseudo", buf->string); + next(buf); + return c; + } + + if (accept(buf, '.')) + { + if (buf->lookahead != CSS_KEYWORD) + fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected keyword after '.'"); + c = new_condition('.', "class", buf->string); + next(buf); + return c; + } + + if (accept(buf, '#')) + { + if (buf->lookahead != CSS_KEYWORD) + fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected keyword after '#'"); + c = new_condition('#', "id", buf->string); + next(buf); + return c; + } + + if (accept(buf, '[')) + { + if (buf->lookahead != CSS_KEYWORD) + fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected keyword after '['"); + + c = new_condition('[', buf->string, NULL); + next(buf); + + if (accept(buf, '=')) + { + c->type = '='; + c->val = parse_attrib_value(buf); + } + else if (accept(buf, '|')) + { + expect(buf, '='); + c->type = '|'; + c->val = parse_attrib_value(buf); + } + else if (accept(buf, '~')) + { + expect(buf, '='); + c->type = '~'; + c->val = parse_attrib_value(buf); + } + + expect(buf, ']'); + + return c; + } + + fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected condition"); +} + +static struct condition *parse_condition_list(struct lexbuf *buf) +{ + struct condition *c, *cc; + + cc = parse_condition(buf); + while (iscond(buf->lookahead)) + { + c = parse_condition(buf); + c->next = cc; + cc = c; + } + return cc; +} + +static struct selector *parse_simple_selector(struct lexbuf *buf) +{ + struct selector *s; + + if (accept(buf, '*')) + { + s = new_selector(NULL); + if (iscond(buf->lookahead)) + s->cond = parse_condition_list(buf); + return s; + } + else if (buf->lookahead == CSS_KEYWORD) + { + s = new_selector(buf->string); + next(buf); + if (iscond(buf->lookahead)) + s->cond = parse_condition_list(buf); + return s; + } + else if (iscond(buf->lookahead)) + { + s = new_selector(NULL); + s->cond = parse_condition_list(buf); + return s; + } + + fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected selector"); +} + +static struct selector *parse_adjacent_selector(struct lexbuf *buf) +{ + struct selector *s, *a, *b; + + a = parse_simple_selector(buf); + if (accept(buf, '+')) + { + b = parse_adjacent_selector(buf); + s = new_selector(NULL); + s->combine = '>'; + s->left = a; + s->right = b; + return s; + } + return a; +} + +static struct selector *parse_child_selector(struct lexbuf *buf) +{ + struct selector *s, *a, *b; + + a = parse_adjacent_selector(buf); + if (accept(buf, '>')) + { + b = parse_child_selector(buf); + s = new_selector(NULL); + s->combine = '>'; + s->left = a; + s->right = b; + return s; + } + return a; +} + +static struct selector *parse_descendant_selector(struct lexbuf *buf) +{ + struct selector *s, *a, *b; + + a = parse_child_selector(buf); + if (buf->lookahead != ',' && buf->lookahead != '{' && buf->lookahead != EOF) + { + b = parse_descendant_selector(buf); + s = new_selector(NULL); + s->combine = ' '; + s->left = a; + s->right = b; + return s; + } + return a; +} + +static struct selector *parse_selector_list(struct lexbuf *buf) +{ + struct selector *s, *ss; + + ss = parse_descendant_selector(buf); + while (accept(buf, ',')) + { + s = parse_descendant_selector(buf); + s->next = ss; + ss = s; + } + return ss; +} + +static struct rule *parse_rule(struct lexbuf *buf) +{ + struct selector *s; + struct property *p; + + s = parse_selector_list(buf); + expect(buf, '{'); + p = parse_declaration_list(buf); + expect(buf, '}'); + return new_rule(s, p); +} + +static void parse_media_list(struct lexbuf *buf) +{ + struct rule *r; + + while (buf->lookahead != '}' && buf->lookahead != EOF) + { + r = parse_rule(buf); + // TODO: free_rule(r); + } +} + +static void parse_at_rule(struct lexbuf *buf) +{ + struct property *p; + struct value *v; + + expect(buf, CSS_KEYWORD); + if (accept(buf, '{')) /* @page */ + { + p = parse_declaration_list(buf); + // TODO: free_properties(p); + expect(buf, '}'); + } + else + { + v = parse_value_list(buf); + // TODO: free_value_list(v); + if (accept(buf, '{')) /* @media */ + { + parse_media_list(buf); + expect(buf, '}'); + } + else /* @import */ + { + expect(buf, ';'); + } + } +} + +static struct rule *parse_stylesheet(struct lexbuf *buf, struct rule *chain) +{ + struct rule *r; + + while (buf->lookahead != EOF) + { + if (accept(buf, '@')) + { + parse_at_rule(buf); + } + else + { + r = parse_rule(buf); + r->next = chain; + chain = r; + } + } + + return chain; +} + +struct rule *fz_parse_css(fz_context *ctx, struct rule *chain, const char *source) +{ + struct lexbuf buf; + css_lex_init(ctx, &buf, source); + next(&buf); + return parse_stylesheet(&buf, chain); +} diff --git a/source/html/handler.c b/source/html/handler.c index 39d5e9c9..77b362d3 100644 --- a/source/html/handler.c +++ b/source/html/handler.c @@ -1,12 +1,5 @@ #include "mupdf/html.h" -struct html_document_s -{ - fz_document super; - fz_context *ctx; - fz_xml *root; -}; - struct html_page_s { }; @@ -28,7 +21,7 @@ html_page * html_load_page(html_document *doc, int number) { printf("html: load page %d\n", number); - return NULL; + return "nothing"; } void @@ -74,6 +67,8 @@ html_open_document_with_stream(fz_context *ctx, fz_stream *file) doc->super.run_page_contents = (void*)html_run_page; doc->super.free_page = (void*)html_free_page; + html_layout_document(doc, 400, 600); + return doc; } diff --git a/source/html/layout.c b/source/html/layout.c new file mode 100644 index 00000000..91e20b9f --- /dev/null +++ b/source/html/layout.c @@ -0,0 +1,153 @@ +#include "mupdf/html.h" + +static const char *default_css = +"html,address,blockquote,body,dd,div,dl,dt,h1,h2,h3,h4,h5,h6,ol,p,ul,center,hr,pre{display:block}" +"span{display:inline}" +"li{display:list-item}" +"head{display:none}" +"body{margin:0px}" +"h1{font-size:2em;margin:.67em 0}" +"h2{font-size:1.5em;margin:.75em 0}" +"h3{font-size:1.17em;margin:.83em 0}" +"h4,p,blockquote,ul,ol,dl,dir,menu{margin:1.12em 0}" +"h5{font-size:.83em;margin:1.5em 0}" +"h6{font-size:.75em;margin:1.67em 0}" +"h1,h2,h3,h4,h5,h6,b,strong{font-weight:bold}" +"blockquote{margin-left:40px;margin-right:40px}" +"i,cite,em,var,address{font-style:italic}" +"pre,tt,code,kbd,samp{font-family:monospace}" +"pre{white-space:pre}" +"big{font-size:1.17em}" +"small,sub,sup{font-size:.83em}" +"sub{vertical-align:sub}" +"sup{vertical-align:super}" +"s,strike,del{text-decoration:line-through}" +"hr{border:1pxinset}" +"ol,ul,dir,menu,dd{margin-left:40px}" +"ol{list-style-type:decimal}" +"ol ul,ul ol,ul ul,ol ol{margin-top:0;margin-bottom:0}" +"u,ins{text-decoration:underline}" +"center{text-align:center}" +"svg{display:none}"; + +char dirname[2048]; +char filename[2048]; + +static char *concat_text(fz_xml *root) +{ + fz_xml *node; + int i = 0, n = 1; + char *s; + for (node = fz_xml_down(root); node; node = fz_xml_next(node)) + { + const char *text = fz_xml_text(node); + n += text ? strlen(text) : 0; + } + s = malloc(n); + for (node = fz_xml_down(root); node; node = fz_xml_next(node)) + { + const char *text = fz_xml_text(node); + if (text) { + n = strlen(text); + memcpy(s+i, text, n); + i += n; + } + } + s[i] = 0; + return s; +} + +static struct rule *load_css(fz_context *ctx, struct rule *css, fz_xml *root) +{ + fz_xml *node; + for (node = root; node; node = fz_xml_next(node)) { + const char *tag = fz_xml_tag(node); +#if 0 + if (tag && !strcmp(tag, "link")) { + char *rel = fz_xml_att(node, "rel"); + if (rel && !strcasecmp(rel, "stylesheet")) { + char *type = fz_xml_att(node, "type"); + if ((type && !strcmp(type, "text/css")) || !type) { + char *href = fz_xml_att(node, "href"); + strcpy(filename, dirname); + strcat(filename, href); + css = css_parse_file(css, filename); + } + } + } +#endif + if (tag && !strcmp(tag, "style")) { +printf("found inline style sheet!\n"); + char *s = concat_text(node); +printf("'%s'\n", s); + css = fz_parse_css(ctx, css, s); + } + if (fz_xml_down(node)) + css = load_css(ctx, css, fz_xml_down(node)); + } + return css; +} + +static void layout_text(struct rule *rule, struct style *style, fz_xml *node) +{ + printf("%s\n", fz_xml_text(node)); +} + +static void layout_tree(struct rule *rule, struct style *up, fz_xml *node) +{ + while (node) + { + struct style style; + style.up = up; + style.count = 0; + + if (fz_xml_tag(node)) + { + printf("open '%s'\n", fz_xml_tag(node)); + struct computed_style cstyle; + apply_styles(rule, &style, node); + + // TODO: check inline style attribute! + //s = fz_xml_att(node, "style"); + //if (s) { + // istyle = parse_declarations(s); + // apply_styles(istyle); + //} + + compute_style(&cstyle, &style); + print_style(&cstyle); + } + else + layout_text(rule, &style, node); + + // TOOD:
+ // TODO: + + if (fz_xml_down(node)) + layout_tree(rule, &style, fz_xml_down(node)); + + printf("end\n"); + node = fz_xml_next(node); + } +} + +void +html_layout_document(html_document *doc, float w, float h) +{ + struct rule *css = NULL; + +#if 0 + strcpy(dirname, argv[i]); + s = strrchr(dirname, '/'); + if (!s) s = strrchr(dirname, '\\'); + if (s) s[1] = 0; + else strcpy(dirname, "./"); +#endif + + css = fz_parse_css(doc->ctx, NULL, default_css); + css = load_css(doc->ctx, css, doc->root); + + print_rules(css); + + layout_tree(css, NULL, doc->root); +} -- cgit v1.2.3 From 5cb1a29be4993d72cf6ab2af128135e2b7e40dd2 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Mon, 13 Oct 2014 16:16:28 +0200 Subject: html: Parse inline style attributes. --- source/html/css-apply.c | 14 +++++++++++++- source/html/css-parse.c | 12 ++++++++++-- source/html/handler.c | 2 +- source/html/layout.c | 25 ++++++++++++++----------- 4 files changed, 38 insertions(+), 15 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 7f3028a9..550ade85 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -156,6 +156,8 @@ count_selector_names(struct selector *sel) return n; } +#define INLINE_SPECIFICITY 1000 + int selector_specificity(struct selector *sel) { @@ -595,7 +597,7 @@ add_property(struct style *style, const char *name, struct value *value, int spe } void -apply_styles(struct rule *rule, struct style *style, fz_xml *node) +apply_styles(struct style *style, struct rule *rule, fz_xml *node) { struct selector *sel; struct property *prop; @@ -617,6 +619,16 @@ apply_styles(struct rule *rule, struct style *style, fz_xml *node) } } +void +apply_inline_style(struct style *style, struct property *prop) +{ + while (prop) + { + add_property(style, prop->name, prop->value, INLINE_SPECIFICITY); + prop = prop->next; + } +} + static const char *inherit_list[] = { "color", "direction", "font-family", "font-size", "font-style", "font-variant", "font-weight", diff --git a/source/html/css-parse.c b/source/html/css-parse.c index 5f7fd254..4ceb10b5 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -448,14 +448,14 @@ static struct property *parse_declaration_list(struct lexbuf *buf) { struct property *p, *pp; - if (buf->lookahead == '}') + if (buf->lookahead == '}' || buf->lookahead == EOF) return NULL; pp = parse_declaration(buf); while (accept(buf, ';')) { - if (buf->lookahead != '}' && buf->lookahead != ';') + if (buf->lookahead != '}' && buf->lookahead != ';' && buf->lookahead != EOF) { p = parse_declaration(buf); p->next = pp; @@ -725,6 +725,14 @@ static struct rule *parse_stylesheet(struct lexbuf *buf, struct rule *chain) return chain; } +struct property *fz_parse_css_properties(fz_context *ctx, const char *source) +{ + struct lexbuf buf; + css_lex_init(ctx, &buf, source); + next(&buf); + return parse_declaration_list(&buf); +} + struct rule *fz_parse_css(fz_context *ctx, struct rule *chain, const char *source) { struct lexbuf buf; diff --git a/source/html/handler.c b/source/html/handler.c index 77b362d3..f5002437 100644 --- a/source/html/handler.c +++ b/source/html/handler.c @@ -21,7 +21,7 @@ html_page * html_load_page(html_document *doc, int number) { printf("html: load page %d\n", number); - return "nothing"; + return (html_page*)"nothing"; } void diff --git a/source/html/layout.c b/source/html/layout.c index 91e20b9f..14edc5ef 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -93,7 +93,7 @@ static void layout_text(struct rule *rule, struct style *style, fz_xml *node) printf("%s\n", fz_xml_text(node)); } -static void layout_tree(struct rule *rule, struct style *up, fz_xml *node) +static void layout_tree(fz_context *ctx, struct rule *rule, struct style *up, fz_xml *node) { while (node) { @@ -103,16 +103,19 @@ static void layout_tree(struct rule *rule, struct style *up, fz_xml *node) if (fz_xml_tag(node)) { - printf("open '%s'\n", fz_xml_tag(node)); struct computed_style cstyle; - apply_styles(rule, &style, node); + const char *s; - // TODO: check inline style attribute! - //s = fz_xml_att(node, "style"); - //if (s) { - // istyle = parse_declarations(s); - // apply_styles(istyle); - //} + printf("open '%s'\n", fz_xml_tag(node)); + apply_styles(&style, rule, node); + + s = fz_xml_att(node, "style"); + if (s) + { + struct property *props = fz_parse_css_properties(ctx, s); + apply_inline_style(&style, props); + // free props + } compute_style(&cstyle, &style); print_style(&cstyle); @@ -124,7 +127,7 @@ static void layout_tree(struct rule *rule, struct style *up, fz_xml *node) // TODO: if (fz_xml_down(node)) - layout_tree(rule, &style, fz_xml_down(node)); + layout_tree(ctx, rule, &style, fz_xml_down(node)); printf("end\n"); node = fz_xml_next(node); @@ -149,5 +152,5 @@ html_layout_document(html_document *doc, float w, float h) print_rules(css); - layout_tree(css, NULL, doc->root); + layout_tree(doc->ctx, css, NULL, doc->root); } -- cgit v1.2.3 From 1ce69ac127c823463204ad522bb7c71ac7fad27a Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 15 Oct 2014 14:43:15 +0200 Subject: html: Use float for dimensions. --- source/html/css-apply.c | 22 +++++++++++----------- source/html/layout.c | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 550ade85..d38d999e 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -696,8 +696,8 @@ get_style_property_string(struct style *node, const char *name, const char *init return value->data; } -static int -compute_number(struct value *value, int em, int hundred, int scale, int initial) +static float +compute_number(struct value *value, float em, float hundred, float scale, float initial) { char *p; @@ -722,9 +722,9 @@ compute_number(struct value *value, int em, int hundred, int scale, int initial) if (p[0] == 'i' && p[1] == 'n') return x * 72; if (p[0] == 'c' && p[1] == 'm') - return x * 72 / 2.54; + return x * 7200 / 254; if (p[0] == 'm' && p[1] == 'm') - return x * 72 / 25.4; + return x * 720 / 254; if (p[0] == 'p' && p[1] == 'c') return x * 12; @@ -743,8 +743,8 @@ void compute_style(struct computed_style *style, struct style *node) { struct value *value; - int em = 12; - int hundred = 100; + float em = 12; + float hundred = 100; memset(style, 0, sizeof *style); @@ -875,13 +875,13 @@ print_style(struct computed_style *style) printf("\tfont-weight = %s;\n", style->bold ? "bold" : "normal"); printf("\tfont-style = %s;\n", style->italic ? "italic" : "normal"); printf("\tfont-variant = %s;\n", style->smallcaps ? "small-caps" : "normal"); - printf("\tfont-size = %d;\n", style->font_size); - printf("\tline-height = %d;\n", style->line_height); - printf("\ttext-indent = %d;\n", style->text_indent); + printf("\tfont-size = %g;\n", style->font_size); + printf("\tline-height = %g;\n", style->line_height); + printf("\ttext-indent = %g;\n", style->text_indent); printf("\tvertical-align = %d;\n", style->vertical_align); - printf("\tmargin = %d %d %d %d;\n", + printf("\tmargin = %g %g %g %g;\n", style->margin[0], style->margin[1], style->margin[2], style->margin[3]); - printf("\tpadding = %d %d %d %d;\n", + printf("\tpadding = %g %g %g %g;\n", style->padding[0], style->padding[1], style->padding[2], style->padding[3]); printf("}\n"); } diff --git a/source/html/layout.c b/source/html/layout.c index 14edc5ef..372a495d 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -22,7 +22,7 @@ static const char *default_css = "sub{vertical-align:sub}" "sup{vertical-align:super}" "s,strike,del{text-decoration:line-through}" -"hr{border:1pxinset}" +"hr{border:1px inset}" "ol,ul,dir,menu,dd{margin-left:40px}" "ol{list-style-type:decimal}" "ol ul,ul ol,ul ul,ol ol{margin-top:0;margin-bottom:0}" -- cgit v1.2.3 From 4ce5833ca8e6e6f0156125a572fbc3b376e41d36 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 21 Oct 2014 16:37:29 +0200 Subject: html: Box generation. --- source/html/css-apply.c | 19 ++-- source/html/layout.c | 255 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 212 insertions(+), 62 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index d38d999e..53a46f50 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -597,10 +597,11 @@ add_property(struct style *style, const char *name, struct value *value, int spe } void -apply_styles(struct style *style, struct rule *rule, fz_xml *node) +apply_styles(fz_context *ctx, struct style *style, struct rule *rule, fz_xml *node) { struct selector *sel; struct property *prop; + const char *s; while (rule) { @@ -617,15 +618,17 @@ apply_styles(struct style *style, struct rule *rule, fz_xml *node) } rule = rule->next; } -} -void -apply_inline_style(struct style *style, struct property *prop) -{ - while (prop) + s = fz_xml_att(node, "style"); + if (s) { - add_property(style, prop->name, prop->value, INLINE_SPECIFICITY); - prop = prop->next; + prop = fz_parse_css_properties(ctx, s); + while (prop) + { + add_property(style, prop->name, prop->value, INLINE_SPECIFICITY); + prop = prop->next; + } + // TODO: free props } } diff --git a/source/html/layout.c b/source/html/layout.c index 372a495d..340b8c58 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -30,10 +30,195 @@ static const char *default_css = "center{text-align:center}" "svg{display:none}"; -char dirname[2048]; -char filename[2048]; +enum +{ + BOX_BLOCK, /* block-level: contains other block and anonymous boxes */ + BOX_ANONYMOUS, /* block-level: contains only inline boxes */ + BOX_INLINE, /* inline-level: contains only inline boxes */ +}; + +struct box +{ + int type; + + float x, y, w, h; + float padding[4]; + float border[4]; + float margin[4]; + + fz_xml *node; + const char *text; + + struct box *up, *down, *last, *next; +}; + +struct box *new_box(fz_context *ctx, struct box *root, int type, struct computed_style *cstyle, fz_xml *node) +{ + struct box *box; + int i; + + box = fz_malloc_struct(ctx, struct box); + box->type = type; + box->x = box->y = 0; + box->w = box->h = 0; + for (i = 0; i < 4; ++i) + { + box->padding[i] = cstyle->padding[i]; + box->margin[i] = cstyle->margin[i]; + box->border[i] = cstyle->border_width[i]; + } + + box->node = node; + + box->up = root; + box->last = NULL; + box->down = NULL; + box->next = NULL; + + if (root) + { + if (!root->last) + { + root->down = root->last = box; + } + else + { + root->last->next = box; + root->last = box; + } + } + + return box; +} + +static struct box *new_block_box(fz_context *ctx, struct box *box, struct computed_style *cstyle, fz_xml *node) +{ + if (box->type == BOX_BLOCK) + { + box = new_box(ctx, box, BOX_BLOCK, cstyle, node); + } + else if (box->type == BOX_ANONYMOUS) + { + fz_warn(ctx, "block-level box inside anonymous box"); + while (box->type != BOX_BLOCK) + box = box->up; + box = new_box(ctx, box, BOX_BLOCK, cstyle, node); + } + else if (box->type == BOX_INLINE) + { + fz_warn(ctx, "block-level box inside inline box"); + while (box->type != BOX_BLOCK) + box = box->up; + box = new_box(ctx, box, BOX_BLOCK, cstyle, node); + } + return box; +} + +static struct box *new_inline_box(fz_context *ctx, struct box *box, struct computed_style *cstyle, fz_xml *node) +{ + if (box->type == BOX_BLOCK) + { + if (box->last && box->last->type == BOX_ANONYMOUS) + box = box->last; + else + box = new_box(ctx, box, BOX_ANONYMOUS, cstyle, NULL); + box = new_box(ctx, box, BOX_INLINE, cstyle, node); + } + else if (box->type == BOX_ANONYMOUS) + { + box = new_box(ctx, box, BOX_INLINE, cstyle, node); + } + else if (box->type == BOX_INLINE) + { + box = new_box(ctx, box, BOX_INLINE, cstyle, node); + } + return box; +} + +static void layout_tree(fz_context *ctx, fz_xml *node, struct box *box, struct style *up_style, struct rule *rule) +{ + struct style style; + struct computed_style cstyle; + struct box *save_box; + + while (node) + { + style.up = up_style; + style.count = 0; + + if (fz_xml_tag(node)) + { + apply_styles(ctx, &style, rule, node); + compute_style(&cstyle, &style); + // print_style(&cstyle); + + // TOOD:
+ // TODO: + + if (cstyle.display != NONE) + { + save_box = box; + + if (cstyle.display == BLOCK) + { + box = new_block_box(ctx, box, &cstyle, node); + } + else if (cstyle.display == INLINE) + { + box = new_inline_box(ctx, box, &cstyle, node); + } + else + { + fz_warn(ctx, "unknown box display type"); + box = new_box(ctx, box, BOX_BLOCK, &cstyle, node); + } + + if (fz_xml_down(node)) + layout_tree(ctx, fz_xml_down(node), box, &style, rule); + + box = save_box; + } + } + else + { + compute_style(&cstyle, &style); + new_inline_box(ctx, box, &cstyle, node); + } + + node = fz_xml_next(node); + } +} + +static void indent(int level) +{ + while (level--) printf(" "); +} + +static void print_box(fz_context *ctx, struct box *box, int level) +{ + while (box) + { + indent(level); + switch (box->type) + { + case BOX_BLOCK: printf("block"); break; + case BOX_ANONYMOUS: printf("anonymous"); break; + case BOX_INLINE: printf("inline"); break; + } + if (box->node) { + const char *tag = fz_xml_tag(box->node); + const char *text = fz_xml_text(box->node); + if (tag) printf(" <%s>", tag); + if (text) printf(" \"%s\"", text); + } + printf("\n"); + if (box->down) + print_box(ctx, box->down, level + 1); + box = box->next; + } +} -static char *concat_text(fz_xml *root) +static char *concat_text(fz_context *ctx, fz_xml *root) { fz_xml *node; int i = 0, n = 1; @@ -43,7 +228,7 @@ static char *concat_text(fz_xml *root) const char *text = fz_xml_text(node); n += text ? strlen(text) : 0; } - s = malloc(n); + s = fz_malloc(ctx, n); for (node = fz_xml_down(root); node; node = fz_xml_next(node)) { const char *text = fz_xml_text(node); @@ -77,10 +262,9 @@ static struct rule *load_css(fz_context *ctx, struct rule *css, fz_xml *root) } #endif if (tag && !strcmp(tag, "style")) { -printf("found inline style sheet!\n"); - char *s = concat_text(node); -printf("'%s'\n", s); + char *s = concat_text(ctx, node); css = fz_parse_css(ctx, css, s); + fz_free(ctx, s); } if (fz_xml_down(node)) css = load_css(ctx, css, fz_xml_down(node)); @@ -88,56 +272,13 @@ printf("'%s'\n", s); return css; } -static void layout_text(struct rule *rule, struct style *style, fz_xml *node) -{ - printf("%s\n", fz_xml_text(node)); -} - -static void layout_tree(fz_context *ctx, struct rule *rule, struct style *up, fz_xml *node) -{ - while (node) - { - struct style style; - style.up = up; - style.count = 0; - - if (fz_xml_tag(node)) - { - struct computed_style cstyle; - const char *s; - - printf("open '%s'\n", fz_xml_tag(node)); - apply_styles(&style, rule, node); - - s = fz_xml_att(node, "style"); - if (s) - { - struct property *props = fz_parse_css_properties(ctx, s); - apply_inline_style(&style, props); - // free props - } - - compute_style(&cstyle, &style); - print_style(&cstyle); - } - else - layout_text(rule, &style, node); - - // TOOD:
- // TODO: - - if (fz_xml_down(node)) - layout_tree(ctx, rule, &style, fz_xml_down(node)); - - printf("end\n"); - node = fz_xml_next(node); - } -} - void html_layout_document(html_document *doc, float w, float h) { struct rule *css = NULL; + struct box *root_box; + struct style style; + struct computed_style cstyle; #if 0 strcpy(dirname, argv[i]); @@ -152,5 +293,11 @@ html_layout_document(html_document *doc, float w, float h) print_rules(css); - layout_tree(doc->ctx, css, NULL, doc->root); + style.up = NULL; + style.count = 0; + compute_style(&cstyle, &style); + root_box = new_box(doc->ctx, NULL, BOX_BLOCK, &cstyle, NULL); + + layout_tree(doc->ctx, doc->root, root_box, NULL, css); + print_box(doc->ctx, root_box, 0); } -- cgit v1.2.3 From 9890cc2bd3c6b81ebaf5f7ce236117dc08c03cee Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 22 Oct 2014 17:21:54 +0200 Subject: html: Split inline box around in-flow block boxes. --- source/html/layout.c | 54 +++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 24 deletions(-) (limited to 'source/html') diff --git a/source/html/layout.c b/source/html/layout.c index 340b8c58..c8ba17e2 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -46,6 +46,8 @@ struct box float border[4]; float margin[4]; + int bold, italic; + fz_xml *node; const char *text; @@ -66,6 +68,9 @@ struct box *new_box(fz_context *ctx, struct box *root, int type, struct computed box->padding[i] = cstyle->padding[i]; box->margin[i] = cstyle->margin[i]; box->border[i] = cstyle->border_width[i]; + + box->bold = cstyle->bold; + box->italic = cstyle->italic; } box->node = node; @@ -91,25 +96,28 @@ struct box *new_box(fz_context *ctx, struct box *root, int type, struct computed return box; } -static struct box *new_block_box(fz_context *ctx, struct box *box, struct computed_style *cstyle, fz_xml *node) +static struct box *new_block_box(fz_context *ctx, struct box **topp, struct computed_style *cstyle, fz_xml *node) { - if (box->type == BOX_BLOCK) + struct box *top = *topp; + struct box *box; + + if (top->type == BOX_BLOCK) { - box = new_box(ctx, box, BOX_BLOCK, cstyle, node); + box = new_box(ctx, top, BOX_BLOCK, cstyle, node); } - else if (box->type == BOX_ANONYMOUS) + else if (top->type == BOX_ANONYMOUS) { - fz_warn(ctx, "block-level box inside anonymous box"); - while (box->type != BOX_BLOCK) - box = box->up; - box = new_box(ctx, box, BOX_BLOCK, cstyle, node); + while (top->type != BOX_BLOCK) + top = top->up; + *topp = top; + box = new_box(ctx, top, BOX_BLOCK, cstyle, node); } - else if (box->type == BOX_INLINE) + else if (top->type == BOX_INLINE) { - fz_warn(ctx, "block-level box inside inline box"); - while (box->type != BOX_BLOCK) - box = box->up; - box = new_box(ctx, box, BOX_BLOCK, cstyle, node); + while (top->type != BOX_BLOCK) + top = top->up; + *topp = top; + box = new_box(ctx, top, BOX_BLOCK, cstyle, node); } return box; } @@ -135,11 +143,11 @@ static struct box *new_inline_box(fz_context *ctx, struct box *box, struct compu return box; } -static void layout_tree(fz_context *ctx, fz_xml *node, struct box *box, struct style *up_style, struct rule *rule) +static void layout_tree(fz_context *ctx, fz_xml *node, struct box *top, struct style *up_style, struct rule *rule) { struct style style; struct computed_style cstyle; - struct box *save_box; + struct box *box; while (node) { @@ -157,32 +165,28 @@ static void layout_tree(fz_context *ctx, fz_xml *node, struct box *box, struct s if (cstyle.display != NONE) { - save_box = box; - if (cstyle.display == BLOCK) { - box = new_block_box(ctx, box, &cstyle, node); + box = new_block_box(ctx, &top, &cstyle, node); } else if (cstyle.display == INLINE) { - box = new_inline_box(ctx, box, &cstyle, node); + box = new_inline_box(ctx, top, &cstyle, node); } else { fz_warn(ctx, "unknown box display type"); - box = new_box(ctx, box, BOX_BLOCK, &cstyle, node); + box = new_box(ctx, top, BOX_BLOCK, &cstyle, node); } if (fz_xml_down(node)) layout_tree(ctx, fz_xml_down(node), box, &style, rule); - - box = save_box; } } else { compute_style(&cstyle, &style); - new_inline_box(ctx, box, &cstyle, node); + new_inline_box(ctx, top, &cstyle, node); } node = fz_xml_next(node); @@ -210,6 +214,8 @@ static void print_box(fz_context *ctx, struct box *box, int level) const char *text = fz_xml_text(box->node); if (tag) printf(" <%s>", tag); if (text) printf(" \"%s\"", text); + if (box->bold) printf(" bold"); + if (box->italic) printf(" italic"); } printf("\n"); if (box->down) @@ -291,7 +297,7 @@ html_layout_document(html_document *doc, float w, float h) css = fz_parse_css(doc->ctx, NULL, default_css); css = load_css(doc->ctx, css, doc->root); - print_rules(css); +// print_rules(css); style.up = NULL; style.count = 0; -- cgit v1.2.3 From d79203b42621257aed8e4c02e4e6c95ec82d9243 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 22 Oct 2014 21:20:42 +0200 Subject: html: Don't compute full styles during box generation. Apply the style sheet rules and save the raw properties in each box. Only resolve the 'display' property that is needed for box generation. --- source/html/css-apply.c | 33 +++++----- source/html/layout.c | 167 ++++++++++++++++++++++++------------------------ 2 files changed, 100 insertions(+), 100 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 53a46f50..1a93e3e4 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -699,6 +699,24 @@ get_style_property_string(struct style *node, const char *name, const char *init return value->data; } +int +get_style_property_display(struct style *node) +{ + struct value *value = get_style_property(node, "display"); + if (value) + { + if (!strcmp(value->data, "none")) + return NONE; + if (!strcmp(value->data, "inline")) + return INLINE; + if (!strcmp(value->data, "block")) + return BLOCK; + if (!strcmp(value->data, "list-item")) + return LIST_ITEM; + } + return INLINE; +} + static float compute_number(struct value *value, float em, float hundred, float scale, float initial) { @@ -751,24 +769,10 @@ compute_style(struct computed_style *style, struct style *node) memset(style, 0, sizeof *style); - style->display = INLINE; style->position = STATIC; style->text_align = LEFT; style->font_size = 12; - value = get_style_property(node, "display"); - if (value) - { - if (!strcmp(value->data, "none")) - style->display = NONE; - if (!strcmp(value->data, "inline")) - style->display = INLINE; - if (!strcmp(value->data, "block")) - style->display = BLOCK; - if (!strcmp(value->data, "list-item")) - style->display = LIST_ITEM; - } - value = get_style_property(node, "position"); if (value) { @@ -871,7 +875,6 @@ void print_style(struct computed_style *style) { printf("style {\n"); - printf("\tdisplay = %d;\n", style->display); printf("\tposition = %d;\n", style->position); printf("\ttext-align = %d;\n", style->text_align); printf("\tfont-family = %s;\n", style->font_family); diff --git a/source/html/layout.c b/source/html/layout.c index c8ba17e2..1d92b502 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -40,159 +40,156 @@ enum struct box { int type; - float x, y, w, h; - float padding[4]; - float border[4]; - float margin[4]; - - int bold, italic; - - fz_xml *node; - const char *text; - struct box *up, *down, *last, *next; + fz_xml *node; + struct style style; }; -struct box *new_box(fz_context *ctx, struct box *root, int type, struct computed_style *cstyle, fz_xml *node) +struct box *new_box(fz_context *ctx, fz_xml *node, struct style *up_style) { struct box *box; - int i; box = fz_malloc_struct(ctx, struct box); - box->type = type; + + box->type = BOX_BLOCK; box->x = box->y = 0; box->w = box->h = 0; - for (i = 0; i < 4; ++i) - { - box->padding[i] = cstyle->padding[i]; - box->margin[i] = cstyle->margin[i]; - box->border[i] = cstyle->border_width[i]; - box->bold = cstyle->bold; - box->italic = cstyle->italic; - } - - box->node = node; - - box->up = root; + box->up = NULL; box->last = NULL; box->down = NULL; box->next = NULL; - if (root) + box->node = node; + + box->style.up = up_style; + box->style.count = 0; + + return box; +} + +void insert_box(fz_context *ctx, struct box *box, int type, struct box *top) +{ + box->type = type; + + box->up = top; + + if (top) { - if (!root->last) + if (!top->last) { - root->down = root->last = box; + top->down = top->last = box; } else { - root->last->next = box; - root->last = box; + top->last->next = box; + top->last = box; } } - - return box; } -static struct box *new_block_box(fz_context *ctx, struct box **topp, struct computed_style *cstyle, fz_xml *node) +static struct box *insert_block_box(fz_context *ctx, struct box *box, struct box *top) { - struct box *top = *topp; - struct box *box; - if (top->type == BOX_BLOCK) { - box = new_box(ctx, top, BOX_BLOCK, cstyle, node); + insert_box(ctx, box, BOX_BLOCK, top); } else if (top->type == BOX_ANONYMOUS) { while (top->type != BOX_BLOCK) top = top->up; - *topp = top; - box = new_box(ctx, top, BOX_BLOCK, cstyle, node); + insert_box(ctx, box, BOX_BLOCK, top); } else if (top->type == BOX_INLINE) { while (top->type != BOX_BLOCK) top = top->up; - *topp = top; - box = new_box(ctx, top, BOX_BLOCK, cstyle, node); + insert_box(ctx, box, BOX_BLOCK, top); } - return box; + return top; } -static struct box *new_inline_box(fz_context *ctx, struct box *box, struct computed_style *cstyle, fz_xml *node) +static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) { - if (box->type == BOX_BLOCK) + if (top->type == BOX_BLOCK) { - if (box->last && box->last->type == BOX_ANONYMOUS) - box = box->last; + if (top->last && top->last->type == BOX_ANONYMOUS) + { + insert_box(ctx, box, BOX_INLINE, top->last); + } else - box = new_box(ctx, box, BOX_ANONYMOUS, cstyle, NULL); - box = new_box(ctx, box, BOX_INLINE, cstyle, node); + { + struct box *anon = new_box(ctx, NULL, &top->style); + insert_box(ctx, anon, BOX_ANONYMOUS, top); + insert_box(ctx, box, BOX_INLINE, anon); + } } else if (box->type == BOX_ANONYMOUS) { - box = new_box(ctx, box, BOX_INLINE, cstyle, node); + insert_box(ctx, box, BOX_INLINE, top); } else if (box->type == BOX_INLINE) { - box = new_box(ctx, box, BOX_INLINE, cstyle, node); + insert_box(ctx, box, BOX_INLINE, top); } - return box; } -static void layout_tree(fz_context *ctx, fz_xml *node, struct box *top, struct style *up_style, struct rule *rule) +static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struct rule *rule) { - struct style style; - struct computed_style cstyle; + struct style *up_style; struct box *box; + int display; + + /* link styles separately because splitting inline blocks breaks the style/box tree symmetry */ + up_style = &top->style; while (node) { - style.up = up_style; - style.count = 0; + box = new_box(ctx, node, up_style); if (fz_xml_tag(node)) { - apply_styles(ctx, &style, rule, node); - compute_style(&cstyle, &style); - // print_style(&cstyle); + apply_styles(ctx, &box->style, rule, node); + + display = get_style_property_display(&box->style); // TOOD:
// TODO: - if (cstyle.display != NONE) + if (display != NONE) { - if (cstyle.display == BLOCK) + if (display == BLOCK) { - box = new_block_box(ctx, &top, &cstyle, node); + top = insert_block_box(ctx, box, top); } - else if (cstyle.display == INLINE) + else if (display == INLINE) { - box = new_inline_box(ctx, top, &cstyle, node); + insert_inline_box(ctx, box, top); } else { fz_warn(ctx, "unknown box display type"); - box = new_box(ctx, top, BOX_BLOCK, &cstyle, node); + insert_box(ctx, box, BOX_BLOCK, top); } if (fz_xml_down(node)) - layout_tree(ctx, fz_xml_down(node), box, &style, rule); + generate_boxes(ctx, fz_xml_down(node), box, rule); } } else { - compute_style(&cstyle, &style); - new_inline_box(ctx, top, &cstyle, node); + insert_inline_box(ctx, box, top); } node = fz_xml_next(node); } } +static void layout_boxes(fz_context *ctx, struct box *top, float w, float h) +{ +} + static void indent(int level) { while (level--) printf(" "); @@ -209,13 +206,12 @@ static void print_box(fz_context *ctx, struct box *box, int level) case BOX_ANONYMOUS: printf("anonymous"); break; case BOX_INLINE: printf("inline"); break; } - if (box->node) { + if (box->node) + { const char *tag = fz_xml_tag(box->node); const char *text = fz_xml_text(box->node); if (tag) printf(" <%s>", tag); if (text) printf(" \"%s\"", text); - if (box->bold) printf(" bold"); - if (box->italic) printf(" italic"); } printf("\n"); if (box->down) @@ -238,7 +234,8 @@ static char *concat_text(fz_context *ctx, fz_xml *root) for (node = fz_xml_down(root); node; node = fz_xml_next(node)) { const char *text = fz_xml_text(node); - if (text) { + if (text) + { n = strlen(text); memcpy(s+i, text, n); i += n; @@ -251,14 +248,18 @@ static char *concat_text(fz_context *ctx, fz_xml *root) static struct rule *load_css(fz_context *ctx, struct rule *css, fz_xml *root) { fz_xml *node; - for (node = root; node; node = fz_xml_next(node)) { + for (node = root; node; node = fz_xml_next(node)) + { const char *tag = fz_xml_tag(node); #if 0 - if (tag && !strcmp(tag, "link")) { + if (tag && !strcmp(tag, "link")) + { char *rel = fz_xml_att(node, "rel"); - if (rel && !strcasecmp(rel, "stylesheet")) { + if (rel && !strcasecmp(rel, "stylesheet")) + { char *type = fz_xml_att(node, "type"); - if ((type && !strcmp(type, "text/css")) || !type) { + if ((type && !strcmp(type, "text/css")) || !type) + { char *href = fz_xml_att(node, "href"); strcpy(filename, dirname); strcat(filename, href); @@ -267,7 +268,8 @@ static struct rule *load_css(fz_context *ctx, struct rule *css, fz_xml *root) } } #endif - if (tag && !strcmp(tag, "style")) { + if (tag && !strcmp(tag, "style")) + { char *s = concat_text(ctx, node); css = fz_parse_css(ctx, css, s); fz_free(ctx, s); @@ -283,8 +285,6 @@ html_layout_document(html_document *doc, float w, float h) { struct rule *css = NULL; struct box *root_box; - struct style style; - struct computed_style cstyle; #if 0 strcpy(dirname, argv[i]); @@ -299,11 +299,8 @@ html_layout_document(html_document *doc, float w, float h) // print_rules(css); - style.up = NULL; - style.count = 0; - compute_style(&cstyle, &style); - root_box = new_box(doc->ctx, NULL, BOX_BLOCK, &cstyle, NULL); - - layout_tree(doc->ctx, doc->root, root_box, NULL, css); + root_box = new_box(doc->ctx, NULL, NULL); + generate_boxes(doc->ctx, doc->root, root_box, css); + layout_boxes(doc->ctx, root_box, w, h); print_box(doc->ctx, root_box, 0); } -- cgit v1.2.3 From b231d01f2ff24f294f9e30cf2ad82a62145ad437 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Thu, 23 Oct 2014 14:45:50 +0200 Subject: html: Start laying out boxes. --- source/html/css-apply.c | 21 +++++++++--------- source/html/layout.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 13 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 1a93e3e4..9a73ee2a 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -761,11 +761,10 @@ compute_number(struct value *value, float em, float hundred, float scale, float } void -compute_style(struct computed_style *style, struct style *node) +compute_style(struct computed_style *style, struct style *node, float width) { struct value *value; float em = 12; - float hundred = 100; memset(style, 0, sizeof *style); @@ -829,25 +828,25 @@ compute_style(struct computed_style *style, struct style *node) style->line_height = compute_number(value, em, em, em, 1.2 * em); value = get_style_property(node, "text-indent"); - style->text_indent = compute_number(value, em, hundred, 1, 0); + style->text_indent = compute_number(value, em, width, 1, 0); value = get_style_property(node, "margin-top"); - style->margin[0] = compute_number(value, em, hundred, 1, 0); + style->margin[0] = compute_number(value, em, width, 1, 0); value = get_style_property(node, "margin-right"); - style->margin[1] = compute_number(value, em, hundred, 1, 0); + style->margin[1] = compute_number(value, em, width, 1, 0); value = get_style_property(node, "margin-bottom"); - style->margin[2] = compute_number(value, em, hundred, 1, 0); + style->margin[2] = compute_number(value, em, width, 1, 0); value = get_style_property(node, "margin-left"); - style->margin[3] = compute_number(value, em, hundred, 1, 0); + style->margin[3] = compute_number(value, em, width, 1, 0); value = get_style_property(node, "padding-top"); - style->padding[0] = compute_number(value, em, hundred, 1, 0); + style->padding[0] = compute_number(value, em, width, 1, 0); value = get_style_property(node, "padding-right"); - style->padding[1] = compute_number(value, em, hundred, 1, 0); + style->padding[1] = compute_number(value, em, width, 1, 0); value = get_style_property(node, "padding-bottom"); - style->padding[2] = compute_number(value, em, hundred, 1, 0); + style->padding[2] = compute_number(value, em, width, 1, 0); value = get_style_property(node, "padding-left"); - style->padding[3] = compute_number(value, em, hundred, 1, 0); + style->padding[3] = compute_number(value, em, width, 1, 0); { const char *font_family = get_style_property_string(node, "font-family", "serif"); diff --git a/source/html/layout.c b/source/html/layout.c index 1d92b502..2960de73 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -186,8 +186,55 @@ static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struc } } -static void layout_boxes(fz_context *ctx, struct box *top, float w, float h) +static void layout_inline(fz_context *ctx, struct box *box, struct box *top) { + struct computed_style style; + struct box *child; + + compute_style(&style, &box->style, top->w); + + box->y = top->y; + box->h = style.font_size; + for (child = box->down; child; child = child->next) + { + layout_inline(ctx, child, top); + } +} + +static void layout_anonymous(fz_context *ctx, struct box *box, struct box *top) +{ + struct computed_style style; + struct box *child; + + compute_style(&style, &box->style, top->w); + + box->y = top->y + top->h; + box->h = 0; + for (child = box->down; child; child = child->next) + { + layout_inline(ctx, child, box); + if (child->h > box->h) + box->h = child->h; + } +} + +static void layout_block(fz_context *ctx, struct box *box, struct box *top) +{ + struct computed_style style; + struct box *child; + + compute_style(&style, &box->style, top->w); + + box->y = top->y + top->h; + box->h = 0; + for (child = box->down; child; child = child->next) + { + if (child->type == BOX_BLOCK) + layout_block(ctx, child, box); + else if (child->type == BOX_ANONYMOUS) + layout_anonymous(ctx, child, box); + box->h += child->h; + } } static void indent(int level) @@ -199,6 +246,7 @@ static void print_box(fz_context *ctx, struct box *box, int level) { while (box) { + printf("%-5d", (int)box->y); indent(level); switch (box->type) { @@ -285,6 +333,7 @@ html_layout_document(html_document *doc, float w, float h) { struct rule *css = NULL; struct box *root_box; + struct box *win_box; #if 0 strcpy(dirname, argv[i]); @@ -301,6 +350,12 @@ html_layout_document(html_document *doc, float w, float h) root_box = new_box(doc->ctx, NULL, NULL); generate_boxes(doc->ctx, doc->root, root_box, css); - layout_boxes(doc->ctx, root_box, w, h); + + win_box = new_box(doc->ctx, NULL, NULL); + win_box->w = w; + win_box->h = 0; + + layout_block(doc->ctx, root_box, win_box); + print_box(doc->ctx, root_box, 0); } -- cgit v1.2.3 From 5dc64869a5e3bdf851d82ff445b32b609084931b Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Thu, 23 Oct 2014 16:35:51 +0200 Subject: html: Create lists in order when parsing CSS. --- source/html/css-parse.c | 51 +++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 23 deletions(-) (limited to 'source/html') diff --git a/source/html/css-parse.c b/source/html/css-parse.c index 4ceb10b5..066eb0f7 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -446,24 +446,22 @@ static struct property *parse_declaration(struct lexbuf *buf) static struct property *parse_declaration_list(struct lexbuf *buf) { - struct property *p, *pp; + struct property *head, *tail; if (buf->lookahead == '}' || buf->lookahead == EOF) return NULL; - pp = parse_declaration(buf); + head = tail = parse_declaration(buf); while (accept(buf, ';')) { if (buf->lookahead != '}' && buf->lookahead != ';' && buf->lookahead != EOF) { - p = parse_declaration(buf); - p->next = pp; - pp = p; + tail = tail->next = parse_declaration(buf); } } - return pp; + return head; } static const char *parse_attrib_value(struct lexbuf *buf) @@ -547,16 +545,14 @@ static struct condition *parse_condition(struct lexbuf *buf) static struct condition *parse_condition_list(struct lexbuf *buf) { - struct condition *c, *cc; + struct condition *head, *tail; - cc = parse_condition(buf); + head = tail = parse_condition(buf); while (iscond(buf->lookahead)) { - c = parse_condition(buf); - c->next = cc; - cc = c; + tail = tail->next = parse_condition(buf); } - return cc; + return head; } static struct selector *parse_simple_selector(struct lexbuf *buf) @@ -641,16 +637,14 @@ static struct selector *parse_descendant_selector(struct lexbuf *buf) static struct selector *parse_selector_list(struct lexbuf *buf) { - struct selector *s, *ss; + struct selector *head, *tail; - ss = parse_descendant_selector(buf); + head = tail = parse_descendant_selector(buf); while (accept(buf, ',')) { - s = parse_descendant_selector(buf); - s->next = ss; - ss = s; + tail = tail->next = parse_descendant_selector(buf); } - return ss; + return head; } static struct rule *parse_rule(struct lexbuf *buf) @@ -706,7 +700,19 @@ static void parse_at_rule(struct lexbuf *buf) static struct rule *parse_stylesheet(struct lexbuf *buf, struct rule *chain) { - struct rule *r; + struct rule *rule, **nextp, *tail; + + tail = chain; + if (tail) + { + while (tail->next) + tail = tail->next; + nextp = &tail->next; + } + else + { + nextp = &tail; + } while (buf->lookahead != EOF) { @@ -716,13 +722,12 @@ static struct rule *parse_stylesheet(struct lexbuf *buf, struct rule *chain) } else { - r = parse_rule(buf); - r->next = chain; - chain = r; + rule = *nextp = parse_rule(buf); + nextp = &rule->next; } } - return chain; + return chain ? chain : tail; } struct property *fz_parse_css_properties(fz_context *ctx, const char *source) -- cgit v1.2.3 From 7159498b095238ca8c8c87cc99d83c46fc5cd19b Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Thu, 23 Oct 2014 16:13:42 +0200 Subject: html: Apply margins. --- source/html/css-apply.c | 30 +++++++++++++++--------------- source/html/layout.c | 34 ++++++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 21 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 9a73ee2a..a99eed2b 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -706,15 +706,15 @@ get_style_property_display(struct style *node) if (value) { if (!strcmp(value->data, "none")) - return NONE; + return DIS_NONE; if (!strcmp(value->data, "inline")) - return INLINE; + return DIS_INLINE; if (!strcmp(value->data, "block")) - return BLOCK; + return DIS_BLOCK; if (!strcmp(value->data, "list-item")) - return LIST_ITEM; + return DIS_LIST_ITEM; } - return INLINE; + return DIS_INLINE; } static float @@ -768,34 +768,34 @@ compute_style(struct computed_style *style, struct style *node, float width) memset(style, 0, sizeof *style); - style->position = STATIC; - style->text_align = LEFT; + style->position = POS_STATIC; + style->text_align = TA_LEFT; style->font_size = 12; value = get_style_property(node, "position"); if (value) { if (!strcmp(value->data, "static")) - style->position = STATIC; + style->position = POS_STATIC; if (!strcmp(value->data, "relative")) - style->position = RELATIVE; + style->position = POS_RELATIVE; if (!strcmp(value->data, "absolute")) - style->position = ABSOLUTE; + style->position = POS_ABSOLUTE; if (!strcmp(value->data, "fixed")) - style->position = FIXED; + style->position = POS_FIXED; } value = get_style_property(node, "text-align"); if (value) { if (!strcmp(value->data, "left")) - style->text_align = LEFT; + style->text_align = TA_LEFT; if (!strcmp(value->data, "right")) - style->text_align = RIGHT; + style->text_align = TA_RIGHT; if (!strcmp(value->data, "center")) - style->text_align = CENTER; + style->text_align = TA_CENTER; if (!strcmp(value->data, "justify")) - style->text_align = JUSTIFY; + style->text_align = TA_JUSTIFY; } value = get_style_property(node, "vertical-align"); diff --git a/source/html/layout.c b/source/html/layout.c index 2960de73..6b2c7d44 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -157,13 +157,13 @@ static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struc // TOOD:
// TODO: - if (display != NONE) + if (display != DIS_NONE) { - if (display == BLOCK) + if (display == DIS_BLOCK) { top = insert_block_box(ctx, box, top); } - else if (display == INLINE) + else if (display == DIS_INLINE) { insert_inline_box(ctx, box, top); } @@ -190,14 +190,27 @@ static void layout_inline(fz_context *ctx, struct box *box, struct box *top) { struct computed_style style; struct box *child; + const char *s; compute_style(&style, &box->style, top->w); + box->x = top->x + top->w; box->y = top->y; box->h = style.font_size; + box->w = 0; + + s = fz_xml_text(box->node); + if (s) + { + box->w += strlen(s) * 0.5 * style.font_size; + } + for (child = box->down; child; child = child->next) { layout_inline(ctx, child, top); + if (child->h > box->h) + box->h = child->h; + top->w += child->w; } } @@ -208,13 +221,17 @@ static void layout_anonymous(fz_context *ctx, struct box *box, struct box *top) compute_style(&style, &box->style, top->w); + box->x = top->x; box->y = top->y + top->h; box->h = 0; + box->w = 0; + for (child = box->down; child; child = child->next) { layout_inline(ctx, child, box); if (child->h > box->h) box->h = child->h; + box->w += child->w; } } @@ -225,8 +242,11 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top) compute_style(&style, &box->style, top->w); - box->y = top->y + top->h; + box->x = top->x + style.margin[LEFT]; + box->y = top->y + top->h + style.margin[TOP]; + box->w = top->w - (style.margin[LEFT] + style.margin[RIGHT]); box->h = 0; + for (child = box->down; child; child = child->next) { if (child->type == BOX_BLOCK) @@ -235,6 +255,8 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top) layout_anonymous(ctx, child, box); box->h += child->h; } + + box->h += style.margin[BOTTOM]; } static void indent(int level) @@ -246,7 +268,7 @@ static void print_box(fz_context *ctx, struct box *box, int level) { while (box) { - printf("%-5d", (int)box->y); + printf("%-5d %-5d", (int)box->x, (int)box->y); indent(level); switch (box->type) { @@ -346,7 +368,7 @@ html_layout_document(html_document *doc, float w, float h) css = fz_parse_css(doc->ctx, NULL, default_css); css = load_css(doc->ctx, css, doc->root); -// print_rules(css); + print_rules(css); root_box = new_box(doc->ctx, NULL, NULL); generate_boxes(doc->ctx, doc->root, root_box, css); -- cgit v1.2.3 From 24c8a6cca270c27a4940ed7398ec01664e488e6f Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 4 Nov 2014 11:13:00 +0100 Subject: html: Rename ANONYMOUS to FLOW box and fix typo. --- source/html/layout.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'source/html') diff --git a/source/html/layout.c b/source/html/layout.c index 6b2c7d44..8079213d 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -32,8 +32,8 @@ static const char *default_css = enum { - BOX_BLOCK, /* block-level: contains other block and anonymous boxes */ - BOX_ANONYMOUS, /* block-level: contains only inline boxes */ + BOX_BLOCK, /* block-level: contains block and flow boxes */ + BOX_FLOW, /* block-level: contains only inline boxes */ BOX_INLINE, /* inline-level: contains only inline boxes */ }; @@ -95,7 +95,7 @@ static struct box *insert_block_box(fz_context *ctx, struct box *box, struct box { insert_box(ctx, box, BOX_BLOCK, top); } - else if (top->type == BOX_ANONYMOUS) + else if (top->type == BOX_FLOW) { while (top->type != BOX_BLOCK) top = top->up; @@ -114,22 +114,22 @@ static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) { if (top->type == BOX_BLOCK) { - if (top->last && top->last->type == BOX_ANONYMOUS) + if (top->last && top->last->type == BOX_FLOW) { insert_box(ctx, box, BOX_INLINE, top->last); } else { - struct box *anon = new_box(ctx, NULL, &top->style); - insert_box(ctx, anon, BOX_ANONYMOUS, top); - insert_box(ctx, box, BOX_INLINE, anon); + struct box *flow = new_box(ctx, NULL, &top->style); + insert_box(ctx, flow, BOX_FLOW, top); + insert_box(ctx, box, BOX_INLINE, flow); } } - else if (box->type == BOX_ANONYMOUS) + else if (top->type == BOX_FLOW) { insert_box(ctx, box, BOX_INLINE, top); } - else if (box->type == BOX_INLINE) + else if (top->type == BOX_INLINE) { insert_box(ctx, box, BOX_INLINE, top); } @@ -214,7 +214,7 @@ static void layout_inline(fz_context *ctx, struct box *box, struct box *top) } } -static void layout_anonymous(fz_context *ctx, struct box *box, struct box *top) +static void layout_flow(fz_context *ctx, struct box *box, struct box *top) { struct computed_style style; struct box *child; @@ -251,8 +251,8 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top) { if (child->type == BOX_BLOCK) layout_block(ctx, child, box); - else if (child->type == BOX_ANONYMOUS) - layout_anonymous(ctx, child, box); + else if (child->type == BOX_FLOW) + layout_flow(ctx, child, box); box->h += child->h; } @@ -273,7 +273,7 @@ static void print_box(fz_context *ctx, struct box *box, int level) switch (box->type) { case BOX_BLOCK: printf("block"); break; - case BOX_ANONYMOUS: printf("anonymous"); break; + case BOX_FLOW: printf("flow"); break; case BOX_INLINE: printf("inline"); break; } if (box->node) -- cgit v1.2.3 From d05e5e738f22b914607900b8d1f2e38670e2ba24 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 4 Nov 2014 14:27:32 +0100 Subject: html: Partially compute styles when generating boxes. Resolve final width and em-scaled numbers at layout time. --- source/html/css-apply.c | 151 ++++++++++++++++++++++++++++-------------------- source/html/handler.c | 15 +++-- source/html/layout.c | 92 ++++++++++++++++------------- 3 files changed, 147 insertions(+), 111 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index a99eed2b..8526f7b9 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -717,60 +717,84 @@ get_style_property_display(struct style *node) return DIS_INLINE; } -static float -compute_number(struct value *value, float em, float hundred, float scale, float initial) +static struct number +make_number(float v, int u) +{ + struct number n; + n.value = v; + n.unit = u; + return n; +} + +static struct number +number_from_value(struct value *value, float initial, int initial_unit) { char *p; if (!value) - return initial; + return make_number(initial, initial_unit); if (value->type == CSS_PERCENT) - return strtof(value->data, &p) * hundred / 100; + return make_number(strtof(value->data, NULL), N_PERCENT); if (value->type == CSS_NUMBER) - return strtof(value->data, &p) * scale; + return make_number(strtof(value->data, NULL), N_NUMBER); if (value->type == CSS_LENGTH) { float x = strtof(value->data, &p); if (p[0] == 'e' && p[1] == 'm') - return x * em; + return make_number(x, N_SCALE); if (p[0] == 'e' && p[1] == 'x') - return x * em / 2; + return make_number(x / 2, N_SCALE); if (p[0] == 'i' && p[1] == 'n') - return x * 72; + return make_number(x * 72, N_NUMBER); if (p[0] == 'c' && p[1] == 'm') - return x * 7200 / 254; + return make_number(x * 7200 / 254, N_NUMBER); if (p[0] == 'm' && p[1] == 'm') - return x * 720 / 254; + return make_number(x * 720 / 254, N_NUMBER); if (p[0] == 'p' && p[1] == 'c') - return x * 12; + return make_number(x * 12, N_NUMBER); if (p[0] == 'p' && p[1] == 't') - return x; + return make_number(x, N_NUMBER); if (p[0] == 'p' && p[1] == 'x') - return x; + return make_number(x, N_NUMBER); - return x; + return make_number(x, N_NUMBER); } - return initial; + return make_number(initial, initial_unit); +} + +static struct number number_from_property(struct style *node, const char *property, float initial, int initial_unit) +{ + return number_from_value(get_style_property(node, property), initial, initial_unit); +} + +float +from_number(struct number number, float em, float width) +{ + switch (number.unit) { + default: + case N_NUMBER: return number.value; + case N_SCALE: return number.value * em; + case N_PERCENT: return number.value * width; + } } void -compute_style(struct computed_style *style, struct style *node, float width) +compute_style(struct computed_style *style, struct style *node) { struct value *value; - float em = 12; memset(style, 0, sizeof *style); style->position = POS_STATIC; style->text_align = TA_LEFT; - style->font_size = 12; + style->font_size = make_number(1, N_SCALE); value = get_style_property(node, "position"); if (value) @@ -808,45 +832,37 @@ compute_style(struct computed_style *style, struct style *node, float width) } value = get_style_property(node, "font-size"); - if (value) { - if (!strcmp(value->data, "xx-large")) style->font_size = 20; - else if (!strcmp(value->data, "x-large")) style->font_size = 16; - else if (!strcmp(value->data, "large")) style->font_size = 14; - else if (!strcmp(value->data, "medium")) style->font_size = 12; - else if (!strcmp(value->data, "small")) style->font_size = 10; - else if (!strcmp(value->data, "x-small")) style->font_size = 8; - else if (!strcmp(value->data, "xx-small")) style->font_size = 6; - else if (!strcmp(value->data, "larger")) style->font_size = em + 2; - else if (!strcmp(value->data, "smaller")) style->font_size = em - 2; - else style->font_size = compute_number(value, em, em, 1, 12); - } else { - style->font_size = 12; - } - em = style->font_size; - - value = get_style_property(node, "line-height"); - style->line_height = compute_number(value, em, em, em, 1.2 * em); - - value = get_style_property(node, "text-indent"); - style->text_indent = compute_number(value, em, width, 1, 0); - - value = get_style_property(node, "margin-top"); - style->margin[0] = compute_number(value, em, width, 1, 0); - value = get_style_property(node, "margin-right"); - style->margin[1] = compute_number(value, em, width, 1, 0); - value = get_style_property(node, "margin-bottom"); - style->margin[2] = compute_number(value, em, width, 1, 0); - value = get_style_property(node, "margin-left"); - style->margin[3] = compute_number(value, em, width, 1, 0); - - value = get_style_property(node, "padding-top"); - style->padding[0] = compute_number(value, em, width, 1, 0); - value = get_style_property(node, "padding-right"); - style->padding[1] = compute_number(value, em, width, 1, 0); - value = get_style_property(node, "padding-bottom"); - style->padding[2] = compute_number(value, em, width, 1, 0); - value = get_style_property(node, "padding-left"); - style->padding[3] = compute_number(value, em, width, 1, 0); + if (value) + { + if (!strcmp(value->data, "xx-large")) style->font_size = make_number(20, N_NUMBER); + else if (!strcmp(value->data, "x-large")) style->font_size = make_number(16, N_NUMBER); + else if (!strcmp(value->data, "large")) style->font_size = make_number(14, N_NUMBER); + else if (!strcmp(value->data, "medium")) style->font_size = make_number(12, N_NUMBER); + else if (!strcmp(value->data, "small")) style->font_size = make_number(10, N_NUMBER); + else if (!strcmp(value->data, "x-small")) style->font_size = make_number(8, N_NUMBER); + else if (!strcmp(value->data, "xx-small")) style->font_size = make_number(6, N_NUMBER); + else if (!strcmp(value->data, "larger")) style->font_size = make_number(1.25f, N_SCALE); + else if (!strcmp(value->data, "smaller")) style->font_size = make_number(0.8f, N_SCALE); + else style->font_size = number_from_value(value, 12, N_NUMBER); + } + else + { + style->font_size = make_number(1, N_SCALE); + } + + style->line_height = number_from_property(node, "line-height", 1.2, N_SCALE); + + style->text_indent = number_from_property(node, "text-indent", 0, N_NUMBER); + + style->margin[0] = number_from_property(node, "margin-top", 0, N_NUMBER); + style->margin[1] = number_from_property(node, "margin-right", 0, N_NUMBER); + style->margin[2] = number_from_property(node, "margin-bottom", 0, N_NUMBER); + style->margin[3] = number_from_property(node, "margin-left", 0, N_NUMBER); + + style->padding[0] = number_from_property(node, "padding-top", 0, N_NUMBER); + style->padding[1] = number_from_property(node, "padding-right", 0, N_NUMBER); + style->padding[2] = number_from_property(node, "padding-bottom", 0, N_NUMBER); + style->padding[3] = number_from_property(node, "padding-left", 0, N_NUMBER); { const char *font_family = get_style_property_string(node, "font-family", "serif"); @@ -880,13 +896,20 @@ print_style(struct computed_style *style) printf("\tfont-weight = %s;\n", style->bold ? "bold" : "normal"); printf("\tfont-style = %s;\n", style->italic ? "italic" : "normal"); printf("\tfont-variant = %s;\n", style->smallcaps ? "small-caps" : "normal"); - printf("\tfont-size = %g;\n", style->font_size); - printf("\tline-height = %g;\n", style->line_height); - printf("\ttext-indent = %g;\n", style->text_indent); + + printf("\tfont-size = %g%c;\n", style->font_size.value, style->font_size.unit); + printf("\tline-height = %g%c;\n", style->line_height.value, style->line_height.unit); + printf("\ttext-indent = %g%c;\n", style->text_indent.value, style->text_indent.unit); printf("\tvertical-align = %d;\n", style->vertical_align); - printf("\tmargin = %g %g %g %g;\n", - style->margin[0], style->margin[1], style->margin[2], style->margin[3]); - printf("\tpadding = %g %g %g %g;\n", - style->padding[0], style->padding[1], style->padding[2], style->padding[3]); + printf("\tmargin = %g%c %g%c %g%c %g%c;\n", + style->margin[0].value, style->margin[0].unit, + style->margin[1].value, style->margin[1].unit, + style->margin[2].value, style->margin[2].unit, + style->margin[3].value, style->margin[3].unit); + printf("\tpadding = %g%c %g%c %g%c %g%c;\n", + style->padding[0].value, style->padding[0].unit, + style->padding[1].value, style->padding[1].unit, + style->padding[2].value, style->padding[2].unit, + style->padding[3].value, style->padding[3].unit); printf("}\n"); } diff --git a/source/html/handler.c b/source/html/handler.c index f5002437..859721c8 100644 --- a/source/html/handler.c +++ b/source/html/handler.c @@ -1,9 +1,5 @@ #include "mupdf/html.h" -struct html_page_s -{ -}; - void html_close_document(html_document *doc) { @@ -21,7 +17,7 @@ html_page * html_load_page(html_document *doc, int number) { printf("html: load page %d\n", number); - return (html_page*)"nothing"; + return doc->box; } void @@ -43,6 +39,7 @@ void html_run_page(html_document *doc, html_page *page, fz_device *dev, const fz_matrix *ctm, fz_cookie *cookie) { printf("html: run page\n"); + html_run_box(doc->ctx, page, dev, ctm); } html_document * @@ -50,15 +47,14 @@ html_open_document_with_stream(fz_context *ctx, fz_stream *file) { html_document *doc; fz_buffer *buf; - fz_xml *root; + fz_xml *xml; buf = fz_read_all(file, 0); - root = fz_parse_xml(ctx, buf->data, buf->len, 1); + xml = fz_parse_xml(ctx, buf->data, buf->len, 1); fz_drop_buffer(ctx, buf); doc = fz_malloc_struct(ctx, html_document); doc->ctx = ctx; - doc->root = root; doc->super.close = (void*)html_close_document; doc->super.count_pages = (void*)html_count_pages; @@ -67,6 +63,9 @@ html_open_document_with_stream(fz_context *ctx, fz_stream *file) doc->super.run_page_contents = (void*)html_run_page; doc->super.free_page = (void*)html_free_page; + doc->xml = xml; + doc->box = NULL; + html_layout_document(doc, 400, 600); return doc; diff --git a/source/html/layout.c b/source/html/layout.c index 8079213d..898e0eb7 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -43,10 +43,10 @@ struct box float x, y, w, h; struct box *up, *down, *last, *next; fz_xml *node; - struct style style; + struct computed_style style; }; -struct box *new_box(fz_context *ctx, fz_xml *node, struct style *up_style) +struct box *new_box(fz_context *ctx, fz_xml *node) { struct box *box; @@ -63,9 +63,6 @@ struct box *new_box(fz_context *ctx, fz_xml *node, struct style *up_style) box->node = node; - box->style.up = up_style; - box->style.count = 0; - return box; } @@ -120,7 +117,7 @@ static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) } else { - struct box *flow = new_box(ctx, NULL, &top->style); + struct box *flow = new_box(ctx, NULL); insert_box(ctx, flow, BOX_FLOW, top); insert_box(ctx, box, BOX_INLINE, flow); } @@ -135,24 +132,24 @@ static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) } } -static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struct rule *rule) +static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struct rule *rule, struct style *up_style) { - struct style *up_style; + struct style style; struct box *box; int display; - /* link styles separately because splitting inline blocks breaks the style/box tree symmetry */ - up_style = &top->style; - while (node) { - box = new_box(ctx, node, up_style); + style.up = up_style; + style.count = 0; + + box = new_box(ctx, node); if (fz_xml_tag(node)) { - apply_styles(ctx, &box->style, rule, node); + apply_styles(ctx, &style, rule, node); - display = get_style_property_display(&box->style); + display = get_style_property_display(&style); // TOOD:
// TODO: @@ -174,7 +171,7 @@ static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struc } if (fz_xml_down(node)) - generate_boxes(ctx, fz_xml_down(node), box, rule); + generate_boxes(ctx, fz_xml_down(node), box, rule, &style); } } else @@ -182,44 +179,44 @@ static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struc insert_inline_box(ctx, box, top); } + compute_style(&box->style, &style); + node = fz_xml_next(node); } } -static void layout_inline(fz_context *ctx, struct box *box, struct box *top) +static void layout_inline(fz_context *ctx, struct box *box, struct box *top, float em) { - struct computed_style style; struct box *child; const char *s; - compute_style(&style, &box->style, top->w); + em = from_number(box->style.font_size, em, em); box->x = top->x + top->w; box->y = top->y; - box->h = style.font_size; + box->h = em; box->w = 0; s = fz_xml_text(box->node); if (s) { - box->w += strlen(s) * 0.5 * style.font_size; + box->w += strlen(s) * 0.5 * em; } for (child = box->down; child; child = child->next) { - layout_inline(ctx, child, top); + layout_inline(ctx, child, top, em); if (child->h > box->h) box->h = child->h; top->w += child->w; } } -static void layout_flow(fz_context *ctx, struct box *box, struct box *top) +static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float em) { - struct computed_style style; struct box *child; - compute_style(&style, &box->style, top->w); + em = from_number(box->style.font_size, em, em); box->x = top->x; box->y = top->y + top->h; @@ -228,35 +225,40 @@ static void layout_flow(fz_context *ctx, struct box *box, struct box *top) for (child = box->down; child; child = child->next) { - layout_inline(ctx, child, box); + layout_inline(ctx, child, box, em); if (child->h > box->h) box->h = child->h; box->w += child->w; } } -static void layout_block(fz_context *ctx, struct box *box, struct box *top) +static void layout_block(fz_context *ctx, struct box *box, struct box *top, float em) { - struct computed_style style; struct box *child; + float margin[4]; - compute_style(&style, &box->style, top->w); + em = from_number(box->style.font_size, em, em); - box->x = top->x + style.margin[LEFT]; - box->y = top->y + top->h + style.margin[TOP]; - box->w = top->w - (style.margin[LEFT] + style.margin[RIGHT]); + margin[0] = from_number(box->style.margin[0], em, top->w); + margin[1] = from_number(box->style.margin[1], em, top->w); + margin[2] = from_number(box->style.margin[2], em, top->w); + margin[3] = from_number(box->style.margin[3], em, top->w); + + box->x = top->x + margin[LEFT]; + box->y = top->y + top->h + margin[TOP]; + box->w = top->w - (margin[LEFT] + margin[RIGHT]); box->h = 0; for (child = box->down; child; child = child->next) { if (child->type == BOX_BLOCK) - layout_block(ctx, child, box); + layout_block(ctx, child, box, em); else if (child->type == BOX_FLOW) - layout_flow(ctx, child, box); + layout_flow(ctx, child, box, em); box->h += child->h; } - box->h += style.margin[BOTTOM]; + box->h += margin[BOTTOM]; } static void indent(int level) @@ -290,6 +292,12 @@ static void print_box(fz_context *ctx, struct box *box, int level) } } +void +html_run_box(fz_context *ctx, struct box *box, fz_device *dev, const fz_matrix *ctm) +{ + +} + static char *concat_text(fz_context *ctx, fz_xml *root) { fz_xml *node; @@ -356,6 +364,7 @@ html_layout_document(html_document *doc, float w, float h) struct rule *css = NULL; struct box *root_box; struct box *win_box; + struct style style; #if 0 strcpy(dirname, argv[i]); @@ -366,18 +375,23 @@ html_layout_document(html_document *doc, float w, float h) #endif css = fz_parse_css(doc->ctx, NULL, default_css); - css = load_css(doc->ctx, css, doc->root); + css = load_css(doc->ctx, css, doc->xml); print_rules(css); - root_box = new_box(doc->ctx, NULL, NULL); - generate_boxes(doc->ctx, doc->root, root_box, css); + style.up = NULL; + style.count = 0; + root_box = new_box(doc->ctx, NULL); - win_box = new_box(doc->ctx, NULL, NULL); + generate_boxes(doc->ctx, doc->xml, root_box, css, &style); + + win_box = new_box(doc->ctx, NULL); win_box->w = w; win_box->h = 0; - layout_block(doc->ctx, root_box, win_box); + layout_block(doc->ctx, root_box, win_box, 12); print_box(doc->ctx, root_box, 0); + + doc->box = root_box; } -- cgit v1.2.3 From 59a3ca3072abebde69c11d5070c0bc42773f0f44 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 4 Nov 2014 15:13:56 +0100 Subject: html: Prune unused style properties in computed_style. --- source/html/css-apply.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 8526f7b9..4f58154a 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -792,23 +792,9 @@ compute_style(struct computed_style *style, struct style *node) memset(style, 0, sizeof *style); - style->position = POS_STATIC; style->text_align = TA_LEFT; style->font_size = make_number(1, N_SCALE); - value = get_style_property(node, "position"); - if (value) - { - if (!strcmp(value->data, "static")) - style->position = POS_STATIC; - if (!strcmp(value->data, "relative")) - style->position = POS_RELATIVE; - if (!strcmp(value->data, "absolute")) - style->position = POS_ABSOLUTE; - if (!strcmp(value->data, "fixed")) - style->position = POS_FIXED; - } - value = get_style_property(node, "text-align"); if (value) { @@ -890,16 +876,14 @@ void print_style(struct computed_style *style) { printf("style {\n"); - printf("\tposition = %d;\n", style->position); - printf("\ttext-align = %d;\n", style->text_align); - printf("\tfont-family = %s;\n", style->font_family); - printf("\tfont-weight = %s;\n", style->bold ? "bold" : "normal"); - printf("\tfont-style = %s;\n", style->italic ? "italic" : "normal"); - printf("\tfont-variant = %s;\n", style->smallcaps ? "small-caps" : "normal"); - printf("\tfont-size = %g%c;\n", style->font_size.value, style->font_size.unit); + printf("\tfont = %s", style->font_family); + printf(" %s", style->bold ? "bold" : "normal"); + printf(" %s", style->italic ? "italic" : "normal"); + printf(" %s;\n", style->smallcaps ? "small-caps" : "normal"); printf("\tline-height = %g%c;\n", style->line_height.value, style->line_height.unit); printf("\ttext-indent = %g%c;\n", style->text_indent.value, style->text_indent.unit); + printf("\ttext-align = %d;\n", style->text_align); printf("\tvertical-align = %d;\n", style->vertical_align); printf("\tmargin = %g%c %g%c %g%c %g%c;\n", style->margin[0].value, style->margin[0].unit, -- cgit v1.2.3 From b8f932bba1ca5003700a8c6465e6b67bffb5ea38 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 4 Nov 2014 17:01:19 +0100 Subject: html: Parse white-space property. --- source/html/css-apply.c | 55 +++++++++++++++++++++++++++++++++---------------- source/html/css-parse.c | 1 - 2 files changed, 37 insertions(+), 19 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 4f58154a..0e451ce0 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -699,24 +699,6 @@ get_style_property_string(struct style *node, const char *name, const char *init return value->data; } -int -get_style_property_display(struct style *node) -{ - struct value *value = get_style_property(node, "display"); - if (value) - { - if (!strcmp(value->data, "none")) - return DIS_NONE; - if (!strcmp(value->data, "inline")) - return DIS_INLINE; - if (!strcmp(value->data, "block")) - return DIS_BLOCK; - if (!strcmp(value->data, "list-item")) - return DIS_LIST_ITEM; - } - return DIS_INLINE; -} - static struct number make_number(float v, int u) { @@ -785,6 +767,39 @@ from_number(struct number number, float em, float width) } } +int +get_style_property_display(struct style *node) +{ + struct value *value = get_style_property(node, "display"); + if (value) + { + if (!strcmp(value->data, "none")) + return DIS_NONE; + if (!strcmp(value->data, "inline")) + return DIS_INLINE; + if (!strcmp(value->data, "block")) + return DIS_BLOCK; + if (!strcmp(value->data, "list-item")) + return DIS_LIST_ITEM; + } + return DIS_INLINE; +} + +int +get_style_property_white_space(struct style *node) +{ + struct value *value = get_style_property(node, "white-space"); + if (value) + { + if (!strcmp(value->data, "normal")) return WS_NORMAL; + if (!strcmp(value->data, "pre")) return WS_PRE; + if (!strcmp(value->data, "nowrap")) return WS_NOWRAP; + if (!strcmp(value->data, "pre-wrap")) return WS_PRE_WRAP; + if (!strcmp(value->data, "pre-line")) return WS_PRE_LINE; + } + return WS_NORMAL; +} + void compute_style(struct computed_style *style, struct style *node) { @@ -793,8 +808,12 @@ compute_style(struct computed_style *style, struct style *node) memset(style, 0, sizeof *style); style->text_align = TA_LEFT; + style->vertical_align = 0; + style->white_space = WS_NORMAL; style->font_size = make_number(1, N_SCALE); + style->white_space = get_style_property_white_space(node); + value = get_style_property(node, "text-align"); if (value) { diff --git a/source/html/css-parse.c b/source/html/css-parse.c index 066eb0f7..28176d14 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -1,4 +1,3 @@ -#include "mupdf/fitz.h" #include "mupdf/html.h" struct lexbuf -- cgit v1.2.3 From 24d9a0f9720f7faade99f34c478bb24225174e91 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 4 Nov 2014 17:02:33 +0100 Subject: html: Create word and glue list for flow boxes. --- source/html/layout.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) (limited to 'source/html') diff --git a/source/html/layout.c b/source/html/layout.c index 898e0eb7..3bdb26af 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -43,9 +43,30 @@ struct box float x, y, w, h; struct box *up, *down, *last, *next; fz_xml *node; + struct flow *flow_head, **flow_tail; struct computed_style style; }; +enum +{ + FLOW_WORD, + FLOW_GLUE, +}; + +struct flow +{ + int type; + struct computed_style *style; + char *text, *broken_text; + float width, broken_width; + struct flow *next; +}; + +static int iswhite(int c) +{ + return c == ' ' || c == '\t' || c == '\r' || c == '\n'; +} + struct box *new_box(fz_context *ctx, fz_xml *node) { struct box *box; @@ -63,6 +84,9 @@ struct box *new_box(fz_context *ctx, fz_xml *node) box->node = node; + box->flow_head = NULL; + box->flow_tail = &box->flow_head; + return box; } @@ -185,6 +209,61 @@ static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struc } } +static struct flow *add_flow(fz_context *ctx, struct box *top, struct computed_style *style, int type) +{ + struct flow *flow = fz_malloc_struct(ctx, struct flow); + flow->type = type; + flow->style = style; + *top->flow_tail = flow; + top->flow_tail = &flow->next; + return flow; +} + +static void add_flow_space(fz_context *ctx, struct box *top, struct computed_style *style, float em) +{ + struct flow *flow; + + /* delete space at the beginning of the line */ + if (!top->flow_head) + return; + + flow = add_flow(ctx, top, style, FLOW_GLUE); + flow->text = " "; + flow->width = 0.5 * em; + flow->broken_text = ""; + flow->broken_width = 0; +} + +static void add_flow_word(fz_context *ctx, struct box *top, struct computed_style *style, float em, const char *a, const char *b) +{ + struct flow *flow = add_flow(ctx, top, style, FLOW_WORD); + flow->text = fz_malloc(ctx, b - a + 1); + memcpy(flow->text, a, b - a); + flow->text[b - a] = 0; + flow->width = (b - a) * 0.5 * em; +} + +static void layout_text(fz_context *ctx, struct box *top, const char *text, struct computed_style *style, float em) +{ + while (*text) + { + if (iswhite(*text)) + { + ++text; + while (iswhite(*text)) + ++text; + add_flow_space(ctx, top, style, em); + } + if (*text) + { + const char *mark = text++; + while (*text && !iswhite(*text)) + ++text; + add_flow_word(ctx, top, style, em, mark, text); + } + } +} + static void layout_inline(fz_context *ctx, struct box *box, struct box *top, float em) { struct box *child; @@ -200,6 +279,8 @@ static void layout_inline(fz_context *ctx, struct box *box, struct box *top, flo s = fz_xml_text(box->node); if (s) { + layout_text(ctx, top, s, &box->style, em); + box->w += strlen(s) * 0.5 * em; } @@ -254,7 +335,10 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa if (child->type == BOX_BLOCK) layout_block(ctx, child, box, em); else if (child->type == BOX_FLOW) + { layout_flow(ctx, child, box, em); + // TOOD: remove flow box if no flow content + } box->h += child->h; } @@ -266,6 +350,21 @@ static void indent(int level) while (level--) printf(" "); } +static void print_flow(fz_context *ctx, struct flow *flow, int level) +{ + while (flow) + { + printf(" "); + indent(level); + switch (flow->type) + { + case FLOW_WORD: printf("word \"%s\"\n", flow->text); break; + case FLOW_GLUE: printf("glue \"%s\" / \"%s\"\n", flow->text, flow->broken_text); break; + } + flow = flow->next; + } +} + static void print_box(fz_context *ctx, struct box *box, int level) { while (box) @@ -288,6 +387,8 @@ static void print_box(fz_context *ctx, struct box *box, int level) printf("\n"); if (box->down) print_box(ctx, box->down, level + 1); + if (box->flow_head) + print_flow(ctx, box->flow_head, level + 1); box = box->next; } } -- cgit v1.2.3 From 36667a0003cc5ac230d94f3483bcc77e8cfc600e Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 5 Nov 2014 16:02:19 +0100 Subject: html: Generate flow nodes during box generation. --- source/html/css-apply.c | 13 ++-- source/html/layout.c | 174 ++++++++++++++++++++++-------------------------- 2 files changed, 88 insertions(+), 99 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 0e451ce0..d5ceb24d 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -801,16 +801,21 @@ get_style_property_white_space(struct style *node) } void -compute_style(struct computed_style *style, struct style *node) +default_computed_style(struct computed_style *style) { - struct value *value; - memset(style, 0, sizeof *style); - style->text_align = TA_LEFT; style->vertical_align = 0; style->white_space = WS_NORMAL; style->font_size = make_number(1, N_SCALE); +} + +void +compute_style(struct computed_style *style, struct style *node) +{ + struct value *value; + + default_computed_style(style); style->white_space = get_style_property_white_space(node); diff --git a/source/html/layout.c b/source/html/layout.c index 3bdb26af..b8627e34 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -56,9 +56,9 @@ enum struct flow { int type; + float x, y, w, h; struct computed_style *style; char *text, *broken_text; - float width, broken_width; struct flow *next; }; @@ -67,6 +67,62 @@ static int iswhite(int c) return c == ' ' || c == '\t' || c == '\r' || c == '\n'; } +static struct flow *add_flow(fz_context *ctx, struct box *top, struct computed_style *style, int type) +{ + struct flow *flow = fz_malloc_struct(ctx, struct flow); + flow->type = type; + flow->style = style; + *top->flow_tail = flow; + top->flow_tail = &flow->next; + return flow; +} + +static void add_flow_space(fz_context *ctx, struct box *top, struct computed_style *style) +{ + struct flow *flow; + + /* delete space at the beginning of the line */ + if (!top->flow_head) + return; + + flow = add_flow(ctx, top, style, FLOW_GLUE); + flow->text = " "; + flow->broken_text = ""; +} + +static void add_flow_word(fz_context *ctx, struct box *top, struct computed_style *style, const char *a, const char *b) +{ + struct flow *flow = add_flow(ctx, top, style, FLOW_WORD); + flow->text = fz_malloc(ctx, b - a + 1); + memcpy(flow->text, a, b - a); + flow->text[b - a] = 0; +} + +static void generate_text(fz_context *ctx, struct box *box, const char *text) +{ + struct box *flow = box; + while (flow->type != BOX_FLOW) + flow = flow->up; + + while (*text) + { + if (iswhite(*text)) + { + ++text; + while (iswhite(*text)) + ++text; + add_flow_space(ctx, flow, &box->style); + } + if (*text) + { + const char *mark = text++; + while (*text && !iswhite(*text)) + ++text; + add_flow_word(ctx, flow, &box->style, mark, text); + } + } +} + struct box *new_box(fz_context *ctx, fz_xml *node) { struct box *box; @@ -87,6 +143,8 @@ struct box *new_box(fz_context *ctx, fz_xml *node) box->flow_head = NULL; box->flow_tail = &box->flow_head; + default_computed_style(&box->style); + return box; } @@ -175,7 +233,7 @@ static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struc display = get_style_property_display(&style); - // TOOD:
+ // TODO:
// TODO: if (display != DIS_NONE) @@ -196,11 +254,14 @@ static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struc if (fz_xml_down(node)) generate_boxes(ctx, fz_xml_down(node), box, rule, &style); + + // TODO: remove empty flow boxes } } else { insert_inline_box(ctx, box, top); + generate_text(ctx, box, fz_xml_text(node)); } compute_style(&box->style, &style); @@ -209,93 +270,18 @@ static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struc } } -static struct flow *add_flow(fz_context *ctx, struct box *top, struct computed_style *style, int type) -{ - struct flow *flow = fz_malloc_struct(ctx, struct flow); - flow->type = type; - flow->style = style; - *top->flow_tail = flow; - top->flow_tail = &flow->next; - return flow; -} - -static void add_flow_space(fz_context *ctx, struct box *top, struct computed_style *style, float em) -{ - struct flow *flow; - - /* delete space at the beginning of the line */ - if (!top->flow_head) - return; - - flow = add_flow(ctx, top, style, FLOW_GLUE); - flow->text = " "; - flow->width = 0.5 * em; - flow->broken_text = ""; - flow->broken_width = 0; -} - -static void add_flow_word(fz_context *ctx, struct box *top, struct computed_style *style, float em, const char *a, const char *b) -{ - struct flow *flow = add_flow(ctx, top, style, FLOW_WORD); - flow->text = fz_malloc(ctx, b - a + 1); - memcpy(flow->text, a, b - a); - flow->text[b - a] = 0; - flow->width = (b - a) * 0.5 * em; -} - -static void layout_text(fz_context *ctx, struct box *top, const char *text, struct computed_style *style, float em) -{ - while (*text) - { - if (iswhite(*text)) - { - ++text; - while (iswhite(*text)) - ++text; - add_flow_space(ctx, top, style, em); - } - if (*text) - { - const char *mark = text++; - while (*text && !iswhite(*text)) - ++text; - add_flow_word(ctx, top, style, em, mark, text); - } - } -} - -static void layout_inline(fz_context *ctx, struct box *box, struct box *top, float em) +static void layout_text(fz_context *ctx, struct flow *node, struct box *top, float em) { - struct box *child; - const char *s; - - em = from_number(box->style.font_size, em, em); - - box->x = top->x + top->w; - box->y = top->y; - box->h = em; - box->w = 0; - - s = fz_xml_text(box->node); - if (s) - { - layout_text(ctx, top, s, &box->style, em); - - box->w += strlen(s) * 0.5 * em; - } - - for (child = box->down; child; child = child->next) - { - layout_inline(ctx, child, top, em); - if (child->h > box->h) - box->h = child->h; - top->w += child->w; - } + em = from_number(node->style->font_size, em, em); + node->x = top->x + top->w; + node->y = top->y; + node->h = em; + node->w = strlen(node->text) * 0.5 * em; } static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float em) { - struct box *child; + struct flow *node; em = from_number(box->style.font_size, em, em); @@ -304,12 +290,12 @@ static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float box->h = 0; box->w = 0; - for (child = box->down; child; child = child->next) + for (node = box->flow_head; node; node = node->next) { - layout_inline(ctx, child, box, em); - if (child->h > box->h) - box->h = child->h; - box->w += child->w; + layout_text(ctx, node, box, em); + if (node->h > box->h) + box->h = node->h; + box->w += node->w; } } @@ -335,10 +321,7 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa if (child->type == BOX_BLOCK) layout_block(ctx, child, box, em); else if (child->type == BOX_FLOW) - { layout_flow(ctx, child, box, em); - // TOOD: remove flow box if no flow content - } box->h += child->h; } @@ -354,7 +337,7 @@ static void print_flow(fz_context *ctx, struct flow *flow, int level) { while (flow) { - printf(" "); + printf("%-5d %-5d", (int)flow->x, (int)flow->y); indent(level); switch (flow->type) { @@ -482,14 +465,15 @@ html_layout_document(html_document *doc, float w, float h) style.up = NULL; style.count = 0; - root_box = new_box(doc->ctx, NULL); - generate_boxes(doc->ctx, doc->xml, root_box, css, &style); + root_box = new_box(doc->ctx, NULL); win_box = new_box(doc->ctx, NULL); win_box->w = w; win_box->h = 0; + generate_boxes(doc->ctx, doc->xml, root_box, css, &style); + layout_block(doc->ctx, root_box, win_box, 12); print_box(doc->ctx, root_box, 0); -- cgit v1.2.3 From 7cb2a64e678f0179cb75d2de0321d5d4ca35183f Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 11 Nov 2014 17:03:25 +0100 Subject: html: Draw text and shade padding boxes. --- source/html/font.c | 40 ++++++++++++++++ source/html/layout.c | 130 +++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 155 insertions(+), 15 deletions(-) create mode 100644 source/html/font.c (limited to 'source/html') diff --git a/source/html/font.c b/source/html/font.c new file mode 100644 index 00000000..102bb8df --- /dev/null +++ b/source/html/font.c @@ -0,0 +1,40 @@ +#include "mupdf/html.h" +#include "mupdf/pdf.h" /* for pdf_lookup_substitute_font */ + +#include +#include FT_FREETYPE_H + +static int ft_is_bold(FT_Face face) +{ + return face->style_flags & FT_STYLE_FLAG_BOLD; +} + +static int ft_is_italic(FT_Face face) +{ + return face->style_flags & FT_STYLE_FLAG_ITALIC; +} + +fz_font * +html_load_font(fz_context *ctx, + const char *family, const char *variant, const char *style, const char *weight) +{ + unsigned char *data; + unsigned int size; + fz_font *font; + + int is_bold = !strcmp(weight, "bold"); + int is_italic = !strcmp(style, "italic"); + + int is_mono = !strcmp(family, "monospace"); + int is_sans = !strcmp(family, "sans-serif"); + + // TODO: keep a cache of loaded fonts + + data = pdf_lookup_substitute_font(is_mono, !is_sans, is_bold, is_italic, &size); + + font = fz_new_font_from_memory(ctx, family, data, size, 0, 1); + font->ft_bold = is_bold && !ft_is_bold(font->ft_face); + font->ft_italic = is_italic && !ft_is_italic(font->ft_face); + + return font; +} diff --git a/source/html/layout.c b/source/html/layout.c index b8627e34..9fd22094 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -30,6 +30,8 @@ static const char *default_css = "center{text-align:center}" "svg{display:none}"; +static fz_font *font = NULL; + enum { BOX_BLOCK, /* block-level: contains block and flow boxes */ @@ -40,7 +42,9 @@ enum struct box { int type; - float x, y, w, h; + float x, y, w, h; /* content */ + float padding[4]; + float margin[4]; struct box *up, *down, *last, *next; fz_xml *node; struct flow *flow_head, **flow_tail; @@ -56,7 +60,7 @@ enum struct flow { int type; - float x, y, w, h; + float x, y, w, h, em; struct computed_style *style; char *text, *broken_text; struct flow *next; @@ -272,11 +276,25 @@ static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struc static void layout_text(fz_context *ctx, struct flow *node, struct box *top, float em) { + const char *s; + int c, g; + float w; + em = from_number(node->style->font_size, em, em); node->x = top->x + top->w; node->y = top->y; node->h = em; - node->w = strlen(node->text) * 0.5 * em; + + w = 0; + s = node->text; + while (*s) + { + s += fz_chartorune(&c, s); + g = fz_encode_character(ctx, font, c); + w += fz_advance_glyph(ctx, font, g) * em; + } + node->w = w; + node->em = em; } static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float em) @@ -302,18 +320,24 @@ static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float static void layout_block(fz_context *ctx, struct box *box, struct box *top, float em) { struct box *child; - float margin[4]; em = from_number(box->style.font_size, em, em); - margin[0] = from_number(box->style.margin[0], em, top->w); - margin[1] = from_number(box->style.margin[1], em, top->w); - margin[2] = from_number(box->style.margin[2], em, top->w); - margin[3] = from_number(box->style.margin[3], em, top->w); + box->margin[0] = from_number(box->style.margin[0], em, top->w); + box->margin[1] = from_number(box->style.margin[1], em, top->w); + box->margin[2] = from_number(box->style.margin[2], em, top->w); + box->margin[3] = from_number(box->style.margin[3], em, top->w); + + box->padding[0] = from_number(box->style.padding[0], em, top->w); + box->padding[1] = from_number(box->style.padding[1], em, top->w); + box->padding[2] = from_number(box->style.padding[2], em, top->w); + box->padding[3] = from_number(box->style.padding[3], em, top->w); + + // TODO: collapse vertical margins - box->x = top->x + margin[LEFT]; - box->y = top->y + top->h + margin[TOP]; - box->w = top->w - (margin[LEFT] + margin[RIGHT]); + box->x = top->x + box->margin[LEFT] + box->padding[LEFT]; + box->y = top->y + top->h + box->margin[TOP] + box->padding[TOP]; + box->w = top->w - (box->margin[LEFT] + box->margin[RIGHT] + box->padding[LEFT] + box->padding[RIGHT]); box->h = 0; for (child = box->down; child; child = child->next) @@ -322,10 +346,8 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa layout_block(ctx, child, box, em); else if (child->type == BOX_FLOW) layout_flow(ctx, child, box, em); - box->h += child->h; + box->h += child->h + child->padding[TOP] + child->padding[BOTTOM] + child->margin[TOP] + child->margin[BOTTOM]; } - - box->h += margin[BOTTOM]; } static void indent(int level) @@ -376,10 +398,86 @@ static void print_box(fz_context *ctx, struct box *box, int level) } } +static void +draw_flow_box(fz_context *ctx, struct box *box, fz_device *dev, const fz_matrix *ctm) +{ + struct flow *node; + fz_text *text; + fz_matrix trm; + const char *s; + float black[1]; + float x, y; + int c, g; + + black[0] = 0; + + for (node = box->flow_head; node; node = node->next) + { + if (node->type == FLOW_WORD) + { + fz_scale(&trm, node->em, -node->em); + text = fz_new_text(ctx, font, &trm, 0); + + x = node->x; + y = node->y + node->em * 0.8; + s = node->text; + while (*s) + { + s += fz_chartorune(&c, s); + g = fz_encode_character(ctx, font, c); + fz_add_text(ctx, text, g, c, x, y); + x += fz_advance_glyph(ctx, font, g) * node->em; + } + + fz_fill_text(dev, text, ctm, fz_device_gray(ctx), black, 1); + + fz_free_text(ctx, text); + } + } +} + +static void +draw_block_box(fz_context *ctx, struct box *box, fz_device *dev, const fz_matrix *ctm) +{ + fz_path *path; + float black[1]; + float x0, y0, x1, y1; + + // TODO: background fill + // TODO: border stroke + + black[0] = 0; + + x0 = box->x - box->padding[LEFT]; + y0 = box->y - box->padding[TOP]; + x1 = box->x + box->w + box->padding[RIGHT]; + y1 = box->y + box->h + box->padding[BOTTOM]; + + path = fz_new_path(ctx); + fz_moveto(ctx, path, x0, y0); + fz_lineto(ctx, path, x1, y0); + fz_lineto(ctx, path, x1, y1); + fz_lineto(ctx, path, x0, y1); + fz_closepath(ctx, path); + + fz_fill_path(dev, path, 0, ctm, fz_device_gray(ctx), black, 0.1); + + fz_free_path(ctx, path); + + for (box = box->down; box; box = box->next) + { + switch (box->type) + { + case BOX_BLOCK: draw_block_box(ctx, box, dev, ctm); break; + case BOX_FLOW: draw_flow_box(ctx, box, dev, ctm); break; + } + } +} + void html_run_box(fz_context *ctx, struct box *box, fz_device *dev, const fz_matrix *ctm) { - + draw_block_box(ctx, box, dev, ctm); } static char *concat_text(fz_context *ctx, fz_xml *root) @@ -458,6 +556,8 @@ html_layout_document(html_document *doc, float w, float h) else strcpy(dirname, "./"); #endif + font = html_load_font(doc->ctx, "serif", "normal", "normal", "normal"); + css = fz_parse_css(doc->ctx, NULL, default_css); css = load_css(doc->ctx, css, doc->xml); -- cgit v1.2.3 From d8699f7f7a5ee7192e1e437eaffa75f415204073 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 11 Nov 2014 17:25:07 +0100 Subject: html: Collapse adjacent top/bottom margins. --- source/html/layout.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'source/html') diff --git a/source/html/layout.c b/source/html/layout.c index 9fd22094..84c02e3d 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -317,9 +317,11 @@ static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float } } -static void layout_block(fz_context *ctx, struct box *box, struct box *top, float em) +static void layout_block(fz_context *ctx, struct box *box, struct box *top, float em, float top_collapse_margin) { struct box *child; + float box_collapse_margin; + float bottom; em = from_number(box->style.font_size, em, em); @@ -333,7 +335,14 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa box->padding[2] = from_number(box->style.padding[2], em, top->w); box->padding[3] = from_number(box->style.padding[3], em, top->w); - // TODO: collapse vertical margins + // TODO: collapse top/top and bottom/bottom margins + + box_collapse_margin = 0; + + if (box->margin[TOP] > top_collapse_margin) + box->margin[TOP] -= top_collapse_margin; + else + box->margin[TOP] = 0; box->x = top->x + box->margin[LEFT] + box->padding[LEFT]; box->y = top->y + top->h + box->margin[TOP] + box->padding[TOP]; @@ -343,10 +352,20 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa for (child = box->down; child; child = child->next) { if (child->type == BOX_BLOCK) - layout_block(ctx, child, box, em); + { + layout_block(ctx, child, box, em, box_collapse_margin); + box->h += child->h + child->padding[TOP] + child->padding[BOTTOM] + child->margin[TOP] + child->margin[BOTTOM]; + box_collapse_margin = child->margin[BOTTOM]; + } else if (child->type == BOX_FLOW) + { layout_flow(ctx, child, box, em); - box->h += child->h + child->padding[TOP] + child->padding[BOTTOM] + child->margin[TOP] + child->margin[BOTTOM]; + if (child->h > 0) + { + box->h += child->h; + box_collapse_margin = 0; + } + } } } @@ -574,7 +593,7 @@ html_layout_document(html_document *doc, float w, float h) generate_boxes(doc->ctx, doc->xml, root_box, css, &style); - layout_block(doc->ctx, root_box, win_box, 12); + layout_block(doc->ctx, root_box, win_box, 12, 0); print_box(doc->ctx, root_box, 0); -- cgit v1.2.3 From a5f282cac059b279823520ae3e3dfd2138a1fe23 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 12 Nov 2014 02:24:39 +0100 Subject: html: Collapse top/top and bottom/bottom margins. --- source/html/layout.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'source/html') diff --git a/source/html/layout.c b/source/html/layout.c index 84c02e3d..6d9753ba 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -335,9 +335,10 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa box->padding[2] = from_number(box->style.padding[2], em, top->w); box->padding[3] = from_number(box->style.padding[3], em, top->w); - // TODO: collapse top/top and bottom/bottom margins - - box_collapse_margin = 0; + if (box->padding[TOP] == 0) + box_collapse_margin = box->margin[TOP]; + else + box_collapse_margin = 0; if (box->margin[TOP] > top_collapse_margin) box->margin[TOP] -= top_collapse_margin; @@ -367,6 +368,16 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa } } } + + if (box->padding[BOTTOM] == 0) + { + if (box->margin[BOTTOM] > 0) + { + box->h -= box_collapse_margin; + if (box->margin[BOTTOM] < box_collapse_margin) + box->margin[BOTTOM] = box_collapse_margin; + } + } } static void indent(int level) -- cgit v1.2.3 From d50623858386a8d99f71e6361296a50db164f103 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 12 Nov 2014 15:37:56 +0100 Subject: html: Fix bug in percentage from_number calculations. --- source/html/css-apply.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index d5ceb24d..325b0dab 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -763,7 +763,7 @@ from_number(struct number number, float em, float width) default: case N_NUMBER: return number.value; case N_SCALE: return number.value * em; - case N_PERCENT: return number.value * width; + case N_PERCENT: return number.value * 0.01 * width; } } -- cgit v1.2.3 From c90b2253e40cc5646319bcc79e69b1dc7154db92 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 12 Nov 2014 15:38:45 +0100 Subject: html: Line breaking and font styling. --- source/html/css-apply.c | 33 +++++++-------- source/html/font.c | 52 +++++++++++------------- source/html/layout.c | 106 ++++++++++++++++++++++++++++++++++++------------ 3 files changed, 118 insertions(+), 73 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 325b0dab..63a4941c 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -767,6 +767,17 @@ from_number(struct number number, float em, float width) } } +float +from_number_scale(struct number number, float scale, float em, float width) +{ + switch (number.unit) { + default: + case N_NUMBER: return number.value * scale; + case N_SCALE: return number.value * em; + case N_PERCENT: return number.value * 0.01 * width; + } +} + int get_style_property_display(struct style *node) { @@ -811,7 +822,7 @@ default_computed_style(struct computed_style *style) } void -compute_style(struct computed_style *style, struct style *node) +compute_style(html_document *doc, struct computed_style *style, struct style *node) { struct value *value; @@ -879,20 +890,7 @@ compute_style(struct computed_style *style, struct style *node) const char *font_variant = get_style_property_string(node, "font-variant", "normal"); const char *font_style = get_style_property_string(node, "font-style", "normal"); const char *font_weight = get_style_property_string(node, "font-weight", "normal"); - - style->font_family = font_family; - - style->smallcaps = 0; - if (!strcmp(font_variant, "small-caps")) - style->smallcaps = 1; - - style->italic = 0; - if (!strcmp(font_style, "italic") || !strcmp(font_style, "oblique")) - style->italic = 1; - - style->bold = 0; - if (!strcmp(font_weight, "bold") || !strcmp(font_weight, "bolder") || atoi(font_weight) > 400) - style->bold = 1; + style->font = html_load_font(doc, font_family, font_variant, font_style, font_weight); } } @@ -901,10 +899,7 @@ print_style(struct computed_style *style) { printf("style {\n"); printf("\tfont-size = %g%c;\n", style->font_size.value, style->font_size.unit); - printf("\tfont = %s", style->font_family); - printf(" %s", style->bold ? "bold" : "normal"); - printf(" %s", style->italic ? "italic" : "normal"); - printf(" %s;\n", style->smallcaps ? "small-caps" : "normal"); + printf("\tfont = %s;\n", style->font->name); printf("\tline-height = %g%c;\n", style->line_height.value, style->line_height.unit); printf("\ttext-indent = %g%c;\n", style->text_indent.value, style->text_indent.unit); printf("\ttext-align = %d;\n", style->text_align); diff --git a/source/html/font.c b/source/html/font.c index 102bb8df..9c408367 100644 --- a/source/html/font.c +++ b/source/html/font.c @@ -1,40 +1,36 @@ #include "mupdf/html.h" -#include "mupdf/pdf.h" /* for pdf_lookup_substitute_font */ +#include "mupdf/pdf.h" /* for pdf_lookup_builtin_font */ -#include -#include FT_FREETYPE_H - -static int ft_is_bold(FT_Face face) -{ - return face->style_flags & FT_STYLE_FLAG_BOLD; -} - -static int ft_is_italic(FT_Face face) -{ - return face->style_flags & FT_STYLE_FLAG_ITALIC; -} +static const char *font_names[16] = { + "Times-Roman", "Times-Italic", "Times-Bold", "Times-BoldItalic", + "Helvetica", "Helvetica-Oblique", "Helvetica-Bold", "Helvetica-BoldOblique", + "Courier", "Courier-Oblique", "Courier-Bold", "Courier-BoldOblique", + "Courier", "Courier-Oblique", "Courier-Bold", "Courier-BoldOblique", +}; fz_font * -html_load_font(fz_context *ctx, +html_load_font(html_document *doc, const char *family, const char *variant, const char *style, const char *weight) { + fz_context *ctx = doc->ctx; unsigned char *data; unsigned int size; - fz_font *font; - - int is_bold = !strcmp(weight, "bold"); - int is_italic = !strcmp(style, "italic"); int is_mono = !strcmp(family, "monospace"); int is_sans = !strcmp(family, "sans-serif"); - - // TODO: keep a cache of loaded fonts - - data = pdf_lookup_substitute_font(is_mono, !is_sans, is_bold, is_italic, &size); - - font = fz_new_font_from_memory(ctx, family, data, size, 0, 1); - font->ft_bold = is_bold && !ft_is_bold(font->ft_face); - font->ft_italic = is_italic && !ft_is_italic(font->ft_face); - - return font; + int is_bold = !strcmp(weight, "bold") || !strcmp(weight, "bolder") || atoi(weight) > 400; + int is_italic = !strcmp(style, "italic") || !strcmp(style, "oblique"); + + int idx = is_mono * 8 + is_sans * 4 + is_bold * 2 + is_italic; + if (!doc->fonts[idx]) + { + data = pdf_lookup_builtin_font(font_names[idx], &size); + if (!data) { + printf("data=%p idx=%d s=%s\n", data, idx, font_names[idx]); + abort(); + } + doc->fonts[idx] = fz_new_font_from_memory(ctx, font_names[idx], data, size, 0, 1); + } + + return doc->fonts[idx]; } diff --git a/source/html/layout.c b/source/html/layout.c index 6d9753ba..d07b2dab 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -30,8 +30,6 @@ static const char *default_css = "center{text-align:center}" "svg{display:none}"; -static fz_font *font = NULL; - enum { BOX_BLOCK, /* block-level: contains block and flow boxes */ @@ -218,8 +216,9 @@ static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) } } -static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struct rule *rule, struct style *up_style) +static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, struct rule *rule, struct style *up_style) { + fz_context *ctx = doc->ctx; struct style style; struct box *box; int display; @@ -257,7 +256,7 @@ static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struc } if (fz_xml_down(node)) - generate_boxes(ctx, fz_xml_down(node), box, rule, &style); + generate_boxes(doc, fz_xml_down(node), box, rule, &style); // TODO: remove empty flow boxes } @@ -268,60 +267,117 @@ static void generate_boxes(fz_context *ctx, fz_xml *node, struct box *top, struc generate_text(ctx, box, fz_xml_text(node)); } - compute_style(&box->style, &style); + compute_style(doc, &box->style, &style); node = fz_xml_next(node); } } -static void layout_text(fz_context *ctx, struct flow *node, struct box *top, float em) +static void measure_word(fz_context *ctx, struct flow *node, float em) { const char *s; int c, g; float w; em = from_number(node->style->font_size, em, em); - node->x = top->x + top->w; - node->y = top->y; - node->h = em; + node->x = 0; + node->y = 0; + node->h = from_number_scale(node->style->line_height, em, em, em); w = 0; s = node->text; while (*s) { s += fz_chartorune(&c, s); - g = fz_encode_character(ctx, font, c); - w += fz_advance_glyph(ctx, font, g) * em; + g = fz_encode_character(ctx, node->style->font, c); + w += fz_advance_glyph(ctx, node->style->font, g) * em; } node->w = w; node->em = em; } +static float layout_line(fz_context *ctx, float indent, struct flow *node, struct flow *end, struct box *box) +{ + float x = box->x + indent; + float y = box->y + box->h; + float h = 0; + + while (node != end) + { + node->x = x; + node->y = y; + x += node->w; + if (node->h > h) + h = node->h; + node = node->next; + } + + return h; +} + static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float em) { - struct flow *node; + struct flow *node, *first_word, *last_glue; + float line_w, line_h; + float indent; em = from_number(box->style.font_size, em, em); + indent = from_number(top->style.text_indent, em, top->w); + box->x = top->x; box->y = top->y + top->h; - box->h = 0; box->w = 0; + box->h = 0; + first_word = box->flow_head; + last_glue = NULL; + line_w = indent; for (node = box->flow_head; node; node = node->next) { - layout_text(ctx, node, box, em); - if (node->h > box->h) - box->h = node->h; - box->w += node->w; + if (node->type == FLOW_GLUE) + last_glue = node; + + measure_word(ctx, node, em); + if (last_glue && line_w + node->w > top->w) + { + line_h = layout_line(ctx, indent, first_word, last_glue, box); + if (line_w > box->w) + box->w = line_w; + box->h += line_h; + + if (node == last_glue && node->next) + { + node = node->next; + measure_word(ctx, node, em); + } + + first_word = node; + last_glue = NULL; + line_w = node->w; + indent = 0; + } + else if (line_w + node->w > top->w) + { + printf("WARNING: line overflow! (%s)\n", node->text); + line_w += node->w; + } + else + { + line_w += node->w; + } } + + line_h = layout_line(ctx, indent, first_word, NULL, box); + if (line_w > box->w) + box->w = line_w; + box->h += line_h; } static void layout_block(fz_context *ctx, struct box *box, struct box *top, float em, float top_collapse_margin) { struct box *child; float box_collapse_margin; - float bottom; em = from_number(box->style.font_size, em, em); @@ -422,8 +478,8 @@ static void print_box(fz_context *ctx, struct box *box, int level) printf("\n"); if (box->down) print_box(ctx, box->down, level + 1); - if (box->flow_head) - print_flow(ctx, box->flow_head, level + 1); +// if (box->flow_head) +// print_flow(ctx, box->flow_head, level + 1); box = box->next; } } @@ -446,7 +502,7 @@ draw_flow_box(fz_context *ctx, struct box *box, fz_device *dev, const fz_matrix if (node->type == FLOW_WORD) { fz_scale(&trm, node->em, -node->em); - text = fz_new_text(ctx, font, &trm, 0); + text = fz_new_text(ctx, node->style->font, &trm, 0); x = node->x; y = node->y + node->em * 0.8; @@ -454,9 +510,9 @@ draw_flow_box(fz_context *ctx, struct box *box, fz_device *dev, const fz_matrix while (*s) { s += fz_chartorune(&c, s); - g = fz_encode_character(ctx, font, c); + g = fz_encode_character(ctx, node->style->font, c); fz_add_text(ctx, text, g, c, x, y); - x += fz_advance_glyph(ctx, font, g) * node->em; + x += fz_advance_glyph(ctx, node->style->font, g) * node->em; } fz_fill_text(dev, text, ctm, fz_device_gray(ctx), black, 1); @@ -586,8 +642,6 @@ html_layout_document(html_document *doc, float w, float h) else strcpy(dirname, "./"); #endif - font = html_load_font(doc->ctx, "serif", "normal", "normal", "normal"); - css = fz_parse_css(doc->ctx, NULL, default_css); css = load_css(doc->ctx, css, doc->xml); @@ -602,7 +656,7 @@ html_layout_document(html_document *doc, float w, float h) win_box->w = w; win_box->h = 0; - generate_boxes(doc->ctx, doc->xml, root_box, css, &style); + generate_boxes(doc, doc->xml, root_box, css, &style); layout_block(doc->ctx, root_box, win_box, 12, 0); -- cgit v1.2.3 From 2dca8942c2ad00fefdd95133c2620f318ccde1b2 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Thu, 13 Nov 2014 12:03:28 +0100 Subject: html: Create value lists in the correct order. --- source/html/css-parse.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'source/html') diff --git a/source/html/css-parse.c b/source/html/css-parse.c index 28176d14..fe91a933 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -408,19 +408,20 @@ static struct value *parse_value(struct lexbuf *buf) static struct value *parse_value_list(struct lexbuf *buf) { - struct value *v, *vv; + struct value *head, *tail; - vv = NULL; + head = tail = NULL; while (buf->lookahead != '}' && buf->lookahead != ';' && buf->lookahead != '!' && buf->lookahead != ')' && buf->lookahead != EOF) { - v = parse_value(buf); - v->next = vv; - vv = v; + if (!head) + head = tail = parse_value(buf); + else + tail = tail->next = parse_value(buf); } - return vv; + return head; } static struct property *parse_declaration(struct lexbuf *buf) -- cgit v1.2.3 From eea982f2ea75a39a0c1218f528cfaa6678baf263 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Thu, 13 Nov 2014 12:06:46 +0100 Subject: html: Parse external CSS files and basic pagination. Show a translated view of the continuous layout for each page. --- source/html/css-parse.c | 27 ++++++++++++++++ source/html/handler.c | 34 ++++++++++++++------ source/html/layout.c | 82 +++++++++++++++---------------------------------- 3 files changed, 76 insertions(+), 67 deletions(-) (limited to 'source/html') diff --git a/source/html/css-parse.c b/source/html/css-parse.c index fe91a933..93c5ff58 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -745,3 +745,30 @@ struct rule *fz_parse_css(fz_context *ctx, struct rule *chain, const char *sourc next(&buf); return parse_stylesheet(&buf, chain); } + +struct rule *fz_parse_css_file(fz_context *ctx, struct rule *chain, const char *filename) +{ + fz_stream *stm = NULL; + fz_buffer *buf = NULL; + + fz_var(buf); + + stm = fz_open_file(ctx, filename); + fz_try(ctx) + { + buf = fz_read_all(stm, 0); + fz_write_buffer_byte(ctx, buf, 0); + chain = fz_parse_css(ctx, chain, buf->data); + } + fz_always(ctx) + { + fz_drop_buffer(ctx, buf); + fz_close(stm); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } + + return chain; +} diff --git a/source/html/handler.c b/source/html/handler.c index 859721c8..0c7463cb 100644 --- a/source/html/handler.c +++ b/source/html/handler.c @@ -10,14 +10,21 @@ html_close_document(html_document *doc) int html_count_pages(html_document *doc) { - return 1; + int count; + + if (!doc->box) html_layout_document(doc, 400, 400); + + count = ceilf(doc->box->h / doc->page_h); +printf("count pages! %g / %g = %d\n", doc->box->h, doc->page_h, count); + return count; } html_page * html_load_page(html_document *doc, int number) { - printf("html: load page %d\n", number); - return doc->box; +printf("load page %d\n", number); + if (!doc->box) html_layout_document(doc, 400, 400); + return (void*)((intptr_t)number + 1); } void @@ -28,18 +35,20 @@ html_free_page(html_document *doc, html_page *page) fz_rect * html_bound_page(html_document *doc, html_page *page, fz_rect *bbox) { + if (!doc->box) html_layout_document(doc, 400, 400); printf("html: bound page\n"); bbox->x0 = bbox->y0 = 0; - bbox->x1 = 400; - bbox->y1 = 600; + bbox->x1 = doc->page_w; + bbox->y1 = doc->page_h; return bbox; } void html_run_page(html_document *doc, html_page *page, fz_device *dev, const fz_matrix *ctm, fz_cookie *cookie) { - printf("html: run page\n"); - html_run_box(doc->ctx, page, dev, ctm); + int n = ((intptr_t)page) - 1; + printf("html: run page %d\n", n); + html_run_box(doc->ctx, doc->box, n * doc->page_h, dev, ctm); } html_document * @@ -50,11 +59,13 @@ html_open_document_with_stream(fz_context *ctx, fz_stream *file) fz_xml *xml; buf = fz_read_all(file, 0); + fz_write_buffer_byte(ctx, buf, 0); xml = fz_parse_xml(ctx, buf->data, buf->len, 1); fz_drop_buffer(ctx, buf); doc = fz_malloc_struct(ctx, html_document); doc->ctx = ctx; + doc->dirname = NULL; doc->super.close = (void*)html_close_document; doc->super.count_pages = (void*)html_count_pages; @@ -66,8 +77,6 @@ html_open_document_with_stream(fz_context *ctx, fz_stream *file) doc->xml = xml; doc->box = NULL; - html_layout_document(doc, 400, 600); - return doc; } @@ -76,6 +85,7 @@ html_open_document(fz_context *ctx, const char *filename) { fz_stream *file; html_document *doc; + char *s; file = fz_open_file(ctx, filename); if (!file) @@ -94,6 +104,12 @@ html_open_document(fz_context *ctx, const char *filename) fz_rethrow(ctx); } + doc->dirname = fz_strdup(ctx, filename); + s = strrchr(doc->dirname, '/'); + if (!s) s = strrchr(doc->dirname, '\\'); + if (s) s[1] = 0; + else doc->dirname[0] = 0; + return doc; } diff --git a/source/html/layout.c b/source/html/layout.c index d07b2dab..76d5b786 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -5,7 +5,7 @@ static const char *default_css = "span{display:inline}" "li{display:list-item}" "head{display:none}" -"body{margin:0px}" +"body{margin:1em}" "h1{font-size:2em;margin:.67em 0}" "h2{font-size:1.5em;margin:.75em 0}" "h3{font-size:1.17em;margin:.83em 0}" @@ -30,40 +30,6 @@ static const char *default_css = "center{text-align:center}" "svg{display:none}"; -enum -{ - BOX_BLOCK, /* block-level: contains block and flow boxes */ - BOX_FLOW, /* block-level: contains only inline boxes */ - BOX_INLINE, /* inline-level: contains only inline boxes */ -}; - -struct box -{ - int type; - float x, y, w, h; /* content */ - float padding[4]; - float margin[4]; - struct box *up, *down, *last, *next; - fz_xml *node; - struct flow *flow_head, **flow_tail; - struct computed_style style; -}; - -enum -{ - FLOW_WORD, - FLOW_GLUE, -}; - -struct flow -{ - int type; - float x, y, w, h, em; - struct computed_style *style; - char *text, *broken_text; - struct flow *next; -}; - static int iswhite(int c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n'; @@ -561,9 +527,11 @@ draw_block_box(fz_context *ctx, struct box *box, fz_device *dev, const fz_matrix } void -html_run_box(fz_context *ctx, struct box *box, fz_device *dev, const fz_matrix *ctm) +html_run_box(fz_context *ctx, struct box *box, float offset, fz_device *dev, const fz_matrix *inctm) { - draw_block_box(ctx, box, dev, ctm); + fz_matrix ctm = *inctm; + fz_pre_translate(&ctm, 0, -offset); + draw_block_box(ctx, box, dev, &ctm); } static char *concat_text(fz_context *ctx, fz_xml *root) @@ -591,13 +559,16 @@ static char *concat_text(fz_context *ctx, fz_xml *root) return s; } -static struct rule *load_css(fz_context *ctx, struct rule *css, fz_xml *root) +static struct rule *load_css(html_document *doc, struct rule *css, fz_xml *root) { + fz_context *ctx = doc->ctx; fz_xml *node; + char filename[2048]; + for (node = root; node; node = fz_xml_next(node)) { const char *tag = fz_xml_tag(node); -#if 0 +#if 1 if (tag && !strcmp(tag, "link")) { char *rel = fz_xml_att(node, "rel"); @@ -607,9 +578,9 @@ static struct rule *load_css(fz_context *ctx, struct rule *css, fz_xml *root) if ((type && !strcmp(type, "text/css")) || !type) { char *href = fz_xml_att(node, "href"); - strcpy(filename, dirname); - strcat(filename, href); - css = css_parse_file(css, filename); + fz_strlcpy(filename, doc->dirname, sizeof filename); + fz_strlcat(filename, href, sizeof filename); + css = fz_parse_css_file(ctx, css, filename); } } } @@ -621,29 +592,24 @@ static struct rule *load_css(fz_context *ctx, struct rule *css, fz_xml *root) fz_free(ctx, s); } if (fz_xml_down(node)) - css = load_css(ctx, css, fz_xml_down(node)); + css = load_css(doc, css, fz_xml_down(node)); } return css; } void -html_layout_document(html_document *doc, float w, float h) +html_layout_document(html_document *doc, float page_w, float page_h) { struct rule *css = NULL; struct box *root_box; - struct box *win_box; + struct box *page_box; struct style style; -#if 0 - strcpy(dirname, argv[i]); - s = strrchr(dirname, '/'); - if (!s) s = strrchr(dirname, '\\'); - if (s) s[1] = 0; - else strcpy(dirname, "./"); -#endif + doc->page_w = page_w; + doc->page_h = page_h; css = fz_parse_css(doc->ctx, NULL, default_css); - css = load_css(doc->ctx, css, doc->xml); + css = load_css(doc, css, doc->xml); print_rules(css); @@ -652,15 +618,15 @@ html_layout_document(html_document *doc, float w, float h) root_box = new_box(doc->ctx, NULL); - win_box = new_box(doc->ctx, NULL); - win_box->w = w; - win_box->h = 0; + page_box = new_box(doc->ctx, NULL); + page_box->w = page_w; + page_box->h = 0; generate_boxes(doc, doc->xml, root_box, css, &style); - layout_block(doc->ctx, root_box, win_box, 12, 0); + layout_block(doc->ctx, root_box, page_box, 12, 0); - print_box(doc->ctx, root_box, 0); + // print_box(doc->ctx, root_box, 0); doc->box = root_box; } -- cgit v1.2.3 From 95b7dff5c86a8a9c09c8771a15ea7963044597ef Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Thu, 13 Nov 2014 22:50:23 +0100 Subject: html: Text alignment. --- source/html/layout.c | 116 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 80 insertions(+), 36 deletions(-) (limited to 'source/html') diff --git a/source/html/layout.c b/source/html/layout.c index 76d5b786..afac6a1a 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -262,17 +262,35 @@ static void measure_word(fz_context *ctx, struct flow *node, float em) node->em = em; } -static float layout_line(fz_context *ctx, float indent, struct flow *node, struct flow *end, struct box *box) +static float layout_line(fz_context *ctx, float indent, float page_w, float line_w, int align, struct flow *node, struct flow *end, struct box *box) { float x = box->x + indent; float y = box->y + box->h; float h = 0; + float slop = page_w - line_w; + float justify = 0; + int n = 0; + + if (align == TA_JUSTIFY) + { + struct flow *it; + for (it = node; it != end; it = it->next) + if (it->type == FLOW_GLUE) + ++n; + justify = slop / n; + } + else if (align == TA_RIGHT) + x += slop; + else if (align == TA_CENTER) + x += slop / 2; while (node != end) { node->x = x; node->y = y; x += node->w; + if (node->type == FLOW_GLUE) + x += justify; if (node->h > h) h = node->h; node = node->next; @@ -281,63 +299,89 @@ static float layout_line(fz_context *ctx, float indent, struct flow *node, struc return h; } +static struct flow *find_next_glue(struct flow *node, float *w) +{ + while (node && node->type == FLOW_GLUE) + { + *w += node->w; + node = node->next; + } + while (node && node->type != FLOW_GLUE) + { + *w += node->w; + node = node->next; + } + return node; +} + +static struct flow *find_next_word(struct flow *node, float *w) +{ + while (node && node->type != FLOW_WORD) + { + *w += node->w; + node = node->next; + } + return node; +} + static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float em) { - struct flow *node, *first_word, *last_glue; - float line_w, line_h; + struct flow *node, *line_start, *word_start, *word_end, *line_end; + float glue_w; + float word_w; + float line_w; float indent; + int align; em = from_number(box->style.font_size, em, em); - indent = from_number(top->style.text_indent, em, top->w); + align = top->style.text_align; box->x = top->x; box->y = top->y + top->h; - box->w = 0; + box->w = top->w; box->h = 0; - first_word = box->flow_head; - last_glue = NULL; - line_w = indent; - for (node = box->flow_head; node; node = node->next) - { - if (node->type == FLOW_GLUE) - last_glue = node; + if (!box->flow_head) + return; + for (node = box->flow_head; node; node = node->next) measure_word(ctx, node, em); - if (last_glue && line_w + node->w > top->w) - { - line_h = layout_line(ctx, indent, first_word, last_glue, box); - if (line_w > box->w) - box->w = line_w; - box->h += line_h; - if (node == last_glue && node->next) - { - node = node->next; - measure_word(ctx, node, em); - } + line_start = find_next_word(box->flow_head, &glue_w); + line_end = NULL; - first_word = node; - last_glue = NULL; - line_w = node->w; - indent = 0; - } - else if (line_w + node->w > top->w) + line_w = indent; + word_w = 0; + word_start = line_start; + while (word_start) + { + word_end = find_next_glue(word_start, &word_w); + if (line_w + word_w <= top->w) { - printf("WARNING: line overflow! (%s)\n", node->text); - line_w += node->w; + line_w += word_w; + glue_w = 0; + line_end = word_end; + word_start = find_next_word(word_end, &glue_w); + word_w = glue_w; } else { - line_w += node->w; + box->h += layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box); + line_start = word_start; + line_end = NULL; + indent = 0; + line_w = 0; + word_w = 0; } } - line_h = layout_line(ctx, indent, first_word, NULL, box); - if (line_w > box->w) - box->w = line_w; - box->h += line_h; + /* don't justify the last line of a paragraph */ + if (align == TA_JUSTIFY) + align = TA_LEFT; + + if (line_start) + box->h += layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box); } static void layout_block(fz_context *ctx, struct box *box, struct box *top, float em, float top_collapse_margin) -- cgit v1.2.3 From 5ba0b431a80707230c0e7e14c2b4eb520efb3e2d Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Fri, 14 Nov 2014 10:52:55 +0100 Subject: html: Fix CSS parsing mixed-case selectors and comments. --- source/html/css-parse.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'source/html') diff --git a/source/html/css-parse.c b/source/html/css-parse.c index 93c5ff58..63abee42 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -35,13 +35,13 @@ static int iswhite(int c) static int isnmstart(int c) { - return c == '\\' || c == '_' || (c >= 'a' && c <= 'z') || + return c == '\\' || c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= 128 && c <= 255); } static int isnmchar(int c) { - return c == '\\' || c == '_' || (c >= 'a' && c <= 'z') || + return c == '\\' || c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || (c >= 128 && c <= 255); } @@ -196,6 +196,7 @@ static int css_lex(struct lexbuf *buf) while (buf->c) { +restart: while (iswhite(buf->c)) css_lex_next(buf); @@ -213,7 +214,7 @@ static int css_lex(struct lexbuf *buf) while (buf->c == '*') css_lex_next(buf); if (css_lex_accept(buf, '/')) - continue; + goto restart; } css_lex_next(buf); } -- cgit v1.2.3 From 8758df6c290525eb2246977d84816d171e95309b Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Fri, 14 Nov 2014 10:55:39 +0100 Subject: html: Print log messages when starting the layout stages. --- source/html/handler.c | 2 ++ source/html/layout.c | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'source/html') diff --git a/source/html/handler.c b/source/html/handler.c index 0c7463cb..6b19304b 100644 --- a/source/html/handler.c +++ b/source/html/handler.c @@ -60,6 +60,8 @@ html_open_document_with_stream(fz_context *ctx, fz_stream *file) buf = fz_read_all(file, 0); fz_write_buffer_byte(ctx, buf, 0); + +printf("html: parsing XHTML.\n"); xml = fz_parse_xml(ctx, buf->data, buf->len, 1); fz_drop_buffer(ctx, buf); diff --git a/source/html/layout.c b/source/html/layout.c index afac6a1a..00ad79f6 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -652,10 +652,11 @@ html_layout_document(html_document *doc, float page_w, float page_h) doc->page_w = page_w; doc->page_h = page_h; +printf("html: parsing style sheets.\n"); css = fz_parse_css(doc->ctx, NULL, default_css); css = load_css(doc, css, doc->xml); - print_rules(css); + // print_rules(css); style.up = NULL; style.count = 0; @@ -666,9 +667,11 @@ html_layout_document(html_document *doc, float page_w, float page_h) page_box->w = page_w; page_box->h = 0; +printf("html: applying styles and generating boxes.\n"); generate_boxes(doc, doc->xml, root_box, css, &style); - +printf("html: laying out text.\n"); layout_block(doc->ctx, root_box, page_box, 12, 0); +printf("html: finished.\n"); // print_box(doc->ctx, root_box, 0); -- cgit v1.2.3 From b3a9f7e5d838e095a5cf4f6d73a73316089190ec Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Fri, 14 Nov 2014 11:15:58 +0100 Subject: html: Only draw the boxes and lines if they're on the current page. --- source/html/css-parse.c | 2 +- source/html/handler.c | 2 +- source/html/layout.c | 20 +++++++++++++------- 3 files changed, 15 insertions(+), 9 deletions(-) (limited to 'source/html') diff --git a/source/html/css-parse.c b/source/html/css-parse.c index 63abee42..1708f550 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -759,7 +759,7 @@ struct rule *fz_parse_css_file(fz_context *ctx, struct rule *chain, const char * { buf = fz_read_all(stm, 0); fz_write_buffer_byte(ctx, buf, 0); - chain = fz_parse_css(ctx, chain, buf->data); + chain = fz_parse_css(ctx, chain, (char*)buf->data); } fz_always(ctx) { diff --git a/source/html/handler.c b/source/html/handler.c index 6b19304b..c3f9c3df 100644 --- a/source/html/handler.c +++ b/source/html/handler.c @@ -48,7 +48,7 @@ html_run_page(html_document *doc, html_page *page, fz_device *dev, const fz_matr { int n = ((intptr_t)page) - 1; printf("html: run page %d\n", n); - html_run_box(doc->ctx, doc->box, n * doc->page_h, dev, ctm); + html_run_box(doc->ctx, doc->box, n * doc->page_h, (n+1) * doc->page_h, dev, ctm); } html_document * diff --git a/source/html/layout.c b/source/html/layout.c index 00ad79f6..9533e634 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -495,7 +495,7 @@ static void print_box(fz_context *ctx, struct box *box, int level) } static void -draw_flow_box(fz_context *ctx, struct box *box, fz_device *dev, const fz_matrix *ctm) +draw_flow_box(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm) { struct flow *node; fz_text *text; @@ -509,6 +509,9 @@ draw_flow_box(fz_context *ctx, struct box *box, fz_device *dev, const fz_matrix for (node = box->flow_head; node; node = node->next) { + if (node->y > page_bot || node->y + node->h < page_top) + continue; + if (node->type == FLOW_WORD) { fz_scale(&trm, node->em, -node->em); @@ -533,7 +536,7 @@ draw_flow_box(fz_context *ctx, struct box *box, fz_device *dev, const fz_matrix } static void -draw_block_box(fz_context *ctx, struct box *box, fz_device *dev, const fz_matrix *ctm) +draw_block_box(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm) { fz_path *path; float black[1]; @@ -549,6 +552,9 @@ draw_block_box(fz_context *ctx, struct box *box, fz_device *dev, const fz_matrix x1 = box->x + box->w + box->padding[RIGHT]; y1 = box->y + box->h + box->padding[BOTTOM]; + if (y0 > page_bot || y1 < page_top) + return; + path = fz_new_path(ctx); fz_moveto(ctx, path, x0, y0); fz_lineto(ctx, path, x1, y0); @@ -564,18 +570,18 @@ draw_block_box(fz_context *ctx, struct box *box, fz_device *dev, const fz_matrix { switch (box->type) { - case BOX_BLOCK: draw_block_box(ctx, box, dev, ctm); break; - case BOX_FLOW: draw_flow_box(ctx, box, dev, ctm); break; + case BOX_BLOCK: draw_block_box(ctx, box, page_top, page_bot, dev, ctm); break; + case BOX_FLOW: draw_flow_box(ctx, box, page_top, page_bot, dev, ctm); break; } } } void -html_run_box(fz_context *ctx, struct box *box, float offset, fz_device *dev, const fz_matrix *inctm) +html_run_box(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *inctm) { fz_matrix ctm = *inctm; - fz_pre_translate(&ctm, 0, -offset); - draw_block_box(ctx, box, dev, &ctm); + fz_pre_translate(&ctm, 0, -page_top); + draw_block_box(ctx, box, page_top, page_bot, dev, &ctm); } static char *concat_text(fz_context *ctx, fz_xml *root) -- cgit v1.2.3 From dceae0fa07781c1242ed15420bf3158824932c0a Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Fri, 14 Nov 2014 11:33:50 +0100 Subject: html: Insert space for page breaks so lines don't get split across pages. --- source/html/layout.c | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) (limited to 'source/html') diff --git a/source/html/layout.c b/source/html/layout.c index 9533e634..f2a8582c 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -262,11 +262,22 @@ static void measure_word(fz_context *ctx, struct flow *node, float em) node->em = em; } -static float layout_line(fz_context *ctx, float indent, float page_w, float line_w, int align, struct flow *node, struct flow *end, struct box *box) +static float measure_line(struct flow *node, struct flow *end) +{ + float h = 0; + while (node) + { + if (node->h > h) + h = node->h; + node = node->next; + } + return h; +} + +static void layout_line(fz_context *ctx, float indent, float page_w, float line_w, int align, struct flow *node, struct flow *end, struct box *box) { float x = box->x + indent; float y = box->y + box->h; - float h = 0; float slop = page_w - line_w; float justify = 0; int n = 0; @@ -291,12 +302,8 @@ static float layout_line(fz_context *ctx, float indent, float page_w, float line x += node->w; if (node->type == FLOW_GLUE) x += justify; - if (node->h > h) - h = node->h; node = node->next; } - - return h; } static struct flow *find_next_glue(struct flow *node, float *w) @@ -324,13 +331,14 @@ static struct flow *find_next_word(struct flow *node, float *w) return node; } -static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float em) +static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float em, float page_h) { struct flow *node, *line_start, *word_start, *word_end, *line_end; float glue_w; float word_w; float line_w; float indent; + float avail, line_h; int align; em = from_number(box->style.font_size, em, em); @@ -367,7 +375,12 @@ static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float } else { - box->h += layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box); + avail = page_h - fmodf(box->y + box->h, page_h); + line_h = measure_line(line_start, line_end); + if (line_h > avail) + box->h += avail; + layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box); + box->h += line_h; line_start = word_start; line_end = NULL; indent = 0; @@ -381,10 +394,17 @@ static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float align = TA_LEFT; if (line_start) - box->h += layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box); + { + avail = page_h - fmodf(box->y + box->h, page_h); + line_h = measure_line(line_start, line_end); + if (line_h > avail) + box->h += avail; + layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box); + box->h += line_h; + } } -static void layout_block(fz_context *ctx, struct box *box, struct box *top, float em, float top_collapse_margin) +static void layout_block(fz_context *ctx, struct box *box, struct box *top, float em, float top_collapse_margin, float page_h) { struct box *child; float box_collapse_margin; @@ -420,13 +440,13 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa { if (child->type == BOX_BLOCK) { - layout_block(ctx, child, box, em, box_collapse_margin); + layout_block(ctx, child, box, em, box_collapse_margin, page_h); box->h += child->h + child->padding[TOP] + child->padding[BOTTOM] + child->margin[TOP] + child->margin[BOTTOM]; box_collapse_margin = child->margin[BOTTOM]; } else if (child->type == BOX_FLOW) { - layout_flow(ctx, child, box, em); + layout_flow(ctx, child, box, em, page_h); if (child->h > 0) { box->h += child->h; @@ -676,7 +696,7 @@ printf("html: parsing style sheets.\n"); printf("html: applying styles and generating boxes.\n"); generate_boxes(doc, doc->xml, root_box, css, &style); printf("html: laying out text.\n"); - layout_block(doc->ctx, root_box, page_box, 12, 0); + layout_block(doc->ctx, root_box, page_box, 12, 0, page_h); printf("html: finished.\n"); // print_box(doc->ctx, root_box, 0); -- cgit v1.2.3 From 4860398de42bbaee9bbbdd28ccb16761d5f06e0b Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Mon, 17 Nov 2014 13:49:16 +0100 Subject: html: Fix adjacency selector matching. --- source/html/css-apply.c | 2 +- source/html/css-parse.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 63a4941c..8284c5ac 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -349,7 +349,7 @@ match_selector(struct selector *sel, fz_xml *node) if (sel->combine == '+') { fz_xml *prev = fz_xml_prev(node); - while (prev && !fz_xml_tag(prev) && fz_xml_prev(prev)) + while (prev && !fz_xml_tag(prev)) prev = fz_xml_prev(prev); if (!prev) return 0; diff --git a/source/html/css-parse.c b/source/html/css-parse.c index 1708f550..c3ec8431 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -594,7 +594,7 @@ static struct selector *parse_adjacent_selector(struct lexbuf *buf) { b = parse_adjacent_selector(buf); s = new_selector(NULL); - s->combine = '>'; + s->combine = '+'; s->left = a; s->right = b; return s; -- cgit v1.2.3 From 6a603b5b55262c443bf780f3c112a586cb3d9901 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Mon, 17 Nov 2014 13:49:33 +0100 Subject: html: Fix line breaking bugs resulting in infinite loops. --- source/html/layout.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source/html') diff --git a/source/html/layout.c b/source/html/layout.c index f2a8582c..4f778cc5 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -265,7 +265,7 @@ static void measure_word(fz_context *ctx, struct flow *node, float em) static float measure_line(struct flow *node, struct flow *end) { float h = 0; - while (node) + while (node != end) { if (node->h > h) h = node->h; @@ -381,6 +381,7 @@ static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float box->h += avail; layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box); box->h += line_h; + word_start = find_next_word(line_end, &glue_w); line_start = word_start; line_end = NULL; indent = 0; -- cgit v1.2.3 From bceb717f5d088f440a8046acf2e1d8f0169fdab3 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Mon, 17 Nov 2014 13:51:41 +0100 Subject: html: Don't create boxes for invisible elements. --- source/html/layout.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'source/html') diff --git a/source/html/layout.c b/source/html/layout.c index 4f778cc5..c948e02b 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -187,6 +187,7 @@ static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, st fz_context *ctx = doc->ctx; struct style style; struct box *box; + const char *tag; int display; while (node) @@ -194,9 +195,8 @@ static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, st style.up = up_style; style.count = 0; - box = new_box(ctx, node); - - if (fz_xml_tag(node)) + tag = fz_xml_tag(node); + if (tag) { apply_styles(ctx, &style, rule, node); @@ -207,6 +207,8 @@ static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, st if (display != DIS_NONE) { + box = new_box(ctx, node); + if (display == DIS_BLOCK) { top = insert_block_box(ctx, box, top); @@ -224,17 +226,18 @@ static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, st if (fz_xml_down(node)) generate_boxes(doc, fz_xml_down(node), box, rule, &style); + compute_style(doc, &box->style, &style); // TODO: remove empty flow boxes } } else { + box = new_box(ctx, node); insert_inline_box(ctx, box, top); generate_text(ctx, box, fz_xml_text(node)); + compute_style(doc, &box->style, &style); } - compute_style(doc, &box->style, &style); - node = fz_xml_next(node); } } -- cgit v1.2.3 From 1af9460e3fe591b228870045fe150b61b495a5c4 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Mon, 17 Nov 2014 13:52:03 +0100 Subject: html: Pick a reasonable default page size. --- source/html/handler.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'source/html') diff --git a/source/html/handler.c b/source/html/handler.c index c3f9c3df..cbce9409 100644 --- a/source/html/handler.c +++ b/source/html/handler.c @@ -1,5 +1,8 @@ #include "mupdf/html.h" +#define DEFW (450) +#define DEFH (600) + void html_close_document(html_document *doc) { @@ -12,7 +15,7 @@ html_count_pages(html_document *doc) { int count; - if (!doc->box) html_layout_document(doc, 400, 400); + if (!doc->box) html_layout_document(doc, DEFW, DEFH); count = ceilf(doc->box->h / doc->page_h); printf("count pages! %g / %g = %d\n", doc->box->h, doc->page_h, count); @@ -23,7 +26,7 @@ html_page * html_load_page(html_document *doc, int number) { printf("load page %d\n", number); - if (!doc->box) html_layout_document(doc, 400, 400); + if (!doc->box) html_layout_document(doc, DEFW, DEFH); return (void*)((intptr_t)number + 1); } @@ -35,7 +38,7 @@ html_free_page(html_document *doc, html_page *page) fz_rect * html_bound_page(html_document *doc, html_page *page, fz_rect *bbox) { - if (!doc->box) html_layout_document(doc, 400, 400); + if (!doc->box) html_layout_document(doc, DEFW, DEFH); printf("html: bound page\n"); bbox->x0 = bbox->y0 = 0; bbox->x1 = doc->page_w; -- cgit v1.2.3 From 18ef4f69516c0c7548217532062c62029fb56180 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Mon, 17 Nov 2014 14:44:24 +0100 Subject: html: Handle text-align when splitting flow boxes. --- source/html/layout.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'source/html') diff --git a/source/html/layout.c b/source/html/layout.c index c948e02b..bb653cf9 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -22,13 +22,14 @@ static const char *default_css = "sub{vertical-align:sub}" "sup{vertical-align:super}" "s,strike,del{text-decoration:line-through}" -"hr{border:1px inset}" +"hr{border-width:1px;border-color:black}" "ol,ul,dir,menu,dd{margin-left:40px}" "ol{list-style-type:decimal}" "ol ul,ul ol,ul ul,ol ol{margin-top:0;margin-bottom:0}" "u,ins{text-decoration:underline}" "center{text-align:center}" -"svg{display:none}"; +"svg{display:none}" +; static int iswhite(int c) { @@ -168,6 +169,7 @@ static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) else { struct box *flow = new_box(ctx, NULL); + flow->is_first_flow = !top->last; insert_box(ctx, flow, BOX_FLOW, top); insert_box(ctx, box, BOX_INLINE, flow); } @@ -345,7 +347,7 @@ static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float int align; em = from_number(box->style.font_size, em, em); - indent = from_number(top->style.text_indent, em, top->w); + indent = box->is_first_flow ? from_number(top->style.text_indent, em, top->w) : 0; align = top->style.text_align; box->x = top->x; -- cgit v1.2.3 From 8b54b9faf55996ade4dff112aa1b6fa1e086ef6f Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Mon, 17 Nov 2014 15:01:11 +0100 Subject: html: Break tag. --- source/html/layout.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) (limited to 'source/html') diff --git a/source/html/layout.c b/source/html/layout.c index bb653cf9..2cb2ced4 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -158,6 +158,27 @@ static struct box *insert_block_box(fz_context *ctx, struct box *box, struct box return top; } +static struct box *insert_break_box(fz_context *ctx, struct box *box, struct box *top) +{ + if (top->type == BOX_BLOCK) + { + insert_box(ctx, box, BOX_BREAK, top); + } + else if (top->type == BOX_FLOW) + { + while (top->type != BOX_BLOCK) + top = top->up; + insert_box(ctx, box, BOX_BREAK, top); + } + else if (top->type == BOX_INLINE) + { + while (top->type != BOX_BLOCK) + top = top->up; + insert_box(ctx, box, BOX_BREAK, top); + } + return top; +} + static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) { if (top->type == BOX_BLOCK) @@ -204,10 +225,16 @@ static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, st display = get_style_property_display(&style); - // TODO:
+ if (!strcmp(tag, "br")) + { + box = new_box(ctx, node); + top = insert_break_box(ctx, box, top); + compute_style(doc, &box->style, &style); + } + // TODO: - if (display != DIS_NONE) + else if (display != DIS_NONE) { box = new_box(ctx, node); @@ -414,6 +441,7 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa { struct box *child; float box_collapse_margin; + int prev_br; em = from_number(box->style.font_size, em, em); @@ -442,6 +470,7 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa box->w = top->w - (box->margin[LEFT] + box->margin[RIGHT] + box->padding[LEFT] + box->padding[RIGHT]); box->h = 0; + prev_br = 0; for (child = box->down; child; child = child->next) { if (child->type == BOX_BLOCK) @@ -449,6 +478,14 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa layout_block(ctx, child, box, em, box_collapse_margin, page_h); box->h += child->h + child->padding[TOP] + child->padding[BOTTOM] + child->margin[TOP] + child->margin[BOTTOM]; box_collapse_margin = child->margin[BOTTOM]; + prev_br = 0; + } + else if (child->type == BOX_BREAK) + { + /* TODO: interaction with page breaks */ + if (prev_br) + box->h += from_number_scale(box->style.line_height, em, em, em); + prev_br = 1; } else if (child->type == BOX_FLOW) { @@ -457,6 +494,7 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa { box->h += child->h; box_collapse_margin = 0; + prev_br = 0; } } } @@ -501,6 +539,7 @@ static void print_box(fz_context *ctx, struct box *box, int level) switch (box->type) { case BOX_BLOCK: printf("block"); break; + case BOX_BREAK: printf("break"); break; case BOX_FLOW: printf("flow"); break; case BOX_INLINE: printf("inline"); break; } -- cgit v1.2.3 From 880a2fc8ad25bc4a1e64bb600f4605dd3d864eaa Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Mon, 17 Nov 2014 15:16:26 +0100 Subject: html: Insert block boxes for list-item nodes. TODO: bullets and numbers --- source/html/layout.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'source/html') diff --git a/source/html/layout.c b/source/html/layout.c index 2cb2ced4..3439ccdb 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -242,6 +242,10 @@ static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, st { top = insert_block_box(ctx, box, top); } + else if (display == DIS_LIST_ITEM) + { + top = insert_block_box(ctx, box, top); + } else if (display == DIS_INLINE) { insert_inline_box(ctx, box, top); @@ -256,6 +260,7 @@ static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, st generate_boxes(doc, fz_xml_down(node), box, rule, &style); compute_style(doc, &box->style, &style); + // TODO: remove empty flow boxes } } -- cgit v1.2.3 From bb875f77f23ac4c51a072f4fc6692ce2dc352997 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 18 Nov 2014 13:32:21 +0100 Subject: html: Text and background colors. --- source/html/css-apply.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++- source/html/layout.c | 38 ++++++++++++--------- 2 files changed, 109 insertions(+), 16 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 8284c5ac..351f05e6 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -751,7 +751,8 @@ number_from_value(struct value *value, float initial, int initial_unit) return make_number(initial, initial_unit); } -static struct number number_from_property(struct style *node, const char *property, float initial, int initial_unit) +static struct number +number_from_property(struct style *node, const char *property, float initial, int initial_unit) { return number_from_value(get_style_property(node, property), initial, initial_unit); } @@ -778,6 +779,85 @@ from_number_scale(struct number number, float scale, float em, float width) } } +static struct color +make_color(int r, int g, int b, int a) +{ + struct color c; + c.r = r; + c.g = g; + c.b = b; + c.a = a; + return c; +} + +static int tohex(int c) +{ + if (c - '0' < 10) + return c - '0'; + return (c | 32) - 'a' + 10; +} + +static struct color +color_from_value(struct value *value) +{ + if (!value) + return make_color(0, 0, 0, 0); + if (value->type == CSS_COLOR) + { + int r = tohex(value->data[0]) * 16 + tohex(value->data[1]); + int g = tohex(value->data[2]) * 16 + tohex(value->data[3]); + int b = tohex(value->data[4]) * 16 + tohex(value->data[5]); + return make_color(r, g, b, 255); + } + if (value->type == CSS_KEYWORD) + { + if (!strcmp(value->data, "transparent")) + return make_color(0, 0, 0, 0); + if (!strcmp(value->data, "maroon")) + return make_color(0x80, 0x00, 0x00, 255); + if (!strcmp(value->data, "red")) + return make_color(0xFF, 0x00, 0x00, 255); + if (!strcmp(value->data, "orange")) + return make_color(0xFF, 0xA5, 0x00, 255); + if (!strcmp(value->data, "yellow")) + return make_color(0xFF, 0xFF, 0x00, 255); + if (!strcmp(value->data, "olive")) + return make_color(0x80, 0x80, 0x00, 255); + if (!strcmp(value->data, "purple")) + return make_color(0x80, 0x00, 0x80, 255); + if (!strcmp(value->data, "fuchsia")) + return make_color(0xFF, 0x00, 0xFF, 255); + if (!strcmp(value->data, "white")) + return make_color(0xFF, 0xFF, 0xFF, 255); + if (!strcmp(value->data, "lime")) + return make_color(0x00, 0xFF, 0x00, 255); + if (!strcmp(value->data, "green")) + return make_color(0x00, 0x80, 0x00, 255); + if (!strcmp(value->data, "navy")) + return make_color(0x00, 0x00, 0x80, 255); + if (!strcmp(value->data, "blue")) + return make_color(0x00, 0x00, 0xFF, 255); + if (!strcmp(value->data, "aqua")) + return make_color(0x00, 0xFF, 0xFF, 255); + if (!strcmp(value->data, "teal")) + return make_color(0x00, 0x80, 0x80, 255); + if (!strcmp(value->data, "black")) + return make_color(0x00, 0x00, 0x00, 255); + if (!strcmp(value->data, "silver")) + return make_color(0xC0, 0xC0, 0xC0, 255); + if (!strcmp(value->data, "gray")) + return make_color(0x80, 0x80, 0x80, 255); + return make_color(0, 0, 0, 255); + } + return make_color(0, 0, 0, 0); +} + +static struct color +color_from_property(struct style *node, const char *property) +{ + return color_from_value(get_style_property(node, property)); +} + int get_style_property_display(struct style *node) { @@ -819,6 +899,8 @@ default_computed_style(struct computed_style *style) style->vertical_align = 0; style->white_space = WS_NORMAL; style->font_size = make_number(1, N_SCALE); + style->background_color = make_color(0, 0, 0, 0); + style->color = make_color(0, 0, 0, 255); } void @@ -885,6 +967,9 @@ compute_style(html_document *doc, struct computed_style *style, struct style *no style->padding[2] = number_from_property(node, "padding-bottom", 0, N_NUMBER); style->padding[3] = number_from_property(node, "padding-left", 0, N_NUMBER); + style->color = color_from_property(node, "color"); + style->background_color = color_from_property(node, "background-color"); + { const char *font_family = get_style_property_string(node, "font-family", "serif"); const char *font_variant = get_style_property_string(node, "font-variant", "normal"); diff --git a/source/html/layout.c b/source/html/layout.c index 3439ccdb..f5436b10 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -571,12 +571,10 @@ draw_flow_box(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_text *text; fz_matrix trm; const char *s; - float black[1]; + float color[3]; float x, y; int c, g; - black[0] = 0; - for (node = box->flow_head; node; node = node->next) { if (node->y > page_bot || node->y + node->h < page_top) @@ -598,7 +596,11 @@ draw_flow_box(fz_context *ctx, struct box *box, float page_top, float page_bot, x += fz_advance_glyph(ctx, node->style->font, g) * node->em; } - fz_fill_text(dev, text, ctm, fz_device_gray(ctx), black, 1); + color[0] = node->style->color.r / 255.0f; + color[1] = node->style->color.g / 255.0f; + color[2] = node->style->color.b / 255.0f; + + fz_fill_text(dev, text, ctm, fz_device_rgb(ctx), color, 1); fz_free_text(ctx, text); } @@ -609,14 +611,11 @@ static void draw_block_box(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm) { fz_path *path; - float black[1]; float x0, y0, x1, y1; // TODO: background fill // TODO: border stroke - black[0] = 0; - x0 = box->x - box->padding[LEFT]; y0 = box->y - box->padding[TOP]; x1 = box->x + box->w + box->padding[RIGHT]; @@ -625,16 +624,25 @@ draw_block_box(fz_context *ctx, struct box *box, float page_top, float page_bot, if (y0 > page_bot || y1 < page_top) return; - path = fz_new_path(ctx); - fz_moveto(ctx, path, x0, y0); - fz_lineto(ctx, path, x1, y0); - fz_lineto(ctx, path, x1, y1); - fz_lineto(ctx, path, x0, y1); - fz_closepath(ctx, path); + if (box->style.background_color.a > 0) + { + float color[3]; - fz_fill_path(dev, path, 0, ctm, fz_device_gray(ctx), black, 0.1); + color[0] = box->style.background_color.r / 255.0f; + color[1] = box->style.background_color.g / 255.0f; + color[2] = box->style.background_color.b / 255.0f; - fz_free_path(ctx, path); + path = fz_new_path(ctx); + fz_moveto(ctx, path, x0, y0); + fz_lineto(ctx, path, x1, y0); + fz_lineto(ctx, path, x1, y1); + fz_lineto(ctx, path, x0, y1); + fz_closepath(ctx, path); + + fz_fill_path(dev, path, 0, ctm, fz_device_rgb(ctx), color, box->style.background_color.a / 255.0f); + + fz_free_path(ctx, path); + } for (box = box->down; box; box = box->next) { -- cgit v1.2.3 From 3ba9c348795b3923ff65e917c23b454470698489 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 18 Nov 2014 13:56:58 +0100 Subject: html: Borders. --- source/html/css-apply.c | 88 +++++++++++++++++++++++---------- source/html/handler.c | 2 +- source/html/layout.c | 126 +++++++++++++++++++++++++++++++++--------------- 3 files changed, 149 insertions(+), 67 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 351f05e6..d642d98c 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -500,10 +500,10 @@ add_shorthand_border_width(struct style *style, struct value *value, int spec) if (n == 1) { - add_property(style, "border-top-width", value, spec); - add_property(style, "border-right-width", value, spec); - add_property(style, "border-bottom-width", value, spec); - add_property(style, "border-left-width", value, spec); + add_property(style, "border-width-top", value, spec); + add_property(style, "border-width-right", value, spec); + add_property(style, "border-width-bottom", value, spec); + add_property(style, "border-width-left", value, spec); } if (n == 2) @@ -511,10 +511,10 @@ add_shorthand_border_width(struct style *style, struct value *value, int spec) struct value *a = new_value(value->type, value->data); struct value *b = new_value(value->next->type, value->next->data); - add_property(style, "border-top-width", a, spec); - add_property(style, "border-right-width", b, spec); - add_property(style, "border-bottom-width", a, spec); - add_property(style, "border-left-width", b, spec); + add_property(style, "border-width-top", a, spec); + add_property(style, "border-width-right", b, spec); + add_property(style, "border-width-bottom", a, spec); + add_property(style, "border-width-left", b, spec); } if (n == 3) @@ -523,10 +523,10 @@ add_shorthand_border_width(struct style *style, struct value *value, int spec) struct value *b = new_value(value->next->type, value->next->data); struct value *c = new_value(value->next->next->type, value->next->next->data); - add_property(style, "border-top-width", a, spec); - add_property(style, "border-right-width", b, spec); - add_property(style, "border-bottom-width", c, spec); - add_property(style, "border-left-width", b, spec); + add_property(style, "border-width-top", a, spec); + add_property(style, "border-width-right", b, spec); + add_property(style, "border-width-bottom", c, spec); + add_property(style, "border-width-left", b, spec); } if (n == 4) @@ -536,13 +536,18 @@ add_shorthand_border_width(struct style *style, struct value *value, int spec) struct value *c = new_value(value->next->next->type, value->next->next->data); struct value *d = new_value(value->next->next->next->type, value->next->next->next->data); - add_property(style, "border-top-width", a, spec); - add_property(style, "border-right-width", b, spec); - add_property(style, "border-bottom-width", c, spec); - add_property(style, "border-left-width", d, spec); + add_property(style, "border-width-top", a, spec); + add_property(style, "border-width-right", b, spec); + add_property(style, "border-width-bottom", c, spec); + add_property(style, "border-width-left", d, spec); } } +static void +add_shorthand_border(struct style *style, struct value *value, int spec) +{ +} + static void add_property(struct style *style, const char *name, struct value *value, int spec) { @@ -563,10 +568,15 @@ add_property(struct style *style, const char *name, struct value *value, int spe add_shorthand_border_width(style, value, spec); return; } + if (!strcmp(name, "border")) + { + add_shorthand_border(style, value, spec); + return; + } + /* shorthand expansions: */ /* TODO: border-color */ /* TODO: border-style */ - /* TODO: border */ /* TODO: font */ /* TODO: list-style */ /* TODO: background */ @@ -757,6 +767,23 @@ number_from_property(struct style *node, const char *property, float initial, in return number_from_value(get_style_property(node, property), initial, initial_unit); } +static struct number +border_width_from_property(struct style *node, const char *property) +{ + struct value *value = get_style_property(node, property); + if (value) + { + if (!strcmp(value->data, "thin")) + return make_number(1, N_NUMBER); + if (!strcmp(value->data, "medium")) + return make_number(2, N_NUMBER); + if (!strcmp(value->data, "thick")) + return make_number(4, N_NUMBER); + return number_from_value(value, 0, N_NUMBER); + } + return make_number(2, N_NUMBER); /* initial: 'medium' */ +} + float from_number(struct number number, float em, float width) { @@ -798,10 +825,10 @@ static int tohex(int c) } static struct color -color_from_value(struct value *value) +color_from_value(struct value *value, struct color initial) { if (!value) - return make_color(0, 0, 0, 0); + return initial; if (value->type == CSS_COLOR) { int r = tohex(value->data[0]) * 16 + tohex(value->data[1]); @@ -849,13 +876,13 @@ color_from_value(struct value *value) return make_color(0x80, 0x80, 0x80, 255); return make_color(0, 0, 0, 255); } - return make_color(0, 0, 0, 0); + return initial; } static struct color -color_from_property(struct style *node, const char *property) +color_from_property(struct style *node, const char *property, struct color initial) { - return color_from_value(get_style_property(node, property)); + return color_from_value(get_style_property(node, property), initial); } int @@ -899,8 +926,6 @@ default_computed_style(struct computed_style *style) style->vertical_align = 0; style->white_space = WS_NORMAL; style->font_size = make_number(1, N_SCALE); - style->background_color = make_color(0, 0, 0, 0); - style->color = make_color(0, 0, 0, 255); } void @@ -908,6 +933,9 @@ compute_style(html_document *doc, struct computed_style *style, struct style *no { struct value *value; + struct color black = { 0, 0, 0, 255 }; + struct color transparent = { 0, 0, 0, 0 }; + default_computed_style(style); style->white_space = get_style_property_white_space(node); @@ -967,8 +995,16 @@ compute_style(html_document *doc, struct computed_style *style, struct style *no style->padding[2] = number_from_property(node, "padding-bottom", 0, N_NUMBER); style->padding[3] = number_from_property(node, "padding-left", 0, N_NUMBER); - style->color = color_from_property(node, "color"); - style->background_color = color_from_property(node, "background-color"); + style->border_width[0] = border_width_from_property(node, "border-width-top"); + style->border_width[1] = border_width_from_property(node, "border-width-right"); + style->border_width[2] = border_width_from_property(node, "border-width-bottom"); + style->border_width[3] = border_width_from_property(node, "border-width-left"); + + style->color = color_from_property(node, "color", black); + style->background_color = color_from_property(node, "background-color", transparent); + style->border_color = color_from_property(node, "border-color", style->color); + + style->border_style = !strcmp(get_style_property_string(node, "border-style", "none"), "solid"); { const char *font_family = get_style_property_string(node, "font-family", "serif"); diff --git a/source/html/handler.c b/source/html/handler.c index cbce9409..fda21f5c 100644 --- a/source/html/handler.c +++ b/source/html/handler.c @@ -125,7 +125,7 @@ html_recognize(fz_context *doc, const char *magic) if (ext) { - if (!fz_strcasecmp(ext, ".xhtml") || !fz_strcasecmp(ext, ".html")) + if (!fz_strcasecmp(ext, ".xml") || !fz_strcasecmp(ext, ".xhtml") || !fz_strcasecmp(ext, ".html")) return 100; } if (!strcmp(magic, "application/html+xml") || !strcmp(magic, "application/xml") || !strcmp(magic, "text/xml")) diff --git a/source/html/layout.c b/source/html/layout.c index f5436b10..b5a22557 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -1,5 +1,10 @@ #include "mupdf/html.h" +#define L LEFT +#define R RIGHT +#define T TOP +#define B BOTTOM + static const char *default_css = "html,address,blockquote,body,dd,div,dl,dt,h1,h2,h3,h4,h5,h6,ol,p,ul,center,hr,pre{display:block}" "span{display:inline}" @@ -22,7 +27,7 @@ static const char *default_css = "sub{vertical-align:sub}" "sup{vertical-align:super}" "s,strike,del{text-decoration:line-through}" -"hr{border-width:1px;border-color:black}" +"hr{border-width:thin;border-color:black;border-style:solid;margin:.5em 0}" "ol,ul,dir,menu,dd{margin-left:40px}" "ol{list-style-type:decimal}" "ol ul,ul ol,ul ul,ol ol{margin-top:0;margin-bottom:0}" @@ -448,31 +453,45 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa float box_collapse_margin; int prev_br; + float *margin = box->margin; + float *border = box->border; + float *padding = box->padding; + em = from_number(box->style.font_size, em, em); - box->margin[0] = from_number(box->style.margin[0], em, top->w); - box->margin[1] = from_number(box->style.margin[1], em, top->w); - box->margin[2] = from_number(box->style.margin[2], em, top->w); - box->margin[3] = from_number(box->style.margin[3], em, top->w); + margin[0] = from_number(box->style.margin[0], em, top->w); + margin[1] = from_number(box->style.margin[1], em, top->w); + margin[2] = from_number(box->style.margin[2], em, top->w); + margin[3] = from_number(box->style.margin[3], em, top->w); + + padding[0] = from_number(box->style.padding[0], em, top->w); + padding[1] = from_number(box->style.padding[1], em, top->w); + padding[2] = from_number(box->style.padding[2], em, top->w); + padding[3] = from_number(box->style.padding[3], em, top->w); - box->padding[0] = from_number(box->style.padding[0], em, top->w); - box->padding[1] = from_number(box->style.padding[1], em, top->w); - box->padding[2] = from_number(box->style.padding[2], em, top->w); - box->padding[3] = from_number(box->style.padding[3], em, top->w); + if (box->style.border_style) + { + border[0] = from_number(box->style.border_width[0], em, top->w); + border[1] = from_number(box->style.border_width[1], em, top->w); + border[2] = from_number(box->style.border_width[2], em, top->w); + border[3] = from_number(box->style.border_width[3], em, top->w); + } + else + border[0] = border[1] = border[2] = border[3] = 0; - if (box->padding[TOP] == 0) - box_collapse_margin = box->margin[TOP]; + if (padding[T] == 0 && border[T] == 0) + box_collapse_margin = margin[T]; else box_collapse_margin = 0; - if (box->margin[TOP] > top_collapse_margin) - box->margin[TOP] -= top_collapse_margin; + if (margin[T] > top_collapse_margin) + margin[T] -= top_collapse_margin; else - box->margin[TOP] = 0; + margin[T] = 0; - box->x = top->x + box->margin[LEFT] + box->padding[LEFT]; - box->y = top->y + top->h + box->margin[TOP] + box->padding[TOP]; - box->w = top->w - (box->margin[LEFT] + box->margin[RIGHT] + box->padding[LEFT] + box->padding[RIGHT]); + box->x = top->x + margin[L] + border[L] + padding[L]; + box->y = top->y + top->h + margin[T] + border[T] + padding[T]; + box->w = top->w - (margin[L] + margin[R] + border[L] + border[R] + padding[L] + padding[R]); box->h = 0; prev_br = 0; @@ -481,8 +500,11 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa if (child->type == BOX_BLOCK) { layout_block(ctx, child, box, em, box_collapse_margin, page_h); - box->h += child->h + child->padding[TOP] + child->padding[BOTTOM] + child->margin[TOP] + child->margin[BOTTOM]; - box_collapse_margin = child->margin[BOTTOM]; + box->h += child->h + + child->padding[T] + child->padding[B] + + child->border[T] + child->border[B] + + child->margin[T] + child->margin[B]; + box_collapse_margin = child->margin[B]; prev_br = 0; } else if (child->type == BOX_BREAK) @@ -504,13 +526,13 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa } } - if (box->padding[BOTTOM] == 0) + if (padding[B] == 0 && border[B] == 0) { - if (box->margin[BOTTOM] > 0) + if (margin[B] > 0) { box->h -= box_collapse_margin; - if (box->margin[BOTTOM] < box_collapse_margin) - box->margin[BOTTOM] = box_collapse_margin; + if (margin[B] < box_collapse_margin) + margin[B] = box_collapse_margin; } } } @@ -607,41 +629,65 @@ draw_flow_box(fz_context *ctx, struct box *box, float page_top, float page_bot, } } +static void +draw_rect(fz_context *ctx, fz_device *dev, const fz_matrix *ctm, float *rgba, float x0, float y0, float x1, float y1) +{ + fz_path *path = fz_new_path(ctx); + + fz_moveto(ctx, path, x0, y0); + fz_lineto(ctx, path, x1, y0); + fz_lineto(ctx, path, x1, y1); + fz_lineto(ctx, path, x0, y1); + fz_closepath(ctx, path); + + fz_fill_path(dev, path, 0, ctm, fz_device_rgb(ctx), rgba, rgba[3]); + + fz_free_path(ctx, path); +} + static void draw_block_box(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm) { - fz_path *path; float x0, y0, x1, y1; + float color[4]; // TODO: background fill // TODO: border stroke - x0 = box->x - box->padding[LEFT]; - y0 = box->y - box->padding[TOP]; - x1 = box->x + box->w + box->padding[RIGHT]; - y1 = box->y + box->h + box->padding[BOTTOM]; + float *border = box->border; + float *padding = box->padding; + + x0 = box->x - padding[L]; + y0 = box->y - padding[T]; + x1 = box->x + box->w + padding[R]; + y1 = box->y + box->h + padding[B]; if (y0 > page_bot || y1 < page_top) return; if (box->style.background_color.a > 0) { - float color[3]; - color[0] = box->style.background_color.r / 255.0f; color[1] = box->style.background_color.g / 255.0f; color[2] = box->style.background_color.b / 255.0f; + color[3] = box->style.background_color.a / 255.0f; + draw_rect(ctx, dev, ctm, color, x0, y0, x1, y1); + } - path = fz_new_path(ctx); - fz_moveto(ctx, path, x0, y0); - fz_lineto(ctx, path, x1, y0); - fz_lineto(ctx, path, x1, y1); - fz_lineto(ctx, path, x0, y1); - fz_closepath(ctx, path); - - fz_fill_path(dev, path, 0, ctm, fz_device_rgb(ctx), color, box->style.background_color.a / 255.0f); - - fz_free_path(ctx, path); + if (box->style.border_color.a > 0) + { + color[0] = box->style.border_color.r / 255.0f; + color[1] = box->style.border_color.g / 255.0f; + color[2] = box->style.border_color.b / 255.0f; + color[3] = box->style.border_color.a / 255.0f; + if (border[T] > 0) + draw_rect(ctx, dev, ctm, color, x0 - border[L], y0 - border[T], x1 + border[R], y0); + if (border[B] > 0) + draw_rect(ctx, dev, ctm, color, x0 - border[L], y1, x1 + border[R], y1 + border[B]); + if (border[L] > 0) + draw_rect(ctx, dev, ctm, color, x0 - border[L], y0 - border[T], x0, y1 + border[B]); + if (border[R] > 0) + draw_rect(ctx, dev, ctm, color, x1, y0 - border[T], x1 + border[R], y1 + border[B]); } for (box = box->down; box; box = box->next) -- cgit v1.2.3 From d88d131bae7d516b1b8ad9c94706d0813bbb1497 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 18 Nov 2014 14:22:39 +0100 Subject: html: Border shorthand css parsing. --- source/html/css-apply.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index d642d98c..eecb8111 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -381,6 +381,19 @@ match_selector(struct selector *sel, fz_xml *node) * Annotating nodes with properties and expanding shorthand forms. */ +static const char *border_width_kw[] = { + "thin", "medium", "thick", +}; + +static const char *border_style_kw[] = { + "none", "hidden", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset", +}; + +static const char *color_kw[] = { + "transparent", "maroon", "red", "orange", "yellow", "olive", "purple", "fuchsia", "white", + "lime", "green", "navy", "blue", "aqua", "teal", "black", "silver", "gray", +}; + static int count_values(struct value *value) { @@ -546,6 +559,54 @@ add_shorthand_border_width(struct style *style, struct value *value, int spec) static void add_shorthand_border(struct style *style, struct value *value, int spec) { + int i; + + while (value) + { + if (value->type == CSS_COLOR) + { + add_property(style, "border-color", value, spec); + } + else if (value->type == CSS_KEYWORD) + { + for (i = 0; i < nelem(border_width_kw); ++i) + { + if (!strcmp(value->data, border_width_kw[i])) + { + add_property(style, "border-width-top", value, spec); + add_property(style, "border-width-right", value, spec); + add_property(style, "border-width-bottom", value, spec); + add_property(style, "border-width-left", value, spec); + goto next; + } + } + for (i = 0; i < nelem(border_style_kw); ++i) + { + if (!strcmp(value->data, border_style_kw[i])) + { + add_property(style, "border-style", value, spec); + goto next; + } + } + for (i = 0; i < nelem(color_kw); ++i) + { + if (!strcmp(value->data, color_kw[i])) + { + add_property(style, "border-color", value, spec); + goto next; + } + } + } + else + { + add_property(style, "border-width-top", value, spec); + add_property(style, "border-width-right", value, spec); + add_property(style, "border-width-bottom", value, spec); + add_property(style, "border-width-left", value, spec); + } +next: + value = value->next; + } } static void -- cgit v1.2.3 From f18636e80edab0dadd07917ea26ec4c18102b99a Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 18 Nov 2014 16:09:40 +0100 Subject: html: Cleanups. --- source/html/css-apply.c | 27 +++++++++++++++++++++------ source/html/layout.c | 5 +---- 2 files changed, 22 insertions(+), 10 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index eecb8111..67814440 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -984,7 +984,7 @@ default_computed_style(struct computed_style *style) { memset(style, 0, sizeof *style); style->text_align = TA_LEFT; - style->vertical_align = 0; + style->vertical_align = VA_BASELINE; style->white_space = WS_NORMAL; style->font_size = make_number(1, N_SCALE); } @@ -1017,10 +1017,16 @@ compute_style(html_document *doc, struct computed_style *style, struct style *no value = get_style_property(node, "vertical-align"); if (value) { - if (!strcmp(value->data, "super")) - style->vertical_align = 1; + if (!strcmp(value->data, "baseline")) + style->vertical_align = VA_BASELINE; if (!strcmp(value->data, "sub")) - style->vertical_align = -1; + style->vertical_align = VA_SUB; + if (!strcmp(value->data, "super")) + style->vertical_align = VA_SUPER; + if (!strcmp(value->data, "top")) + style->vertical_align = VA_TOP; + if (!strcmp(value->data, "bottom")) + style->vertical_align = VA_BOTTOM; } value = get_style_property(node, "font-size"); @@ -1042,6 +1048,17 @@ compute_style(html_document *doc, struct computed_style *style, struct style *no style->font_size = make_number(1, N_SCALE); } + value = get_style_property(node, "border-style"); + if (value) + { + if (!strcmp(value->data, "none")) + style->border_style = BS_NONE; + if (!strcmp(value->data, "hidden")) + style->border_style = BS_NONE; + if (!strcmp(value->data, "solid")) + style->border_style = BS_SOLID; + } + style->line_height = number_from_property(node, "line-height", 1.2, N_SCALE); style->text_indent = number_from_property(node, "text-indent", 0, N_NUMBER); @@ -1065,8 +1082,6 @@ compute_style(html_document *doc, struct computed_style *style, struct style *no style->background_color = color_from_property(node, "background-color", transparent); style->border_color = color_from_property(node, "border-color", style->color); - style->border_style = !strcmp(get_style_property_string(node, "border-style", "none"), "solid"); - { const char *font_family = get_style_property_string(node, "font-family", "serif"); const char *font_variant = get_style_property_string(node, "font-variant", "normal"); diff --git a/source/html/layout.c b/source/html/layout.c index b5a22557..001e15e4 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -1,9 +1,6 @@ #include "mupdf/html.h" -#define L LEFT -#define R RIGHT -#define T TOP -#define B BOTTOM +enum { T, R, B, L }; static const char *default_css = "html,address,blockquote,body,dd,div,dl,dt,h1,h2,h3,h4,h5,h6,ol,p,ul,center,hr,pre{display:block}" -- cgit v1.2.3 From c64f2faf180e5c14aff85e46e6fe68114f741eda Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 18 Nov 2014 17:40:00 +0100 Subject: html: Vertical and baseline alignment. --- source/html/layout.c | 64 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 20 deletions(-) (limited to 'source/html') diff --git a/source/html/layout.c b/source/html/layout.c index 001e15e4..796f5fb5 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -230,8 +230,8 @@ static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, st if (!strcmp(tag, "br")) { box = new_box(ctx, node); - top = insert_break_box(ctx, box, top); compute_style(doc, &box->style, &style); + top = insert_break_box(ctx, box, top); } // TODO: @@ -239,6 +239,7 @@ static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, st else if (display != DIS_NONE) { box = new_box(ctx, node); + compute_style(doc, &box->style, &style); if (display == DIS_BLOCK) { @@ -261,17 +262,22 @@ static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, st if (fz_xml_down(node)) generate_boxes(doc, fz_xml_down(node), box, rule, &style); - compute_style(doc, &box->style, &style); - // TODO: remove empty flow boxes } } else { - box = new_box(ctx, node); - insert_inline_box(ctx, box, top); - generate_text(ctx, box, fz_xml_text(node)); - compute_style(doc, &box->style, &style); + if (top->type != BOX_INLINE) + { + box = new_box(ctx, node); + insert_inline_box(ctx, box, top); + box->style = top->style; + generate_text(ctx, box, fz_xml_text(node)); + } + else + { + generate_text(ctx, top, fz_xml_text(node)); + } } node = fz_xml_next(node); @@ -301,24 +307,29 @@ static void measure_word(fz_context *ctx, struct flow *node, float em) node->em = em; } -static float measure_line(struct flow *node, struct flow *end) +static float measure_line(struct flow *node, struct flow *end, float *baseline) { - float h = 0; + float max_a = 0, max_d = 0, h = 0; while (node != end) { - if (node->h > h) - h = node->h; + float a = node->em * 0.8; + float d = node->em * 0.2; + if (a > max_a) max_a = a; + if (d > max_d) max_d = d; + if (node->h > h) h = node->h; node = node->next; } + *baseline = max_a + (h - max_a - max_d) / 2; return h; } -static void layout_line(fz_context *ctx, float indent, float page_w, float line_w, int align, struct flow *node, struct flow *end, struct box *box) +static void layout_line(fz_context *ctx, float indent, float page_w, float line_w, int align, struct flow *node, struct flow *end, struct box *box, float baseline) { float x = box->x + indent; float y = box->y + box->h; float slop = page_w - line_w; float justify = 0; + float va; int n = 0; if (align == TA_JUSTIFY) @@ -336,8 +347,21 @@ static void layout_line(fz_context *ctx, float indent, float page_w, float line_ while (node != end) { + switch (node->style->vertical_align) + { + default: + case VA_BASELINE: + va = 0; + break; + case VA_SUB: + va = node->em * 0.2f; + break; + case VA_SUPER: + va = node->em * -0.3f; + break; + } node->x = x; - node->y = y; + node->y = y + baseline + va; x += node->w; if (node->type == FLOW_GLUE) x += justify; @@ -378,6 +402,7 @@ static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float float line_w; float indent; float avail, line_h; + float baseline; int align; em = from_number(box->style.font_size, em, em); @@ -415,10 +440,10 @@ static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float else { avail = page_h - fmodf(box->y + box->h, page_h); - line_h = measure_line(line_start, line_end); + line_h = measure_line(line_start, line_end, &baseline); if (line_h > avail) box->h += avail; - layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box); + layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box, baseline); box->h += line_h; word_start = find_next_word(line_end, &glue_w); line_start = word_start; @@ -436,10 +461,10 @@ static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float if (line_start) { avail = page_h - fmodf(box->y + box->h, page_h); - line_h = measure_line(line_start, line_end); + line_h = measure_line(line_start, line_end, &baseline); if (line_h > avail) box->h += avail; - layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box); + layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box, baseline); box->h += line_h; } } @@ -570,9 +595,8 @@ static void print_box(fz_context *ctx, struct box *box, int level) if (box->node) { const char *tag = fz_xml_tag(box->node); - const char *text = fz_xml_text(box->node); if (tag) printf(" <%s>", tag); - if (text) printf(" \"%s\"", text); + else printf(" anonymous"); } printf("\n"); if (box->down) @@ -605,7 +629,7 @@ draw_flow_box(fz_context *ctx, struct box *box, float page_top, float page_bot, text = fz_new_text(ctx, node->style->font, &trm, 0); x = node->x; - y = node->y + node->em * 0.8; + y = node->y; s = node->text; while (*s) { -- cgit v1.2.3 From 105d9d938396f867607406167c6e78f18625004d Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 19 Nov 2014 14:57:18 +0100 Subject: html: Images. --- source/html/css-parse.c | 8 +---- source/html/layout.c | 96 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 87 insertions(+), 17 deletions(-) (limited to 'source/html') diff --git a/source/html/css-parse.c b/source/html/css-parse.c index c3ec8431..d454dbf1 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -749,22 +749,16 @@ struct rule *fz_parse_css(fz_context *ctx, struct rule *chain, const char *sourc struct rule *fz_parse_css_file(fz_context *ctx, struct rule *chain, const char *filename) { - fz_stream *stm = NULL; - fz_buffer *buf = NULL; + fz_buffer *buf = fz_read_file(ctx, filename); - fz_var(buf); - - stm = fz_open_file(ctx, filename); fz_try(ctx) { - buf = fz_read_all(stm, 0); fz_write_buffer_byte(ctx, buf, 0); chain = fz_parse_css(ctx, chain, (char*)buf->data); } fz_always(ctx) { fz_drop_buffer(ctx, buf); - fz_close(stm); } fz_catch(ctx) { diff --git a/source/html/layout.c b/source/html/layout.c index 796f5fb5..8285b829 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -69,6 +69,12 @@ static void add_flow_word(fz_context *ctx, struct box *top, struct computed_styl flow->text[b - a] = 0; } +static void add_flow_image(fz_context *ctx, struct box *top, struct computed_style *style, fz_image *img) +{ + struct flow *flow = add_flow(ctx, top, style, FLOW_IMAGE); + flow->image = fz_keep_image(ctx, img); +} + static void generate_text(fz_context *ctx, struct box *box, const char *text) { struct box *flow = box; @@ -94,6 +100,27 @@ static void generate_text(fz_context *ctx, struct box *box, const char *text) } } +static void generate_image(html_document *doc, struct box *box, const char *src) +{ + fz_context *ctx = doc->ctx; + fz_image *img; + fz_buffer *buf; + char filename[2048]; + + struct box *flow = box; + while (flow->type != BOX_FLOW) + flow = flow->up; + + fz_strlcpy(filename, doc->dirname, sizeof filename); + fz_strlcat(filename, src, sizeof filename); + + buf = fz_read_file(ctx, filename); + img = fz_new_image_from_buffer(ctx, buf); + fz_drop_buffer(ctx, buf); + + add_flow_image(ctx, flow, &box->style, img); +} + struct box *new_box(fz_context *ctx, fz_xml *node) { struct box *box; @@ -234,7 +261,17 @@ static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, st top = insert_break_box(ctx, box, top); } - // TODO: + else if (!strcmp(tag, "img")) + { + const char *src = fz_xml_att(node, "src"); + if (src) + { + box = new_box(ctx, node); + compute_style(doc, &box->style, &style); + insert_inline_box(ctx, box, top); + generate_image(doc, box, src); + } + } else if (display != DIS_NONE) { @@ -284,6 +321,14 @@ static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, st } } +static void measure_image(fz_context *ctx, struct flow *node, float em) +{ + node->x = 0; + node->y = 0; + node->w = node->image->w; + node->h = node->image->h; +} + static void measure_word(fz_context *ctx, struct flow *node, float em) { const char *s; @@ -312,11 +357,20 @@ static float measure_line(struct flow *node, struct flow *end, float *baseline) float max_a = 0, max_d = 0, h = 0; while (node != end) { - float a = node->em * 0.8; - float d = node->em * 0.2; - if (a > max_a) max_a = a; - if (d > max_d) max_d = d; + if (node->type == FLOW_IMAGE) + { + if (node->h > max_a) + max_a = node->h; + } + else + { + float a = node->em * 0.8; + float d = node->em * 0.2; + if (a > max_a) max_a = a; + if (d > max_d) max_d = d; + } if (node->h > h) h = node->h; + if (max_a + max_d > h) h = max_a + max_d; node = node->next; } *baseline = max_a + (h - max_a - max_d) / 2; @@ -361,7 +415,10 @@ static void layout_line(fz_context *ctx, float indent, float page_w, float line_ break; } node->x = x; - node->y = y + baseline + va; + if (node->type == FLOW_IMAGE) + node->y = y + baseline - node->h; + else + node->y = y + baseline + va; x += node->w; if (node->type == FLOW_GLUE) x += justify; @@ -386,7 +443,7 @@ static struct flow *find_next_glue(struct flow *node, float *w) static struct flow *find_next_word(struct flow *node, float *w) { - while (node && node->type != FLOW_WORD) + while (node && node->type == FLOW_GLUE) { *w += node->w; node = node->next; @@ -418,7 +475,10 @@ static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float return; for (node = box->flow_head; node; node = node->next) - measure_word(ctx, node, em); + if (node->type == FLOW_IMAGE) + measure_image(ctx, node, em); + else + measure_word(ctx, node, em); line_start = find_next_word(box->flow_head, &glue_w); line_end = NULL; @@ -574,6 +634,7 @@ static void print_flow(fz_context *ctx, struct flow *flow, int level) { case FLOW_WORD: printf("word \"%s\"\n", flow->text); break; case FLOW_GLUE: printf("glue \"%s\" / \"%s\"\n", flow->text, flow->broken_text); break; + case FLOW_IMAGE: printf("image\n"); break; } flow = flow->next; } @@ -620,8 +681,16 @@ draw_flow_box(fz_context *ctx, struct box *box, float page_top, float page_bot, for (node = box->flow_head; node; node = node->next) { - if (node->y > page_bot || node->y + node->h < page_top) - continue; + if (node->type == FLOW_IMAGE) + { + if (node->y > page_bot || node->y + node->h < page_top) + continue; + } + else + { + if (node->y > page_bot || node->y < page_top) + continue; + } if (node->type == FLOW_WORD) { @@ -647,6 +716,13 @@ draw_flow_box(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_free_text(ctx, text); } + else if (node->type == FLOW_IMAGE) + { + fz_matrix local_ctm = *ctm; + fz_pre_translate(&local_ctm, node->x, node->y); + fz_pre_scale(&local_ctm, node->w, node->h); + fz_fill_image(dev, node->image, &local_ctm, 1); + } } } -- cgit v1.2.3 From bd11f27be2e8f6e06ee664ebcc40b17f78a2e9d4 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 19 Nov 2014 15:03:33 +0100 Subject: html: Limit image size to fit the page. --- source/html/layout.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'source/html') diff --git a/source/html/layout.c b/source/html/layout.c index 8285b829..acc3d71b 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -321,12 +321,18 @@ static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, st } } -static void measure_image(fz_context *ctx, struct flow *node, float em) +static void measure_image(fz_context *ctx, struct flow *node, float w, float h) { + float xs = 1, ys = 1, s = 1; node->x = 0; node->y = 0; - node->w = node->image->w; - node->h = node->image->h; + if (node->image->w > w) + xs = w / node->image->w; + if (node->image->h > h) + ys = h / node->image->h; + s = fz_min(xs, ys); + node->w = node->image->w * s; + node->h = node->image->h * s; } static void measure_word(fz_context *ctx, struct flow *node, float em) @@ -476,7 +482,7 @@ static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float for (node = box->flow_head; node; node = node->next) if (node->type == FLOW_IMAGE) - measure_image(ctx, node, em); + measure_image(ctx, node, top->w, page_h); else measure_word(ctx, node, em); -- cgit v1.2.3 From bb238db8919162c8976980b8aa48f70664f2f29d Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Mon, 24 Nov 2014 15:52:47 +0100 Subject: html: Pass font size to html_layout_document. --- source/html/handler.c | 7 ++++--- source/html/layout.c | 6 ++++-- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'source/html') diff --git a/source/html/handler.c b/source/html/handler.c index fda21f5c..c89e82ae 100644 --- a/source/html/handler.c +++ b/source/html/handler.c @@ -15,7 +15,7 @@ html_count_pages(html_document *doc) { int count; - if (!doc->box) html_layout_document(doc, DEFW, DEFH); + if (!doc->box) html_layout_document(doc, DEFW, DEFH, 12); count = ceilf(doc->box->h / doc->page_h); printf("count pages! %g / %g = %d\n", doc->box->h, doc->page_h, count); @@ -26,7 +26,7 @@ html_page * html_load_page(html_document *doc, int number) { printf("load page %d\n", number); - if (!doc->box) html_layout_document(doc, DEFW, DEFH); + if (!doc->box) html_layout_document(doc, DEFW, DEFH, 12); return (void*)((intptr_t)number + 1); } @@ -38,7 +38,7 @@ html_free_page(html_document *doc, html_page *page) fz_rect * html_bound_page(html_document *doc, html_page *page, fz_rect *bbox) { - if (!doc->box) html_layout_document(doc, DEFW, DEFH); + if (!doc->box) html_layout_document(doc, DEFW, DEFH, 12); printf("html: bound page\n"); bbox->x0 = bbox->y0 = 0; bbox->x1 = doc->page_w; @@ -73,6 +73,7 @@ printf("html: parsing XHTML.\n"); doc->dirname = NULL; doc->super.close = (void*)html_close_document; + doc->super.layout = (void*)html_layout_document; doc->super.count_pages = (void*)html_count_pages; doc->super.load_page = (void*)html_load_page; doc->super.bound_page = (void*)html_bound_page; diff --git a/source/html/layout.c b/source/html/layout.c index acc3d71b..822e2937 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -875,7 +875,7 @@ static struct rule *load_css(html_document *doc, struct rule *css, fz_xml *root) } void -html_layout_document(html_document *doc, float page_w, float page_h) +html_layout_document(html_document *doc, float page_w, float page_h, float em) { struct rule *css = NULL; struct box *root_box; @@ -900,10 +900,12 @@ printf("html: parsing style sheets.\n"); page_box->w = page_w; page_box->h = 0; + // TODO: split generate and layout + printf("html: applying styles and generating boxes.\n"); generate_boxes(doc, doc->xml, root_box, css, &style); printf("html: laying out text.\n"); - layout_block(doc->ctx, root_box, page_box, 12, 0, page_h); + layout_block(doc->ctx, root_box, page_box, em, 0, page_h); printf("html: finished.\n"); // print_box(doc->ctx, root_box, 0); -- cgit v1.2.3 From cf42f2f4d5e95b7254479e80614d1814e74e2387 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 25 Nov 2014 23:50:27 +0100 Subject: html: Split html parsing cache and state into html_context. html_document is now a simple client of html_context. --- source/html/css-apply.c | 4 +- source/html/font.c | 9 ++- source/html/handler.c | 150 +++++++++++++++++++++++++++--------------------- source/html/layout.c | 135 +++++++++++++++++++++++++++---------------- 4 files changed, 173 insertions(+), 125 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 67814440..bbfc7ffa 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -990,7 +990,7 @@ default_computed_style(struct computed_style *style) } void -compute_style(html_document *doc, struct computed_style *style, struct style *node) +compute_style(fz_context *ctx, html_context *htx, struct computed_style *style, struct style *node) { struct value *value; @@ -1087,7 +1087,7 @@ compute_style(html_document *doc, struct computed_style *style, struct style *no const char *font_variant = get_style_property_string(node, "font-variant", "normal"); const char *font_style = get_style_property_string(node, "font-style", "normal"); const char *font_weight = get_style_property_string(node, "font-weight", "normal"); - style->font = html_load_font(doc, font_family, font_variant, font_style, font_weight); + style->font = html_load_font(ctx, htx, font_family, font_variant, font_style, font_weight); } } diff --git a/source/html/font.c b/source/html/font.c index 9c408367..51654ae9 100644 --- a/source/html/font.c +++ b/source/html/font.c @@ -9,10 +9,9 @@ static const char *font_names[16] = { }; fz_font * -html_load_font(html_document *doc, +html_load_font(fz_context *ctx, html_context *htx, const char *family, const char *variant, const char *style, const char *weight) { - fz_context *ctx = doc->ctx; unsigned char *data; unsigned int size; @@ -22,15 +21,15 @@ html_load_font(html_document *doc, int is_italic = !strcmp(style, "italic") || !strcmp(style, "oblique"); int idx = is_mono * 8 + is_sans * 4 + is_bold * 2 + is_italic; - if (!doc->fonts[idx]) + if (!htx->fonts[idx]) { data = pdf_lookup_builtin_font(font_names[idx], &size); if (!data) { printf("data=%p idx=%d s=%s\n", data, idx, font_names[idx]); abort(); } - doc->fonts[idx] = fz_new_font_from_memory(ctx, font_names[idx], data, size, 0, 1); + htx->fonts[idx] = fz_new_font_from_memory(ctx, font_names[idx], data, size, 0, 1); } - return doc->fonts[idx]; + return htx->fonts[idx]; } diff --git a/source/html/handler.c b/source/html/handler.c index c89e82ae..626ed443 100644 --- a/source/html/handler.c +++ b/source/html/handler.c @@ -2,125 +2,141 @@ #define DEFW (450) #define DEFH (600) +#define DEFEM (12) -void -html_close_document(html_document *doc) +typedef struct html_document_s html_document; + +struct html_document_s +{ + fz_document super; + fz_context *ctx; + html_context htx; + struct box *box; +}; + +static void +htdoc_close_document(html_document *doc) { fz_context *ctx = doc->ctx; + html_fini(ctx, &doc->htx); fz_free(ctx, doc); } -int -html_count_pages(html_document *doc) +static int +htdoc_count_pages(html_document *doc) { int count; - if (!doc->box) html_layout_document(doc, DEFW, DEFH, 12); + // TODO: reflow - count = ceilf(doc->box->h / doc->page_h); -printf("count pages! %g / %g = %d\n", doc->box->h, doc->page_h, count); + count = ceilf(doc->box->h / doc->htx.page_h); +printf("count pages! %g / %g = %d\n", doc->box->h, doc->htx.page_h, count); return count; } -html_page * -html_load_page(html_document *doc, int number) +static void * +htdoc_load_page(html_document *doc, int number) { printf("load page %d\n", number); - if (!doc->box) html_layout_document(doc, DEFW, DEFH, 12); + // TODO: reflow return (void*)((intptr_t)number + 1); } -void -html_free_page(html_document *doc, html_page *page) +static void +htdoc_free_page(html_document *doc, void *page) +{ +} + +static void +htdoc_layout(html_document *doc, float w, float h, float em) { + html_layout(doc->ctx, &doc->htx, doc->box, w, h, em); } -fz_rect * -html_bound_page(html_document *doc, html_page *page, fz_rect *bbox) +static fz_rect * +htdoc_bound_page(html_document *doc, void *page, fz_rect *bbox) { - if (!doc->box) html_layout_document(doc, DEFW, DEFH, 12); + // TODO: reflow printf("html: bound page\n"); bbox->x0 = bbox->y0 = 0; - bbox->x1 = doc->page_w; - bbox->y1 = doc->page_h; + bbox->x1 = doc->htx.page_w; + bbox->y1 = doc->htx.page_h; return bbox; } -void -html_run_page(html_document *doc, html_page *page, fz_device *dev, const fz_matrix *ctm, fz_cookie *cookie) +static void +htdoc_run_page(html_document *doc, void *page, fz_device *dev, const fz_matrix *ctm, fz_cookie *cookie) { int n = ((intptr_t)page) - 1; printf("html: run page %d\n", n); - html_run_box(doc->ctx, doc->box, n * doc->page_h, (n+1) * doc->page_h, dev, ctm); + html_draw(doc->ctx, &doc->htx, doc->box, n * doc->htx.page_h, (n+1) * doc->htx.page_h, dev, ctm); } -html_document * -html_open_document_with_stream(fz_context *ctx, fz_stream *file) + +static html_document * +htdoc_open_document_with_stream(fz_context *ctx, fz_stream *file) { html_document *doc; + fz_archive *zip; fz_buffer *buf; - fz_xml *xml; - buf = fz_read_all(file, 0); - fz_write_buffer_byte(ctx, buf, 0); - -printf("html: parsing XHTML.\n"); - xml = fz_parse_xml(ctx, buf->data, buf->len, 1); - fz_drop_buffer(ctx, buf); + zip = fz_open_directory(ctx, "."); doc = fz_malloc_struct(ctx, html_document); doc->ctx = ctx; - doc->dirname = NULL; + html_init(ctx, &doc->htx, zip); - doc->super.close = (void*)html_close_document; - doc->super.layout = (void*)html_layout_document; - doc->super.count_pages = (void*)html_count_pages; - doc->super.load_page = (void*)html_load_page; - doc->super.bound_page = (void*)html_bound_page; - doc->super.run_page_contents = (void*)html_run_page; - doc->super.free_page = (void*)html_free_page; + doc->super.close = (void*)htdoc_close_document; + doc->super.layout = (void*)htdoc_layout; + doc->super.count_pages = (void*)htdoc_count_pages; + doc->super.load_page = (void*)htdoc_load_page; + doc->super.bound_page = (void*)htdoc_bound_page; + doc->super.run_page_contents = (void*)htdoc_run_page; + doc->super.free_page = (void*)htdoc_free_page; - doc->xml = xml; - doc->box = NULL; + buf = fz_read_all(file, 0); + fz_write_buffer_byte(ctx, buf, 0); + doc->box = html_generate(ctx, &doc->htx, ".", buf); + fz_drop_buffer(ctx, buf); return doc; } -html_document * -html_open_document(fz_context *ctx, const char *filename) +static html_document * +htdoc_open_document(fz_context *ctx, const char *filename) { - fz_stream *file; + char dirname[2048]; + fz_archive *zip; + fz_buffer *buf; html_document *doc; - char *s; - file = fz_open_file(ctx, filename); - if (!file) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", filename, strerror(errno)); + fz_dirname(dirname, filename, sizeof dirname); + zip = fz_open_directory(ctx, dirname); - fz_try(ctx) - { - doc = html_open_document_with_stream(ctx, file); - } - fz_always(ctx) - { - fz_close(file); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } + doc = fz_malloc_struct(ctx, html_document); + doc->ctx = ctx; + html_init(ctx, &doc->htx, zip); + + doc->super.close = (void*)htdoc_close_document; + doc->super.layout = (void*)htdoc_layout; + doc->super.count_pages = (void*)htdoc_count_pages; + doc->super.load_page = (void*)htdoc_load_page; + doc->super.bound_page = (void*)htdoc_bound_page; + doc->super.run_page_contents = (void*)htdoc_run_page; + doc->super.free_page = (void*)htdoc_free_page; + + buf = fz_read_file(ctx, filename); + fz_write_buffer_byte(ctx, buf, 0); + doc->box = html_generate(ctx, &doc->htx, ".", buf); + fz_drop_buffer(ctx, buf); - doc->dirname = fz_strdup(ctx, filename); - s = strrchr(doc->dirname, '/'); - if (!s) s = strrchr(doc->dirname, '\\'); - if (s) s[1] = 0; - else doc->dirname[0] = 0; + htdoc_layout(doc, DEFW, DEFH, DEFEM); return doc; } static int -html_recognize(fz_context *doc, const char *magic) +htdoc_recognize(fz_context *doc, const char *magic) { char *ext = strrchr(magic, '.'); @@ -137,7 +153,7 @@ html_recognize(fz_context *doc, const char *magic) fz_document_handler html_document_handler = { - (fz_document_recognize_fn *)&html_recognize, - (fz_document_open_fn *)&html_open_document, - (fz_document_open_with_stream_fn *)&html_open_document_with_stream + (fz_document_recognize_fn *)&htdoc_recognize, + (fz_document_open_fn *)&htdoc_open_document, + (fz_document_open_with_stream_fn *)&htdoc_open_document_with_stream }; diff --git a/source/html/layout.c b/source/html/layout.c index 822e2937..f07108b5 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -100,33 +100,30 @@ static void generate_text(fz_context *ctx, struct box *box, const char *text) } } -static void generate_image(html_document *doc, struct box *box, const char *src) +static void generate_image(fz_context *ctx, html_context *htx, const char *base_uri, struct box *box, const char *src) { - fz_context *ctx = doc->ctx; fz_image *img; fz_buffer *buf; - char filename[2048]; + char path[2048]; struct box *flow = box; while (flow->type != BOX_FLOW) flow = flow->up; - fz_strlcpy(filename, doc->dirname, sizeof filename); - fz_strlcat(filename, src, sizeof filename); + fz_strlcpy(path, base_uri, sizeof path); + fz_strlcat(path, "/", sizeof path); + fz_strlcat(path, src, sizeof path); + fz_cleanname(path); - buf = fz_read_file(ctx, filename); + buf = fz_read_archive_entry(ctx, htx->zip, path); img = fz_new_image_from_buffer(ctx, buf); fz_drop_buffer(ctx, buf); add_flow_image(ctx, flow, &box->style, img); } -struct box *new_box(fz_context *ctx, fz_xml *node) +static void init_box(fz_context *ctx, struct box *box, fz_xml *node) { - struct box *box; - - box = fz_malloc_struct(ctx, struct box); - box->type = BOX_BLOCK; box->x = box->y = 0; box->w = box->h = 0; @@ -142,11 +139,16 @@ struct box *new_box(fz_context *ctx, fz_xml *node) box->flow_tail = &box->flow_head; default_computed_style(&box->style); +} +static struct box *new_box(fz_context *ctx, fz_xml *node) +{ + struct box *box = fz_malloc_struct(ctx, struct box); + init_box(ctx, box, node); return box; } -void insert_box(fz_context *ctx, struct box *box, int type, struct box *top) +static void insert_box(fz_context *ctx, struct box *box, int type, struct box *top) { box->type = type; @@ -234,9 +236,9 @@ static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) } } -static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, struct rule *rule, struct style *up_style) +static void generate_boxes(fz_context *ctx, html_context *htx, const char *base_uri, + fz_xml *node, struct box *top, struct rule *rule, struct style *up_style) { - fz_context *ctx = doc->ctx; struct style style; struct box *box; const char *tag; @@ -257,7 +259,7 @@ static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, st if (!strcmp(tag, "br")) { box = new_box(ctx, node); - compute_style(doc, &box->style, &style); + compute_style(ctx, htx, &box->style, &style); top = insert_break_box(ctx, box, top); } @@ -267,16 +269,16 @@ static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, st if (src) { box = new_box(ctx, node); - compute_style(doc, &box->style, &style); + compute_style(ctx, htx, &box->style, &style); insert_inline_box(ctx, box, top); - generate_image(doc, box, src); + generate_image(ctx, htx, base_uri, box, src); } } else if (display != DIS_NONE) { box = new_box(ctx, node); - compute_style(doc, &box->style, &style); + compute_style(ctx, htx, &box->style, &style); if (display == DIS_BLOCK) { @@ -297,7 +299,7 @@ static void generate_boxes(html_document *doc, fz_xml *node, struct box *top, st } if (fz_xml_down(node)) - generate_boxes(doc, fz_xml_down(node), box, rule, &style); + generate_boxes(ctx, htx, base_uri, fz_xml_down(node), box, rule, &style); // TODO: remove empty flow boxes } @@ -804,7 +806,7 @@ draw_block_box(fz_context *ctx, struct box *box, float page_top, float page_bot, } void -html_run_box(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *inctm) +html_draw(fz_context *ctx, html_context *htx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *inctm) { fz_matrix ctm = *inctm; fz_pre_translate(&ctm, 0, -page_top); @@ -836,16 +838,15 @@ static char *concat_text(fz_context *ctx, fz_xml *root) return s; } -static struct rule *load_css(html_document *doc, struct rule *css, fz_xml *root) +static struct rule *html_load_css(fz_context *ctx, html_context *htx, const char *base_uri, struct rule *css, fz_xml *root) { - fz_context *ctx = doc->ctx; fz_xml *node; - char filename[2048]; + fz_buffer *buf; + char path[2048]; for (node = root; node; node = fz_xml_next(node)) { const char *tag = fz_xml_tag(node); -#if 1 if (tag && !strcmp(tag, "link")) { char *rel = fz_xml_att(node, "rel"); @@ -855,13 +856,21 @@ static struct rule *load_css(html_document *doc, struct rule *css, fz_xml *root) if ((type && !strcmp(type, "text/css")) || !type) { char *href = fz_xml_att(node, "href"); - fz_strlcpy(filename, doc->dirname, sizeof filename); - fz_strlcat(filename, href, sizeof filename); - css = fz_parse_css_file(ctx, css, filename); + if (href) + { + fz_strlcpy(path, base_uri, sizeof path); + fz_strlcat(path, "/", sizeof path); + fz_strlcat(path, href, sizeof path); + fz_cleanname(path); + + buf = fz_read_archive_entry(ctx, htx->zip, path); + fz_write_buffer_byte(ctx, buf, 0); + css = fz_parse_css(ctx, css, (char*)buf->data); + fz_drop_buffer(ctx, buf); + } } } } -#endif if (tag && !strcmp(tag, "style")) { char *s = concat_text(ctx, node); @@ -869,46 +878,70 @@ static struct rule *load_css(html_document *doc, struct rule *css, fz_xml *root) fz_free(ctx, s); } if (fz_xml_down(node)) - css = load_css(doc, css, fz_xml_down(node)); + css = html_load_css(ctx, htx, base_uri, css, fz_xml_down(node)); } return css; } void -html_layout_document(html_document *doc, float page_w, float page_h, float em) +html_layout(fz_context *ctx, html_context *htx, struct box *box, float w, float h, float em) +{ + struct box page_box; + + htx->page_w = w; + htx->page_h = h; + + printf("html: laying out text.\n"); + + init_box(ctx, &page_box, NULL); + page_box.w = w; + page_box.h = 0; + + layout_block(ctx, box, &page_box, em, 0, h); + + printf("html: finished.\n"); +} + +struct box * +html_generate(fz_context *ctx, html_context *htx, const char *base_uri, fz_buffer *buf) { - struct rule *css = NULL; - struct box *root_box; - struct box *page_box; + fz_xml *xml; + struct rule *css; + struct box *box; struct style style; - doc->page_w = page_w; - doc->page_h = page_h; + printf("html: parsing XHTML.\n"); + xml = fz_parse_xml(ctx, buf->data, buf->len, 1); -printf("html: parsing style sheets.\n"); - css = fz_parse_css(doc->ctx, NULL, default_css); - css = load_css(doc, css, doc->xml); + printf("html: parsing style sheets.\n"); + css = fz_parse_css(ctx, NULL, default_css); + css = html_load_css(ctx, htx, base_uri, css, xml); // print_rules(css); + printf("html: applying styles and generating boxes.\n"); + box = new_box(ctx, NULL); + style.up = NULL; style.count = 0; - root_box = new_box(doc->ctx, NULL); - - page_box = new_box(doc->ctx, NULL); - page_box->w = page_w; - page_box->h = 0; + generate_boxes(ctx, htx, base_uri, xml, box, css, &style); - // TODO: split generate and layout + return box; +} -printf("html: applying styles and generating boxes.\n"); - generate_boxes(doc, doc->xml, root_box, css, &style); -printf("html: laying out text.\n"); - layout_block(doc->ctx, root_box, page_box, em, 0, page_h); -printf("html: finished.\n"); +void html_init(fz_context *ctx, html_context *html, fz_archive *zip) +{ + memset(html, 0, sizeof *html); + html->zip = zip; +} - // print_box(doc->ctx, root_box, 0); +void html_rebind(html_context *html, fz_context *ctx) +{ + fz_rebind_archive(html->zip, ctx); +} - doc->box = root_box; +void html_fini(fz_context *ctx, html_context *html) +{ + fz_close_archive(ctx, html->zip); } -- cgit v1.2.3 From 673f6e7149c3c5b0e2a1fe334c3b04124fc807c6 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 26 Nov 2014 02:14:34 +0100 Subject: html: Clean up some names. --- source/html/css-apply.c | 4 ++-- source/html/font.c | 18 +++++++++++++---- source/html/handler.c | 43 ++++++++++++++++++++++------------------- source/html/layout.c | 51 ++++++++++++++++--------------------------------- 4 files changed, 55 insertions(+), 61 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index bbfc7ffa..289811c6 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -990,7 +990,7 @@ default_computed_style(struct computed_style *style) } void -compute_style(fz_context *ctx, html_context *htx, struct computed_style *style, struct style *node) +compute_style(fz_context *ctx, fz_html_font_set *set, struct computed_style *style, struct style *node) { struct value *value; @@ -1087,7 +1087,7 @@ compute_style(fz_context *ctx, html_context *htx, struct computed_style *style, const char *font_variant = get_style_property_string(node, "font-variant", "normal"); const char *font_style = get_style_property_string(node, "font-style", "normal"); const char *font_weight = get_style_property_string(node, "font-weight", "normal"); - style->font = html_load_font(ctx, htx, font_family, font_variant, font_style, font_weight); + style->font = fz_html_load_font(ctx, set, font_family, font_variant, font_style, font_weight); } } diff --git a/source/html/font.c b/source/html/font.c index 51654ae9..ce8c2ed1 100644 --- a/source/html/font.c +++ b/source/html/font.c @@ -9,7 +9,7 @@ static const char *font_names[16] = { }; fz_font * -html_load_font(fz_context *ctx, html_context *htx, +fz_html_load_font(fz_context *ctx, fz_html_font_set *set, const char *family, const char *variant, const char *style, const char *weight) { unsigned char *data; @@ -21,15 +21,25 @@ html_load_font(fz_context *ctx, html_context *htx, int is_italic = !strcmp(style, "italic") || !strcmp(style, "oblique"); int idx = is_mono * 8 + is_sans * 4 + is_bold * 2 + is_italic; - if (!htx->fonts[idx]) + if (!set->fonts[idx]) { data = pdf_lookup_builtin_font(font_names[idx], &size); if (!data) { printf("data=%p idx=%d s=%s\n", data, idx, font_names[idx]); abort(); } - htx->fonts[idx] = fz_new_font_from_memory(ctx, font_names[idx], data, size, 0, 1); + set->fonts[idx] = fz_new_font_from_memory(ctx, font_names[idx], data, size, 0, 1); } - return htx->fonts[idx]; + return set->fonts[idx]; +} + +fz_html_font_set *fz_new_html_font_set(fz_context *ctx) +{ + return fz_malloc_struct(ctx, fz_html_font_set); +} + +void fz_free_html_font_set(fz_context *ctx, fz_html_font_set *set) +{ + fz_free(ctx, set); } diff --git a/source/html/handler.c b/source/html/handler.c index 626ed443..11d21d56 100644 --- a/source/html/handler.c +++ b/source/html/handler.c @@ -10,16 +10,18 @@ struct html_document_s { fz_document super; fz_context *ctx; - html_context htx; + fz_archive *zip; + fz_html_font_set *set; + float page_w, page_h, em; struct box *box; }; static void htdoc_close_document(html_document *doc) { - fz_context *ctx = doc->ctx; - html_fini(ctx, &doc->htx); - fz_free(ctx, doc); + fz_close_archive(doc->ctx, doc->zip); + fz_free_html_font_set(doc->ctx, doc->set); + fz_free(doc->ctx, doc); } static int @@ -29,8 +31,8 @@ htdoc_count_pages(html_document *doc) // TODO: reflow - count = ceilf(doc->box->h / doc->htx.page_h); -printf("count pages! %g / %g = %d\n", doc->box->h, doc->htx.page_h, count); + count = ceilf(doc->box->h / doc->page_h); +printf("count pages! %g / %g = %d\n", doc->box->h, doc->page_h, count); return count; } @@ -50,7 +52,10 @@ htdoc_free_page(html_document *doc, void *page) static void htdoc_layout(html_document *doc, float w, float h, float em) { - html_layout(doc->ctx, &doc->htx, doc->box, w, h, em); + doc->page_w = w; + doc->page_h = h; + doc->em = em; + fz_layout_html(doc->ctx, doc->box, w, h, em); } static fz_rect * @@ -59,8 +64,8 @@ htdoc_bound_page(html_document *doc, void *page, fz_rect *bbox) // TODO: reflow printf("html: bound page\n"); bbox->x0 = bbox->y0 = 0; - bbox->x1 = doc->htx.page_w; - bbox->y1 = doc->htx.page_h; + bbox->x1 = doc->page_w; + bbox->y1 = doc->page_h; return bbox; } @@ -69,22 +74,19 @@ htdoc_run_page(html_document *doc, void *page, fz_device *dev, const fz_matrix * { int n = ((intptr_t)page) - 1; printf("html: run page %d\n", n); - html_draw(doc->ctx, &doc->htx, doc->box, n * doc->htx.page_h, (n+1) * doc->htx.page_h, dev, ctm); + fz_draw_html(doc->ctx, doc->box, n * doc->page_h, (n+1) * doc->page_h, dev, ctm); } - static html_document * htdoc_open_document_with_stream(fz_context *ctx, fz_stream *file) { html_document *doc; - fz_archive *zip; fz_buffer *buf; - zip = fz_open_directory(ctx, "."); - doc = fz_malloc_struct(ctx, html_document); doc->ctx = ctx; - html_init(ctx, &doc->htx, zip); + doc->zip = fz_open_directory(ctx, "."); + doc->set = fz_new_html_font_set(ctx); doc->super.close = (void*)htdoc_close_document; doc->super.layout = (void*)htdoc_layout; @@ -96,9 +98,11 @@ htdoc_open_document_with_stream(fz_context *ctx, fz_stream *file) buf = fz_read_all(file, 0); fz_write_buffer_byte(ctx, buf, 0); - doc->box = html_generate(ctx, &doc->htx, ".", buf); + doc->box = fz_generate_html(ctx, doc->set, doc->zip, ".", buf); fz_drop_buffer(ctx, buf); + htdoc_layout(doc, DEFW, DEFH, DEFEM); + return doc; } @@ -106,16 +110,15 @@ static html_document * htdoc_open_document(fz_context *ctx, const char *filename) { char dirname[2048]; - fz_archive *zip; fz_buffer *buf; html_document *doc; fz_dirname(dirname, filename, sizeof dirname); - zip = fz_open_directory(ctx, dirname); doc = fz_malloc_struct(ctx, html_document); doc->ctx = ctx; - html_init(ctx, &doc->htx, zip); + doc->zip = fz_open_directory(ctx, dirname); + doc->set = fz_new_html_font_set(ctx); doc->super.close = (void*)htdoc_close_document; doc->super.layout = (void*)htdoc_layout; @@ -127,7 +130,7 @@ htdoc_open_document(fz_context *ctx, const char *filename) buf = fz_read_file(ctx, filename); fz_write_buffer_byte(ctx, buf, 0); - doc->box = html_generate(ctx, &doc->htx, ".", buf); + doc->box = fz_generate_html(ctx, doc->set, doc->zip, ".", buf); fz_drop_buffer(ctx, buf); htdoc_layout(doc, DEFW, DEFH, DEFEM); diff --git a/source/html/layout.c b/source/html/layout.c index f07108b5..3243a6ae 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -100,7 +100,7 @@ static void generate_text(fz_context *ctx, struct box *box, const char *text) } } -static void generate_image(fz_context *ctx, html_context *htx, const char *base_uri, struct box *box, const char *src) +static void generate_image(fz_context *ctx, fz_archive *zip, const char *base_uri, struct box *box, const char *src) { fz_image *img; fz_buffer *buf; @@ -115,7 +115,7 @@ static void generate_image(fz_context *ctx, html_context *htx, const char *base_ fz_strlcat(path, src, sizeof path); fz_cleanname(path); - buf = fz_read_archive_entry(ctx, htx->zip, path); + buf = fz_read_archive_entry(ctx, zip, path); img = fz_new_image_from_buffer(ctx, buf); fz_drop_buffer(ctx, buf); @@ -236,7 +236,7 @@ static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) } } -static void generate_boxes(fz_context *ctx, html_context *htx, const char *base_uri, +static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const char *base_uri, fz_xml *node, struct box *top, struct rule *rule, struct style *up_style) { struct style style; @@ -259,7 +259,7 @@ static void generate_boxes(fz_context *ctx, html_context *htx, const char *base_ if (!strcmp(tag, "br")) { box = new_box(ctx, node); - compute_style(ctx, htx, &box->style, &style); + compute_style(ctx, set, &box->style, &style); top = insert_break_box(ctx, box, top); } @@ -269,16 +269,16 @@ static void generate_boxes(fz_context *ctx, html_context *htx, const char *base_ if (src) { box = new_box(ctx, node); - compute_style(ctx, htx, &box->style, &style); + compute_style(ctx, set, &box->style, &style); insert_inline_box(ctx, box, top); - generate_image(ctx, htx, base_uri, box, src); + generate_image(ctx, zip, base_uri, box, src); } } else if (display != DIS_NONE) { box = new_box(ctx, node); - compute_style(ctx, htx, &box->style, &style); + compute_style(ctx, set, &box->style, &style); if (display == DIS_BLOCK) { @@ -299,7 +299,7 @@ static void generate_boxes(fz_context *ctx, html_context *htx, const char *base_ } if (fz_xml_down(node)) - generate_boxes(ctx, htx, base_uri, fz_xml_down(node), box, rule, &style); + generate_boxes(ctx, set, zip, base_uri, fz_xml_down(node), box, rule, &style); // TODO: remove empty flow boxes } @@ -806,7 +806,7 @@ draw_block_box(fz_context *ctx, struct box *box, float page_top, float page_bot, } void -html_draw(fz_context *ctx, html_context *htx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *inctm) +fz_draw_html(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *inctm) { fz_matrix ctm = *inctm; fz_pre_translate(&ctm, 0, -page_top); @@ -838,7 +838,7 @@ static char *concat_text(fz_context *ctx, fz_xml *root) return s; } -static struct rule *html_load_css(fz_context *ctx, html_context *htx, const char *base_uri, struct rule *css, fz_xml *root) +static struct rule *html_load_css(fz_context *ctx, fz_archive *zip, const char *base_uri, struct rule *css, fz_xml *root) { fz_xml *node; fz_buffer *buf; @@ -863,7 +863,7 @@ static struct rule *html_load_css(fz_context *ctx, html_context *htx, const char fz_strlcat(path, href, sizeof path); fz_cleanname(path); - buf = fz_read_archive_entry(ctx, htx->zip, path); + buf = fz_read_archive_entry(ctx, zip, path); fz_write_buffer_byte(ctx, buf, 0); css = fz_parse_css(ctx, css, (char*)buf->data); fz_drop_buffer(ctx, buf); @@ -878,19 +878,16 @@ static struct rule *html_load_css(fz_context *ctx, html_context *htx, const char fz_free(ctx, s); } if (fz_xml_down(node)) - css = html_load_css(ctx, htx, base_uri, css, fz_xml_down(node)); + css = html_load_css(ctx, zip, base_uri, css, fz_xml_down(node)); } return css; } void -html_layout(fz_context *ctx, html_context *htx, struct box *box, float w, float h, float em) +fz_layout_html(fz_context *ctx, struct box *box, float w, float h, float em) { struct box page_box; - htx->page_w = w; - htx->page_h = h; - printf("html: laying out text.\n"); init_box(ctx, &page_box, NULL); @@ -903,7 +900,7 @@ html_layout(fz_context *ctx, html_context *htx, struct box *box, float w, float } struct box * -html_generate(fz_context *ctx, html_context *htx, const char *base_uri, fz_buffer *buf) +fz_generate_html(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const char *base_uri, fz_buffer *buf) { fz_xml *xml; struct rule *css; @@ -915,7 +912,7 @@ html_generate(fz_context *ctx, html_context *htx, const char *base_uri, fz_buffe printf("html: parsing style sheets.\n"); css = fz_parse_css(ctx, NULL, default_css); - css = html_load_css(ctx, htx, base_uri, css, xml); + css = html_load_css(ctx, zip, base_uri, css, xml); // print_rules(css); @@ -925,23 +922,7 @@ html_generate(fz_context *ctx, html_context *htx, const char *base_uri, fz_buffe style.up = NULL; style.count = 0; - generate_boxes(ctx, htx, base_uri, xml, box, css, &style); + generate_boxes(ctx, set, zip, base_uri, xml, box, css, &style); return box; } - -void html_init(fz_context *ctx, html_context *html, fz_archive *zip) -{ - memset(html, 0, sizeof *html); - html->zip = zip; -} - -void html_rebind(html_context *html, fz_context *ctx) -{ - fz_rebind_archive(html->zip, ctx); -} - -void html_fini(fz_context *ctx, html_context *html) -{ - fz_close_archive(ctx, html->zip); -} -- cgit v1.2.3 From 08a4d6d49f91e295fa6265a91ce030fc9c585922 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 26 Nov 2014 02:16:00 +0100 Subject: epub: Add EPUB document type. --- source/html/epub-doc.c | 305 +++++++++++++++++++++++++++++++++++++++++++++++++ source/html/layout.c | 1 + 2 files changed, 306 insertions(+) create mode 100644 source/html/epub-doc.c (limited to 'source/html') diff --git a/source/html/epub-doc.c b/source/html/epub-doc.c new file mode 100644 index 00000000..11b43e0a --- /dev/null +++ b/source/html/epub-doc.c @@ -0,0 +1,305 @@ +#include "mupdf/html.h" + +#define DEFW (450) +#define DEFH (600) +#define DEFEM (12) + +typedef struct epub_document_s epub_document; +typedef struct epub_chapter_s epub_chapter; +typedef struct epub_page_s epub_page; + +struct epub_document_s +{ + fz_document super; + fz_context *ctx; + fz_archive *zip; + fz_html_font_set *set; + float page_w, page_h, em; + int count; + epub_chapter *spine; +}; + +struct epub_chapter_s +{ + int start; + struct box *box; + epub_chapter *next; +}; + +static void +epub_layout(epub_document *doc, float w, float h, float em) +{ + fz_context *ctx = doc->ctx; + epub_chapter *ch; + + doc->page_w = w; + doc->page_h = h; + doc->em = em; + + printf("epub: laying out chapters.\n"); + for (ch = doc->spine; ch; ch = ch->next) + fz_layout_html(ctx, ch->box, w, h, em); + printf("epub: done.\n"); +} + +static int +epub_count_pages(epub_document *doc) +{ + epub_chapter *ch; + int count = 0; + for (ch = doc->spine; ch; ch = ch->next) + count += ceilf(ch->box->h / doc->page_h); + return count; +} + +static epub_page * +epub_load_page(epub_document *doc, int number) +{ + return (void*)((intptr_t)number + 1); +} + +static void +epub_free_page(epub_document *doc, epub_page *page) +{ +} + +static fz_rect * +epub_bound_page(epub_document *doc, epub_page *page, fz_rect *bbox) +{ + bbox->x0 = 0; + bbox->y0 = 0; + bbox->x1 = doc->page_w; + bbox->y1 = doc->page_h; + return bbox; +} + +static void +epub_run_page(epub_document *doc, epub_page *page, fz_device *dev, const fz_matrix *ctm, fz_cookie *cookie) +{ + fz_context *ctx = doc->ctx; + epub_chapter *ch; + int n = ((intptr_t)page) - 1; + int count = 0; + for (ch = doc->spine; ch; ch = ch->next) + { + int cn = ceilf(ch->box->h / doc->page_h); + if (n < count + cn) + { + fz_draw_html(ctx, ch->box, (n-count) * doc->page_h, (n-count+1) * doc->page_h, dev, ctm); + break; + } + count += cn; + } +} + +static void +epub_close_document(epub_document *doc) +{ + /* TODO:free all chapters */ + fz_close_archive(doc->ctx, doc->zip); + fz_free_html_font_set(doc->ctx, doc->set); + fz_free(doc->ctx, doc); +} + +static const char * +rel_path_from_idref(fz_xml *manifest, const char *idref) +{ + fz_xml *item; + if (!idref) + return NULL; + item = fz_xml_find_down(manifest, "item"); + while (item) + { + const char *id = fz_xml_att(item, "id"); + if (id && !strcmp(id, idref)) + return fz_xml_att(item, "href"); + item = fz_xml_find_next(item, "item"); + } + return NULL; +} + +static const char * +path_from_idref(char *path, fz_xml *manifest, const char *base_uri, const char *idref, int n) +{ + const char *rel_path = rel_path_from_idref(manifest, idref); + if (!rel_path) + { + path[0] = 0; + return NULL; + } + fz_strlcpy(path, base_uri, n); + fz_strlcat(path, "/", n); + fz_strlcat(path, rel_path, n); + return fz_cleanname(path); +} + +static epub_chapter * +epub_parse_chapter(epub_document *doc, const char *path) +{ + fz_context *ctx = doc->ctx; + fz_archive *zip = doc->zip; + fz_buffer *buf; + epub_chapter *ch; + char base_uri[2048]; + + fz_dirname(base_uri, path, sizeof base_uri); + + buf = fz_read_archive_entry(ctx, zip, path); + fz_write_buffer_byte(ctx, buf, 0); + + ch = fz_malloc_struct(ctx, epub_chapter); + ch->box = fz_generate_html(ctx, doc->set, zip, base_uri, buf); + ch->next = NULL; + + fz_drop_buffer(ctx, buf); + + return ch; +} + +static void +epub_parse_header(epub_document *doc) +{ + fz_context *ctx = doc->ctx; + fz_archive *zip = doc->zip; + fz_buffer *buf; + fz_xml *container_xml, *content_opf; + fz_xml *container, *rootfiles, *rootfile; + fz_xml *package, *manifest, *spine, *itemref; + char base_uri[2048]; + const char *full_path; + char ncx[2048], s[2048]; + epub_chapter *head, *tail; + + /* parse META-INF/container.xml to find OPF */ + + buf = fz_read_archive_entry(ctx, zip, "META-INF/container.xml"); + fz_write_buffer_byte(ctx, buf, 0); + container_xml = fz_parse_xml(ctx, buf->data, buf->len, 0); + fz_drop_buffer(ctx, buf); + + container = fz_xml_find(container_xml, "container"); + rootfiles = fz_xml_find_down(container, "rootfiles"); + rootfile = fz_xml_find_down(rootfiles, "rootfile"); + full_path = fz_xml_att(rootfile, "full-path"); + if (!full_path) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find root file in EPUB"); + + printf("epub: found root: %s\n", full_path); + + fz_dirname(base_uri, full_path, sizeof base_uri); + + /* parse OPF to find NCX and spine */ + + buf = fz_read_archive_entry(ctx, zip, full_path); + fz_write_buffer_byte(ctx, buf, 0); + content_opf = fz_parse_xml(ctx, buf->data, buf->len, 0); + fz_drop_buffer(ctx, buf); + + package = fz_xml_find(content_opf, "package"); + manifest = fz_xml_find_down(package, "manifest"); + spine = fz_xml_find_down(package, "spine"); + + if (path_from_idref(ncx, manifest, base_uri, fz_xml_att(spine, "toc"), sizeof ncx)) + { + /* TODO: parse NCX to create fz_outline */ + printf("epub: found outline: %s\n", ncx); + } + + head = tail = NULL; + itemref = fz_xml_find_down(spine, "itemref"); + while (itemref) + { + if (path_from_idref(s, manifest, base_uri, fz_xml_att(itemref, "idref"), sizeof s)) + { + printf("epub: found spine %s\n", s); + if (!head) + head = tail = epub_parse_chapter(doc, s); + else + tail = tail->next = epub_parse_chapter(doc, s); + } + itemref = fz_xml_find_next(itemref, "itemref"); + } + + doc->spine = head; + + printf("epub: done.\n"); + + fz_free_xml(ctx, container_xml); + fz_free_xml(ctx, content_opf); +} + +static epub_document * +epub_init(fz_context *ctx, fz_archive *zip) +{ + epub_document *doc; + + doc = fz_malloc_struct(ctx, epub_document); + doc->ctx = ctx; + doc->zip = zip; + doc->set = fz_new_html_font_set(ctx); + + doc->super.close = (void*)epub_close_document; + doc->super.layout = (void*)epub_layout; + doc->super.count_pages = (void*)epub_count_pages; + doc->super.load_page = (void*)epub_load_page; + doc->super.bound_page = (void*)epub_bound_page; + doc->super.run_page_contents = (void*)epub_run_page; + doc->super.free_page = (void*)epub_free_page; + + fz_try(ctx) + { + epub_parse_header(doc); + epub_layout(doc, DEFW, DEFH, DEFEM); + } + fz_catch(ctx) + { + epub_close_document(doc); + fz_rethrow(ctx); + } + + return doc; +} + +static epub_document * +epub_open_document_with_stream(fz_context *ctx, fz_stream *file) +{ + return epub_init(ctx, fz_open_archive_with_stream(ctx, file)); +} + +static epub_document * +epub_open_document(fz_context *ctx, const char *filename) +{ + if (strstr(filename, "META-INF/container.xml") || strstr(filename, "META-INF\\container.xml")) + { + char dirname[2048], *p; + fz_strlcpy(dirname, filename, sizeof dirname); + p = strstr(dirname, "META-INF"); + *p = 0; + if (!dirname[0]) + fz_strlcpy(dirname, ".", sizeof dirname); + return epub_init(ctx, fz_open_directory(ctx, dirname)); + } + + return epub_init(ctx, fz_open_archive(ctx, filename)); +} + +static int +epub_recognize(fz_context *doc, const char *magic) +{ + char *ext = strrchr(magic, '.'); + if (ext) + if (!fz_strcasecmp(ext, ".epub")) + return 100; + if (strstr(magic, "META-INF/container.xml") || strstr(magic, "META-INF\\container.xml")) + return 200; + if (!strcmp(magic, "application/epub+zip")) + return 100; + return 0; +} + +fz_document_handler epub_document_handler = +{ + (fz_document_recognize_fn *)&epub_recognize, + (fz_document_open_fn *)&epub_open_document, + (fz_document_open_with_stream_fn *)&epub_open_document_with_stream +}; diff --git a/source/html/layout.c b/source/html/layout.c index 3243a6ae..31c41a71 100644 --- a/source/html/layout.c +++ b/source/html/layout.c @@ -31,6 +31,7 @@ static const char *default_css = "u,ins{text-decoration:underline}" "center{text-align:center}" "svg{display:none}" +"a{color:blue}" ; static int iswhite(int c) -- cgit v1.2.3 From a3b0ce19561c42cc165a0c459286100af50ba615 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 26 Nov 2014 02:23:54 +0100 Subject: html: Some cleaning. --- source/html/css-parse.c | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'source/html') diff --git a/source/html/css-parse.c b/source/html/css-parse.c index d454dbf1..d4aa39ec 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -746,24 +746,3 @@ struct rule *fz_parse_css(fz_context *ctx, struct rule *chain, const char *sourc next(&buf); return parse_stylesheet(&buf, chain); } - -struct rule *fz_parse_css_file(fz_context *ctx, struct rule *chain, const char *filename) -{ - fz_buffer *buf = fz_read_file(ctx, filename); - - fz_try(ctx) - { - fz_write_buffer_byte(ctx, buf, 0); - chain = fz_parse_css(ctx, chain, (char*)buf->data); - } - fz_always(ctx) - { - fz_drop_buffer(ctx, buf); - } - fz_catch(ctx) - { - fz_rethrow(ctx); - } - - return chain; -} -- cgit v1.2.3 From a27f2e924f7c8d55fa62b89833c61621a9ca1b87 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 26 Nov 2014 02:25:18 +0100 Subject: html: Rename files. --- source/html/font.c | 45 --- source/html/handler.c | 162 -------- source/html/html-doc.c | 162 ++++++++ source/html/html-font.c | 45 +++ source/html/html-layout.c | 929 ++++++++++++++++++++++++++++++++++++++++++++++ source/html/layout.c | 929 ---------------------------------------------- 6 files changed, 1136 insertions(+), 1136 deletions(-) delete mode 100644 source/html/font.c delete mode 100644 source/html/handler.c create mode 100644 source/html/html-doc.c create mode 100644 source/html/html-font.c create mode 100644 source/html/html-layout.c delete mode 100644 source/html/layout.c (limited to 'source/html') diff --git a/source/html/font.c b/source/html/font.c deleted file mode 100644 index ce8c2ed1..00000000 --- a/source/html/font.c +++ /dev/null @@ -1,45 +0,0 @@ -#include "mupdf/html.h" -#include "mupdf/pdf.h" /* for pdf_lookup_builtin_font */ - -static const char *font_names[16] = { - "Times-Roman", "Times-Italic", "Times-Bold", "Times-BoldItalic", - "Helvetica", "Helvetica-Oblique", "Helvetica-Bold", "Helvetica-BoldOblique", - "Courier", "Courier-Oblique", "Courier-Bold", "Courier-BoldOblique", - "Courier", "Courier-Oblique", "Courier-Bold", "Courier-BoldOblique", -}; - -fz_font * -fz_html_load_font(fz_context *ctx, fz_html_font_set *set, - const char *family, const char *variant, const char *style, const char *weight) -{ - unsigned char *data; - unsigned int size; - - int is_mono = !strcmp(family, "monospace"); - int is_sans = !strcmp(family, "sans-serif"); - int is_bold = !strcmp(weight, "bold") || !strcmp(weight, "bolder") || atoi(weight) > 400; - int is_italic = !strcmp(style, "italic") || !strcmp(style, "oblique"); - - int idx = is_mono * 8 + is_sans * 4 + is_bold * 2 + is_italic; - if (!set->fonts[idx]) - { - data = pdf_lookup_builtin_font(font_names[idx], &size); - if (!data) { - printf("data=%p idx=%d s=%s\n", data, idx, font_names[idx]); - abort(); - } - set->fonts[idx] = fz_new_font_from_memory(ctx, font_names[idx], data, size, 0, 1); - } - - return set->fonts[idx]; -} - -fz_html_font_set *fz_new_html_font_set(fz_context *ctx) -{ - return fz_malloc_struct(ctx, fz_html_font_set); -} - -void fz_free_html_font_set(fz_context *ctx, fz_html_font_set *set) -{ - fz_free(ctx, set); -} diff --git a/source/html/handler.c b/source/html/handler.c deleted file mode 100644 index 11d21d56..00000000 --- a/source/html/handler.c +++ /dev/null @@ -1,162 +0,0 @@ -#include "mupdf/html.h" - -#define DEFW (450) -#define DEFH (600) -#define DEFEM (12) - -typedef struct html_document_s html_document; - -struct html_document_s -{ - fz_document super; - fz_context *ctx; - fz_archive *zip; - fz_html_font_set *set; - float page_w, page_h, em; - struct box *box; -}; - -static void -htdoc_close_document(html_document *doc) -{ - fz_close_archive(doc->ctx, doc->zip); - fz_free_html_font_set(doc->ctx, doc->set); - fz_free(doc->ctx, doc); -} - -static int -htdoc_count_pages(html_document *doc) -{ - int count; - - // TODO: reflow - - count = ceilf(doc->box->h / doc->page_h); -printf("count pages! %g / %g = %d\n", doc->box->h, doc->page_h, count); - return count; -} - -static void * -htdoc_load_page(html_document *doc, int number) -{ -printf("load page %d\n", number); - // TODO: reflow - return (void*)((intptr_t)number + 1); -} - -static void -htdoc_free_page(html_document *doc, void *page) -{ -} - -static void -htdoc_layout(html_document *doc, float w, float h, float em) -{ - doc->page_w = w; - doc->page_h = h; - doc->em = em; - fz_layout_html(doc->ctx, doc->box, w, h, em); -} - -static fz_rect * -htdoc_bound_page(html_document *doc, void *page, fz_rect *bbox) -{ - // TODO: reflow - printf("html: bound page\n"); - bbox->x0 = bbox->y0 = 0; - bbox->x1 = doc->page_w; - bbox->y1 = doc->page_h; - return bbox; -} - -static void -htdoc_run_page(html_document *doc, void *page, fz_device *dev, const fz_matrix *ctm, fz_cookie *cookie) -{ - int n = ((intptr_t)page) - 1; - printf("html: run page %d\n", n); - fz_draw_html(doc->ctx, doc->box, n * doc->page_h, (n+1) * doc->page_h, dev, ctm); -} - -static html_document * -htdoc_open_document_with_stream(fz_context *ctx, fz_stream *file) -{ - html_document *doc; - fz_buffer *buf; - - doc = fz_malloc_struct(ctx, html_document); - doc->ctx = ctx; - doc->zip = fz_open_directory(ctx, "."); - doc->set = fz_new_html_font_set(ctx); - - doc->super.close = (void*)htdoc_close_document; - doc->super.layout = (void*)htdoc_layout; - doc->super.count_pages = (void*)htdoc_count_pages; - doc->super.load_page = (void*)htdoc_load_page; - doc->super.bound_page = (void*)htdoc_bound_page; - doc->super.run_page_contents = (void*)htdoc_run_page; - doc->super.free_page = (void*)htdoc_free_page; - - buf = fz_read_all(file, 0); - fz_write_buffer_byte(ctx, buf, 0); - doc->box = fz_generate_html(ctx, doc->set, doc->zip, ".", buf); - fz_drop_buffer(ctx, buf); - - htdoc_layout(doc, DEFW, DEFH, DEFEM); - - return doc; -} - -static html_document * -htdoc_open_document(fz_context *ctx, const char *filename) -{ - char dirname[2048]; - fz_buffer *buf; - html_document *doc; - - fz_dirname(dirname, filename, sizeof dirname); - - doc = fz_malloc_struct(ctx, html_document); - doc->ctx = ctx; - doc->zip = fz_open_directory(ctx, dirname); - doc->set = fz_new_html_font_set(ctx); - - doc->super.close = (void*)htdoc_close_document; - doc->super.layout = (void*)htdoc_layout; - doc->super.count_pages = (void*)htdoc_count_pages; - doc->super.load_page = (void*)htdoc_load_page; - doc->super.bound_page = (void*)htdoc_bound_page; - doc->super.run_page_contents = (void*)htdoc_run_page; - doc->super.free_page = (void*)htdoc_free_page; - - buf = fz_read_file(ctx, filename); - fz_write_buffer_byte(ctx, buf, 0); - doc->box = fz_generate_html(ctx, doc->set, doc->zip, ".", buf); - fz_drop_buffer(ctx, buf); - - htdoc_layout(doc, DEFW, DEFH, DEFEM); - - return doc; -} - -static int -htdoc_recognize(fz_context *doc, const char *magic) -{ - char *ext = strrchr(magic, '.'); - - if (ext) - { - if (!fz_strcasecmp(ext, ".xml") || !fz_strcasecmp(ext, ".xhtml") || !fz_strcasecmp(ext, ".html")) - return 100; - } - if (!strcmp(magic, "application/html+xml") || !strcmp(magic, "application/xml") || !strcmp(magic, "text/xml")) - return 100; - - return 0; -} - -fz_document_handler html_document_handler = -{ - (fz_document_recognize_fn *)&htdoc_recognize, - (fz_document_open_fn *)&htdoc_open_document, - (fz_document_open_with_stream_fn *)&htdoc_open_document_with_stream -}; diff --git a/source/html/html-doc.c b/source/html/html-doc.c new file mode 100644 index 00000000..11d21d56 --- /dev/null +++ b/source/html/html-doc.c @@ -0,0 +1,162 @@ +#include "mupdf/html.h" + +#define DEFW (450) +#define DEFH (600) +#define DEFEM (12) + +typedef struct html_document_s html_document; + +struct html_document_s +{ + fz_document super; + fz_context *ctx; + fz_archive *zip; + fz_html_font_set *set; + float page_w, page_h, em; + struct box *box; +}; + +static void +htdoc_close_document(html_document *doc) +{ + fz_close_archive(doc->ctx, doc->zip); + fz_free_html_font_set(doc->ctx, doc->set); + fz_free(doc->ctx, doc); +} + +static int +htdoc_count_pages(html_document *doc) +{ + int count; + + // TODO: reflow + + count = ceilf(doc->box->h / doc->page_h); +printf("count pages! %g / %g = %d\n", doc->box->h, doc->page_h, count); + return count; +} + +static void * +htdoc_load_page(html_document *doc, int number) +{ +printf("load page %d\n", number); + // TODO: reflow + return (void*)((intptr_t)number + 1); +} + +static void +htdoc_free_page(html_document *doc, void *page) +{ +} + +static void +htdoc_layout(html_document *doc, float w, float h, float em) +{ + doc->page_w = w; + doc->page_h = h; + doc->em = em; + fz_layout_html(doc->ctx, doc->box, w, h, em); +} + +static fz_rect * +htdoc_bound_page(html_document *doc, void *page, fz_rect *bbox) +{ + // TODO: reflow + printf("html: bound page\n"); + bbox->x0 = bbox->y0 = 0; + bbox->x1 = doc->page_w; + bbox->y1 = doc->page_h; + return bbox; +} + +static void +htdoc_run_page(html_document *doc, void *page, fz_device *dev, const fz_matrix *ctm, fz_cookie *cookie) +{ + int n = ((intptr_t)page) - 1; + printf("html: run page %d\n", n); + fz_draw_html(doc->ctx, doc->box, n * doc->page_h, (n+1) * doc->page_h, dev, ctm); +} + +static html_document * +htdoc_open_document_with_stream(fz_context *ctx, fz_stream *file) +{ + html_document *doc; + fz_buffer *buf; + + doc = fz_malloc_struct(ctx, html_document); + doc->ctx = ctx; + doc->zip = fz_open_directory(ctx, "."); + doc->set = fz_new_html_font_set(ctx); + + doc->super.close = (void*)htdoc_close_document; + doc->super.layout = (void*)htdoc_layout; + doc->super.count_pages = (void*)htdoc_count_pages; + doc->super.load_page = (void*)htdoc_load_page; + doc->super.bound_page = (void*)htdoc_bound_page; + doc->super.run_page_contents = (void*)htdoc_run_page; + doc->super.free_page = (void*)htdoc_free_page; + + buf = fz_read_all(file, 0); + fz_write_buffer_byte(ctx, buf, 0); + doc->box = fz_generate_html(ctx, doc->set, doc->zip, ".", buf); + fz_drop_buffer(ctx, buf); + + htdoc_layout(doc, DEFW, DEFH, DEFEM); + + return doc; +} + +static html_document * +htdoc_open_document(fz_context *ctx, const char *filename) +{ + char dirname[2048]; + fz_buffer *buf; + html_document *doc; + + fz_dirname(dirname, filename, sizeof dirname); + + doc = fz_malloc_struct(ctx, html_document); + doc->ctx = ctx; + doc->zip = fz_open_directory(ctx, dirname); + doc->set = fz_new_html_font_set(ctx); + + doc->super.close = (void*)htdoc_close_document; + doc->super.layout = (void*)htdoc_layout; + doc->super.count_pages = (void*)htdoc_count_pages; + doc->super.load_page = (void*)htdoc_load_page; + doc->super.bound_page = (void*)htdoc_bound_page; + doc->super.run_page_contents = (void*)htdoc_run_page; + doc->super.free_page = (void*)htdoc_free_page; + + buf = fz_read_file(ctx, filename); + fz_write_buffer_byte(ctx, buf, 0); + doc->box = fz_generate_html(ctx, doc->set, doc->zip, ".", buf); + fz_drop_buffer(ctx, buf); + + htdoc_layout(doc, DEFW, DEFH, DEFEM); + + return doc; +} + +static int +htdoc_recognize(fz_context *doc, const char *magic) +{ + char *ext = strrchr(magic, '.'); + + if (ext) + { + if (!fz_strcasecmp(ext, ".xml") || !fz_strcasecmp(ext, ".xhtml") || !fz_strcasecmp(ext, ".html")) + return 100; + } + if (!strcmp(magic, "application/html+xml") || !strcmp(magic, "application/xml") || !strcmp(magic, "text/xml")) + return 100; + + return 0; +} + +fz_document_handler html_document_handler = +{ + (fz_document_recognize_fn *)&htdoc_recognize, + (fz_document_open_fn *)&htdoc_open_document, + (fz_document_open_with_stream_fn *)&htdoc_open_document_with_stream +}; diff --git a/source/html/html-font.c b/source/html/html-font.c new file mode 100644 index 00000000..ce8c2ed1 --- /dev/null +++ b/source/html/html-font.c @@ -0,0 +1,45 @@ +#include "mupdf/html.h" +#include "mupdf/pdf.h" /* for pdf_lookup_builtin_font */ + +static const char *font_names[16] = { + "Times-Roman", "Times-Italic", "Times-Bold", "Times-BoldItalic", + "Helvetica", "Helvetica-Oblique", "Helvetica-Bold", "Helvetica-BoldOblique", + "Courier", "Courier-Oblique", "Courier-Bold", "Courier-BoldOblique", + "Courier", "Courier-Oblique", "Courier-Bold", "Courier-BoldOblique", +}; + +fz_font * +fz_html_load_font(fz_context *ctx, fz_html_font_set *set, + const char *family, const char *variant, const char *style, const char *weight) +{ + unsigned char *data; + unsigned int size; + + int is_mono = !strcmp(family, "monospace"); + int is_sans = !strcmp(family, "sans-serif"); + int is_bold = !strcmp(weight, "bold") || !strcmp(weight, "bolder") || atoi(weight) > 400; + int is_italic = !strcmp(style, "italic") || !strcmp(style, "oblique"); + + int idx = is_mono * 8 + is_sans * 4 + is_bold * 2 + is_italic; + if (!set->fonts[idx]) + { + data = pdf_lookup_builtin_font(font_names[idx], &size); + if (!data) { + printf("data=%p idx=%d s=%s\n", data, idx, font_names[idx]); + abort(); + } + set->fonts[idx] = fz_new_font_from_memory(ctx, font_names[idx], data, size, 0, 1); + } + + return set->fonts[idx]; +} + +fz_html_font_set *fz_new_html_font_set(fz_context *ctx) +{ + return fz_malloc_struct(ctx, fz_html_font_set); +} + +void fz_free_html_font_set(fz_context *ctx, fz_html_font_set *set) +{ + fz_free(ctx, set); +} diff --git a/source/html/html-layout.c b/source/html/html-layout.c new file mode 100644 index 00000000..31c41a71 --- /dev/null +++ b/source/html/html-layout.c @@ -0,0 +1,929 @@ +#include "mupdf/html.h" + +enum { T, R, B, L }; + +static const char *default_css = +"html,address,blockquote,body,dd,div,dl,dt,h1,h2,h3,h4,h5,h6,ol,p,ul,center,hr,pre{display:block}" +"span{display:inline}" +"li{display:list-item}" +"head{display:none}" +"body{margin:1em}" +"h1{font-size:2em;margin:.67em 0}" +"h2{font-size:1.5em;margin:.75em 0}" +"h3{font-size:1.17em;margin:.83em 0}" +"h4,p,blockquote,ul,ol,dl,dir,menu{margin:1.12em 0}" +"h5{font-size:.83em;margin:1.5em 0}" +"h6{font-size:.75em;margin:1.67em 0}" +"h1,h2,h3,h4,h5,h6,b,strong{font-weight:bold}" +"blockquote{margin-left:40px;margin-right:40px}" +"i,cite,em,var,address{font-style:italic}" +"pre,tt,code,kbd,samp{font-family:monospace}" +"pre{white-space:pre}" +"big{font-size:1.17em}" +"small,sub,sup{font-size:.83em}" +"sub{vertical-align:sub}" +"sup{vertical-align:super}" +"s,strike,del{text-decoration:line-through}" +"hr{border-width:thin;border-color:black;border-style:solid;margin:.5em 0}" +"ol,ul,dir,menu,dd{margin-left:40px}" +"ol{list-style-type:decimal}" +"ol ul,ul ol,ul ul,ol ol{margin-top:0;margin-bottom:0}" +"u,ins{text-decoration:underline}" +"center{text-align:center}" +"svg{display:none}" +"a{color:blue}" +; + +static int iswhite(int c) +{ + return c == ' ' || c == '\t' || c == '\r' || c == '\n'; +} + +static struct flow *add_flow(fz_context *ctx, struct box *top, struct computed_style *style, int type) +{ + struct flow *flow = fz_malloc_struct(ctx, struct flow); + flow->type = type; + flow->style = style; + *top->flow_tail = flow; + top->flow_tail = &flow->next; + return flow; +} + +static void add_flow_space(fz_context *ctx, struct box *top, struct computed_style *style) +{ + struct flow *flow; + + /* delete space at the beginning of the line */ + if (!top->flow_head) + return; + + flow = add_flow(ctx, top, style, FLOW_GLUE); + flow->text = " "; + flow->broken_text = ""; +} + +static void add_flow_word(fz_context *ctx, struct box *top, struct computed_style *style, const char *a, const char *b) +{ + struct flow *flow = add_flow(ctx, top, style, FLOW_WORD); + flow->text = fz_malloc(ctx, b - a + 1); + memcpy(flow->text, a, b - a); + flow->text[b - a] = 0; +} + +static void add_flow_image(fz_context *ctx, struct box *top, struct computed_style *style, fz_image *img) +{ + struct flow *flow = add_flow(ctx, top, style, FLOW_IMAGE); + flow->image = fz_keep_image(ctx, img); +} + +static void generate_text(fz_context *ctx, struct box *box, const char *text) +{ + struct box *flow = box; + while (flow->type != BOX_FLOW) + flow = flow->up; + + while (*text) + { + if (iswhite(*text)) + { + ++text; + while (iswhite(*text)) + ++text; + add_flow_space(ctx, flow, &box->style); + } + if (*text) + { + const char *mark = text++; + while (*text && !iswhite(*text)) + ++text; + add_flow_word(ctx, flow, &box->style, mark, text); + } + } +} + +static void generate_image(fz_context *ctx, fz_archive *zip, const char *base_uri, struct box *box, const char *src) +{ + fz_image *img; + fz_buffer *buf; + char path[2048]; + + struct box *flow = box; + while (flow->type != BOX_FLOW) + flow = flow->up; + + fz_strlcpy(path, base_uri, sizeof path); + fz_strlcat(path, "/", sizeof path); + fz_strlcat(path, src, sizeof path); + fz_cleanname(path); + + buf = fz_read_archive_entry(ctx, zip, path); + img = fz_new_image_from_buffer(ctx, buf); + fz_drop_buffer(ctx, buf); + + add_flow_image(ctx, flow, &box->style, img); +} + +static void init_box(fz_context *ctx, struct box *box, fz_xml *node) +{ + box->type = BOX_BLOCK; + box->x = box->y = 0; + box->w = box->h = 0; + + box->up = NULL; + box->last = NULL; + box->down = NULL; + box->next = NULL; + + box->node = node; + + box->flow_head = NULL; + box->flow_tail = &box->flow_head; + + default_computed_style(&box->style); +} + +static struct box *new_box(fz_context *ctx, fz_xml *node) +{ + struct box *box = fz_malloc_struct(ctx, struct box); + init_box(ctx, box, node); + return box; +} + +static void insert_box(fz_context *ctx, struct box *box, int type, struct box *top) +{ + box->type = type; + + box->up = top; + + if (top) + { + if (!top->last) + { + top->down = top->last = box; + } + else + { + top->last->next = box; + top->last = box; + } + } +} + +static struct box *insert_block_box(fz_context *ctx, struct box *box, struct box *top) +{ + if (top->type == BOX_BLOCK) + { + insert_box(ctx, box, BOX_BLOCK, top); + } + else if (top->type == BOX_FLOW) + { + while (top->type != BOX_BLOCK) + top = top->up; + insert_box(ctx, box, BOX_BLOCK, top); + } + else if (top->type == BOX_INLINE) + { + while (top->type != BOX_BLOCK) + top = top->up; + insert_box(ctx, box, BOX_BLOCK, top); + } + return top; +} + +static struct box *insert_break_box(fz_context *ctx, struct box *box, struct box *top) +{ + if (top->type == BOX_BLOCK) + { + insert_box(ctx, box, BOX_BREAK, top); + } + else if (top->type == BOX_FLOW) + { + while (top->type != BOX_BLOCK) + top = top->up; + insert_box(ctx, box, BOX_BREAK, top); + } + else if (top->type == BOX_INLINE) + { + while (top->type != BOX_BLOCK) + top = top->up; + insert_box(ctx, box, BOX_BREAK, top); + } + return top; +} + +static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) +{ + if (top->type == BOX_BLOCK) + { + if (top->last && top->last->type == BOX_FLOW) + { + insert_box(ctx, box, BOX_INLINE, top->last); + } + else + { + struct box *flow = new_box(ctx, NULL); + flow->is_first_flow = !top->last; + insert_box(ctx, flow, BOX_FLOW, top); + insert_box(ctx, box, BOX_INLINE, flow); + } + } + else if (top->type == BOX_FLOW) + { + insert_box(ctx, box, BOX_INLINE, top); + } + else if (top->type == BOX_INLINE) + { + insert_box(ctx, box, BOX_INLINE, top); + } +} + +static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const char *base_uri, + fz_xml *node, struct box *top, struct rule *rule, struct style *up_style) +{ + struct style style; + struct box *box; + const char *tag; + int display; + + while (node) + { + style.up = up_style; + style.count = 0; + + tag = fz_xml_tag(node); + if (tag) + { + apply_styles(ctx, &style, rule, node); + + display = get_style_property_display(&style); + + if (!strcmp(tag, "br")) + { + box = new_box(ctx, node); + compute_style(ctx, set, &box->style, &style); + top = insert_break_box(ctx, box, top); + } + + else if (!strcmp(tag, "img")) + { + const char *src = fz_xml_att(node, "src"); + if (src) + { + box = new_box(ctx, node); + compute_style(ctx, set, &box->style, &style); + insert_inline_box(ctx, box, top); + generate_image(ctx, zip, base_uri, box, src); + } + } + + else if (display != DIS_NONE) + { + box = new_box(ctx, node); + compute_style(ctx, set, &box->style, &style); + + if (display == DIS_BLOCK) + { + top = insert_block_box(ctx, box, top); + } + else if (display == DIS_LIST_ITEM) + { + top = insert_block_box(ctx, box, top); + } + else if (display == DIS_INLINE) + { + insert_inline_box(ctx, box, top); + } + else + { + fz_warn(ctx, "unknown box display type"); + insert_box(ctx, box, BOX_BLOCK, top); + } + + if (fz_xml_down(node)) + generate_boxes(ctx, set, zip, base_uri, fz_xml_down(node), box, rule, &style); + + // TODO: remove empty flow boxes + } + } + else + { + if (top->type != BOX_INLINE) + { + box = new_box(ctx, node); + insert_inline_box(ctx, box, top); + box->style = top->style; + generate_text(ctx, box, fz_xml_text(node)); + } + else + { + generate_text(ctx, top, fz_xml_text(node)); + } + } + + node = fz_xml_next(node); + } +} + +static void measure_image(fz_context *ctx, struct flow *node, float w, float h) +{ + float xs = 1, ys = 1, s = 1; + node->x = 0; + node->y = 0; + if (node->image->w > w) + xs = w / node->image->w; + if (node->image->h > h) + ys = h / node->image->h; + s = fz_min(xs, ys); + node->w = node->image->w * s; + node->h = node->image->h * s; +} + +static void measure_word(fz_context *ctx, struct flow *node, float em) +{ + const char *s; + int c, g; + float w; + + em = from_number(node->style->font_size, em, em); + node->x = 0; + node->y = 0; + node->h = from_number_scale(node->style->line_height, em, em, em); + + w = 0; + s = node->text; + while (*s) + { + s += fz_chartorune(&c, s); + g = fz_encode_character(ctx, node->style->font, c); + w += fz_advance_glyph(ctx, node->style->font, g) * em; + } + node->w = w; + node->em = em; +} + +static float measure_line(struct flow *node, struct flow *end, float *baseline) +{ + float max_a = 0, max_d = 0, h = 0; + while (node != end) + { + if (node->type == FLOW_IMAGE) + { + if (node->h > max_a) + max_a = node->h; + } + else + { + float a = node->em * 0.8; + float d = node->em * 0.2; + if (a > max_a) max_a = a; + if (d > max_d) max_d = d; + } + if (node->h > h) h = node->h; + if (max_a + max_d > h) h = max_a + max_d; + node = node->next; + } + *baseline = max_a + (h - max_a - max_d) / 2; + return h; +} + +static void layout_line(fz_context *ctx, float indent, float page_w, float line_w, int align, struct flow *node, struct flow *end, struct box *box, float baseline) +{ + float x = box->x + indent; + float y = box->y + box->h; + float slop = page_w - line_w; + float justify = 0; + float va; + int n = 0; + + if (align == TA_JUSTIFY) + { + struct flow *it; + for (it = node; it != end; it = it->next) + if (it->type == FLOW_GLUE) + ++n; + justify = slop / n; + } + else if (align == TA_RIGHT) + x += slop; + else if (align == TA_CENTER) + x += slop / 2; + + while (node != end) + { + switch (node->style->vertical_align) + { + default: + case VA_BASELINE: + va = 0; + break; + case VA_SUB: + va = node->em * 0.2f; + break; + case VA_SUPER: + va = node->em * -0.3f; + break; + } + node->x = x; + if (node->type == FLOW_IMAGE) + node->y = y + baseline - node->h; + else + node->y = y + baseline + va; + x += node->w; + if (node->type == FLOW_GLUE) + x += justify; + node = node->next; + } +} + +static struct flow *find_next_glue(struct flow *node, float *w) +{ + while (node && node->type == FLOW_GLUE) + { + *w += node->w; + node = node->next; + } + while (node && node->type != FLOW_GLUE) + { + *w += node->w; + node = node->next; + } + return node; +} + +static struct flow *find_next_word(struct flow *node, float *w) +{ + while (node && node->type == FLOW_GLUE) + { + *w += node->w; + node = node->next; + } + return node; +} + +static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float em, float page_h) +{ + struct flow *node, *line_start, *word_start, *word_end, *line_end; + float glue_w; + float word_w; + float line_w; + float indent; + float avail, line_h; + float baseline; + int align; + + em = from_number(box->style.font_size, em, em); + indent = box->is_first_flow ? from_number(top->style.text_indent, em, top->w) : 0; + align = top->style.text_align; + + box->x = top->x; + box->y = top->y + top->h; + box->w = top->w; + box->h = 0; + + if (!box->flow_head) + return; + + for (node = box->flow_head; node; node = node->next) + if (node->type == FLOW_IMAGE) + measure_image(ctx, node, top->w, page_h); + else + measure_word(ctx, node, em); + + line_start = find_next_word(box->flow_head, &glue_w); + line_end = NULL; + + line_w = indent; + word_w = 0; + word_start = line_start; + while (word_start) + { + word_end = find_next_glue(word_start, &word_w); + if (line_w + word_w <= top->w) + { + line_w += word_w; + glue_w = 0; + line_end = word_end; + word_start = find_next_word(word_end, &glue_w); + word_w = glue_w; + } + else + { + avail = page_h - fmodf(box->y + box->h, page_h); + line_h = measure_line(line_start, line_end, &baseline); + if (line_h > avail) + box->h += avail; + layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box, baseline); + box->h += line_h; + word_start = find_next_word(line_end, &glue_w); + line_start = word_start; + line_end = NULL; + indent = 0; + line_w = 0; + word_w = 0; + } + } + + /* don't justify the last line of a paragraph */ + if (align == TA_JUSTIFY) + align = TA_LEFT; + + if (line_start) + { + avail = page_h - fmodf(box->y + box->h, page_h); + line_h = measure_line(line_start, line_end, &baseline); + if (line_h > avail) + box->h += avail; + layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box, baseline); + box->h += line_h; + } +} + +static void layout_block(fz_context *ctx, struct box *box, struct box *top, float em, float top_collapse_margin, float page_h) +{ + struct box *child; + float box_collapse_margin; + int prev_br; + + float *margin = box->margin; + float *border = box->border; + float *padding = box->padding; + + em = from_number(box->style.font_size, em, em); + + margin[0] = from_number(box->style.margin[0], em, top->w); + margin[1] = from_number(box->style.margin[1], em, top->w); + margin[2] = from_number(box->style.margin[2], em, top->w); + margin[3] = from_number(box->style.margin[3], em, top->w); + + padding[0] = from_number(box->style.padding[0], em, top->w); + padding[1] = from_number(box->style.padding[1], em, top->w); + padding[2] = from_number(box->style.padding[2], em, top->w); + padding[3] = from_number(box->style.padding[3], em, top->w); + + if (box->style.border_style) + { + border[0] = from_number(box->style.border_width[0], em, top->w); + border[1] = from_number(box->style.border_width[1], em, top->w); + border[2] = from_number(box->style.border_width[2], em, top->w); + border[3] = from_number(box->style.border_width[3], em, top->w); + } + else + border[0] = border[1] = border[2] = border[3] = 0; + + if (padding[T] == 0 && border[T] == 0) + box_collapse_margin = margin[T]; + else + box_collapse_margin = 0; + + if (margin[T] > top_collapse_margin) + margin[T] -= top_collapse_margin; + else + margin[T] = 0; + + box->x = top->x + margin[L] + border[L] + padding[L]; + box->y = top->y + top->h + margin[T] + border[T] + padding[T]; + box->w = top->w - (margin[L] + margin[R] + border[L] + border[R] + padding[L] + padding[R]); + box->h = 0; + + prev_br = 0; + for (child = box->down; child; child = child->next) + { + if (child->type == BOX_BLOCK) + { + layout_block(ctx, child, box, em, box_collapse_margin, page_h); + box->h += child->h + + child->padding[T] + child->padding[B] + + child->border[T] + child->border[B] + + child->margin[T] + child->margin[B]; + box_collapse_margin = child->margin[B]; + prev_br = 0; + } + else if (child->type == BOX_BREAK) + { + /* TODO: interaction with page breaks */ + if (prev_br) + box->h += from_number_scale(box->style.line_height, em, em, em); + prev_br = 1; + } + else if (child->type == BOX_FLOW) + { + layout_flow(ctx, child, box, em, page_h); + if (child->h > 0) + { + box->h += child->h; + box_collapse_margin = 0; + prev_br = 0; + } + } + } + + if (padding[B] == 0 && border[B] == 0) + { + if (margin[B] > 0) + { + box->h -= box_collapse_margin; + if (margin[B] < box_collapse_margin) + margin[B] = box_collapse_margin; + } + } +} + +static void indent(int level) +{ + while (level--) printf(" "); +} + +static void print_flow(fz_context *ctx, struct flow *flow, int level) +{ + while (flow) + { + printf("%-5d %-5d", (int)flow->x, (int)flow->y); + indent(level); + switch (flow->type) + { + case FLOW_WORD: printf("word \"%s\"\n", flow->text); break; + case FLOW_GLUE: printf("glue \"%s\" / \"%s\"\n", flow->text, flow->broken_text); break; + case FLOW_IMAGE: printf("image\n"); break; + } + flow = flow->next; + } +} + +static void print_box(fz_context *ctx, struct box *box, int level) +{ + while (box) + { + printf("%-5d %-5d", (int)box->x, (int)box->y); + indent(level); + switch (box->type) + { + case BOX_BLOCK: printf("block"); break; + case BOX_BREAK: printf("break"); break; + case BOX_FLOW: printf("flow"); break; + case BOX_INLINE: printf("inline"); break; + } + if (box->node) + { + const char *tag = fz_xml_tag(box->node); + if (tag) printf(" <%s>", tag); + else printf(" anonymous"); + } + printf("\n"); + if (box->down) + print_box(ctx, box->down, level + 1); +// if (box->flow_head) +// print_flow(ctx, box->flow_head, level + 1); + box = box->next; + } +} + +static void +draw_flow_box(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm) +{ + struct flow *node; + fz_text *text; + fz_matrix trm; + const char *s; + float color[3]; + float x, y; + int c, g; + + for (node = box->flow_head; node; node = node->next) + { + if (node->type == FLOW_IMAGE) + { + if (node->y > page_bot || node->y + node->h < page_top) + continue; + } + else + { + if (node->y > page_bot || node->y < page_top) + continue; + } + + if (node->type == FLOW_WORD) + { + fz_scale(&trm, node->em, -node->em); + text = fz_new_text(ctx, node->style->font, &trm, 0); + + x = node->x; + y = node->y; + s = node->text; + while (*s) + { + s += fz_chartorune(&c, s); + g = fz_encode_character(ctx, node->style->font, c); + fz_add_text(ctx, text, g, c, x, y); + x += fz_advance_glyph(ctx, node->style->font, g) * node->em; + } + + color[0] = node->style->color.r / 255.0f; + color[1] = node->style->color.g / 255.0f; + color[2] = node->style->color.b / 255.0f; + + fz_fill_text(dev, text, ctm, fz_device_rgb(ctx), color, 1); + + fz_free_text(ctx, text); + } + else if (node->type == FLOW_IMAGE) + { + fz_matrix local_ctm = *ctm; + fz_pre_translate(&local_ctm, node->x, node->y); + fz_pre_scale(&local_ctm, node->w, node->h); + fz_fill_image(dev, node->image, &local_ctm, 1); + } + } +} + +static void +draw_rect(fz_context *ctx, fz_device *dev, const fz_matrix *ctm, float *rgba, float x0, float y0, float x1, float y1) +{ + fz_path *path = fz_new_path(ctx); + + fz_moveto(ctx, path, x0, y0); + fz_lineto(ctx, path, x1, y0); + fz_lineto(ctx, path, x1, y1); + fz_lineto(ctx, path, x0, y1); + fz_closepath(ctx, path); + + fz_fill_path(dev, path, 0, ctm, fz_device_rgb(ctx), rgba, rgba[3]); + + fz_free_path(ctx, path); +} + +static void +draw_block_box(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm) +{ + float x0, y0, x1, y1; + float color[4]; + + // TODO: background fill + // TODO: border stroke + + float *border = box->border; + float *padding = box->padding; + + x0 = box->x - padding[L]; + y0 = box->y - padding[T]; + x1 = box->x + box->w + padding[R]; + y1 = box->y + box->h + padding[B]; + + if (y0 > page_bot || y1 < page_top) + return; + + if (box->style.background_color.a > 0) + { + color[0] = box->style.background_color.r / 255.0f; + color[1] = box->style.background_color.g / 255.0f; + color[2] = box->style.background_color.b / 255.0f; + color[3] = box->style.background_color.a / 255.0f; + draw_rect(ctx, dev, ctm, color, x0, y0, x1, y1); + } + + if (box->style.border_color.a > 0) + { + color[0] = box->style.border_color.r / 255.0f; + color[1] = box->style.border_color.g / 255.0f; + color[2] = box->style.border_color.b / 255.0f; + color[3] = box->style.border_color.a / 255.0f; + if (border[T] > 0) + draw_rect(ctx, dev, ctm, color, x0 - border[L], y0 - border[T], x1 + border[R], y0); + if (border[B] > 0) + draw_rect(ctx, dev, ctm, color, x0 - border[L], y1, x1 + border[R], y1 + border[B]); + if (border[L] > 0) + draw_rect(ctx, dev, ctm, color, x0 - border[L], y0 - border[T], x0, y1 + border[B]); + if (border[R] > 0) + draw_rect(ctx, dev, ctm, color, x1, y0 - border[T], x1 + border[R], y1 + border[B]); + } + + for (box = box->down; box; box = box->next) + { + switch (box->type) + { + case BOX_BLOCK: draw_block_box(ctx, box, page_top, page_bot, dev, ctm); break; + case BOX_FLOW: draw_flow_box(ctx, box, page_top, page_bot, dev, ctm); break; + } + } +} + +void +fz_draw_html(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *inctm) +{ + fz_matrix ctm = *inctm; + fz_pre_translate(&ctm, 0, -page_top); + draw_block_box(ctx, box, page_top, page_bot, dev, &ctm); +} + +static char *concat_text(fz_context *ctx, fz_xml *root) +{ + fz_xml *node; + int i = 0, n = 1; + char *s; + for (node = fz_xml_down(root); node; node = fz_xml_next(node)) + { + const char *text = fz_xml_text(node); + n += text ? strlen(text) : 0; + } + s = fz_malloc(ctx, n); + for (node = fz_xml_down(root); node; node = fz_xml_next(node)) + { + const char *text = fz_xml_text(node); + if (text) + { + n = strlen(text); + memcpy(s+i, text, n); + i += n; + } + } + s[i] = 0; + return s; +} + +static struct rule *html_load_css(fz_context *ctx, fz_archive *zip, const char *base_uri, struct rule *css, fz_xml *root) +{ + fz_xml *node; + fz_buffer *buf; + char path[2048]; + + for (node = root; node; node = fz_xml_next(node)) + { + const char *tag = fz_xml_tag(node); + if (tag && !strcmp(tag, "link")) + { + char *rel = fz_xml_att(node, "rel"); + if (rel && !strcasecmp(rel, "stylesheet")) + { + char *type = fz_xml_att(node, "type"); + if ((type && !strcmp(type, "text/css")) || !type) + { + char *href = fz_xml_att(node, "href"); + if (href) + { + fz_strlcpy(path, base_uri, sizeof path); + fz_strlcat(path, "/", sizeof path); + fz_strlcat(path, href, sizeof path); + fz_cleanname(path); + + buf = fz_read_archive_entry(ctx, zip, path); + fz_write_buffer_byte(ctx, buf, 0); + css = fz_parse_css(ctx, css, (char*)buf->data); + fz_drop_buffer(ctx, buf); + } + } + } + } + if (tag && !strcmp(tag, "style")) + { + char *s = concat_text(ctx, node); + css = fz_parse_css(ctx, css, s); + fz_free(ctx, s); + } + if (fz_xml_down(node)) + css = html_load_css(ctx, zip, base_uri, css, fz_xml_down(node)); + } + return css; +} + +void +fz_layout_html(fz_context *ctx, struct box *box, float w, float h, float em) +{ + struct box page_box; + + printf("html: laying out text.\n"); + + init_box(ctx, &page_box, NULL); + page_box.w = w; + page_box.h = 0; + + layout_block(ctx, box, &page_box, em, 0, h); + + printf("html: finished.\n"); +} + +struct box * +fz_generate_html(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const char *base_uri, fz_buffer *buf) +{ + fz_xml *xml; + struct rule *css; + struct box *box; + struct style style; + + printf("html: parsing XHTML.\n"); + xml = fz_parse_xml(ctx, buf->data, buf->len, 1); + + printf("html: parsing style sheets.\n"); + css = fz_parse_css(ctx, NULL, default_css); + css = html_load_css(ctx, zip, base_uri, css, xml); + + // print_rules(css); + + printf("html: applying styles and generating boxes.\n"); + box = new_box(ctx, NULL); + + style.up = NULL; + style.count = 0; + + generate_boxes(ctx, set, zip, base_uri, xml, box, css, &style); + + return box; +} diff --git a/source/html/layout.c b/source/html/layout.c deleted file mode 100644 index 31c41a71..00000000 --- a/source/html/layout.c +++ /dev/null @@ -1,929 +0,0 @@ -#include "mupdf/html.h" - -enum { T, R, B, L }; - -static const char *default_css = -"html,address,blockquote,body,dd,div,dl,dt,h1,h2,h3,h4,h5,h6,ol,p,ul,center,hr,pre{display:block}" -"span{display:inline}" -"li{display:list-item}" -"head{display:none}" -"body{margin:1em}" -"h1{font-size:2em;margin:.67em 0}" -"h2{font-size:1.5em;margin:.75em 0}" -"h3{font-size:1.17em;margin:.83em 0}" -"h4,p,blockquote,ul,ol,dl,dir,menu{margin:1.12em 0}" -"h5{font-size:.83em;margin:1.5em 0}" -"h6{font-size:.75em;margin:1.67em 0}" -"h1,h2,h3,h4,h5,h6,b,strong{font-weight:bold}" -"blockquote{margin-left:40px;margin-right:40px}" -"i,cite,em,var,address{font-style:italic}" -"pre,tt,code,kbd,samp{font-family:monospace}" -"pre{white-space:pre}" -"big{font-size:1.17em}" -"small,sub,sup{font-size:.83em}" -"sub{vertical-align:sub}" -"sup{vertical-align:super}" -"s,strike,del{text-decoration:line-through}" -"hr{border-width:thin;border-color:black;border-style:solid;margin:.5em 0}" -"ol,ul,dir,menu,dd{margin-left:40px}" -"ol{list-style-type:decimal}" -"ol ul,ul ol,ul ul,ol ol{margin-top:0;margin-bottom:0}" -"u,ins{text-decoration:underline}" -"center{text-align:center}" -"svg{display:none}" -"a{color:blue}" -; - -static int iswhite(int c) -{ - return c == ' ' || c == '\t' || c == '\r' || c == '\n'; -} - -static struct flow *add_flow(fz_context *ctx, struct box *top, struct computed_style *style, int type) -{ - struct flow *flow = fz_malloc_struct(ctx, struct flow); - flow->type = type; - flow->style = style; - *top->flow_tail = flow; - top->flow_tail = &flow->next; - return flow; -} - -static void add_flow_space(fz_context *ctx, struct box *top, struct computed_style *style) -{ - struct flow *flow; - - /* delete space at the beginning of the line */ - if (!top->flow_head) - return; - - flow = add_flow(ctx, top, style, FLOW_GLUE); - flow->text = " "; - flow->broken_text = ""; -} - -static void add_flow_word(fz_context *ctx, struct box *top, struct computed_style *style, const char *a, const char *b) -{ - struct flow *flow = add_flow(ctx, top, style, FLOW_WORD); - flow->text = fz_malloc(ctx, b - a + 1); - memcpy(flow->text, a, b - a); - flow->text[b - a] = 0; -} - -static void add_flow_image(fz_context *ctx, struct box *top, struct computed_style *style, fz_image *img) -{ - struct flow *flow = add_flow(ctx, top, style, FLOW_IMAGE); - flow->image = fz_keep_image(ctx, img); -} - -static void generate_text(fz_context *ctx, struct box *box, const char *text) -{ - struct box *flow = box; - while (flow->type != BOX_FLOW) - flow = flow->up; - - while (*text) - { - if (iswhite(*text)) - { - ++text; - while (iswhite(*text)) - ++text; - add_flow_space(ctx, flow, &box->style); - } - if (*text) - { - const char *mark = text++; - while (*text && !iswhite(*text)) - ++text; - add_flow_word(ctx, flow, &box->style, mark, text); - } - } -} - -static void generate_image(fz_context *ctx, fz_archive *zip, const char *base_uri, struct box *box, const char *src) -{ - fz_image *img; - fz_buffer *buf; - char path[2048]; - - struct box *flow = box; - while (flow->type != BOX_FLOW) - flow = flow->up; - - fz_strlcpy(path, base_uri, sizeof path); - fz_strlcat(path, "/", sizeof path); - fz_strlcat(path, src, sizeof path); - fz_cleanname(path); - - buf = fz_read_archive_entry(ctx, zip, path); - img = fz_new_image_from_buffer(ctx, buf); - fz_drop_buffer(ctx, buf); - - add_flow_image(ctx, flow, &box->style, img); -} - -static void init_box(fz_context *ctx, struct box *box, fz_xml *node) -{ - box->type = BOX_BLOCK; - box->x = box->y = 0; - box->w = box->h = 0; - - box->up = NULL; - box->last = NULL; - box->down = NULL; - box->next = NULL; - - box->node = node; - - box->flow_head = NULL; - box->flow_tail = &box->flow_head; - - default_computed_style(&box->style); -} - -static struct box *new_box(fz_context *ctx, fz_xml *node) -{ - struct box *box = fz_malloc_struct(ctx, struct box); - init_box(ctx, box, node); - return box; -} - -static void insert_box(fz_context *ctx, struct box *box, int type, struct box *top) -{ - box->type = type; - - box->up = top; - - if (top) - { - if (!top->last) - { - top->down = top->last = box; - } - else - { - top->last->next = box; - top->last = box; - } - } -} - -static struct box *insert_block_box(fz_context *ctx, struct box *box, struct box *top) -{ - if (top->type == BOX_BLOCK) - { - insert_box(ctx, box, BOX_BLOCK, top); - } - else if (top->type == BOX_FLOW) - { - while (top->type != BOX_BLOCK) - top = top->up; - insert_box(ctx, box, BOX_BLOCK, top); - } - else if (top->type == BOX_INLINE) - { - while (top->type != BOX_BLOCK) - top = top->up; - insert_box(ctx, box, BOX_BLOCK, top); - } - return top; -} - -static struct box *insert_break_box(fz_context *ctx, struct box *box, struct box *top) -{ - if (top->type == BOX_BLOCK) - { - insert_box(ctx, box, BOX_BREAK, top); - } - else if (top->type == BOX_FLOW) - { - while (top->type != BOX_BLOCK) - top = top->up; - insert_box(ctx, box, BOX_BREAK, top); - } - else if (top->type == BOX_INLINE) - { - while (top->type != BOX_BLOCK) - top = top->up; - insert_box(ctx, box, BOX_BREAK, top); - } - return top; -} - -static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) -{ - if (top->type == BOX_BLOCK) - { - if (top->last && top->last->type == BOX_FLOW) - { - insert_box(ctx, box, BOX_INLINE, top->last); - } - else - { - struct box *flow = new_box(ctx, NULL); - flow->is_first_flow = !top->last; - insert_box(ctx, flow, BOX_FLOW, top); - insert_box(ctx, box, BOX_INLINE, flow); - } - } - else if (top->type == BOX_FLOW) - { - insert_box(ctx, box, BOX_INLINE, top); - } - else if (top->type == BOX_INLINE) - { - insert_box(ctx, box, BOX_INLINE, top); - } -} - -static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const char *base_uri, - fz_xml *node, struct box *top, struct rule *rule, struct style *up_style) -{ - struct style style; - struct box *box; - const char *tag; - int display; - - while (node) - { - style.up = up_style; - style.count = 0; - - tag = fz_xml_tag(node); - if (tag) - { - apply_styles(ctx, &style, rule, node); - - display = get_style_property_display(&style); - - if (!strcmp(tag, "br")) - { - box = new_box(ctx, node); - compute_style(ctx, set, &box->style, &style); - top = insert_break_box(ctx, box, top); - } - - else if (!strcmp(tag, "img")) - { - const char *src = fz_xml_att(node, "src"); - if (src) - { - box = new_box(ctx, node); - compute_style(ctx, set, &box->style, &style); - insert_inline_box(ctx, box, top); - generate_image(ctx, zip, base_uri, box, src); - } - } - - else if (display != DIS_NONE) - { - box = new_box(ctx, node); - compute_style(ctx, set, &box->style, &style); - - if (display == DIS_BLOCK) - { - top = insert_block_box(ctx, box, top); - } - else if (display == DIS_LIST_ITEM) - { - top = insert_block_box(ctx, box, top); - } - else if (display == DIS_INLINE) - { - insert_inline_box(ctx, box, top); - } - else - { - fz_warn(ctx, "unknown box display type"); - insert_box(ctx, box, BOX_BLOCK, top); - } - - if (fz_xml_down(node)) - generate_boxes(ctx, set, zip, base_uri, fz_xml_down(node), box, rule, &style); - - // TODO: remove empty flow boxes - } - } - else - { - if (top->type != BOX_INLINE) - { - box = new_box(ctx, node); - insert_inline_box(ctx, box, top); - box->style = top->style; - generate_text(ctx, box, fz_xml_text(node)); - } - else - { - generate_text(ctx, top, fz_xml_text(node)); - } - } - - node = fz_xml_next(node); - } -} - -static void measure_image(fz_context *ctx, struct flow *node, float w, float h) -{ - float xs = 1, ys = 1, s = 1; - node->x = 0; - node->y = 0; - if (node->image->w > w) - xs = w / node->image->w; - if (node->image->h > h) - ys = h / node->image->h; - s = fz_min(xs, ys); - node->w = node->image->w * s; - node->h = node->image->h * s; -} - -static void measure_word(fz_context *ctx, struct flow *node, float em) -{ - const char *s; - int c, g; - float w; - - em = from_number(node->style->font_size, em, em); - node->x = 0; - node->y = 0; - node->h = from_number_scale(node->style->line_height, em, em, em); - - w = 0; - s = node->text; - while (*s) - { - s += fz_chartorune(&c, s); - g = fz_encode_character(ctx, node->style->font, c); - w += fz_advance_glyph(ctx, node->style->font, g) * em; - } - node->w = w; - node->em = em; -} - -static float measure_line(struct flow *node, struct flow *end, float *baseline) -{ - float max_a = 0, max_d = 0, h = 0; - while (node != end) - { - if (node->type == FLOW_IMAGE) - { - if (node->h > max_a) - max_a = node->h; - } - else - { - float a = node->em * 0.8; - float d = node->em * 0.2; - if (a > max_a) max_a = a; - if (d > max_d) max_d = d; - } - if (node->h > h) h = node->h; - if (max_a + max_d > h) h = max_a + max_d; - node = node->next; - } - *baseline = max_a + (h - max_a - max_d) / 2; - return h; -} - -static void layout_line(fz_context *ctx, float indent, float page_w, float line_w, int align, struct flow *node, struct flow *end, struct box *box, float baseline) -{ - float x = box->x + indent; - float y = box->y + box->h; - float slop = page_w - line_w; - float justify = 0; - float va; - int n = 0; - - if (align == TA_JUSTIFY) - { - struct flow *it; - for (it = node; it != end; it = it->next) - if (it->type == FLOW_GLUE) - ++n; - justify = slop / n; - } - else if (align == TA_RIGHT) - x += slop; - else if (align == TA_CENTER) - x += slop / 2; - - while (node != end) - { - switch (node->style->vertical_align) - { - default: - case VA_BASELINE: - va = 0; - break; - case VA_SUB: - va = node->em * 0.2f; - break; - case VA_SUPER: - va = node->em * -0.3f; - break; - } - node->x = x; - if (node->type == FLOW_IMAGE) - node->y = y + baseline - node->h; - else - node->y = y + baseline + va; - x += node->w; - if (node->type == FLOW_GLUE) - x += justify; - node = node->next; - } -} - -static struct flow *find_next_glue(struct flow *node, float *w) -{ - while (node && node->type == FLOW_GLUE) - { - *w += node->w; - node = node->next; - } - while (node && node->type != FLOW_GLUE) - { - *w += node->w; - node = node->next; - } - return node; -} - -static struct flow *find_next_word(struct flow *node, float *w) -{ - while (node && node->type == FLOW_GLUE) - { - *w += node->w; - node = node->next; - } - return node; -} - -static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float em, float page_h) -{ - struct flow *node, *line_start, *word_start, *word_end, *line_end; - float glue_w; - float word_w; - float line_w; - float indent; - float avail, line_h; - float baseline; - int align; - - em = from_number(box->style.font_size, em, em); - indent = box->is_first_flow ? from_number(top->style.text_indent, em, top->w) : 0; - align = top->style.text_align; - - box->x = top->x; - box->y = top->y + top->h; - box->w = top->w; - box->h = 0; - - if (!box->flow_head) - return; - - for (node = box->flow_head; node; node = node->next) - if (node->type == FLOW_IMAGE) - measure_image(ctx, node, top->w, page_h); - else - measure_word(ctx, node, em); - - line_start = find_next_word(box->flow_head, &glue_w); - line_end = NULL; - - line_w = indent; - word_w = 0; - word_start = line_start; - while (word_start) - { - word_end = find_next_glue(word_start, &word_w); - if (line_w + word_w <= top->w) - { - line_w += word_w; - glue_w = 0; - line_end = word_end; - word_start = find_next_word(word_end, &glue_w); - word_w = glue_w; - } - else - { - avail = page_h - fmodf(box->y + box->h, page_h); - line_h = measure_line(line_start, line_end, &baseline); - if (line_h > avail) - box->h += avail; - layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box, baseline); - box->h += line_h; - word_start = find_next_word(line_end, &glue_w); - line_start = word_start; - line_end = NULL; - indent = 0; - line_w = 0; - word_w = 0; - } - } - - /* don't justify the last line of a paragraph */ - if (align == TA_JUSTIFY) - align = TA_LEFT; - - if (line_start) - { - avail = page_h - fmodf(box->y + box->h, page_h); - line_h = measure_line(line_start, line_end, &baseline); - if (line_h > avail) - box->h += avail; - layout_line(ctx, indent, top->w, line_w, align, line_start, line_end, box, baseline); - box->h += line_h; - } -} - -static void layout_block(fz_context *ctx, struct box *box, struct box *top, float em, float top_collapse_margin, float page_h) -{ - struct box *child; - float box_collapse_margin; - int prev_br; - - float *margin = box->margin; - float *border = box->border; - float *padding = box->padding; - - em = from_number(box->style.font_size, em, em); - - margin[0] = from_number(box->style.margin[0], em, top->w); - margin[1] = from_number(box->style.margin[1], em, top->w); - margin[2] = from_number(box->style.margin[2], em, top->w); - margin[3] = from_number(box->style.margin[3], em, top->w); - - padding[0] = from_number(box->style.padding[0], em, top->w); - padding[1] = from_number(box->style.padding[1], em, top->w); - padding[2] = from_number(box->style.padding[2], em, top->w); - padding[3] = from_number(box->style.padding[3], em, top->w); - - if (box->style.border_style) - { - border[0] = from_number(box->style.border_width[0], em, top->w); - border[1] = from_number(box->style.border_width[1], em, top->w); - border[2] = from_number(box->style.border_width[2], em, top->w); - border[3] = from_number(box->style.border_width[3], em, top->w); - } - else - border[0] = border[1] = border[2] = border[3] = 0; - - if (padding[T] == 0 && border[T] == 0) - box_collapse_margin = margin[T]; - else - box_collapse_margin = 0; - - if (margin[T] > top_collapse_margin) - margin[T] -= top_collapse_margin; - else - margin[T] = 0; - - box->x = top->x + margin[L] + border[L] + padding[L]; - box->y = top->y + top->h + margin[T] + border[T] + padding[T]; - box->w = top->w - (margin[L] + margin[R] + border[L] + border[R] + padding[L] + padding[R]); - box->h = 0; - - prev_br = 0; - for (child = box->down; child; child = child->next) - { - if (child->type == BOX_BLOCK) - { - layout_block(ctx, child, box, em, box_collapse_margin, page_h); - box->h += child->h + - child->padding[T] + child->padding[B] + - child->border[T] + child->border[B] + - child->margin[T] + child->margin[B]; - box_collapse_margin = child->margin[B]; - prev_br = 0; - } - else if (child->type == BOX_BREAK) - { - /* TODO: interaction with page breaks */ - if (prev_br) - box->h += from_number_scale(box->style.line_height, em, em, em); - prev_br = 1; - } - else if (child->type == BOX_FLOW) - { - layout_flow(ctx, child, box, em, page_h); - if (child->h > 0) - { - box->h += child->h; - box_collapse_margin = 0; - prev_br = 0; - } - } - } - - if (padding[B] == 0 && border[B] == 0) - { - if (margin[B] > 0) - { - box->h -= box_collapse_margin; - if (margin[B] < box_collapse_margin) - margin[B] = box_collapse_margin; - } - } -} - -static void indent(int level) -{ - while (level--) printf(" "); -} - -static void print_flow(fz_context *ctx, struct flow *flow, int level) -{ - while (flow) - { - printf("%-5d %-5d", (int)flow->x, (int)flow->y); - indent(level); - switch (flow->type) - { - case FLOW_WORD: printf("word \"%s\"\n", flow->text); break; - case FLOW_GLUE: printf("glue \"%s\" / \"%s\"\n", flow->text, flow->broken_text); break; - case FLOW_IMAGE: printf("image\n"); break; - } - flow = flow->next; - } -} - -static void print_box(fz_context *ctx, struct box *box, int level) -{ - while (box) - { - printf("%-5d %-5d", (int)box->x, (int)box->y); - indent(level); - switch (box->type) - { - case BOX_BLOCK: printf("block"); break; - case BOX_BREAK: printf("break"); break; - case BOX_FLOW: printf("flow"); break; - case BOX_INLINE: printf("inline"); break; - } - if (box->node) - { - const char *tag = fz_xml_tag(box->node); - if (tag) printf(" <%s>", tag); - else printf(" anonymous"); - } - printf("\n"); - if (box->down) - print_box(ctx, box->down, level + 1); -// if (box->flow_head) -// print_flow(ctx, box->flow_head, level + 1); - box = box->next; - } -} - -static void -draw_flow_box(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm) -{ - struct flow *node; - fz_text *text; - fz_matrix trm; - const char *s; - float color[3]; - float x, y; - int c, g; - - for (node = box->flow_head; node; node = node->next) - { - if (node->type == FLOW_IMAGE) - { - if (node->y > page_bot || node->y + node->h < page_top) - continue; - } - else - { - if (node->y > page_bot || node->y < page_top) - continue; - } - - if (node->type == FLOW_WORD) - { - fz_scale(&trm, node->em, -node->em); - text = fz_new_text(ctx, node->style->font, &trm, 0); - - x = node->x; - y = node->y; - s = node->text; - while (*s) - { - s += fz_chartorune(&c, s); - g = fz_encode_character(ctx, node->style->font, c); - fz_add_text(ctx, text, g, c, x, y); - x += fz_advance_glyph(ctx, node->style->font, g) * node->em; - } - - color[0] = node->style->color.r / 255.0f; - color[1] = node->style->color.g / 255.0f; - color[2] = node->style->color.b / 255.0f; - - fz_fill_text(dev, text, ctm, fz_device_rgb(ctx), color, 1); - - fz_free_text(ctx, text); - } - else if (node->type == FLOW_IMAGE) - { - fz_matrix local_ctm = *ctm; - fz_pre_translate(&local_ctm, node->x, node->y); - fz_pre_scale(&local_ctm, node->w, node->h); - fz_fill_image(dev, node->image, &local_ctm, 1); - } - } -} - -static void -draw_rect(fz_context *ctx, fz_device *dev, const fz_matrix *ctm, float *rgba, float x0, float y0, float x1, float y1) -{ - fz_path *path = fz_new_path(ctx); - - fz_moveto(ctx, path, x0, y0); - fz_lineto(ctx, path, x1, y0); - fz_lineto(ctx, path, x1, y1); - fz_lineto(ctx, path, x0, y1); - fz_closepath(ctx, path); - - fz_fill_path(dev, path, 0, ctm, fz_device_rgb(ctx), rgba, rgba[3]); - - fz_free_path(ctx, path); -} - -static void -draw_block_box(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm) -{ - float x0, y0, x1, y1; - float color[4]; - - // TODO: background fill - // TODO: border stroke - - float *border = box->border; - float *padding = box->padding; - - x0 = box->x - padding[L]; - y0 = box->y - padding[T]; - x1 = box->x + box->w + padding[R]; - y1 = box->y + box->h + padding[B]; - - if (y0 > page_bot || y1 < page_top) - return; - - if (box->style.background_color.a > 0) - { - color[0] = box->style.background_color.r / 255.0f; - color[1] = box->style.background_color.g / 255.0f; - color[2] = box->style.background_color.b / 255.0f; - color[3] = box->style.background_color.a / 255.0f; - draw_rect(ctx, dev, ctm, color, x0, y0, x1, y1); - } - - if (box->style.border_color.a > 0) - { - color[0] = box->style.border_color.r / 255.0f; - color[1] = box->style.border_color.g / 255.0f; - color[2] = box->style.border_color.b / 255.0f; - color[3] = box->style.border_color.a / 255.0f; - if (border[T] > 0) - draw_rect(ctx, dev, ctm, color, x0 - border[L], y0 - border[T], x1 + border[R], y0); - if (border[B] > 0) - draw_rect(ctx, dev, ctm, color, x0 - border[L], y1, x1 + border[R], y1 + border[B]); - if (border[L] > 0) - draw_rect(ctx, dev, ctm, color, x0 - border[L], y0 - border[T], x0, y1 + border[B]); - if (border[R] > 0) - draw_rect(ctx, dev, ctm, color, x1, y0 - border[T], x1 + border[R], y1 + border[B]); - } - - for (box = box->down; box; box = box->next) - { - switch (box->type) - { - case BOX_BLOCK: draw_block_box(ctx, box, page_top, page_bot, dev, ctm); break; - case BOX_FLOW: draw_flow_box(ctx, box, page_top, page_bot, dev, ctm); break; - } - } -} - -void -fz_draw_html(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *inctm) -{ - fz_matrix ctm = *inctm; - fz_pre_translate(&ctm, 0, -page_top); - draw_block_box(ctx, box, page_top, page_bot, dev, &ctm); -} - -static char *concat_text(fz_context *ctx, fz_xml *root) -{ - fz_xml *node; - int i = 0, n = 1; - char *s; - for (node = fz_xml_down(root); node; node = fz_xml_next(node)) - { - const char *text = fz_xml_text(node); - n += text ? strlen(text) : 0; - } - s = fz_malloc(ctx, n); - for (node = fz_xml_down(root); node; node = fz_xml_next(node)) - { - const char *text = fz_xml_text(node); - if (text) - { - n = strlen(text); - memcpy(s+i, text, n); - i += n; - } - } - s[i] = 0; - return s; -} - -static struct rule *html_load_css(fz_context *ctx, fz_archive *zip, const char *base_uri, struct rule *css, fz_xml *root) -{ - fz_xml *node; - fz_buffer *buf; - char path[2048]; - - for (node = root; node; node = fz_xml_next(node)) - { - const char *tag = fz_xml_tag(node); - if (tag && !strcmp(tag, "link")) - { - char *rel = fz_xml_att(node, "rel"); - if (rel && !strcasecmp(rel, "stylesheet")) - { - char *type = fz_xml_att(node, "type"); - if ((type && !strcmp(type, "text/css")) || !type) - { - char *href = fz_xml_att(node, "href"); - if (href) - { - fz_strlcpy(path, base_uri, sizeof path); - fz_strlcat(path, "/", sizeof path); - fz_strlcat(path, href, sizeof path); - fz_cleanname(path); - - buf = fz_read_archive_entry(ctx, zip, path); - fz_write_buffer_byte(ctx, buf, 0); - css = fz_parse_css(ctx, css, (char*)buf->data); - fz_drop_buffer(ctx, buf); - } - } - } - } - if (tag && !strcmp(tag, "style")) - { - char *s = concat_text(ctx, node); - css = fz_parse_css(ctx, css, s); - fz_free(ctx, s); - } - if (fz_xml_down(node)) - css = html_load_css(ctx, zip, base_uri, css, fz_xml_down(node)); - } - return css; -} - -void -fz_layout_html(fz_context *ctx, struct box *box, float w, float h, float em) -{ - struct box page_box; - - printf("html: laying out text.\n"); - - init_box(ctx, &page_box, NULL); - page_box.w = w; - page_box.h = 0; - - layout_block(ctx, box, &page_box, em, 0, h); - - printf("html: finished.\n"); -} - -struct box * -fz_generate_html(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const char *base_uri, fz_buffer *buf) -{ - fz_xml *xml; - struct rule *css; - struct box *box; - struct style style; - - printf("html: parsing XHTML.\n"); - xml = fz_parse_xml(ctx, buf->data, buf->len, 1); - - printf("html: parsing style sheets.\n"); - css = fz_parse_css(ctx, NULL, default_css); - css = html_load_css(ctx, zip, base_uri, css, xml); - - // print_rules(css); - - printf("html: applying styles and generating boxes.\n"); - box = new_box(ctx, NULL); - - style.up = NULL; - style.count = 0; - - generate_boxes(ctx, set, zip, base_uri, xml, box, css, &style); - - return box; -} -- cgit v1.2.3 From 1d2d217346c246f7283a1274bb7313e41084337b Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 26 Nov 2014 02:47:36 +0100 Subject: html: Namespace prefix CSS functions. --- source/html/css-apply.c | 213 +++++++++++++--------------------------------- source/html/css-parse.c | 32 +++---- source/html/html-font.c | 2 +- source/html/html-layout.c | 38 ++++----- 4 files changed, 96 insertions(+), 189 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 289811c6..a1b8d800 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -3,73 +3,58 @@ static void add_property(struct style *style, const char *name, struct value *value, int spec); struct rule * -new_rule(struct selector *selector, struct property *declaration) +fz_new_css_rule(fz_context *ctx, struct selector *selector, struct property *declaration) { - struct rule *rule; - - rule = malloc(sizeof(struct rule)); + struct rule *rule = fz_malloc_struct(ctx, struct rule); rule->selector = selector; rule->declaration = declaration; rule->next = NULL; - return rule; } struct selector * -new_selector(const char *name) +fz_new_css_selector(fz_context *ctx, const char *name) { - struct selector *sel; - - sel = malloc(sizeof(struct selector)); + struct selector *sel = fz_malloc_struct(ctx, struct selector); sel->name = name ? strdup(name) : NULL; sel->combine = 0; sel->cond = NULL; sel->left = NULL; sel->right = NULL; sel->next = NULL; - return sel; } struct condition * -new_condition(int type, const char *key, const char *val) +fz_new_css_condition(fz_context *ctx, int type, const char *key, const char *val) { - struct condition *cond; - - cond = malloc(sizeof(struct condition)); + struct condition *cond = fz_malloc_struct(ctx, struct condition); cond->type = type; cond->key = key ? strdup(key) : NULL; cond->val = val ? strdup(val) : NULL; cond->next = NULL; - return cond; } struct property * -new_property(const char *name, struct value *value, int spec) +fz_new_css_property(fz_context *ctx, const char *name, struct value *value, int spec) { - struct property *prop; - - prop = malloc(sizeof(struct property)); + struct property *prop = fz_malloc_struct(ctx, struct property); prop->name = strdup(name); prop->value = value; prop->spec = spec; prop->next = NULL; - return prop; } struct value * -new_value(int type, const char *data) +fz_new_css_value(fz_context *ctx, int type, const char *data) { - struct value *val; - - val = malloc(sizeof(struct value)); + struct value *val = fz_malloc_struct(ctx, struct value); val->type = type; val->data = strdup(data); val->args = NULL; val->next = NULL; - return val; } @@ -158,7 +143,7 @@ count_selector_names(struct selector *sel) #define INLINE_SPECIFICITY 1000 -int +static int selector_specificity(struct selector *sel) { int b = count_selector_ids(sel); @@ -269,7 +254,7 @@ print_rules(struct rule *rule) * Selector matching */ -int +static int match_id_condition(fz_xml *node, const char *p) { const char *s = fz_xml_att(node, "id"); @@ -278,7 +263,7 @@ match_id_condition(fz_xml *node, const char *p) return 0; } -int +static int match_class_condition(fz_xml *node, const char *p) { const char *s = fz_xml_att(node, "class"); @@ -295,7 +280,7 @@ match_class_condition(fz_xml *node, const char *p) return 0; } -int +static int match_condition(struct condition *cond, fz_xml *node) { if (!cond) @@ -311,7 +296,7 @@ match_condition(struct condition *cond, fz_xml *node) return match_condition(cond->next, node); } -int +static int match_selector(struct selector *sel, fz_xml *node) { if (!node) @@ -407,153 +392,75 @@ count_values(struct value *value) } static void -add_shorthand_margin(struct style *style, struct value *value, int spec) +add_shorthand_trbl(struct style *style, struct value *value, int spec, + const char *name_t, const char *name_r, const char *name_b, const char *name_l) { int n = count_values(value); if (n == 1) { - add_property(style, "margin-top", value, spec); - add_property(style, "margin-right", value, spec); - add_property(style, "margin-bottom", value, spec); - add_property(style, "margin-left", value, spec); + add_property(style, name_t, value, spec); + add_property(style, name_r, value, spec); + add_property(style, name_b, value, spec); + add_property(style, name_l, value, spec); } if (n == 2) { - struct value *a = new_value(value->type, value->data); - struct value *b = new_value(value->next->type, value->next->data); + struct value *a = value; + struct value *b = value->next; - add_property(style, "margin-top", a, spec); - add_property(style, "margin-right", b, spec); - add_property(style, "margin-bottom", a, spec); - add_property(style, "margin-left", b, spec); + add_property(style, name_t, a, spec); + add_property(style, name_r, b, spec); + add_property(style, name_b, a, spec); + add_property(style, name_l, b, spec); } if (n == 3) { - struct value *a = new_value(value->type, value->data); - struct value *b = new_value(value->next->type, value->next->data); - struct value *c = new_value(value->next->next->type, value->next->next->data); - - add_property(style, "margin-top", a, spec); - add_property(style, "margin-right", b, spec); - add_property(style, "margin-bottom", c, spec); - add_property(style, "margin-left", b, spec); + struct value *a = value; + struct value *b = value->next; + struct value *c = value->next->next; + + add_property(style, name_t, a, spec); + add_property(style, name_r, b, spec); + add_property(style, name_b, c, spec); + add_property(style, name_l, b, spec); } if (n == 4) { - struct value *a = new_value(value->type, value->data); - struct value *b = new_value(value->next->type, value->next->data); - struct value *c = new_value(value->next->next->type, value->next->next->data); - struct value *d = new_value(value->next->next->next->type, value->next->next->next->data); - - add_property(style, "margin-top", a, spec); - add_property(style, "margin-right", b, spec); - add_property(style, "margin-bottom", c, spec); - add_property(style, "margin-left", d, spec); + struct value *a = value; + struct value *b = value->next; + struct value *c = value->next->next; + struct value *d = value->next->next->next; + + add_property(style, name_t, a, spec); + add_property(style, name_r, b, spec); + add_property(style, name_b, c, spec); + add_property(style, name_l, d, spec); } } static void -add_shorthand_padding(struct style *style, struct value *value, int spec) +add_shorthand_margin(struct style *style, struct value *value, int spec) { - int n = count_values(value); - - if (n == 1) - { - add_property(style, "padding-top", value, spec); - add_property(style, "padding-right", value, spec); - add_property(style, "padding-bottom", value, spec); - add_property(style, "padding-left", value, spec); - } - - if (n == 2) - { - struct value *a = new_value(value->type, value->data); - struct value *b = new_value(value->next->type, value->next->data); - - add_property(style, "padding-top", a, spec); - add_property(style, "padding-right", b, spec); - add_property(style, "padding-bottom", a, spec); - add_property(style, "padding-left", b, spec); - } - - if (n == 3) - { - struct value *a = new_value(value->type, value->data); - struct value *b = new_value(value->next->type, value->next->data); - struct value *c = new_value(value->next->next->type, value->next->next->data); - - add_property(style, "padding-top", a, spec); - add_property(style, "padding-right", b, spec); - add_property(style, "padding-bottom", c, spec); - add_property(style, "padding-left", b, spec); - } + add_shorthand_trbl(style, value, spec, + "margin-top", "margin-right", "margin-bottom", "margin-left"); +} - if (n == 4) - { - struct value *a = new_value(value->type, value->data); - struct value *b = new_value(value->next->type, value->next->data); - struct value *c = new_value(value->next->next->type, value->next->next->data); - struct value *d = new_value(value->next->next->next->type, value->next->next->next->data); - - add_property(style, "padding-top", a, spec); - add_property(style, "padding-right", b, spec); - add_property(style, "padding-bottom", c, spec); - add_property(style, "padding-left", d, spec); - } +static void +add_shorthand_padding(struct style *style, struct value *value, int spec) +{ + add_shorthand_trbl(style, value, spec, + "padding-top", "padding-right", "padding-bottom", "padding-left"); } static void add_shorthand_border_width(struct style *style, struct value *value, int spec) { - int n = count_values(value); - - if (n == 1) - { - add_property(style, "border-width-top", value, spec); - add_property(style, "border-width-right", value, spec); - add_property(style, "border-width-bottom", value, spec); - add_property(style, "border-width-left", value, spec); - } - - if (n == 2) - { - struct value *a = new_value(value->type, value->data); - struct value *b = new_value(value->next->type, value->next->data); - - add_property(style, "border-width-top", a, spec); - add_property(style, "border-width-right", b, spec); - add_property(style, "border-width-bottom", a, spec); - add_property(style, "border-width-left", b, spec); - } - - if (n == 3) - { - struct value *a = new_value(value->type, value->data); - struct value *b = new_value(value->next->type, value->next->data); - struct value *c = new_value(value->next->next->type, value->next->next->data); - - add_property(style, "border-width-top", a, spec); - add_property(style, "border-width-right", b, spec); - add_property(style, "border-width-bottom", c, spec); - add_property(style, "border-width-left", b, spec); - } - - if (n == 4) - { - struct value *a = new_value(value->type, value->data); - struct value *b = new_value(value->next->type, value->next->data); - struct value *c = new_value(value->next->next->type, value->next->next->data); - struct value *d = new_value(value->next->next->next->type, value->next->next->next->data); - - add_property(style, "border-width-top", a, spec); - add_property(style, "border-width-right", b, spec); - add_property(style, "border-width-bottom", c, spec); - add_property(style, "border-width-left", d, spec); - } + add_shorthand_trbl(style, value, spec, + "border-width-top", "border-width-right", "border-width-bottom", "border-width-left"); } static void @@ -846,7 +753,7 @@ border_width_from_property(struct style *node, const char *property) } float -from_number(struct number number, float em, float width) +fz_from_css_number(struct number number, float em, float width) { switch (number.unit) { default: @@ -857,7 +764,7 @@ from_number(struct number number, float em, float width) } float -from_number_scale(struct number number, float scale, float em, float width) +fz_from_css_number_scale(struct number number, float scale, float em, float width) { switch (number.unit) { default: @@ -947,7 +854,7 @@ color_from_property(struct style *node, const char *property, struct color initi } int -get_style_property_display(struct style *node) +fz_get_css_style_property_display(struct style *node) { struct value *value = get_style_property(node, "display"); if (value) @@ -964,7 +871,7 @@ get_style_property_display(struct style *node) return DIS_INLINE; } -int +static int get_style_property_white_space(struct style *node) { struct value *value = get_style_property(node, "white-space"); @@ -1087,7 +994,7 @@ compute_style(fz_context *ctx, fz_html_font_set *set, struct computed_style *sty const char *font_variant = get_style_property_string(node, "font-variant", "normal"); const char *font_style = get_style_property_string(node, "font-style", "normal"); const char *font_weight = get_style_property_string(node, "font-weight", "normal"); - style->font = fz_html_load_font(ctx, set, font_family, font_variant, font_style, font_weight); + style->font = fz_load_html_font(ctx, set, font_family, font_variant, font_style, font_weight); } } diff --git a/source/html/css-parse.c b/source/html/css-parse.c index d4aa39ec..35d11a1d 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -373,7 +373,7 @@ static struct value *parse_value(struct lexbuf *buf) if (buf->lookahead == CSS_KEYWORD) { - v = new_value(CSS_KEYWORD, buf->string); + v = fz_new_css_value(buf->ctx, CSS_KEYWORD, buf->string); next(buf); if (accept(buf, '(')) @@ -394,15 +394,15 @@ static struct value *parse_value(struct lexbuf *buf) case CSS_STRING: case CSS_COLOR: case CSS_URI: - v = new_value(buf->lookahead, buf->string); + v = fz_new_css_value(buf->ctx, buf->lookahead, buf->string); next(buf); return v; } if (accept(buf, ',')) - return new_value(',', ","); + return fz_new_css_value(buf->ctx, ',', ","); if (accept(buf, '/')) - return new_value('/', "/"); + return fz_new_css_value(buf->ctx, '/', "/"); fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected value"); } @@ -431,7 +431,7 @@ static struct property *parse_declaration(struct lexbuf *buf) if (buf->lookahead != CSS_KEYWORD) fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected keyword in property"); - p = new_property(buf->string, NULL, 0); + p = fz_new_css_property(buf->ctx, buf->string, NULL, 0); next(buf); expect(buf, ':'); @@ -487,7 +487,7 @@ static struct condition *parse_condition(struct lexbuf *buf) { if (buf->lookahead != CSS_KEYWORD) fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected keyword after ':'"); - c = new_condition(':', "pseudo", buf->string); + c = fz_new_css_condition(buf->ctx, ':', "pseudo", buf->string); next(buf); return c; } @@ -496,7 +496,7 @@ static struct condition *parse_condition(struct lexbuf *buf) { if (buf->lookahead != CSS_KEYWORD) fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected keyword after '.'"); - c = new_condition('.', "class", buf->string); + c = fz_new_css_condition(buf->ctx, '.', "class", buf->string); next(buf); return c; } @@ -505,7 +505,7 @@ static struct condition *parse_condition(struct lexbuf *buf) { if (buf->lookahead != CSS_KEYWORD) fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected keyword after '#'"); - c = new_condition('#', "id", buf->string); + c = fz_new_css_condition(buf->ctx, '#', "id", buf->string); next(buf); return c; } @@ -515,7 +515,7 @@ static struct condition *parse_condition(struct lexbuf *buf) if (buf->lookahead != CSS_KEYWORD) fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected keyword after '['"); - c = new_condition('[', buf->string, NULL); + c = fz_new_css_condition(buf->ctx, '[', buf->string, NULL); next(buf); if (accept(buf, '=')) @@ -562,14 +562,14 @@ static struct selector *parse_simple_selector(struct lexbuf *buf) if (accept(buf, '*')) { - s = new_selector(NULL); + s = fz_new_css_selector(buf->ctx, NULL); if (iscond(buf->lookahead)) s->cond = parse_condition_list(buf); return s; } else if (buf->lookahead == CSS_KEYWORD) { - s = new_selector(buf->string); + s = fz_new_css_selector(buf->ctx, buf->string); next(buf); if (iscond(buf->lookahead)) s->cond = parse_condition_list(buf); @@ -577,7 +577,7 @@ static struct selector *parse_simple_selector(struct lexbuf *buf) } else if (iscond(buf->lookahead)) { - s = new_selector(NULL); + s = fz_new_css_selector(buf->ctx, NULL); s->cond = parse_condition_list(buf); return s; } @@ -593,7 +593,7 @@ static struct selector *parse_adjacent_selector(struct lexbuf *buf) if (accept(buf, '+')) { b = parse_adjacent_selector(buf); - s = new_selector(NULL); + s = fz_new_css_selector(buf->ctx, NULL); s->combine = '+'; s->left = a; s->right = b; @@ -610,7 +610,7 @@ static struct selector *parse_child_selector(struct lexbuf *buf) if (accept(buf, '>')) { b = parse_child_selector(buf); - s = new_selector(NULL); + s = fz_new_css_selector(buf->ctx, NULL); s->combine = '>'; s->left = a; s->right = b; @@ -627,7 +627,7 @@ static struct selector *parse_descendant_selector(struct lexbuf *buf) if (buf->lookahead != ',' && buf->lookahead != '{' && buf->lookahead != EOF) { b = parse_descendant_selector(buf); - s = new_selector(NULL); + s = fz_new_css_selector(buf->ctx, NULL); s->combine = ' '; s->left = a; s->right = b; @@ -657,7 +657,7 @@ static struct rule *parse_rule(struct lexbuf *buf) expect(buf, '{'); p = parse_declaration_list(buf); expect(buf, '}'); - return new_rule(s, p); + return fz_new_css_rule(buf->ctx, s, p); } static void parse_media_list(struct lexbuf *buf) diff --git a/source/html/html-font.c b/source/html/html-font.c index ce8c2ed1..e5d42bdc 100644 --- a/source/html/html-font.c +++ b/source/html/html-font.c @@ -9,7 +9,7 @@ static const char *font_names[16] = { }; fz_font * -fz_html_load_font(fz_context *ctx, fz_html_font_set *set, +fz_load_html_font(fz_context *ctx, fz_html_font_set *set, const char *family, const char *variant, const char *style, const char *weight) { unsigned char *data; diff --git a/source/html/html-layout.c b/source/html/html-layout.c index 31c41a71..384a2720 100644 --- a/source/html/html-layout.c +++ b/source/html/html-layout.c @@ -255,7 +255,7 @@ static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *z { apply_styles(ctx, &style, rule, node); - display = get_style_property_display(&style); + display = fz_get_css_style_property_display(&style); if (!strcmp(tag, "br")) { @@ -344,10 +344,10 @@ static void measure_word(fz_context *ctx, struct flow *node, float em) int c, g; float w; - em = from_number(node->style->font_size, em, em); + em = fz_from_css_number(node->style->font_size, em, em); node->x = 0; node->y = 0; - node->h = from_number_scale(node->style->line_height, em, em, em); + node->h = fz_from_css_number_scale(node->style->line_height, em, em, em); w = 0; s = node->text; @@ -471,8 +471,8 @@ static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float float baseline; int align; - em = from_number(box->style.font_size, em, em); - indent = box->is_first_flow ? from_number(top->style.text_indent, em, top->w) : 0; + em = fz_from_css_number(box->style.font_size, em, em); + indent = box->is_first_flow ? fz_from_css_number(top->style.text_indent, em, top->w) : 0; align = top->style.text_align; box->x = top->x; @@ -548,24 +548,24 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa float *border = box->border; float *padding = box->padding; - em = from_number(box->style.font_size, em, em); + em = fz_from_css_number(box->style.font_size, em, em); - margin[0] = from_number(box->style.margin[0], em, top->w); - margin[1] = from_number(box->style.margin[1], em, top->w); - margin[2] = from_number(box->style.margin[2], em, top->w); - margin[3] = from_number(box->style.margin[3], em, top->w); + margin[0] = fz_from_css_number(box->style.margin[0], em, top->w); + margin[1] = fz_from_css_number(box->style.margin[1], em, top->w); + margin[2] = fz_from_css_number(box->style.margin[2], em, top->w); + margin[3] = fz_from_css_number(box->style.margin[3], em, top->w); - padding[0] = from_number(box->style.padding[0], em, top->w); - padding[1] = from_number(box->style.padding[1], em, top->w); - padding[2] = from_number(box->style.padding[2], em, top->w); - padding[3] = from_number(box->style.padding[3], em, top->w); + padding[0] = fz_from_css_number(box->style.padding[0], em, top->w); + padding[1] = fz_from_css_number(box->style.padding[1], em, top->w); + padding[2] = fz_from_css_number(box->style.padding[2], em, top->w); + padding[3] = fz_from_css_number(box->style.padding[3], em, top->w); if (box->style.border_style) { - border[0] = from_number(box->style.border_width[0], em, top->w); - border[1] = from_number(box->style.border_width[1], em, top->w); - border[2] = from_number(box->style.border_width[2], em, top->w); - border[3] = from_number(box->style.border_width[3], em, top->w); + border[0] = fz_from_css_number(box->style.border_width[0], em, top->w); + border[1] = fz_from_css_number(box->style.border_width[1], em, top->w); + border[2] = fz_from_css_number(box->style.border_width[2], em, top->w); + border[3] = fz_from_css_number(box->style.border_width[3], em, top->w); } else border[0] = border[1] = border[2] = border[3] = 0; @@ -602,7 +602,7 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa { /* TODO: interaction with page breaks */ if (prev_br) - box->h += from_number_scale(box->style.line_height, em, em, em); + box->h += fz_from_css_number_scale(box->style.line_height, em, em, em); prev_br = 1; } else if (child->type == BOX_FLOW) -- cgit v1.2.3 From 1155a4dfb5bbe34628be28af2efe22e2860b204d Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 26 Nov 2014 03:04:15 +0100 Subject: html: Fail with '[image]' placeholder on broken images. TODO: Support loading GIF. --- source/html/html-font.c | 12 +++++++----- source/html/html-layout.c | 17 +++++++++++++---- 2 files changed, 20 insertions(+), 9 deletions(-) (limited to 'source/html') diff --git a/source/html/html-font.c b/source/html/html-font.c index e5d42bdc..c7b1cf3c 100644 --- a/source/html/html-font.c +++ b/source/html/html-font.c @@ -1,7 +1,8 @@ #include "mupdf/html.h" #include "mupdf/pdf.h" /* for pdf_lookup_builtin_font */ -static const char *font_names[16] = { +static const char *font_names[16] = +{ "Times-Roman", "Times-Italic", "Times-Bold", "Times-BoldItalic", "Helvetica", "Helvetica-Oblique", "Helvetica-Bold", "Helvetica-BoldOblique", "Courier", "Courier-Oblique", "Courier-Bold", "Courier-BoldOblique", @@ -24,10 +25,8 @@ fz_load_html_font(fz_context *ctx, fz_html_font_set *set, if (!set->fonts[idx]) { data = pdf_lookup_builtin_font(font_names[idx], &size); - if (!data) { - printf("data=%p idx=%d s=%s\n", data, idx, font_names[idx]); - abort(); - } + if (!data) + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot load html font: %s", font_names[idx]); set->fonts[idx] = fz_new_font_from_memory(ctx, font_names[idx], data, size, 0, 1); } @@ -41,5 +40,8 @@ fz_html_font_set *fz_new_html_font_set(fz_context *ctx) void fz_free_html_font_set(fz_context *ctx, fz_html_font_set *set) { + int i; + for (i = 0; i < nelem(set->fonts); ++i) + fz_drop_font(ctx, set->fonts[i]); fz_free(ctx, set); } diff --git a/source/html/html-layout.c b/source/html/html-layout.c index 384a2720..59719de5 100644 --- a/source/html/html-layout.c +++ b/source/html/html-layout.c @@ -116,11 +116,20 @@ static void generate_image(fz_context *ctx, fz_archive *zip, const char *base_ur fz_strlcat(path, src, sizeof path); fz_cleanname(path); - buf = fz_read_archive_entry(ctx, zip, path); - img = fz_new_image_from_buffer(ctx, buf); - fz_drop_buffer(ctx, buf); + fz_try(ctx) + { + buf = fz_read_archive_entry(ctx, zip, path); + img = fz_new_image_from_buffer(ctx, buf); + fz_drop_buffer(ctx, buf); - add_flow_image(ctx, flow, &box->style, img); + add_flow_image(ctx, flow, &box->style, img); + } + fz_catch(ctx) + { + const char *alt = "[image]"; + fz_warn(ctx, "html: cannot add image src='%s'", src); + add_flow_word(ctx, flow, &box->style, alt, alt + 7); + } } static void init_box(fz_context *ctx, struct box *box, fz_xml *node) -- cgit v1.2.3 From 8fd13d8825c14b28787a106acb47e1e3ef47d0f4 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 26 Nov 2014 13:19:26 +0100 Subject: html: Rename rule and style (match) structs. --- source/html/css-apply.c | 598 ++++++++++++++++++++++------------------------ source/html/css-parse.c | 66 ++++- source/html/html-layout.c | 34 +-- 3 files changed, 361 insertions(+), 337 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index a1b8d800..aa02a1b0 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -1,61 +1,86 @@ #include "mupdf/html.h" -static void add_property(struct style *style, const char *name, struct value *value, int spec); - -struct rule * -fz_new_css_rule(fz_context *ctx, struct selector *selector, struct property *declaration) -{ - struct rule *rule = fz_malloc_struct(ctx, struct rule); - rule->selector = selector; - rule->declaration = declaration; - rule->next = NULL; - return rule; -} +static const char *inherit_list[] = { + "color", + "direction", + "font-family", + "font-size", + "font-style", + "font-variant", + "font-weight", + "letter-spacing", + "line-height", + "list-style-image", + "list-style-position", + "list-style-type", + "orphans", + "quotes", + "text-align", + "text-indent", + "text-transform", + "visibility", + "white-space", + "widows", + "word-spacing", +}; -struct selector * -fz_new_css_selector(fz_context *ctx, const char *name) -{ - struct selector *sel = fz_malloc_struct(ctx, struct selector); - sel->name = name ? strdup(name) : NULL; - sel->combine = 0; - sel->cond = NULL; - sel->left = NULL; - sel->right = NULL; - sel->next = NULL; - return sel; -} +static const char *border_width_kw[] = { + "medium", + "thick", + "thin", +}; -struct condition * -fz_new_css_condition(fz_context *ctx, int type, const char *key, const char *val) -{ - struct condition *cond = fz_malloc_struct(ctx, struct condition); - cond->type = type; - cond->key = key ? strdup(key) : NULL; - cond->val = val ? strdup(val) : NULL; - cond->next = NULL; - return cond; -} +static const char *border_style_kw[] = { + "dashed", + "dotted", + "double", + "groove", + "hidden", + "inset", + "none", + "outset", + "ridge", + "solid", +}; -struct property * -fz_new_css_property(fz_context *ctx, const char *name, struct value *value, int spec) -{ - struct property *prop = fz_malloc_struct(ctx, struct property); - prop->name = strdup(name); - prop->value = value; - prop->spec = spec; - prop->next = NULL; - return prop; -} +static const char *color_kw[] = { + "aqua", + "black", + "blue", + "fuchsia", + "gray", + "green", + "lime", + "maroon", + "navy", + "olive", + "orange", + "purple", + "red", + "silver", + "teal", + "transparent", + "white", + "yellow", +}; -struct value * -fz_new_css_value(fz_context *ctx, int type, const char *data) +static int +keyword_in_list(const char *name, const char **list, int n) { - struct value *val = fz_malloc_struct(ctx, struct value); - val->type = type; - val->data = strdup(data); - val->args = NULL; - val->next = NULL; - return val; + int l = 0; + int r = n - 1; + while (l <= r) + { + int m = (l + r) >> 1; + int c = strcmp(name, list[m]); + if (c < 0) + r = m - 1; + else if (c > 0) + l = m + 1; + else + return 1; + } + return 0; } /* @@ -152,104 +177,6 @@ selector_specificity(struct selector *sel) return b * 100 + c * 10 + d; } -/* - * Pretty printing - */ - -void -print_value(struct value *val) -{ - printf("%s", val->data); - if (val->args) - { - printf("("); - print_value(val->args); - printf(")"); - } - if (val->next) - { - printf(" "); - print_value(val->next); - } -} - -void -print_property(struct property *prop) -{ - printf("\t%s: ", prop->name); - print_value(prop->value); - printf(" !%d;\n", prop->spec); -} - -void -print_condition(struct condition *cond) -{ - if (cond->type == '=') - printf("[%s=%s]", cond->key, cond->val); - else if (cond->type == '[') - printf("[%s]", cond->key); - else - printf("%c%s", cond->type, cond->val); - if (cond->next) - print_condition(cond->next); -} - -void -print_selector(struct selector *sel) -{ - if (sel->combine) - { -putchar('('); - print_selector(sel->left); - if (sel->combine == ' ') - printf(" "); - else - printf(" %c ", sel->combine); - print_selector(sel->right); -putchar(')'); - } - else if (sel->name) - printf("%s", sel->name); - else - printf("*"); - if (sel->cond) - { - print_condition(sel->cond); - } -} - -void -print_rule(struct rule *rule) -{ - struct selector *sel; - struct property *prop; - - for (sel = rule->selector; sel; sel = sel->next) - { - print_selector(sel); - printf(" !%d", selector_specificity(sel)); - if (sel->next) - printf(", "); - } - - printf("\n{\n"); - for (prop = rule->declaration; prop; prop = prop->next) - { - print_property(prop); - } - printf("}\n"); -} - -void -print_rules(struct rule *rule) -{ - while (rule) - { - print_rule(rule); - rule = rule->next; - } -} - /* * Selector matching */ @@ -366,19 +293,6 @@ match_selector(struct selector *sel, fz_xml *node) * Annotating nodes with properties and expanding shorthand forms. */ -static const char *border_width_kw[] = { - "thin", "medium", "thick", -}; - -static const char *border_style_kw[] = { - "none", "hidden", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset", -}; - -static const char *color_kw[] = { - "transparent", "maroon", "red", "orange", "yellow", "olive", "purple", "fuchsia", "white", - "lime", "green", "navy", "blue", "aqua", "teal", "black", "silver", "gray", -}; - static int count_values(struct value *value) { @@ -391,18 +305,20 @@ count_values(struct value *value) return n; } +static void add_property(fz_css_match *match, const char *name, struct value *value, int spec); + static void -add_shorthand_trbl(struct style *style, struct value *value, int spec, +add_shorthand_trbl(fz_css_match *match, struct value *value, int spec, const char *name_t, const char *name_r, const char *name_b, const char *name_l) { int n = count_values(value); if (n == 1) { - add_property(style, name_t, value, spec); - add_property(style, name_r, value, spec); - add_property(style, name_b, value, spec); - add_property(style, name_l, value, spec); + add_property(match, name_t, value, spec); + add_property(match, name_r, value, spec); + add_property(match, name_b, value, spec); + add_property(match, name_l, value, spec); } if (n == 2) @@ -410,10 +326,10 @@ add_shorthand_trbl(struct style *style, struct value *value, int spec, struct value *a = value; struct value *b = value->next; - add_property(style, name_t, a, spec); - add_property(style, name_r, b, spec); - add_property(style, name_b, a, spec); - add_property(style, name_l, b, spec); + add_property(match, name_t, a, spec); + add_property(match, name_r, b, spec); + add_property(match, name_b, a, spec); + add_property(match, name_l, b, spec); } if (n == 3) @@ -422,10 +338,10 @@ add_shorthand_trbl(struct style *style, struct value *value, int spec, struct value *b = value->next; struct value *c = value->next->next; - add_property(style, name_t, a, spec); - add_property(style, name_r, b, spec); - add_property(style, name_b, c, spec); - add_property(style, name_l, b, spec); + add_property(match, name_t, a, spec); + add_property(match, name_r, b, spec); + add_property(match, name_b, c, spec); + add_property(match, name_l, b, spec); } if (n == 4) @@ -435,110 +351,95 @@ add_shorthand_trbl(struct style *style, struct value *value, int spec, struct value *c = value->next->next; struct value *d = value->next->next->next; - add_property(style, name_t, a, spec); - add_property(style, name_r, b, spec); - add_property(style, name_b, c, spec); - add_property(style, name_l, d, spec); + add_property(match, name_t, a, spec); + add_property(match, name_r, b, spec); + add_property(match, name_b, c, spec); + add_property(match, name_l, d, spec); } } static void -add_shorthand_margin(struct style *style, struct value *value, int spec) +add_shorthand_margin(fz_css_match *match, struct value *value, int spec) { - add_shorthand_trbl(style, value, spec, + add_shorthand_trbl(match, value, spec, "margin-top", "margin-right", "margin-bottom", "margin-left"); } static void -add_shorthand_padding(struct style *style, struct value *value, int spec) +add_shorthand_padding(fz_css_match *match, struct value *value, int spec) { - add_shorthand_trbl(style, value, spec, + add_shorthand_trbl(match, value, spec, "padding-top", "padding-right", "padding-bottom", "padding-left"); } static void -add_shorthand_border_width(struct style *style, struct value *value, int spec) +add_shorthand_border_width(fz_css_match *match, struct value *value, int spec) { - add_shorthand_trbl(style, value, spec, + add_shorthand_trbl(match, value, spec, "border-width-top", "border-width-right", "border-width-bottom", "border-width-left"); } static void -add_shorthand_border(struct style *style, struct value *value, int spec) +add_shorthand_border(fz_css_match *match, struct value *value, int spec) { - int i; - while (value) { if (value->type == CSS_COLOR) { - add_property(style, "border-color", value, spec); + add_property(match, "border-color", value, spec); } else if (value->type == CSS_KEYWORD) { - for (i = 0; i < nelem(border_width_kw); ++i) + if (keyword_in_list(value->data, border_width_kw, nelem(border_width_kw))) { - if (!strcmp(value->data, border_width_kw[i])) - { - add_property(style, "border-width-top", value, spec); - add_property(style, "border-width-right", value, spec); - add_property(style, "border-width-bottom", value, spec); - add_property(style, "border-width-left", value, spec); - goto next; - } + add_property(match, "border-width-top", value, spec); + add_property(match, "border-width-right", value, spec); + add_property(match, "border-width-bottom", value, spec); + add_property(match, "border-width-left", value, spec); } - for (i = 0; i < nelem(border_style_kw); ++i) + else if (keyword_in_list(value->data, border_style_kw, nelem(border_style_kw))) { - if (!strcmp(value->data, border_style_kw[i])) - { - add_property(style, "border-style", value, spec); - goto next; - } + add_property(match, "border-style", value, spec); } - for (i = 0; i < nelem(color_kw); ++i) + else if (keyword_in_list(value->data, color_kw, nelem(color_kw))) { - if (!strcmp(value->data, color_kw[i])) - { - add_property(style, "border-color", value, spec); - goto next; - } + add_property(match, "border-color", value, spec); } } else { - add_property(style, "border-width-top", value, spec); - add_property(style, "border-width-right", value, spec); - add_property(style, "border-width-bottom", value, spec); - add_property(style, "border-width-left", value, spec); + add_property(match, "border-width-top", value, spec); + add_property(match, "border-width-right", value, spec); + add_property(match, "border-width-bottom", value, spec); + add_property(match, "border-width-left", value, spec); } -next: value = value->next; } } static void -add_property(struct style *style, const char *name, struct value *value, int spec) +add_property(fz_css_match *match, const char *name, struct value *value, int spec) { int i; if (!strcmp(name, "margin")) { - add_shorthand_margin(style, value, spec); + add_shorthand_margin(match, value, spec); return; } if (!strcmp(name, "padding")) { - add_shorthand_padding(style, value, spec); + add_shorthand_padding(match, value, spec); return; } if (!strcmp(name, "border-width")) { - add_shorthand_border_width(style, value, spec); + add_shorthand_border_width(match, value, spec); return; } if (!strcmp(name, "border")) { - add_shorthand_border(style, value, spec); + add_shorthand_border(match, value, spec); return; } @@ -549,33 +450,33 @@ add_property(struct style *style, const char *name, struct value *value, int spe /* TODO: list-style */ /* TODO: background */ - for (i = 0; i < style->count; ++i) + for (i = 0; i < match->count; ++i) { - if (!strcmp(style->prop[i].name, name)) + if (!strcmp(match->prop[i].name, name)) { - if (style->prop[i].spec <= spec) + if (match->prop[i].spec <= spec) { - style->prop[i].value = value; - style->prop[i].spec = spec; + match->prop[i].value = value; + match->prop[i].spec = spec; } return; } } - if (style->count + 1 >= nelem(style->prop)) + if (match->count + 1 >= nelem(match->prop)) { // fz_warn(ctx, "too many css properties"); return; } - style->prop[style->count].name = name; - style->prop[style->count].value = value; - style->prop[style->count].spec = spec; - ++style->count; + match->prop[match->count].name = name; + match->prop[match->count].value = value; + match->prop[match->count].spec = spec; + ++match->count; } void -apply_styles(fz_context *ctx, struct style *style, struct rule *rule, fz_xml *node) +fz_match_css(fz_context *ctx, fz_css_match *match, fz_css_rule *rule, fz_xml *node) { struct selector *sel; struct property *prop; @@ -589,7 +490,7 @@ apply_styles(fz_context *ctx, struct style *style, struct rule *rule, fz_xml *no if (match_selector(sel, node)) { for (prop = rule->declaration; prop; prop = prop->next) - add_property(style, prop->name, prop->value, selector_specificity(sel)); + add_property(match, prop->name, prop->value, selector_specificity(sel)); break; } sel = sel->next; @@ -603,75 +504,44 @@ apply_styles(fz_context *ctx, struct style *style, struct rule *rule, fz_xml *no prop = fz_parse_css_properties(ctx, s); while (prop) { - add_property(style, prop->name, prop->value, INLINE_SPECIFICITY); + add_property(match, prop->name, prop->value, INLINE_SPECIFICITY); prop = prop->next; } // TODO: free props } } -static const char *inherit_list[] = { - "color", "direction", - "font-family", "font-size", "font-style", "font-variant", "font-weight", - "letter-spacing", "line-height", - "list-style-image", "list-style-position", "list-style-type", - "orphans", "quotes", "text-align", "text-indent", "text-transform", - "visibility", "white-space", "widows", "word-spacing", - - /* this is not supposed to be inherited: */ - "vertical-align", -}; - static struct value * -get_raw_property(struct style *node, const char *name) +value_from_raw_property(fz_css_match *match, const char *name) { int i; - for (i = 0; i < node->count; ++i) - if (!strcmp(node->prop[i].name, name)) - return node->prop[i].value; + for (i = 0; i < match->count; ++i) + if (!strcmp(match->prop[i].name, name)) + return match->prop[i].value; return NULL; } -static int -should_inherit_property(const char *name) -{ - int l = 0; - int r = nelem(inherit_list) - 1; - while (l <= r) - { - int m = (l + r) >> 1; - int c = strcmp(name, inherit_list[m]); - if (c < 0) - r = m - 1; - else if (c > 0) - l = m + 1; - else - return 1; - } - return 0; -} - static struct value * -get_style_property(struct style *node, const char *name) +value_from_property(fz_css_match *match, const char *name) { struct value *value; - value = get_raw_property(node, name); - if (node->up) + value = value_from_raw_property(match, name); + if (match->up) { if (value && !strcmp(value->data, "inherit")) - return get_style_property(node->up, name); - if (!value && should_inherit_property(name)) - return get_style_property(node->up, name); + return value_from_property(match->up, name); + if (!value && keyword_in_list(name, inherit_list, nelem(inherit_list))) + return value_from_property(match->up, name); } return value; } static const char * -get_style_property_string(struct style *node, const char *name, const char *initial) +string_from_property(fz_css_match *match, const char *name, const char *initial) { struct value *value; - value = get_style_property(node, name); + value = value_from_property(match, name); if (!value) return initial; return value->data; @@ -730,15 +600,15 @@ number_from_value(struct value *value, float initial, int initial_unit) } static struct number -number_from_property(struct style *node, const char *property, float initial, int initial_unit) +number_from_property(fz_css_match *match, const char *property, float initial, int initial_unit) { - return number_from_value(get_style_property(node, property), initial, initial_unit); + return number_from_value(value_from_property(match, property), initial, initial_unit); } static struct number -border_width_from_property(struct style *node, const char *property) +border_width_from_property(fz_css_match *match, const char *property) { - struct value *value = get_style_property(node, property); + struct value *value = value_from_property(match, property); if (value) { if (!strcmp(value->data, "thin")) @@ -848,15 +718,15 @@ color_from_value(struct value *value, struct color initial) } static struct color -color_from_property(struct style *node, const char *property, struct color initial) +color_from_property(fz_css_match *match, const char *property, struct color initial) { - return color_from_value(get_style_property(node, property), initial); + return color_from_value(value_from_property(match, property), initial); } int -fz_get_css_style_property_display(struct style *node) +fz_get_css_match_display(fz_css_match *match) { - struct value *value = get_style_property(node, "display"); + struct value *value = value_from_property(match, "display"); if (value) { if (!strcmp(value->data, "none")) @@ -872,9 +742,9 @@ fz_get_css_style_property_display(struct style *node) } static int -get_style_property_white_space(struct style *node) +white_space_from_property(fz_css_match *match) { - struct value *value = get_style_property(node, "white-space"); + struct value *value = value_from_property(match, "white-space"); if (value) { if (!strcmp(value->data, "normal")) return WS_NORMAL; @@ -887,7 +757,7 @@ get_style_property_white_space(struct style *node) } void -default_computed_style(struct computed_style *style) +fz_default_css_style(fz_context *ctx, struct computed_style *style) { memset(style, 0, sizeof *style); style->text_align = TA_LEFT; @@ -897,18 +767,18 @@ default_computed_style(struct computed_style *style) } void -compute_style(fz_context *ctx, fz_html_font_set *set, struct computed_style *style, struct style *node) +fz_apply_css_style(fz_context *ctx, fz_html_font_set *set, struct computed_style *style, fz_css_match *match) { struct value *value; struct color black = { 0, 0, 0, 255 }; struct color transparent = { 0, 0, 0, 0 }; - default_computed_style(style); + fz_default_css_style(ctx, style); - style->white_space = get_style_property_white_space(node); + style->white_space = white_space_from_property(match); - value = get_style_property(node, "text-align"); + value = value_from_property(match, "text-align"); if (value) { if (!strcmp(value->data, "left")) @@ -921,7 +791,7 @@ compute_style(fz_context *ctx, fz_html_font_set *set, struct computed_style *sty style->text_align = TA_JUSTIFY; } - value = get_style_property(node, "vertical-align"); + value = value_from_property(match, "vertical-align"); if (value) { if (!strcmp(value->data, "baseline")) @@ -936,7 +806,7 @@ compute_style(fz_context *ctx, fz_html_font_set *set, struct computed_style *sty style->vertical_align = VA_BOTTOM; } - value = get_style_property(node, "font-size"); + value = value_from_property(match, "font-size"); if (value) { if (!strcmp(value->data, "xx-large")) style->font_size = make_number(20, N_NUMBER); @@ -955,7 +825,7 @@ compute_style(fz_context *ctx, fz_html_font_set *set, struct computed_style *sty style->font_size = make_number(1, N_SCALE); } - value = get_style_property(node, "border-style"); + value = value_from_property(match, "border-style"); if (value) { if (!strcmp(value->data, "none")) @@ -966,38 +836,136 @@ compute_style(fz_context *ctx, fz_html_font_set *set, struct computed_style *sty style->border_style = BS_SOLID; } - style->line_height = number_from_property(node, "line-height", 1.2, N_SCALE); + style->line_height = number_from_property(match, "line-height", 1.2, N_SCALE); - style->text_indent = number_from_property(node, "text-indent", 0, N_NUMBER); + style->text_indent = number_from_property(match, "text-indent", 0, N_NUMBER); - style->margin[0] = number_from_property(node, "margin-top", 0, N_NUMBER); - style->margin[1] = number_from_property(node, "margin-right", 0, N_NUMBER); - style->margin[2] = number_from_property(node, "margin-bottom", 0, N_NUMBER); - style->margin[3] = number_from_property(node, "margin-left", 0, N_NUMBER); + style->margin[0] = number_from_property(match, "margin-top", 0, N_NUMBER); + style->margin[1] = number_from_property(match, "margin-right", 0, N_NUMBER); + style->margin[2] = number_from_property(match, "margin-bottom", 0, N_NUMBER); + style->margin[3] = number_from_property(match, "margin-left", 0, N_NUMBER); - style->padding[0] = number_from_property(node, "padding-top", 0, N_NUMBER); - style->padding[1] = number_from_property(node, "padding-right", 0, N_NUMBER); - style->padding[2] = number_from_property(node, "padding-bottom", 0, N_NUMBER); - style->padding[3] = number_from_property(node, "padding-left", 0, N_NUMBER); + style->padding[0] = number_from_property(match, "padding-top", 0, N_NUMBER); + style->padding[1] = number_from_property(match, "padding-right", 0, N_NUMBER); + style->padding[2] = number_from_property(match, "padding-bottom", 0, N_NUMBER); + style->padding[3] = number_from_property(match, "padding-left", 0, N_NUMBER); - style->border_width[0] = border_width_from_property(node, "border-width-top"); - style->border_width[1] = border_width_from_property(node, "border-width-right"); - style->border_width[2] = border_width_from_property(node, "border-width-bottom"); - style->border_width[3] = border_width_from_property(node, "border-width-left"); + style->border_width[0] = border_width_from_property(match, "border-width-top"); + style->border_width[1] = border_width_from_property(match, "border-width-right"); + style->border_width[2] = border_width_from_property(match, "border-width-bottom"); + style->border_width[3] = border_width_from_property(match, "border-width-left"); - style->color = color_from_property(node, "color", black); - style->background_color = color_from_property(node, "background-color", transparent); - style->border_color = color_from_property(node, "border-color", style->color); + style->color = color_from_property(match, "color", black); + style->background_color = color_from_property(match, "background-color", transparent); + style->border_color = color_from_property(match, "border-color", style->color); { - const char *font_family = get_style_property_string(node, "font-family", "serif"); - const char *font_variant = get_style_property_string(node, "font-variant", "normal"); - const char *font_style = get_style_property_string(node, "font-style", "normal"); - const char *font_weight = get_style_property_string(node, "font-weight", "normal"); + const char *font_family = string_from_property(match, "font-family", "serif"); + const char *font_variant = string_from_property(match, "font-variant", "normal"); + const char *font_style = string_from_property(match, "font-style", "normal"); + const char *font_weight = string_from_property(match, "font-weight", "normal"); style->font = fz_load_html_font(ctx, set, font_family, font_variant, font_style, font_weight); } } +/* + * Pretty printing + */ + +void +print_value(struct value *val) +{ + printf("%s", val->data); + if (val->args) + { + printf("("); + print_value(val->args); + printf(")"); + } + if (val->next) + { + printf(" "); + print_value(val->next); + } +} + +void +print_property(struct property *prop) +{ + printf("\t%s: ", prop->name); + print_value(prop->value); + printf(" !%d;\n", prop->spec); +} + +void +print_condition(struct condition *cond) +{ + if (cond->type == '=') + printf("[%s=%s]", cond->key, cond->val); + else if (cond->type == '[') + printf("[%s]", cond->key); + else + printf("%c%s", cond->type, cond->val); + if (cond->next) + print_condition(cond->next); +} + +void +print_selector(struct selector *sel) +{ + if (sel->combine) + { +putchar('('); + print_selector(sel->left); + if (sel->combine == ' ') + printf(" "); + else + printf(" %c ", sel->combine); + print_selector(sel->right); +putchar(')'); + } + else if (sel->name) + printf("%s", sel->name); + else + printf("*"); + if (sel->cond) + { + print_condition(sel->cond); + } +} + +void +print_rule(fz_css_rule *rule) +{ + struct selector *sel; + struct property *prop; + + for (sel = rule->selector; sel; sel = sel->next) + { + print_selector(sel); + printf(" !%d", selector_specificity(sel)); + if (sel->next) + printf(", "); + } + + printf("\n{\n"); + for (prop = rule->declaration; prop; prop = prop->next) + { + print_property(prop); + } + printf("}\n"); +} + +void +print_rules(fz_css_rule *rule) +{ + while (rule) + { + print_rule(rule); + rule = rule->next; + } +} + void print_style(struct computed_style *style) { diff --git a/source/html/css-parse.c b/source/html/css-parse.c index 35d11a1d..fbae49bb 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -1,5 +1,61 @@ #include "mupdf/html.h" +static fz_css_rule * +fz_new_css_rule(fz_context *ctx, struct selector *selector, struct property *declaration) +{ + fz_css_rule *rule = fz_malloc_struct(ctx, fz_css_rule); + rule->selector = selector; + rule->declaration = declaration; + rule->next = NULL; + return rule; +} + +static struct selector * +fz_new_css_selector(fz_context *ctx, const char *name) +{ + struct selector *sel = fz_malloc_struct(ctx, struct selector); + sel->name = name ? fz_strdup(ctx, name) : NULL; + sel->combine = 0; + sel->cond = NULL; + sel->left = NULL; + sel->right = NULL; + sel->next = NULL; + return sel; +} + +static struct condition * +fz_new_css_condition(fz_context *ctx, int type, const char *key, const char *val) +{ + struct condition *cond = fz_malloc_struct(ctx, struct condition); + cond->type = type; + cond->key = key ? fz_strdup(ctx, key) : NULL; + cond->val = val ? fz_strdup(ctx, val) : NULL; + cond->next = NULL; + return cond; +} + +static struct property * +fz_new_css_property(fz_context *ctx, const char *name, struct value *value, int spec) +{ + struct property *prop = fz_malloc_struct(ctx, struct property); + prop->name = fz_strdup(ctx, name); + prop->value = value; + prop->spec = spec; + prop->next = NULL; + return prop; +} + +static struct value * +fz_new_css_value(fz_context *ctx, int type, const char *data) +{ + struct value *val = fz_malloc_struct(ctx, struct value); + val->type = type; + val->data = fz_strdup(ctx, data); + val->args = NULL; + val->next = NULL; + return val; +} + struct lexbuf { fz_context *ctx; @@ -648,7 +704,7 @@ static struct selector *parse_selector_list(struct lexbuf *buf) return head; } -static struct rule *parse_rule(struct lexbuf *buf) +static fz_css_rule *parse_rule(struct lexbuf *buf) { struct selector *s; struct property *p; @@ -662,7 +718,7 @@ static struct rule *parse_rule(struct lexbuf *buf) static void parse_media_list(struct lexbuf *buf) { - struct rule *r; + fz_css_rule *r; while (buf->lookahead != '}' && buf->lookahead != EOF) { @@ -699,9 +755,9 @@ static void parse_at_rule(struct lexbuf *buf) } } -static struct rule *parse_stylesheet(struct lexbuf *buf, struct rule *chain) +static fz_css_rule *parse_stylesheet(struct lexbuf *buf, fz_css_rule *chain) { - struct rule *rule, **nextp, *tail; + fz_css_rule *rule, **nextp, *tail; tail = chain; if (tail) @@ -739,7 +795,7 @@ struct property *fz_parse_css_properties(fz_context *ctx, const char *source) return parse_declaration_list(&buf); } -struct rule *fz_parse_css(fz_context *ctx, struct rule *chain, const char *source) +fz_css_rule *fz_parse_css(fz_context *ctx, fz_css_rule *chain, const char *source) { struct lexbuf buf; css_lex_init(ctx, &buf, source); diff --git a/source/html/html-layout.c b/source/html/html-layout.c index 59719de5..cf3c1249 100644 --- a/source/html/html-layout.c +++ b/source/html/html-layout.c @@ -148,7 +148,7 @@ static void init_box(fz_context *ctx, struct box *box, fz_xml *node) box->flow_head = NULL; box->flow_tail = &box->flow_head; - default_computed_style(&box->style); + fz_default_css_style(ctx, &box->style); } static struct box *new_box(fz_context *ctx, fz_xml *node) @@ -247,29 +247,29 @@ static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) } static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const char *base_uri, - fz_xml *node, struct box *top, struct rule *rule, struct style *up_style) + fz_xml *node, struct box *top, fz_css_rule *rule, fz_css_match *up_match) { - struct style style; + fz_css_match match; struct box *box; const char *tag; int display; while (node) { - style.up = up_style; - style.count = 0; + match.up = up_match; + match.count = 0; tag = fz_xml_tag(node); if (tag) { - apply_styles(ctx, &style, rule, node); + fz_match_css(ctx, &match, rule, node); - display = fz_get_css_style_property_display(&style); + display = fz_get_css_match_display(&match); if (!strcmp(tag, "br")) { box = new_box(ctx, node); - compute_style(ctx, set, &box->style, &style); + fz_apply_css_style(ctx, set, &box->style, &match); top = insert_break_box(ctx, box, top); } @@ -279,7 +279,7 @@ static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *z if (src) { box = new_box(ctx, node); - compute_style(ctx, set, &box->style, &style); + fz_apply_css_style(ctx, set, &box->style, &match); insert_inline_box(ctx, box, top); generate_image(ctx, zip, base_uri, box, src); } @@ -288,7 +288,7 @@ static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *z else if (display != DIS_NONE) { box = new_box(ctx, node); - compute_style(ctx, set, &box->style, &style); + fz_apply_css_style(ctx, set, &box->style, &match); if (display == DIS_BLOCK) { @@ -309,7 +309,7 @@ static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *z } if (fz_xml_down(node)) - generate_boxes(ctx, set, zip, base_uri, fz_xml_down(node), box, rule, &style); + generate_boxes(ctx, set, zip, base_uri, fz_xml_down(node), box, rule, &match); // TODO: remove empty flow boxes } @@ -848,7 +848,7 @@ static char *concat_text(fz_context *ctx, fz_xml *root) return s; } -static struct rule *html_load_css(fz_context *ctx, fz_archive *zip, const char *base_uri, struct rule *css, fz_xml *root) +static fz_css_rule *html_load_css(fz_context *ctx, fz_archive *zip, const char *base_uri, fz_css_rule *css, fz_xml *root) { fz_xml *node; fz_buffer *buf; @@ -913,9 +913,9 @@ struct box * fz_generate_html(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const char *base_uri, fz_buffer *buf) { fz_xml *xml; - struct rule *css; + fz_css_rule *css; struct box *box; - struct style style; + fz_css_match match; printf("html: parsing XHTML.\n"); xml = fz_parse_xml(ctx, buf->data, buf->len, 1); @@ -929,10 +929,10 @@ fz_generate_html(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const printf("html: applying styles and generating boxes.\n"); box = new_box(ctx, NULL); - style.up = NULL; - style.count = 0; + match.up = NULL; + match.count = 0; - generate_boxes(ctx, set, zip, base_uri, xml, box, css, &style); + generate_boxes(ctx, set, zip, base_uri, xml, box, css, &match); return box; } -- cgit v1.2.3 From 3c88d1abef7ab287287a103fa617e50d54eece1d Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 26 Nov 2014 13:26:01 +0100 Subject: html: Remove useless fz_xml node field in box struct. --- source/html/html-layout.c | 71 +++++++---------------------------------------- 1 file changed, 10 insertions(+), 61 deletions(-) (limited to 'source/html') diff --git a/source/html/html-layout.c b/source/html/html-layout.c index cf3c1249..ceea468d 100644 --- a/source/html/html-layout.c +++ b/source/html/html-layout.c @@ -132,7 +132,7 @@ static void generate_image(fz_context *ctx, fz_archive *zip, const char *base_ur } } -static void init_box(fz_context *ctx, struct box *box, fz_xml *node) +static void init_box(fz_context *ctx, struct box *box) { box->type = BOX_BLOCK; box->x = box->y = 0; @@ -143,18 +143,16 @@ static void init_box(fz_context *ctx, struct box *box, fz_xml *node) box->down = NULL; box->next = NULL; - box->node = node; - box->flow_head = NULL; box->flow_tail = &box->flow_head; fz_default_css_style(ctx, &box->style); } -static struct box *new_box(fz_context *ctx, fz_xml *node) +static struct box *new_box(fz_context *ctx) { struct box *box = fz_malloc_struct(ctx, struct box); - init_box(ctx, box, node); + init_box(ctx, box); return box; } @@ -230,7 +228,7 @@ static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) } else { - struct box *flow = new_box(ctx, NULL); + struct box *flow = new_box(ctx); flow->is_first_flow = !top->last; insert_box(ctx, flow, BOX_FLOW, top); insert_box(ctx, box, BOX_INLINE, flow); @@ -268,7 +266,7 @@ static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *z if (!strcmp(tag, "br")) { - box = new_box(ctx, node); + box = new_box(ctx); fz_apply_css_style(ctx, set, &box->style, &match); top = insert_break_box(ctx, box, top); } @@ -278,7 +276,7 @@ static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *z const char *src = fz_xml_att(node, "src"); if (src) { - box = new_box(ctx, node); + box = new_box(ctx); fz_apply_css_style(ctx, set, &box->style, &match); insert_inline_box(ctx, box, top); generate_image(ctx, zip, base_uri, box, src); @@ -287,7 +285,7 @@ static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *z else if (display != DIS_NONE) { - box = new_box(ctx, node); + box = new_box(ctx); fz_apply_css_style(ctx, set, &box->style, &match); if (display == DIS_BLOCK) @@ -318,7 +316,7 @@ static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *z { if (top->type != BOX_INLINE) { - box = new_box(ctx, node); + box = new_box(ctx); insert_inline_box(ctx, box, top); box->style = top->style; generate_text(ctx, box, fz_xml_text(node)); @@ -637,55 +635,6 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa } } -static void indent(int level) -{ - while (level--) printf(" "); -} - -static void print_flow(fz_context *ctx, struct flow *flow, int level) -{ - while (flow) - { - printf("%-5d %-5d", (int)flow->x, (int)flow->y); - indent(level); - switch (flow->type) - { - case FLOW_WORD: printf("word \"%s\"\n", flow->text); break; - case FLOW_GLUE: printf("glue \"%s\" / \"%s\"\n", flow->text, flow->broken_text); break; - case FLOW_IMAGE: printf("image\n"); break; - } - flow = flow->next; - } -} - -static void print_box(fz_context *ctx, struct box *box, int level) -{ - while (box) - { - printf("%-5d %-5d", (int)box->x, (int)box->y); - indent(level); - switch (box->type) - { - case BOX_BLOCK: printf("block"); break; - case BOX_BREAK: printf("break"); break; - case BOX_FLOW: printf("flow"); break; - case BOX_INLINE: printf("inline"); break; - } - if (box->node) - { - const char *tag = fz_xml_tag(box->node); - if (tag) printf(" <%s>", tag); - else printf(" anonymous"); - } - printf("\n"); - if (box->down) - print_box(ctx, box->down, level + 1); -// if (box->flow_head) -// print_flow(ctx, box->flow_head, level + 1); - box = box->next; - } -} - static void draw_flow_box(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm) { @@ -900,7 +849,7 @@ fz_layout_html(fz_context *ctx, struct box *box, float w, float h, float em) printf("html: laying out text.\n"); - init_box(ctx, &page_box, NULL); + init_box(ctx, &page_box); page_box.w = w; page_box.h = 0; @@ -927,7 +876,7 @@ fz_generate_html(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const // print_rules(css); printf("html: applying styles and generating boxes.\n"); - box = new_box(ctx, NULL); + box = new_box(ctx); match.up = NULL; match.count = 0; -- cgit v1.2.3 From ce6e762510c9232d2594bd8d302c6d63f56dcff6 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 26 Nov 2014 13:36:38 +0100 Subject: html: Rename style, box and flow structs. --- source/html/css-apply.c | 6 ++-- source/html/epub-doc.c | 2 +- source/html/html-doc.c | 2 +- source/html/html-layout.c | 90 +++++++++++++++++++++++------------------------ 4 files changed, 49 insertions(+), 51 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index aa02a1b0..95099eda 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -757,7 +757,7 @@ white_space_from_property(fz_css_match *match) } void -fz_default_css_style(fz_context *ctx, struct computed_style *style) +fz_default_css_style(fz_context *ctx, fz_css_style *style) { memset(style, 0, sizeof *style); style->text_align = TA_LEFT; @@ -767,7 +767,7 @@ fz_default_css_style(fz_context *ctx, struct computed_style *style) } void -fz_apply_css_style(fz_context *ctx, fz_html_font_set *set, struct computed_style *style, fz_css_match *match) +fz_apply_css_style(fz_context *ctx, fz_html_font_set *set, fz_css_style *style, fz_css_match *match) { struct value *value; @@ -967,7 +967,7 @@ print_rules(fz_css_rule *rule) } void -print_style(struct computed_style *style) +print_style(fz_css_style *style) { printf("style {\n"); printf("\tfont-size = %g%c;\n", style->font_size.value, style->font_size.unit); diff --git a/source/html/epub-doc.c b/source/html/epub-doc.c index 11b43e0a..3ad81d66 100644 --- a/source/html/epub-doc.c +++ b/source/html/epub-doc.c @@ -22,7 +22,7 @@ struct epub_document_s struct epub_chapter_s { int start; - struct box *box; + fz_html_box *box; epub_chapter *next; }; diff --git a/source/html/html-doc.c b/source/html/html-doc.c index 11d21d56..531e61c4 100644 --- a/source/html/html-doc.c +++ b/source/html/html-doc.c @@ -13,7 +13,7 @@ struct html_document_s fz_archive *zip; fz_html_font_set *set; float page_w, page_h, em; - struct box *box; + fz_html_box *box; }; static void diff --git a/source/html/html-layout.c b/source/html/html-layout.c index ceea468d..412c4484 100644 --- a/source/html/html-layout.c +++ b/source/html/html-layout.c @@ -39,9 +39,9 @@ static int iswhite(int c) return c == ' ' || c == '\t' || c == '\r' || c == '\n'; } -static struct flow *add_flow(fz_context *ctx, struct box *top, struct computed_style *style, int type) +static fz_html_flow *add_flow(fz_context *ctx, fz_html_box *top, fz_css_style *style, int type) { - struct flow *flow = fz_malloc_struct(ctx, struct flow); + fz_html_flow *flow = fz_malloc_struct(ctx, fz_html_flow); flow->type = type; flow->style = style; *top->flow_tail = flow; @@ -49,9 +49,9 @@ static struct flow *add_flow(fz_context *ctx, struct box *top, struct computed_s return flow; } -static void add_flow_space(fz_context *ctx, struct box *top, struct computed_style *style) +static void add_flow_space(fz_context *ctx, fz_html_box *top, fz_css_style *style) { - struct flow *flow; + fz_html_flow *flow; /* delete space at the beginning of the line */ if (!top->flow_head) @@ -62,23 +62,23 @@ static void add_flow_space(fz_context *ctx, struct box *top, struct computed_sty flow->broken_text = ""; } -static void add_flow_word(fz_context *ctx, struct box *top, struct computed_style *style, const char *a, const char *b) +static void add_flow_word(fz_context *ctx, fz_html_box *top, fz_css_style *style, const char *a, const char *b) { - struct flow *flow = add_flow(ctx, top, style, FLOW_WORD); + fz_html_flow *flow = add_flow(ctx, top, style, FLOW_WORD); flow->text = fz_malloc(ctx, b - a + 1); memcpy(flow->text, a, b - a); flow->text[b - a] = 0; } -static void add_flow_image(fz_context *ctx, struct box *top, struct computed_style *style, fz_image *img) +static void add_flow_image(fz_context *ctx, fz_html_box *top, fz_css_style *style, fz_image *img) { - struct flow *flow = add_flow(ctx, top, style, FLOW_IMAGE); + fz_html_flow *flow = add_flow(ctx, top, style, FLOW_IMAGE); flow->image = fz_keep_image(ctx, img); } -static void generate_text(fz_context *ctx, struct box *box, const char *text) +static void generate_text(fz_context *ctx, fz_html_box *box, const char *text) { - struct box *flow = box; + fz_html_box *flow = box; while (flow->type != BOX_FLOW) flow = flow->up; @@ -101,13 +101,13 @@ static void generate_text(fz_context *ctx, struct box *box, const char *text) } } -static void generate_image(fz_context *ctx, fz_archive *zip, const char *base_uri, struct box *box, const char *src) +static void generate_image(fz_context *ctx, fz_archive *zip, const char *base_uri, fz_html_box *box, const char *src) { fz_image *img; fz_buffer *buf; char path[2048]; - struct box *flow = box; + fz_html_box *flow = box; while (flow->type != BOX_FLOW) flow = flow->up; @@ -132,7 +132,7 @@ static void generate_image(fz_context *ctx, fz_archive *zip, const char *base_ur } } -static void init_box(fz_context *ctx, struct box *box) +static void init_box(fz_context *ctx, fz_html_box *box) { box->type = BOX_BLOCK; box->x = box->y = 0; @@ -149,14 +149,14 @@ static void init_box(fz_context *ctx, struct box *box) fz_default_css_style(ctx, &box->style); } -static struct box *new_box(fz_context *ctx) +static fz_html_box *new_box(fz_context *ctx) { - struct box *box = fz_malloc_struct(ctx, struct box); + fz_html_box *box = fz_malloc_struct(ctx, fz_html_box); init_box(ctx, box); return box; } -static void insert_box(fz_context *ctx, struct box *box, int type, struct box *top) +static void insert_box(fz_context *ctx, fz_html_box *box, int type, fz_html_box *top) { box->type = type; @@ -176,7 +176,7 @@ static void insert_box(fz_context *ctx, struct box *box, int type, struct box *t } } -static struct box *insert_block_box(fz_context *ctx, struct box *box, struct box *top) +static fz_html_box *insert_block_box(fz_context *ctx, fz_html_box *box, fz_html_box *top) { if (top->type == BOX_BLOCK) { @@ -197,7 +197,7 @@ static struct box *insert_block_box(fz_context *ctx, struct box *box, struct box return top; } -static struct box *insert_break_box(fz_context *ctx, struct box *box, struct box *top) +static fz_html_box *insert_break_box(fz_context *ctx, fz_html_box *box, fz_html_box *top) { if (top->type == BOX_BLOCK) { @@ -218,7 +218,7 @@ static struct box *insert_break_box(fz_context *ctx, struct box *box, struct box return top; } -static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) +static void insert_inline_box(fz_context *ctx, fz_html_box *box, fz_html_box *top) { if (top->type == BOX_BLOCK) { @@ -228,7 +228,7 @@ static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) } else { - struct box *flow = new_box(ctx); + fz_html_box *flow = new_box(ctx); flow->is_first_flow = !top->last; insert_box(ctx, flow, BOX_FLOW, top); insert_box(ctx, box, BOX_INLINE, flow); @@ -245,10 +245,10 @@ static void insert_inline_box(fz_context *ctx, struct box *box, struct box *top) } static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const char *base_uri, - fz_xml *node, struct box *top, fz_css_rule *rule, fz_css_match *up_match) + fz_xml *node, fz_html_box *top, fz_css_rule *rule, fz_css_match *up_match) { fz_css_match match; - struct box *box; + fz_html_box *box; const char *tag; int display; @@ -331,7 +331,7 @@ static void generate_boxes(fz_context *ctx, fz_html_font_set *set, fz_archive *z } } -static void measure_image(fz_context *ctx, struct flow *node, float w, float h) +static void measure_image(fz_context *ctx, fz_html_flow *node, float w, float h) { float xs = 1, ys = 1, s = 1; node->x = 0; @@ -345,7 +345,7 @@ static void measure_image(fz_context *ctx, struct flow *node, float w, float h) node->h = node->image->h * s; } -static void measure_word(fz_context *ctx, struct flow *node, float em) +static void measure_word(fz_context *ctx, fz_html_flow *node, float em) { const char *s; int c, g; @@ -368,7 +368,7 @@ static void measure_word(fz_context *ctx, struct flow *node, float em) node->em = em; } -static float measure_line(struct flow *node, struct flow *end, float *baseline) +static float measure_line(fz_html_flow *node, fz_html_flow *end, float *baseline) { float max_a = 0, max_d = 0, h = 0; while (node != end) @@ -393,7 +393,7 @@ static float measure_line(struct flow *node, struct flow *end, float *baseline) return h; } -static void layout_line(fz_context *ctx, float indent, float page_w, float line_w, int align, struct flow *node, struct flow *end, struct box *box, float baseline) +static void layout_line(fz_context *ctx, float indent, float page_w, float line_w, int align, fz_html_flow *node, fz_html_flow *end, fz_html_box *box, float baseline) { float x = box->x + indent; float y = box->y + box->h; @@ -404,7 +404,7 @@ static void layout_line(fz_context *ctx, float indent, float page_w, float line_ if (align == TA_JUSTIFY) { - struct flow *it; + fz_html_flow *it; for (it = node; it != end; it = it->next) if (it->type == FLOW_GLUE) ++n; @@ -442,7 +442,7 @@ static void layout_line(fz_context *ctx, float indent, float page_w, float line_ } } -static struct flow *find_next_glue(struct flow *node, float *w) +static fz_html_flow *find_next_glue(fz_html_flow *node, float *w) { while (node && node->type == FLOW_GLUE) { @@ -457,7 +457,7 @@ static struct flow *find_next_glue(struct flow *node, float *w) return node; } -static struct flow *find_next_word(struct flow *node, float *w) +static fz_html_flow *find_next_word(fz_html_flow *node, float *w) { while (node && node->type == FLOW_GLUE) { @@ -467,9 +467,9 @@ static struct flow *find_next_word(struct flow *node, float *w) return node; } -static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float em, float page_h) +static void layout_flow(fz_context *ctx, fz_html_box *box, fz_html_box *top, float em, float page_h) { - struct flow *node, *line_start, *word_start, *word_end, *line_end; + fz_html_flow *node, *line_start, *word_start, *word_end, *line_end; float glue_w; float word_w; float line_w; @@ -545,9 +545,9 @@ static void layout_flow(fz_context *ctx, struct box *box, struct box *top, float } } -static void layout_block(fz_context *ctx, struct box *box, struct box *top, float em, float top_collapse_margin, float page_h) +static void layout_block(fz_context *ctx, fz_html_box *box, fz_html_box *top, float em, float top_collapse_margin, float page_h) { - struct box *child; + fz_html_box *child; float box_collapse_margin; int prev_br; @@ -635,10 +635,9 @@ static void layout_block(fz_context *ctx, struct box *box, struct box *top, floa } } -static void -draw_flow_box(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm) +static void draw_flow_box(fz_context *ctx, fz_html_box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm) { - struct flow *node; + fz_html_flow *node; fz_text *text; fz_matrix trm; const char *s; @@ -693,8 +692,7 @@ draw_flow_box(fz_context *ctx, struct box *box, float page_top, float page_bot, } } -static void -draw_rect(fz_context *ctx, fz_device *dev, const fz_matrix *ctm, float *rgba, float x0, float y0, float x1, float y1) +static void draw_rect(fz_context *ctx, fz_device *dev, const fz_matrix *ctm, float *rgba, float x0, float y0, float x1, float y1) { fz_path *path = fz_new_path(ctx); @@ -709,8 +707,7 @@ draw_rect(fz_context *ctx, fz_device *dev, const fz_matrix *ctm, float *rgba, fl fz_free_path(ctx, path); } -static void -draw_block_box(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm) +static void draw_block_box(fz_context *ctx, fz_html_box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *ctm) { float x0, y0, x1, y1; float color[4]; @@ -765,7 +762,7 @@ draw_block_box(fz_context *ctx, struct box *box, float page_top, float page_bot, } void -fz_draw_html(fz_context *ctx, struct box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *inctm) +fz_draw_html(fz_context *ctx, fz_html_box *box, float page_top, float page_bot, fz_device *dev, const fz_matrix *inctm) { fz_matrix ctm = *inctm; fz_pre_translate(&ctm, 0, -page_top); @@ -797,7 +794,8 @@ static char *concat_text(fz_context *ctx, fz_xml *root) return s; } -static fz_css_rule *html_load_css(fz_context *ctx, fz_archive *zip, const char *base_uri, fz_css_rule *css, fz_xml *root) +static fz_css_rule * +html_load_css(fz_context *ctx, fz_archive *zip, const char *base_uri, fz_css_rule *css, fz_xml *root) { fz_xml *node; fz_buffer *buf; @@ -843,9 +841,9 @@ static fz_css_rule *html_load_css(fz_context *ctx, fz_archive *zip, const char * } void -fz_layout_html(fz_context *ctx, struct box *box, float w, float h, float em) +fz_layout_html(fz_context *ctx, fz_html_box *box, float w, float h, float em) { - struct box page_box; + fz_html_box page_box; printf("html: laying out text.\n"); @@ -858,12 +856,12 @@ fz_layout_html(fz_context *ctx, struct box *box, float w, float h, float em) printf("html: finished.\n"); } -struct box * +fz_html_box * fz_generate_html(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const char *base_uri, fz_buffer *buf) { fz_xml *xml; fz_css_rule *css; - struct box *box; + fz_html_box *box; fz_css_match match; printf("html: parsing XHTML.\n"); -- cgit v1.2.3 From ff7694216fa480c7424b2b6698d08104a7b80e89 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 26 Nov 2014 13:53:24 +0100 Subject: html: Rename internal css structs. --- source/html/css-apply.c | 116 ++++++++++++++++++++++++------------------------ source/html/css-parse.c | 101 ++++++++++++++++++++--------------------- 2 files changed, 106 insertions(+), 111 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 95099eda..eba9bbc0 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -88,7 +88,7 @@ keyword_in_list(const char *name, const char **list, int n) */ static int -count_condition_ids(struct condition *cond) +count_condition_ids(fz_css_condition *cond) { int n = 0; while (cond) @@ -101,7 +101,7 @@ count_condition_ids(struct condition *cond) } static int -count_selector_ids(struct selector *sel) +count_selector_ids(fz_css_selector *sel) { int n = count_condition_ids(sel->cond); if (sel->left && sel->right) @@ -113,7 +113,7 @@ count_selector_ids(struct selector *sel) } static int -count_condition_atts(struct condition *cond) +count_condition_atts(fz_css_condition *cond) { int n = 0; while (cond) @@ -126,7 +126,7 @@ count_condition_atts(struct condition *cond) } static int -count_selector_atts(struct selector *sel) +count_selector_atts(fz_css_selector *sel) { int n = count_condition_atts(sel->cond); if (sel->left && sel->right) @@ -138,7 +138,7 @@ count_selector_atts(struct selector *sel) } static int -count_condition_names(struct condition *cond) +count_condition_names(fz_css_condition *cond) { int n = 0; while (cond) @@ -151,7 +151,7 @@ count_condition_names(struct condition *cond) } static int -count_selector_names(struct selector *sel) +count_selector_names(fz_css_selector *sel) { int n = count_condition_names(sel->cond); if (sel->left && sel->right) @@ -169,7 +169,7 @@ count_selector_names(struct selector *sel) #define INLINE_SPECIFICITY 1000 static int -selector_specificity(struct selector *sel) +selector_specificity(fz_css_selector *sel) { int b = count_selector_ids(sel); int c = count_selector_atts(sel); @@ -208,7 +208,7 @@ match_class_condition(fz_xml *node, const char *p) } static int -match_condition(struct condition *cond, fz_xml *node) +match_condition(fz_css_condition *cond, fz_xml *node) { if (!cond) return 1; @@ -224,7 +224,7 @@ match_condition(struct condition *cond, fz_xml *node) } static int -match_selector(struct selector *sel, fz_xml *node) +match_selector(fz_css_selector *sel, fz_xml *node) { if (!node) return 0; @@ -294,7 +294,7 @@ match_selector(struct selector *sel, fz_xml *node) */ static int -count_values(struct value *value) +count_values(fz_css_value *value) { int n = 0; while (value) @@ -305,10 +305,10 @@ count_values(struct value *value) return n; } -static void add_property(fz_css_match *match, const char *name, struct value *value, int spec); +static void add_property(fz_css_match *match, const char *name, fz_css_value *value, int spec); static void -add_shorthand_trbl(fz_css_match *match, struct value *value, int spec, +add_shorthand_trbl(fz_css_match *match, fz_css_value *value, int spec, const char *name_t, const char *name_r, const char *name_b, const char *name_l) { int n = count_values(value); @@ -323,8 +323,8 @@ add_shorthand_trbl(fz_css_match *match, struct value *value, int spec, if (n == 2) { - struct value *a = value; - struct value *b = value->next; + fz_css_value *a = value; + fz_css_value *b = value->next; add_property(match, name_t, a, spec); add_property(match, name_r, b, spec); @@ -334,9 +334,9 @@ add_shorthand_trbl(fz_css_match *match, struct value *value, int spec, if (n == 3) { - struct value *a = value; - struct value *b = value->next; - struct value *c = value->next->next; + fz_css_value *a = value; + fz_css_value *b = value->next; + fz_css_value *c = value->next->next; add_property(match, name_t, a, spec); add_property(match, name_r, b, spec); @@ -346,10 +346,10 @@ add_shorthand_trbl(fz_css_match *match, struct value *value, int spec, if (n == 4) { - struct value *a = value; - struct value *b = value->next; - struct value *c = value->next->next; - struct value *d = value->next->next->next; + fz_css_value *a = value; + fz_css_value *b = value->next; + fz_css_value *c = value->next->next; + fz_css_value *d = value->next->next->next; add_property(match, name_t, a, spec); add_property(match, name_r, b, spec); @@ -359,28 +359,28 @@ add_shorthand_trbl(fz_css_match *match, struct value *value, int spec, } static void -add_shorthand_margin(fz_css_match *match, struct value *value, int spec) +add_shorthand_margin(fz_css_match *match, fz_css_value *value, int spec) { add_shorthand_trbl(match, value, spec, "margin-top", "margin-right", "margin-bottom", "margin-left"); } static void -add_shorthand_padding(fz_css_match *match, struct value *value, int spec) +add_shorthand_padding(fz_css_match *match, fz_css_value *value, int spec) { add_shorthand_trbl(match, value, spec, "padding-top", "padding-right", "padding-bottom", "padding-left"); } static void -add_shorthand_border_width(fz_css_match *match, struct value *value, int spec) +add_shorthand_border_width(fz_css_match *match, fz_css_value *value, int spec) { add_shorthand_trbl(match, value, spec, "border-width-top", "border-width-right", "border-width-bottom", "border-width-left"); } static void -add_shorthand_border(fz_css_match *match, struct value *value, int spec) +add_shorthand_border(fz_css_match *match, fz_css_value *value, int spec) { while (value) { @@ -418,7 +418,7 @@ add_shorthand_border(fz_css_match *match, struct value *value, int spec) } static void -add_property(fz_css_match *match, const char *name, struct value *value, int spec) +add_property(fz_css_match *match, const char *name, fz_css_value *value, int spec) { int i; @@ -478,8 +478,8 @@ add_property(fz_css_match *match, const char *name, struct value *value, int spe void fz_match_css(fz_context *ctx, fz_css_match *match, fz_css_rule *rule, fz_xml *node) { - struct selector *sel; - struct property *prop; + fz_css_selector *sel; + fz_css_property *prop; const char *s; while (rule) @@ -511,7 +511,7 @@ fz_match_css(fz_context *ctx, fz_css_match *match, fz_css_rule *rule, fz_xml *no } } -static struct value * +static fz_css_value * value_from_raw_property(fz_css_match *match, const char *name) { int i; @@ -521,10 +521,10 @@ value_from_raw_property(fz_css_match *match, const char *name) return NULL; } -static struct value * +static fz_css_value * value_from_property(fz_css_match *match, const char *name) { - struct value *value; + fz_css_value *value; value = value_from_raw_property(match, name); if (match->up) @@ -540,24 +540,24 @@ value_from_property(fz_css_match *match, const char *name) static const char * string_from_property(fz_css_match *match, const char *name, const char *initial) { - struct value *value; + fz_css_value *value; value = value_from_property(match, name); if (!value) return initial; return value->data; } -static struct number +static fz_css_number make_number(float v, int u) { - struct number n; + fz_css_number n; n.value = v; n.unit = u; return n; } -static struct number -number_from_value(struct value *value, float initial, int initial_unit) +static fz_css_number +number_from_value(fz_css_value *value, float initial, int initial_unit) { char *p; @@ -599,16 +599,16 @@ number_from_value(struct value *value, float initial, int initial_unit) return make_number(initial, initial_unit); } -static struct number +static fz_css_number number_from_property(fz_css_match *match, const char *property, float initial, int initial_unit) { return number_from_value(value_from_property(match, property), initial, initial_unit); } -static struct number +static fz_css_number border_width_from_property(fz_css_match *match, const char *property) { - struct value *value = value_from_property(match, property); + fz_css_value *value = value_from_property(match, property); if (value) { if (!strcmp(value->data, "thin")) @@ -623,7 +623,7 @@ border_width_from_property(fz_css_match *match, const char *property) } float -fz_from_css_number(struct number number, float em, float width) +fz_from_css_number(fz_css_number number, float em, float width) { switch (number.unit) { default: @@ -634,7 +634,7 @@ fz_from_css_number(struct number number, float em, float width) } float -fz_from_css_number_scale(struct number number, float scale, float em, float width) +fz_from_css_number_scale(fz_css_number number, float scale, float em, float width) { switch (number.unit) { default: @@ -644,10 +644,10 @@ fz_from_css_number_scale(struct number number, float scale, float em, float widt } } -static struct color +static fz_css_color make_color(int r, int g, int b, int a) { - struct color c; + fz_css_color c; c.r = r; c.g = g; c.b = b; @@ -662,8 +662,8 @@ static int tohex(int c) return (c | 32) - 'a' + 10; } -static struct color -color_from_value(struct value *value, struct color initial) +static fz_css_color +color_from_value(fz_css_value *value, fz_css_color initial) { if (!value) return initial; @@ -717,8 +717,8 @@ color_from_value(struct value *value, struct color initial) return initial; } -static struct color -color_from_property(fz_css_match *match, const char *property, struct color initial) +static fz_css_color +color_from_property(fz_css_match *match, const char *property, fz_css_color initial) { return color_from_value(value_from_property(match, property), initial); } @@ -726,7 +726,7 @@ color_from_property(fz_css_match *match, const char *property, struct color init int fz_get_css_match_display(fz_css_match *match) { - struct value *value = value_from_property(match, "display"); + fz_css_value *value = value_from_property(match, "display"); if (value) { if (!strcmp(value->data, "none")) @@ -744,7 +744,7 @@ fz_get_css_match_display(fz_css_match *match) static int white_space_from_property(fz_css_match *match) { - struct value *value = value_from_property(match, "white-space"); + fz_css_value *value = value_from_property(match, "white-space"); if (value) { if (!strcmp(value->data, "normal")) return WS_NORMAL; @@ -769,10 +769,10 @@ fz_default_css_style(fz_context *ctx, fz_css_style *style) void fz_apply_css_style(fz_context *ctx, fz_html_font_set *set, fz_css_style *style, fz_css_match *match) { - struct value *value; + fz_css_value *value; - struct color black = { 0, 0, 0, 255 }; - struct color transparent = { 0, 0, 0, 0 }; + fz_css_color black = { 0, 0, 0, 255 }; + fz_css_color transparent = { 0, 0, 0, 0 }; fz_default_css_style(ctx, style); @@ -873,7 +873,7 @@ fz_apply_css_style(fz_context *ctx, fz_html_font_set *set, fz_css_style *style, */ void -print_value(struct value *val) +print_value(fz_css_value *val) { printf("%s", val->data); if (val->args) @@ -890,7 +890,7 @@ print_value(struct value *val) } void -print_property(struct property *prop) +print_property(fz_css_property *prop) { printf("\t%s: ", prop->name); print_value(prop->value); @@ -898,7 +898,7 @@ print_property(struct property *prop) } void -print_condition(struct condition *cond) +print_condition(fz_css_condition *cond) { if (cond->type == '=') printf("[%s=%s]", cond->key, cond->val); @@ -911,7 +911,7 @@ print_condition(struct condition *cond) } void -print_selector(struct selector *sel) +print_selector(fz_css_selector *sel) { if (sel->combine) { @@ -937,8 +937,8 @@ putchar(')'); void print_rule(fz_css_rule *rule) { - struct selector *sel; - struct property *prop; + fz_css_selector *sel; + fz_css_property *prop; for (sel = rule->selector; sel; sel = sel->next) { diff --git a/source/html/css-parse.c b/source/html/css-parse.c index fbae49bb..aaf0a623 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -1,7 +1,17 @@ #include "mupdf/html.h" -static fz_css_rule * -fz_new_css_rule(fz_context *ctx, struct selector *selector, struct property *declaration) +struct lexbuf +{ + fz_context *ctx; + const char *s; + int lookahead; + int c; + int color; + int string_len; + char string[1024]; +}; + +static fz_css_rule *fz_new_css_rule(fz_context *ctx, fz_css_selector *selector, fz_css_property *declaration) { fz_css_rule *rule = fz_malloc_struct(ctx, fz_css_rule); rule->selector = selector; @@ -10,10 +20,9 @@ fz_new_css_rule(fz_context *ctx, struct selector *selector, struct property *dec return rule; } -static struct selector * -fz_new_css_selector(fz_context *ctx, const char *name) +static fz_css_selector *fz_new_css_selector(fz_context *ctx, const char *name) { - struct selector *sel = fz_malloc_struct(ctx, struct selector); + fz_css_selector *sel = fz_malloc_struct(ctx, fz_css_selector); sel->name = name ? fz_strdup(ctx, name) : NULL; sel->combine = 0; sel->cond = NULL; @@ -23,10 +32,9 @@ fz_new_css_selector(fz_context *ctx, const char *name) return sel; } -static struct condition * -fz_new_css_condition(fz_context *ctx, int type, const char *key, const char *val) +static fz_css_condition *fz_new_css_condition(fz_context *ctx, int type, const char *key, const char *val) { - struct condition *cond = fz_malloc_struct(ctx, struct condition); + fz_css_condition *cond = fz_malloc_struct(ctx, fz_css_condition); cond->type = type; cond->key = key ? fz_strdup(ctx, key) : NULL; cond->val = val ? fz_strdup(ctx, val) : NULL; @@ -34,10 +42,9 @@ fz_new_css_condition(fz_context *ctx, int type, const char *key, const char *val return cond; } -static struct property * -fz_new_css_property(fz_context *ctx, const char *name, struct value *value, int spec) +static fz_css_property *fz_new_css_property(fz_context *ctx, const char *name, fz_css_value *value, int spec) { - struct property *prop = fz_malloc_struct(ctx, struct property); + fz_css_property *prop = fz_malloc_struct(ctx, fz_css_property); prop->name = fz_strdup(ctx, name); prop->value = value; prop->spec = spec; @@ -45,10 +52,9 @@ fz_new_css_property(fz_context *ctx, const char *name, struct value *value, int return prop; } -static struct value * -fz_new_css_value(fz_context *ctx, int type, const char *data) +static fz_css_value *fz_new_css_value(fz_context *ctx, int type, const char *data) { - struct value *val = fz_malloc_struct(ctx, struct value); + fz_css_value *val = fz_malloc_struct(ctx, fz_css_value); val->type = type; val->data = fz_strdup(ctx, data); val->args = NULL; @@ -56,17 +62,6 @@ fz_new_css_value(fz_context *ctx, int type, const char *data) return val; } -struct lexbuf -{ - fz_context *ctx; - const char *s; - int lookahead; - int c; - int color; - int string_len; - char string[1024]; -}; - static void css_lex_next(struct lexbuf *buf) { // buf->s += fz_chartorune(&buf->c, buf->s); @@ -421,11 +416,11 @@ static int iscond(int t) return t == ':' || t == '.' || t == '#' || t == '['; } -static struct value *parse_value_list(struct lexbuf *buf); +static fz_css_value *parse_value_list(struct lexbuf *buf); -static struct value *parse_value(struct lexbuf *buf) +static fz_css_value *parse_value(struct lexbuf *buf) { - struct value *v; + fz_css_value *v; if (buf->lookahead == CSS_KEYWORD) { @@ -463,9 +458,9 @@ static struct value *parse_value(struct lexbuf *buf) fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected value"); } -static struct value *parse_value_list(struct lexbuf *buf) +static fz_css_value *parse_value_list(struct lexbuf *buf) { - struct value *head, *tail; + fz_css_value *head, *tail; head = tail = NULL; @@ -481,9 +476,9 @@ static struct value *parse_value_list(struct lexbuf *buf) return head; } -static struct property *parse_declaration(struct lexbuf *buf) +static fz_css_property *parse_declaration(struct lexbuf *buf) { - struct property *p; + fz_css_property *p; if (buf->lookahead != CSS_KEYWORD) fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected keyword in property"); @@ -501,9 +496,9 @@ static struct property *parse_declaration(struct lexbuf *buf) return p; } -static struct property *parse_declaration_list(struct lexbuf *buf) +static fz_css_property *parse_declaration_list(struct lexbuf *buf) { - struct property *head, *tail; + fz_css_property *head, *tail; if (buf->lookahead == '}' || buf->lookahead == EOF) return NULL; @@ -535,9 +530,9 @@ static const char *parse_attrib_value(struct lexbuf *buf) fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected attribute value"); } -static struct condition *parse_condition(struct lexbuf *buf) +static fz_css_condition *parse_condition(struct lexbuf *buf) { - struct condition *c; + fz_css_condition *c; if (accept(buf, ':')) { @@ -600,9 +595,9 @@ static struct condition *parse_condition(struct lexbuf *buf) fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected condition"); } -static struct condition *parse_condition_list(struct lexbuf *buf) +static fz_css_condition *parse_condition_list(struct lexbuf *buf) { - struct condition *head, *tail; + fz_css_condition *head, *tail; head = tail = parse_condition(buf); while (iscond(buf->lookahead)) @@ -612,9 +607,9 @@ static struct condition *parse_condition_list(struct lexbuf *buf) return head; } -static struct selector *parse_simple_selector(struct lexbuf *buf) +static fz_css_selector *parse_simple_selector(struct lexbuf *buf) { - struct selector *s; + fz_css_selector *s; if (accept(buf, '*')) { @@ -641,9 +636,9 @@ static struct selector *parse_simple_selector(struct lexbuf *buf) fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected selector"); } -static struct selector *parse_adjacent_selector(struct lexbuf *buf) +static fz_css_selector *parse_adjacent_selector(struct lexbuf *buf) { - struct selector *s, *a, *b; + fz_css_selector *s, *a, *b; a = parse_simple_selector(buf); if (accept(buf, '+')) @@ -658,9 +653,9 @@ static struct selector *parse_adjacent_selector(struct lexbuf *buf) return a; } -static struct selector *parse_child_selector(struct lexbuf *buf) +static fz_css_selector *parse_child_selector(struct lexbuf *buf) { - struct selector *s, *a, *b; + fz_css_selector *s, *a, *b; a = parse_adjacent_selector(buf); if (accept(buf, '>')) @@ -675,9 +670,9 @@ static struct selector *parse_child_selector(struct lexbuf *buf) return a; } -static struct selector *parse_descendant_selector(struct lexbuf *buf) +static fz_css_selector *parse_descendant_selector(struct lexbuf *buf) { - struct selector *s, *a, *b; + fz_css_selector *s, *a, *b; a = parse_child_selector(buf); if (buf->lookahead != ',' && buf->lookahead != '{' && buf->lookahead != EOF) @@ -692,9 +687,9 @@ static struct selector *parse_descendant_selector(struct lexbuf *buf) return a; } -static struct selector *parse_selector_list(struct lexbuf *buf) +static fz_css_selector *parse_selector_list(struct lexbuf *buf) { - struct selector *head, *tail; + fz_css_selector *head, *tail; head = tail = parse_descendant_selector(buf); while (accept(buf, ',')) @@ -706,8 +701,8 @@ static struct selector *parse_selector_list(struct lexbuf *buf) static fz_css_rule *parse_rule(struct lexbuf *buf) { - struct selector *s; - struct property *p; + fz_css_selector *s; + fz_css_property *p; s = parse_selector_list(buf); expect(buf, '{'); @@ -729,8 +724,8 @@ static void parse_media_list(struct lexbuf *buf) static void parse_at_rule(struct lexbuf *buf) { - struct property *p; - struct value *v; + fz_css_property *p; + fz_css_value *v; expect(buf, CSS_KEYWORD); if (accept(buf, '{')) /* @page */ @@ -787,7 +782,7 @@ static fz_css_rule *parse_stylesheet(struct lexbuf *buf, fz_css_rule *chain) return chain ? chain : tail; } -struct property *fz_parse_css_properties(fz_context *ctx, const char *source) +fz_css_property *fz_parse_css_properties(fz_context *ctx, const char *source) { struct lexbuf buf; css_lex_init(ctx, &buf, source); -- cgit v1.2.3 From c4a45e25b92269e9e44594fd410b272718d939bc Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 26 Nov 2014 16:27:20 +0100 Subject: html: Free css structures. --- source/html/css-apply.c | 2 +- source/html/css-parse.c | 74 +++++++++++++++++++++++++++++++++++++++++++---- source/html/epub-doc.c | 17 ++++++++--- source/html/html-doc.c | 1 + source/html/html-layout.c | 29 +++++++++++++++++++ 5 files changed, 112 insertions(+), 11 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index eba9bbc0..81308c82 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -507,7 +507,7 @@ fz_match_css(fz_context *ctx, fz_css_match *match, fz_css_rule *rule, fz_xml *no add_property(match, prop->name, prop->value, INLINE_SPECIFICITY); prop = prop->next; } - // TODO: free props + // TODO: free props (hitch a ride with fz_css_rule?) } } diff --git a/source/html/css-parse.c b/source/html/css-parse.c index aaf0a623..0b12319f 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -62,6 +62,68 @@ static fz_css_value *fz_new_css_value(fz_context *ctx, int type, const char *dat return val; } +static void fz_free_css_value(fz_context *ctx, fz_css_value *val) +{ + while (val) + { + fz_css_value *next = val->next; + fz_free_css_value(ctx, val->args); + fz_free(ctx, val->data); + fz_free(ctx, val); + val = next; + } +} + +static void fz_free_css_condition(fz_context *ctx, fz_css_condition *cond) +{ + while (cond) + { + fz_css_condition *next = cond->next; + fz_free(ctx, cond->key); + fz_free(ctx, cond->val); + fz_free(ctx, cond); + cond = next; + } +} + +static void fz_free_css_selector(fz_context *ctx, fz_css_selector *sel) +{ + while (sel) + { + fz_css_selector *next = sel->next; + fz_free(ctx, sel->name); + fz_free_css_condition(ctx, sel->cond); + fz_free_css_selector(ctx, sel->left); + fz_free_css_selector(ctx, sel->right); + fz_free(ctx, sel); + sel = next; + } +} + +static void fz_free_css_property(fz_context *ctx, fz_css_property *prop) +{ + while (prop) + { + fz_css_property *next = prop->next; + fz_free(ctx, prop->name); + fz_free_css_value(ctx, prop->value); + fz_free(ctx, prop); + prop = next; + } +} + +void fz_free_css(fz_context *ctx, fz_css_rule *rule) +{ + while (rule) + { + fz_css_rule *next = rule->next; + fz_free_css_selector(ctx, rule->selector); + fz_free_css_property(ctx, rule->declaration); + fz_free(ctx, rule); + rule = next; + } +} + static void css_lex_next(struct lexbuf *buf) { // buf->s += fz_chartorune(&buf->c, buf->s); @@ -516,13 +578,13 @@ static fz_css_property *parse_declaration_list(struct lexbuf *buf) return head; } -static const char *parse_attrib_value(struct lexbuf *buf) +static char *parse_attrib_value(struct lexbuf *buf) { - const char *s; + char *s; if (buf->lookahead == CSS_KEYWORD || buf->lookahead == CSS_STRING) { - s = strdup(buf->string); + s = fz_strdup(buf->ctx, buf->string); next(buf); return s; } @@ -718,7 +780,7 @@ static void parse_media_list(struct lexbuf *buf) while (buf->lookahead != '}' && buf->lookahead != EOF) { r = parse_rule(buf); - // TODO: free_rule(r); + fz_free_css(buf->ctx, r); } } @@ -731,13 +793,13 @@ static void parse_at_rule(struct lexbuf *buf) if (accept(buf, '{')) /* @page */ { p = parse_declaration_list(buf); - // TODO: free_properties(p); + fz_free_css_property(buf->ctx, p); expect(buf, '}'); } else { v = parse_value_list(buf); - // TODO: free_value_list(v); + fz_free_css_value(buf->ctx, v); if (accept(buf, '{')) /* @media */ { parse_media_list(buf); diff --git a/source/html/epub-doc.c b/source/html/epub-doc.c index 3ad81d66..811e217e 100644 --- a/source/html/epub-doc.c +++ b/source/html/epub-doc.c @@ -95,10 +95,19 @@ epub_run_page(epub_document *doc, epub_page *page, fz_device *dev, const fz_matr static void epub_close_document(epub_document *doc) { - /* TODO:free all chapters */ - fz_close_archive(doc->ctx, doc->zip); - fz_free_html_font_set(doc->ctx, doc->set); - fz_free(doc->ctx, doc); + fz_context *ctx = doc->ctx; + epub_chapter *ch, *next; + ch = doc->spine; + while (ch) + { + next = ch->next; + fz_free_html(ctx, ch->box); + fz_free(ctx, ch); + ch = next; + } + fz_close_archive(ctx, doc->zip); + fz_free_html_font_set(ctx, doc->set); + fz_free(ctx, doc); } static const char * diff --git a/source/html/html-doc.c b/source/html/html-doc.c index 531e61c4..688a9f88 100644 --- a/source/html/html-doc.c +++ b/source/html/html-doc.c @@ -20,6 +20,7 @@ static void htdoc_close_document(html_document *doc) { fz_close_archive(doc->ctx, doc->zip); + fz_free_html(doc->ctx, doc->box); fz_free_html_font_set(doc->ctx, doc->set); fz_free(doc->ctx, doc); } diff --git a/source/html/html-layout.c b/source/html/html-layout.c index 412c4484..7e1662c3 100644 --- a/source/html/html-layout.c +++ b/source/html/html-layout.c @@ -39,6 +39,20 @@ static int iswhite(int c) return c == ' ' || c == '\t' || c == '\r' || c == '\n'; } +static void fz_free_html_flow(fz_context *ctx, fz_html_flow *flow) +{ + while (flow) + { + fz_html_flow *next = flow->next; + if (flow->type == FLOW_WORD) + fz_free(ctx, flow->text); + if (flow->type == FLOW_IMAGE) + fz_drop_image(ctx, flow->image); + fz_free(ctx, flow); + flow = next; + } +} + static fz_html_flow *add_flow(fz_context *ctx, fz_html_box *top, fz_css_style *style, int type) { fz_html_flow *flow = fz_malloc_struct(ctx, fz_html_flow); @@ -149,6 +163,18 @@ static void init_box(fz_context *ctx, fz_html_box *box) fz_default_css_style(ctx, &box->style); } +void fz_free_html(fz_context *ctx, fz_html_box *box) +{ + while (box) + { + fz_html_box *next = box->next; + fz_free_html_flow(ctx, box->flow_head); + fz_free_html(ctx, box->down); + fz_free(ctx, box); + box = next; + } +} + static fz_html_box *new_box(fz_context *ctx) { fz_html_box *box = fz_malloc_struct(ctx, fz_html_box); @@ -881,5 +907,8 @@ fz_generate_html(fz_context *ctx, fz_html_font_set *set, fz_archive *zip, const generate_boxes(ctx, set, zip, base_uri, xml, box, css, &match); + fz_free_css(ctx, css); + fz_free_xml(ctx, xml); + return box; } -- cgit v1.2.3 From f1bfe4b861621ad7554670acf91cb029e4482569 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 26 Nov 2014 17:26:51 +0100 Subject: html: Free inline style properties at the end. --- source/html/css-apply.c | 15 +++++++++------ source/html/css-parse.c | 2 ++ 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'source/html') diff --git a/source/html/css-apply.c b/source/html/css-apply.c index 81308c82..48d4f04d 100644 --- a/source/html/css-apply.c +++ b/source/html/css-apply.c @@ -476,13 +476,14 @@ add_property(fz_css_match *match, const char *name, fz_css_value *value, int spe } void -fz_match_css(fz_context *ctx, fz_css_match *match, fz_css_rule *rule, fz_xml *node) +fz_match_css(fz_context *ctx, fz_css_match *match, fz_css_rule *css, fz_xml *node) { + fz_css_rule *rule; fz_css_selector *sel; - fz_css_property *prop; + fz_css_property *prop, *head, *tail; const char *s; - while (rule) + for (rule = css; rule; rule = rule->next) { sel = rule->selector; while (sel) @@ -495,19 +496,21 @@ fz_match_css(fz_context *ctx, fz_css_match *match, fz_css_rule *rule, fz_xml *no } sel = sel->next; } - rule = rule->next; } s = fz_xml_att(node, "style"); if (s) { - prop = fz_parse_css_properties(ctx, s); + head = tail = prop = fz_parse_css_properties(ctx, s); while (prop) { add_property(match, prop->name, prop->value, INLINE_SPECIFICITY); + tail = prop; prop = prop->next; } - // TODO: free props (hitch a ride with fz_css_rule?) + if (tail) + tail->next = css->garbage; + css->garbage = head; } } diff --git a/source/html/css-parse.c b/source/html/css-parse.c index 0b12319f..a751903d 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -16,6 +16,7 @@ static fz_css_rule *fz_new_css_rule(fz_context *ctx, fz_css_selector *selector, fz_css_rule *rule = fz_malloc_struct(ctx, fz_css_rule); rule->selector = selector; rule->declaration = declaration; + rule->garbage = NULL; rule->next = NULL; return rule; } @@ -119,6 +120,7 @@ void fz_free_css(fz_context *ctx, fz_css_rule *rule) fz_css_rule *next = rule->next; fz_free_css_selector(ctx, rule->selector); fz_free_css_property(ctx, rule->declaration); + fz_free_css_property(ctx, rule->garbage); fz_free(ctx, rule); rule = next; } -- cgit v1.2.3 From 602146c0c833d7cb41f9d369047e36a2f412f40a Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Thu, 27 Nov 2014 15:55:12 +0100 Subject: html: Record line number and source file for CSS error messages. --- source/html/css-parse.c | 51 +++++++++++++++++++++++++++-------------------- source/html/html-layout.c | 6 +++--- 2 files changed, 32 insertions(+), 25 deletions(-) (limited to 'source/html') diff --git a/source/html/css-parse.c b/source/html/css-parse.c index a751903d..e0bdc616 100644 --- a/source/html/css-parse.c +++ b/source/html/css-parse.c @@ -4,6 +4,8 @@ struct lexbuf { fz_context *ctx; const char *s; + const char *file; + int line; int lookahead; int c; int color; @@ -11,6 +13,11 @@ struct lexbuf char string[1024]; }; +FZ_NORETURN static void fz_css_error(struct lexbuf *buf, const char *msg) +{ + fz_throw(buf->ctx, FZ_ERROR_GENERIC, "css syntax error: %s (%s:%d)", msg, buf->file, buf->line); +} + static fz_css_rule *fz_new_css_rule(fz_context *ctx, fz_css_selector *selector, fz_css_property *declaration) { fz_css_rule *rule = fz_malloc_struct(ctx, fz_css_rule); @@ -128,15 +135,18 @@ void fz_free_css(fz_context *ctx, fz_css_rule *rule) static void css_lex_next(struct lexbuf *buf) { - // buf->s += fz_chartorune(&buf->c, buf->s); buf->c = *(buf->s++); + if (buf->c == '\n') + ++buf->line; } -static void css_lex_init(fz_context *ctx, struct lexbuf *buf, const char *s) +static void css_lex_init(fz_context *ctx, struct lexbuf *buf, const char *s, const char *file, int line) { buf->ctx = ctx; buf->s = s; buf->c = 0; + buf->file = file; + buf->line = line; css_lex_next(buf); buf->color = 0; @@ -163,7 +173,7 @@ static int isnmchar(int c) static void css_push_char(struct lexbuf *buf, int c) { if (buf->string_len + 1 >= nelem(buf->string)) - fz_throw(buf->ctx, FZ_ERROR_GENERIC, "token too long"); + fz_css_error(buf, "token too long"); buf->string[buf->string_len++] = c; } @@ -180,7 +190,7 @@ static int css_lex_accept(struct lexbuf *buf, int t) static void css_lex_expect(struct lexbuf *buf, int t) { if (!css_lex_accept(buf, t)) - fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected '%c'", t); + fz_css_error(buf, "unexpected character"); } static int ishex(int c, int *v) @@ -333,7 +343,7 @@ restart: } css_lex_next(buf); } - fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: unterminated comment"); + fz_css_error(buf, "unterminated comment"); } return '/'; } @@ -400,7 +410,7 @@ restart: sprintf(buf->string, "%06x", buf->color); // XXX return CSS_COLOR; colorerror: - fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error in color"); + fz_css_error(buf, "invalid color"); } if (css_lex_accept(buf, '"')) @@ -469,10 +479,7 @@ static void expect(struct lexbuf *buf, int t) { if (accept(buf, t)) return; - if (t < 256) - fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected '%c'", t); - else - fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: unexpected token"); + fz_css_error(buf, "unexpected token"); } static int iscond(int t) @@ -519,7 +526,7 @@ static fz_css_value *parse_value(struct lexbuf *buf) if (accept(buf, '/')) return fz_new_css_value(buf->ctx, '/', "/"); - fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected value"); + fz_css_error(buf, "expected value"); } static fz_css_value *parse_value_list(struct lexbuf *buf) @@ -545,7 +552,7 @@ static fz_css_property *parse_declaration(struct lexbuf *buf) fz_css_property *p; if (buf->lookahead != CSS_KEYWORD) - fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected keyword in property"); + fz_css_error(buf, "expected keyword in property"); p = fz_new_css_property(buf->ctx, buf->string, NULL, 0); next(buf); @@ -591,7 +598,7 @@ static char *parse_attrib_value(struct lexbuf *buf) return s; } - fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected attribute value"); + fz_css_error(buf, "expected attribute value"); } static fz_css_condition *parse_condition(struct lexbuf *buf) @@ -601,7 +608,7 @@ static fz_css_condition *parse_condition(struct lexbuf *buf) if (accept(buf, ':')) { if (buf->lookahead != CSS_KEYWORD) - fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected keyword after ':'"); + fz_css_error(buf, "expected keyword after ':'"); c = fz_new_css_condition(buf->ctx, ':', "pseudo", buf->string); next(buf); return c; @@ -610,7 +617,7 @@ static fz_css_condition *parse_condition(struct lexbuf *buf) if (accept(buf, '.')) { if (buf->lookahead != CSS_KEYWORD) - fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected keyword after '.'"); + fz_css_error(buf, "expected keyword after '.'"); c = fz_new_css_condition(buf->ctx, '.', "class", buf->string); next(buf); return c; @@ -619,7 +626,7 @@ static fz_css_condition *parse_condition(struct lexbuf *buf) if (accept(buf, '#')) { if (buf->lookahead != CSS_KEYWORD) - fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected keyword after '#'"); + fz_css_error(buf, "expected keyword after '#'"); c = fz_new_css_condition(buf->ctx, '#', "id", buf->string); next(buf); return c; @@ -628,7 +635,7 @@ static fz_css_condition *parse_condition(struct lexbuf *buf) if (accept(buf, '[')) { if (buf->lookahead != CSS_KEYWORD) - fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected keyword after '['"); + fz_css_error(buf, "expected keyword after '['"); c = fz_new_css_condition(buf->ctx, '[', buf->string, NULL); next(buf); @@ -656,7 +663,7 @@ static fz_css_condition *parse_condition(struct lexbuf *buf) return c; } - fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected condition"); + fz_css_error(buf, "expected condition"); } static fz_css_condition *parse_condition_list(struct lexbuf *buf) @@ -697,7 +704,7 @@ static fz_css_selector *parse_simple_selector(struct lexbuf *buf) return s; } - fz_throw(buf->ctx, FZ_ERROR_GENERIC, "syntax error: expected selector"); + fz_css_error(buf, "expected selector"); } static fz_css_selector *parse_adjacent_selector(struct lexbuf *buf) @@ -849,15 +856,15 @@ static fz_css_rule *parse_stylesheet(struct lexbuf *buf, fz_css_rule *chain) fz_css_property *fz_parse_css_properties(fz_context *ctx, const char *source) { struct lexbuf buf; - css_lex_init(ctx, &buf, source); + css_lex_init(ctx, &buf, source, "", 1); next(&buf); return parse_declaration_list(&buf); } -fz_css_rule *fz_parse_css(fz_context *ctx, fz_css_rule *chain, const char *source) +fz_css_rule *fz_parse_css(fz_context *ctx, fz_css_rule *chain, const char *source, const char *file, int line) { struct lexbuf buf; - css_lex_init(ctx, &buf, source); + css_lex_init(ctx, &buf, source, file, line); next(&buf); return parse_stylesheet(&buf, chain); } diff --git a/source/html/html-layout.c b/source/html/html-layout.c index 7e1662c3..ca67e030 100644 --- a/source/html/html-layout.c +++ b/source/html/html-layout.c @@ -848,7 +848,7 @@ html_load_css(fz_context *ctx, fz_archive *zip, const char *base_uri, fz_css_rul buf = fz_read_archive_entry(ctx, zip, path); fz_write_buffer_byte(ctx, buf, 0); - css = fz_parse_css(ctx, css, (char*)buf->data); + css = fz_parse_css(ctx, css, (char*)buf->data, path, 1); fz_drop_buffer(ctx, buf); } } @@ -857,7 +857,7 @@ html_load_css(fz_context *ctx, fz_archive *zip, const char *base_uri, fz_css_rul if (tag && !strcmp(tag, "style")) { char *s = concat_text(ctx, node); - css = fz_parse_css(ctx, css, s); + css = fz_parse_css(ctx, css, s, "