1 /* $OpenBSD: eqn_html.c,v 1.7 2017/01/17 01:47:46 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> 4 * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 #include <sys/types.h> 19 20 #include <assert.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 25 #include "mandoc.h" 26 #include "out.h" 27 #include "html.h" 28 29 static void 30 eqn_box(struct html *p, const struct eqn_box *bp) 31 { 32 struct tag *post, *row, *cell, *t; 33 const struct eqn_box *child, *parent; 34 size_t i, j, rows; 35 36 if (NULL == bp) 37 return; 38 39 post = NULL; 40 41 /* 42 * Special handling for a matrix, which is presented to us in 43 * column order, but must be printed in row-order. 44 */ 45 if (EQN_MATRIX == bp->type) { 46 if (NULL == bp->first) 47 goto out; 48 if (EQN_LIST != bp->first->type) { 49 eqn_box(p, bp->first); 50 goto out; 51 } 52 if (NULL == (parent = bp->first->first)) 53 goto out; 54 /* Estimate the number of rows, first. */ 55 if (NULL == (child = parent->first)) 56 goto out; 57 for (rows = 0; NULL != child; rows++) 58 child = child->next; 59 /* Print row-by-row. */ 60 post = print_otag(p, TAG_MTABLE, ""); 61 for (i = 0; i < rows; i++) { 62 parent = bp->first->first; 63 row = print_otag(p, TAG_MTR, ""); 64 while (NULL != parent) { 65 child = parent->first; 66 for (j = 0; j < i; j++) { 67 if (NULL == child) 68 break; 69 child = child->next; 70 } 71 cell = print_otag(p, TAG_MTD, ""); 72 /* 73 * If we have no data for this 74 * particular cell, then print a 75 * placeholder and continue--don't puke. 76 */ 77 if (NULL != child) 78 eqn_box(p, child->first); 79 print_tagq(p, cell); 80 parent = parent->next; 81 } 82 print_tagq(p, row); 83 } 84 goto out; 85 } 86 87 switch (bp->pos) { 88 case (EQNPOS_TO): 89 post = print_otag(p, TAG_MOVER, ""); 90 break; 91 case (EQNPOS_SUP): 92 post = print_otag(p, TAG_MSUP, ""); 93 break; 94 case (EQNPOS_FROM): 95 post = print_otag(p, TAG_MUNDER, ""); 96 break; 97 case (EQNPOS_SUB): 98 post = print_otag(p, TAG_MSUB, ""); 99 break; 100 case (EQNPOS_OVER): 101 post = print_otag(p, TAG_MFRAC, ""); 102 break; 103 case (EQNPOS_FROMTO): 104 post = print_otag(p, TAG_MUNDEROVER, ""); 105 break; 106 case (EQNPOS_SUBSUP): 107 post = print_otag(p, TAG_MSUBSUP, ""); 108 break; 109 case (EQNPOS_SQRT): 110 post = print_otag(p, TAG_MSQRT, ""); 111 break; 112 default: 113 break; 114 } 115 116 if (bp->top || bp->bottom) { 117 assert(NULL == post); 118 if (bp->top && NULL == bp->bottom) 119 post = print_otag(p, TAG_MOVER, ""); 120 else if (bp->top && bp->bottom) 121 post = print_otag(p, TAG_MUNDEROVER, ""); 122 else if (bp->bottom) 123 post = print_otag(p, TAG_MUNDER, ""); 124 } 125 126 if (EQN_PILE == bp->type) { 127 assert(NULL == post); 128 if (bp->first != NULL && bp->first->type == EQN_LIST) 129 post = print_otag(p, TAG_MTABLE, ""); 130 } else if (bp->type == EQN_LIST && 131 bp->parent && bp->parent->type == EQN_PILE) { 132 assert(NULL == post); 133 post = print_otag(p, TAG_MTR, ""); 134 print_otag(p, TAG_MTD, ""); 135 } 136 137 if (NULL != bp->text) { 138 assert(NULL == post); 139 post = print_otag(p, TAG_MI, ""); 140 print_text(p, bp->text); 141 } else if (NULL == post) { 142 if (NULL != bp->left || NULL != bp->right) 143 post = print_otag(p, TAG_MFENCED, "??", 144 "open", bp->left == NULL ? "" : bp->left, 145 "close", bp->right == NULL ? "" : bp->right); 146 if (NULL == post) 147 post = print_otag(p, TAG_MROW, ""); 148 else 149 print_otag(p, TAG_MROW, ""); 150 } 151 152 eqn_box(p, bp->first); 153 154 out: 155 if (NULL != bp->bottom) { 156 t = print_otag(p, TAG_MO, ""); 157 print_text(p, bp->bottom); 158 print_tagq(p, t); 159 } 160 if (NULL != bp->top) { 161 t = print_otag(p, TAG_MO, ""); 162 print_text(p, bp->top); 163 print_tagq(p, t); 164 } 165 166 if (NULL != post) 167 print_tagq(p, post); 168 169 eqn_box(p, bp->next); 170 } 171 172 void 173 print_eqn(struct html *p, const struct eqn *ep) 174 { 175 struct tag *t; 176 177 t = print_otag(p, TAG_MATH, "c", "eqn"); 178 179 p->flags |= HTML_NONOSPACE; 180 eqn_box(p, ep->root); 181 p->flags &= ~HTML_NONOSPACE; 182 183 print_tagq(p, t); 184 } 185