diff options
author | Tor Andersson <tor.andersson@artifex.com> | 2014-11-04 14:27:32 +0100 |
---|---|---|
committer | Tor Andersson <tor.andersson@artifex.com> | 2014-12-03 12:25:51 +0100 |
commit | d05e5e738f22b914607900b8d1f2e38670e2ba24 (patch) | |
tree | d457c05c9e2d7f09acb1a7b2ce103edf53d8ec43 | |
parent | 24c8a6cca270c27a4940ed7398ec01664e488e6f (diff) | |
download | mupdf-d05e5e738f22b914607900b8d1f2e38670e2ba24.tar.xz |
html: Partially compute styles when generating boxes.
Resolve final width and em-scaled numbers at layout time.
-rw-r--r-- | include/mupdf/html.h | 31 | ||||
-rw-r--r-- | source/html/css-apply.c | 151 | ||||
-rw-r--r-- | source/html/handler.c | 15 | ||||
-rw-r--r-- | source/html/layout.c | 92 |
4 files changed, 168 insertions, 121 deletions
diff --git a/include/mupdf/html.h b/include/mupdf/html.h index 868014d0..613ab65c 100644 --- a/include/mupdf/html.h +++ b/include/mupdf/html.h @@ -4,19 +4,21 @@ #include "mupdf/fitz.h" typedef struct html_document_s html_document; -typedef struct html_page_s html_page; +typedef struct box html_page; struct html_document_s { fz_document super; fz_context *ctx; - fz_xml *root; + fz_xml *xml; + struct box *box; }; html_document *html_open_document(fz_context *ctx, const char *filename); html_document *html_open_document_with_stream(fz_context *ctx, fz_stream *file); void html_layout_document(html_document *doc, float w, float h); +void html_run_box(fz_context *ctx, struct box *page, fz_device *dev, const fz_matrix *ctm); enum { @@ -97,6 +99,14 @@ enum { TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY }; enum { TOP, RIGHT, BOTTOM, LEFT }; +enum { N_NUMBER='p', N_SCALE='m', N_PERCENT='%' }; + +struct number +{ + float value; + int unit; +}; + struct color { unsigned char r, g, b; @@ -105,24 +115,25 @@ struct color struct computed_style { int position; - float top, right, bottom, left; - float margin[4]; - float padding[4]; - float border_width[4]; + struct number top, right, bottom, left; + struct number margin[4]; + struct number padding[4]; + struct number border_width[4]; int border_style; struct color border_color; struct color color; struct color background_color; const char *font_family; int bold, italic, smallcaps; - float font_size; - float line_height; + struct number font_size; + struct number line_height; int vertical_align; int text_align; - float text_indent; + struct number text_indent; }; void apply_styles(fz_context *ctx, struct style *style, struct rule *rule, fz_xml *node); -void compute_style(struct computed_style *cstyle, struct style *style, float width); +void compute_style(struct computed_style *cstyle, struct style *style); +float from_number(struct number, float em, float width); #endif 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: <br> // TODO: <img> @@ -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; } |