]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/mdocml/eqn_html.c
Merge bmake 20151020
[FreeBSD/FreeBSD.git] / contrib / mdocml / eqn_html.c
1 /*      $Id: eqn_html.c,v 1.10 2014/10/12 19:31:41 schwarze Exp $ */
2 /*
3  * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 #include "config.h"
18
19 #include <sys/types.h>
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "mandoc.h"
27 #include "out.h"
28 #include "html.h"
29
30 static void
31 eqn_box(struct html *p, const struct eqn_box *bp)
32 {
33         struct tag      *post, *row, *cell, *t;
34         struct htmlpair  tag[2];
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, 0, NULL);
63                 for (i = 0; i < rows; i++) {
64                         parent = bp->first->first;
65                         row = print_otag(p, TAG_MTR, 0, NULL);
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
74                                         (p, TAG_MTD, 0, NULL);
75                                 /*
76                                  * If we have no data for this
77                                  * particular cell, then print a
78                                  * placeholder and continue--don't puke.
79                                  */
80                                 if (NULL != child)
81                                         eqn_box(p, child->first);
82                                 print_tagq(p, cell);
83                                 parent = parent->next;
84                         }
85                         print_tagq(p, row);
86                 }
87                 goto out;
88         }
89
90         switch (bp->pos) {
91         case (EQNPOS_TO):
92                 post = print_otag(p, TAG_MOVER, 0, NULL);
93                 break;
94         case (EQNPOS_SUP):
95                 post = print_otag(p, TAG_MSUP, 0, NULL);
96                 break;
97         case (EQNPOS_FROM):
98                 post = print_otag(p, TAG_MUNDER, 0, NULL);
99                 break;
100         case (EQNPOS_SUB):
101                 post = print_otag(p, TAG_MSUB, 0, NULL);
102                 break;
103         case (EQNPOS_OVER):
104                 post = print_otag(p, TAG_MFRAC, 0, NULL);
105                 break;
106         case (EQNPOS_FROMTO):
107                 post = print_otag(p, TAG_MUNDEROVER, 0, NULL);
108                 break;
109         case (EQNPOS_SUBSUP):
110                 post = print_otag(p, TAG_MSUBSUP, 0, NULL);
111                 break;
112         case (EQNPOS_SQRT):
113                 post = print_otag(p, TAG_MSQRT, 0, NULL);
114                 break;
115         default:
116                 break;
117         }
118
119         if (bp->top || bp->bottom) {
120                 assert(NULL == post);
121                 if (bp->top && NULL == bp->bottom)
122                         post = print_otag(p, TAG_MOVER, 0, NULL);
123                 else if (bp->top && bp->bottom)
124                         post = print_otag(p, TAG_MUNDEROVER, 0, NULL);
125                 else if (bp->bottom)
126                         post = print_otag(p, TAG_MUNDER, 0, NULL);
127         }
128
129         if (EQN_PILE == bp->type) {
130                 assert(NULL == post);
131                 if (bp->first != NULL && bp->first->type == EQN_LIST)
132                         post = print_otag(p, TAG_MTABLE, 0, NULL);
133         } else if (bp->type == EQN_LIST &&
134             bp->parent && bp->parent->type == EQN_PILE) {
135                 assert(NULL == post);
136                 post = print_otag(p, TAG_MTR, 0, NULL);
137                 print_otag(p, TAG_MTD, 0, NULL);
138         }
139
140         if (NULL != bp->text) {
141                 assert(NULL == post);
142                 post = print_otag(p, TAG_MI, 0, NULL);
143                 print_text(p, bp->text);
144         } else if (NULL == post) {
145                 if (NULL != bp->left || NULL != bp->right) {
146                         PAIR_INIT(&tag[0], ATTR_OPEN,
147                             NULL == bp->left ? "" : bp->left);
148                         PAIR_INIT(&tag[1], ATTR_CLOSE,
149                             NULL == bp->right ? "" : bp->right);
150                         post = print_otag(p, TAG_MFENCED, 2, tag);
151                 }
152                 if (NULL == post)
153                         post = print_otag(p, TAG_MROW, 0, NULL);
154                 else
155                         print_otag(p, TAG_MROW, 0, NULL);
156         }
157
158         eqn_box(p, bp->first);
159
160 out:
161         if (NULL != bp->bottom) {
162                 t = print_otag(p, TAG_MO, 0, NULL);
163                 print_text(p, bp->bottom);
164                 print_tagq(p, t);
165         }
166         if (NULL != bp->top) {
167                 t = print_otag(p, TAG_MO, 0, NULL);
168                 print_text(p, bp->top);
169                 print_tagq(p, t);
170         }
171
172         if (NULL != post)
173                 print_tagq(p, post);
174
175         eqn_box(p, bp->next);
176 }
177
178 void
179 print_eqn(struct html *p, const struct eqn *ep)
180 {
181         struct htmlpair  tag;
182         struct tag      *t;
183
184         PAIR_CLASS_INIT(&tag, "eqn");
185         t = print_otag(p, TAG_MATH, 1, &tag);
186
187         p->flags |= HTML_NONOSPACE;
188         eqn_box(p, ep->root);
189         p->flags &= ~HTML_NONOSPACE;
190
191         print_tagq(p, t);
192 }