#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: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}" "u,ins{text-decoration:underline}" "center{text-align:center}" "svg{display:none}"; 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]; int bold, italic; 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->bold = cstyle->bold; box->italic = cstyle->italic; } 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 **topp, struct computed_style *cstyle, fz_xml *node) { struct box *top = *topp; struct box *box; if (top->type == BOX_BLOCK) { box = new_box(ctx, top, BOX_BLOCK, cstyle, node); } 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); } 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); } 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 *top, struct style *up_style, struct rule *rule) { struct style style; struct computed_style cstyle; struct box *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) { if (cstyle.display == BLOCK) { box = new_block_box(ctx, &top, &cstyle, node); } else if (cstyle.display == INLINE) { box = new_inline_box(ctx, top, &cstyle, node); } else { fz_warn(ctx, "unknown box display type"); box = new_box(ctx, top, BOX_BLOCK, &cstyle, node); } if (fz_xml_down(node)) layout_tree(ctx, fz_xml_down(node), box, &style, rule); } } else { compute_style(&cstyle, &style); new_inline_box(ctx, top, &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); if (box->bold) printf(" bold"); if (box->italic) printf(" italic"); } printf("\n"); if (box->down) print_box(ctx, box->down, level + 1); box = box->next; } } 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 *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")) { 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)); } return css; } 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]); 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); 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); }