1 /* $Id: eqn_html.c,v 1.11 2017/01/17 01:47:51 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 "config.h" 19 20 #include <sys/types.h> 21 22 #include <assert.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include "mandoc.h" 28 #include "out.h" 29 #include "html.h" 30 31 static void 32 eqn_box(struct html *p, const struct eqn_box *bp) 33 { 34 struct tag *post, *row, *cell, *t; 35 const struct eqn_box *child, *parent; 36 size_t i, j, rows; 37 38 if (NULL == bp) 39 return; 40 41 post = NULL; 42 43 /* 44 * Special handling for a matrix, which is presented to us in 45 * column order, but must be printed in row-order. 46 */ 47 if (EQN_MATRIX == bp->type) { 48 if (NULL == bp->first) 49 goto out; 50 if (EQN_LIST != bp->first->type) { 51 eqn_box(p, bp->first); 52 goto out; 53 } 54 if (NULL == (parent = bp->first->first)) 55 goto out; 56 /* Estimate the number of rows, first. */ 57 if (NULL == (child = parent->first)) 58 goto out; 59 for (rows = 0; NULL != child; rows++) 60 child = child->next; 61 /* Print row-by-row. */ 62 post = print_otag(p, TAG_MTABLE, ""); 63 for (i = 0; i < rows; i++) { 64 parent = bp->first->first; 65 row = print_otag(p, TAG_MTR, ""); 66 while (NULL != parent) { 67 child = parent->first; 68 for (j = 0; j < i; j++) { 69 if (NULL == child) 70 break; 71 child = child->next; 72 } 73 cell = print_otag(p, TAG_MTD, ""); 74 /* 75 * If we have no data for this 76 * particular cell, then print a 77 * placeholder and continue--don't puke. 78 */ 79 if (NULL != child) 80 eqn_box(p, child->first); 81 print_tagq(p, cell); 82 parent = parent->next; 83 } 84 print_tagq(p, row); 85 } 86 goto out; 87 } 88 89 switch (bp->pos) { 90 case (EQNPOS_TO): 91 post = print_otag(p, TAG_MOVER, ""); 92 break; 93 case (EQNPOS_SUP): 94 post = print_otag(p, TAG_MSUP, ""); 95 break; 96 case (EQNPOS_FROM): 97 post = print_otag(p, TAG_MUNDER, ""); 98 break; 99 case (EQNPOS_SUB): 100 post = print_otag(p, TAG_MSUB, ""); 101 break; 102 case (EQNPOS_OVER): 103 post = print_otag(p, TAG_MFRAC, ""); 104 break; 105 case (EQNPOS_FROMTO): 106 post = print_otag(p, TAG_MUNDEROVER, ""); 107 break; 108 case (EQNPOS_SUBSUP): 109 post = print_otag(p, TAG_MSUBSUP, ""); 110 break; 111 case (EQNPOS_SQRT): 112 post = print_otag(p, TAG_MSQRT, ""); 113 break; 114 default: 115 break; 116 } 117 118 if (bp->top || bp->bottom) { 119 assert(NULL == post); 120 if (bp->top && NULL == bp->bottom) 121 post = print_otag(p, TAG_MOVER, ""); 122 else if (bp->top && bp->bottom) 123 post = print_otag(p, TAG_MUNDEROVER, ""); 124 else if (bp->bottom) 125 post = print_otag(p, TAG_MUNDER, ""); 126 } 127 128 if (EQN_PILE == bp->type) { 129 assert(NULL == post); 130 if (bp->first != NULL && bp->first->type == EQN_LIST) 131 post = print_otag(p, TAG_MTABLE, ""); 132 } else if (bp->type == EQN_LIST && 133 bp->parent && bp->parent->type == EQN_PILE) { 134 assert(NULL == post); 135 post = print_otag(p, TAG_MTR, ""); 136 print_otag(p, TAG_MTD, ""); 137 } 138 139 if (NULL != bp->text) { 140 assert(NULL == post); 141 post = print_otag(p, TAG_MI, ""); 142 print_text(p, bp->text); 143 } else if (NULL == post) { 144 if (NULL != bp->left || NULL != bp->right) 145 post = print_otag(p, TAG_MFENCED, "??", 146 "open", bp->left == NULL ? "" : bp->left, 147 "close", bp->right == NULL ? "" : bp->right); 148 if (NULL == post) 149 post = print_otag(p, TAG_MROW, ""); 150 else 151 print_otag(p, TAG_MROW, ""); 152 } 153 154 eqn_box(p, bp->first); 155 156 out: 157 if (NULL != bp->bottom) { 158 t = print_otag(p, TAG_MO, ""); 159 print_text(p, bp->bottom); 160 print_tagq(p, t); 161 } 162 if (NULL != bp->top) { 163 t = print_otag(p, TAG_MO, ""); 164 print_text(p, bp->top); 165 print_tagq(p, t); 166 } 167 168 if (NULL != post) 169 print_tagq(p, post); 170 171 eqn_box(p, bp->next); 172 } 173 174 void 175 print_eqn(struct html *p, const struct eqn *ep) 176 { 177 struct tag *t; 178 179 t = print_otag(p, TAG_MATH, "c", "eqn"); 180 181 p->flags |= HTML_NONOSPACE; 182 eqn_box(p, ep->root); 183 p->flags &= ~HTML_NONOSPACE; 184 185 print_tagq(p, t); 186 } 187