File: | content/handlers/html/table.c |
Warning: | line 440, column 4 Value stored to 'a_src' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright 2005 James Bursa <bursa@users.sourceforge.net> |
3 | * Copyright 2005 Richard Wilson <info@tinct.net> |
4 | * |
5 | * This file is part of NetSurf, http://www.netsurf-browser.org/ |
6 | * |
7 | * NetSurf is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by |
9 | * the Free Software Foundation; version 2 of the License. |
10 | * |
11 | * NetSurf is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | */ |
19 | |
20 | /** |
21 | * \file |
22 | * implementation of HTML table processing and layout. |
23 | */ |
24 | |
25 | #include <assert.h> |
26 | #include <dom/dom.h> |
27 | |
28 | #include "utils/log.h" |
29 | #include "utils/utils.h" |
30 | #include "utils/talloc.h" |
31 | #include "css/utils.h" |
32 | |
33 | #include "html/box.h" |
34 | #include "html/table.h" |
35 | |
36 | /* Define to enable verbose table debug */ |
37 | #undef TABLE_DEBUG |
38 | |
39 | /** |
40 | * Container for border values during table border calculations |
41 | */ |
42 | struct border { |
43 | enum css_border_style_e style; /**< border-style */ |
44 | enum css_border_color_e color; /**< border-color type */ |
45 | css_color c; /**< border-color value */ |
46 | css_fixed width; /**< border-width length */ |
47 | css_unit unit; /**< border-width units */ |
48 | }; |
49 | |
50 | |
51 | /** |
52 | * Determine if a border style is more eyecatching than another |
53 | * |
54 | * \param unit_len_ctx Length conversion context |
55 | * \param a Reference border style |
56 | * \param a_src Source of \a a |
57 | * \param b Candidate border style |
58 | * \param b_src Source of \a b |
59 | * \return True if \a b is more eyecatching than \a a |
60 | */ |
61 | static bool_Bool |
62 | table_border_is_more_eyecatching(const css_unit_ctx *unit_len_ctx, |
63 | const struct border *a, |
64 | box_type a_src, |
65 | const struct border *b, |
66 | box_type b_src) |
67 | { |
68 | css_fixed awidth, bwidth; |
69 | int impact = 0; |
70 | |
71 | /* See CSS 2.1 $17.6.2.1 */ |
72 | |
73 | /* 1 + 2 -- hidden beats everything, none beats nothing */ |
74 | if (a->style == CSS_BORDER_STYLE_HIDDEN || |
75 | b->style == CSS_BORDER_STYLE_NONE) |
76 | return false0; |
77 | |
78 | if (b->style == CSS_BORDER_STYLE_HIDDEN || |
79 | a->style == CSS_BORDER_STYLE_NONE) |
80 | return true1; |
81 | |
82 | /* 3a -- wider borders beat narrow ones */ |
83 | /* The widths must be absolute, which will be the case |
84 | * if they've come from a computed style. */ |
85 | assert(a->unit != CSS_UNIT_EM && a->unit != CSS_UNIT_EX)((a->unit != CSS_UNIT_EM && a->unit != CSS_UNIT_EX ) ? (void) (0) : __assert_fail ("a->unit != CSS_UNIT_EM && a->unit != CSS_UNIT_EX" , "content/handlers/html/table.c", 85, __extension__ __PRETTY_FUNCTION__ )); |
86 | assert(b->unit != CSS_UNIT_EM && b->unit != CSS_UNIT_EX)((b->unit != CSS_UNIT_EM && b->unit != CSS_UNIT_EX ) ? (void) (0) : __assert_fail ("b->unit != CSS_UNIT_EM && b->unit != CSS_UNIT_EX" , "content/handlers/html/table.c", 86, __extension__ __PRETTY_FUNCTION__ )); |
87 | awidth = css_unit_len2device_px(NULL((void*)0), unit_len_ctx, a->width, a->unit); |
88 | bwidth = css_unit_len2device_px(NULL((void*)0), unit_len_ctx, b->width, b->unit); |
89 | |
90 | if (awidth < bwidth) |
91 | return true1; |
92 | else if (bwidth < awidth) |
93 | return false0; |
94 | |
95 | /* 3b -- sort by style */ |
96 | switch (a->style) { |
97 | case CSS_BORDER_STYLE_DOUBLE: impact++; fallthrough__attribute__((__fallthrough__)); |
98 | case CSS_BORDER_STYLE_SOLID: impact++; fallthrough__attribute__((__fallthrough__)); |
99 | case CSS_BORDER_STYLE_DASHED: impact++; fallthrough__attribute__((__fallthrough__)); |
100 | case CSS_BORDER_STYLE_DOTTED: impact++; fallthrough__attribute__((__fallthrough__)); |
101 | case CSS_BORDER_STYLE_RIDGE: impact++; fallthrough__attribute__((__fallthrough__)); |
102 | case CSS_BORDER_STYLE_OUTSET: impact++; fallthrough__attribute__((__fallthrough__)); |
103 | case CSS_BORDER_STYLE_GROOVE: impact++; fallthrough__attribute__((__fallthrough__)); |
104 | case CSS_BORDER_STYLE_INSET: impact++; fallthrough__attribute__((__fallthrough__)); |
105 | default: |
106 | break; |
107 | } |
108 | |
109 | switch (b->style) { |
110 | case CSS_BORDER_STYLE_DOUBLE: impact--; fallthrough__attribute__((__fallthrough__)); |
111 | case CSS_BORDER_STYLE_SOLID: impact--; fallthrough__attribute__((__fallthrough__)); |
112 | case CSS_BORDER_STYLE_DASHED: impact--; fallthrough__attribute__((__fallthrough__)); |
113 | case CSS_BORDER_STYLE_DOTTED: impact--; fallthrough__attribute__((__fallthrough__)); |
114 | case CSS_BORDER_STYLE_RIDGE: impact--; fallthrough__attribute__((__fallthrough__)); |
115 | case CSS_BORDER_STYLE_OUTSET: impact--; fallthrough__attribute__((__fallthrough__)); |
116 | case CSS_BORDER_STYLE_GROOVE: impact--; fallthrough__attribute__((__fallthrough__)); |
117 | case CSS_BORDER_STYLE_INSET: impact--; fallthrough__attribute__((__fallthrough__)); |
118 | default: |
119 | break; |
120 | } |
121 | |
122 | if (impact < 0) |
123 | return true1; |
124 | else if (impact > 0) |
125 | return false0; |
126 | |
127 | /* 4a -- sort by origin */ |
128 | impact = 0; |
129 | |
130 | /** \todo COL/COL_GROUP */ |
131 | switch (a_src) { |
132 | case BOX_TABLE_CELL: impact++; fallthrough__attribute__((__fallthrough__)); |
133 | case BOX_TABLE_ROW: impact++; fallthrough__attribute__((__fallthrough__)); |
134 | case BOX_TABLE_ROW_GROUP: impact++; fallthrough__attribute__((__fallthrough__)); |
135 | case BOX_TABLE: impact++; fallthrough__attribute__((__fallthrough__)); |
136 | default: |
137 | break; |
138 | } |
139 | |
140 | /** \todo COL/COL_GROUP */ |
141 | switch (b_src) { |
142 | case BOX_TABLE_CELL: impact--; fallthrough__attribute__((__fallthrough__)); |
143 | case BOX_TABLE_ROW: impact--; fallthrough__attribute__((__fallthrough__)); |
144 | case BOX_TABLE_ROW_GROUP: impact--; fallthrough__attribute__((__fallthrough__)); |
145 | case BOX_TABLE: impact--; fallthrough__attribute__((__fallthrough__)); |
146 | default: |
147 | break; |
148 | } |
149 | |
150 | if (impact < 0) |
151 | return true1; |
152 | else if (impact > 0) |
153 | return false0; |
154 | |
155 | /* 4b -- furthest left (if direction: ltr) and towards top wins */ |
156 | /** \todo Currently assumes b satisifies this */ |
157 | return true1; |
158 | } |
159 | |
160 | |
161 | /** |
162 | * Process a table |
163 | * |
164 | * \param unit_len_ctx Length conversion context |
165 | * \param table Table to process |
166 | * \param a Current border style for cell |
167 | * \param a_src Source of \a a |
168 | * |
169 | * \post \a a will be updated with most eyecatching style |
170 | * \post \a a_src will be updated also |
171 | */ |
172 | static void |
173 | table_cell_top_process_table(const css_unit_ctx *unit_len_ctx, |
174 | struct box *table, |
175 | struct border *a, |
176 | box_type *a_src) |
177 | { |
178 | struct border b; |
179 | box_type b_src; |
180 | |
181 | /* Top border of table */ |
182 | b.style = css_computed_border_top_style(table->style); |
183 | b.color = css_computed_border_top_color(table->style, &b.c); |
184 | css_computed_border_top_width(table->style, &b.width, &b.unit); |
185 | b.width = css_unit_len2device_px(table->style, unit_len_ctx, |
186 | b.width, b.unit); |
187 | b.unit = CSS_UNIT_PX; |
188 | b_src = BOX_TABLE; |
189 | |
190 | if (table_border_is_more_eyecatching(unit_len_ctx, a, *a_src, &b, b_src)) { |
191 | *a = b; |
192 | *a_src = b_src; |
193 | } |
194 | } |
195 | |
196 | |
197 | /** |
198 | * Process a row |
199 | * |
200 | * \param unit_len_ctx Length conversion context |
201 | * \param cell Cell being considered |
202 | * \param row Row to process |
203 | * \param a Current border style for cell |
204 | * \param a_src Source of \a a |
205 | * \return true if row has cells, false otherwise |
206 | * |
207 | * \post \a a will be updated with most eyecatching style |
208 | * \post \a a_src will be updated also |
209 | */ |
210 | static bool_Bool |
211 | table_cell_top_process_row(const css_unit_ctx *unit_len_ctx, |
212 | struct box *cell, |
213 | struct box *row, |
214 | struct border *a, |
215 | box_type *a_src) |
216 | { |
217 | struct border b; |
218 | box_type b_src; |
219 | |
220 | /* Bottom border of row */ |
221 | b.style = css_computed_border_bottom_style(row->style); |
222 | b.color = css_computed_border_bottom_color(row->style, &b.c); |
223 | css_computed_border_bottom_width(row->style, &b.width, &b.unit); |
224 | b.width = css_unit_len2device_px(row->style, unit_len_ctx, |
225 | b.width, b.unit); |
226 | b.unit = CSS_UNIT_PX; |
227 | b_src = BOX_TABLE_ROW; |
228 | |
229 | if (table_border_is_more_eyecatching(unit_len_ctx, a, *a_src, &b, b_src)) { |
230 | *a = b; |
231 | *a_src = b_src; |
232 | } |
233 | |
234 | if (row->children == NULL((void*)0)) { |
235 | /* Row is empty, so consider its top border */ |
236 | b.style = css_computed_border_top_style(row->style); |
237 | b.color = css_computed_border_top_color(row->style, &b.c); |
238 | css_computed_border_top_width(row->style, &b.width, &b.unit); |
239 | b.width = css_unit_len2device_px(row->style, unit_len_ctx, |
240 | b.width, b.unit); |
241 | b.unit = CSS_UNIT_PX; |
242 | b_src = BOX_TABLE_ROW; |
243 | |
244 | if (table_border_is_more_eyecatching(unit_len_ctx, |
245 | a, *a_src, &b, b_src)) { |
246 | *a = b; |
247 | *a_src = b_src; |
248 | } |
249 | |
250 | return false0; |
251 | } else { |
252 | /* Process cells that are directly above the cell being |
253 | * considered. They may not be in this row, but in one of the |
254 | * rows above it in the case where rowspan > 1. */ |
255 | struct box *c; |
256 | bool_Bool processed = false0; |
257 | |
258 | while (processed == false0) { |
259 | for (c = row->children; c != NULL((void*)0); c = c->next) { |
260 | /* Ignore cells to the left */ |
261 | if (c->start_column + c->columns - 1 < |
262 | cell->start_column) |
263 | continue; |
264 | /* Ignore cells to the right */ |
265 | if (c->start_column > cell->start_column + |
266 | cell->columns - 1) |
267 | continue; |
268 | |
269 | /* Flag that we've processed a cell */ |
270 | processed = true1; |
271 | |
272 | /* Consider bottom border */ |
273 | b.style = css_computed_border_bottom_style( |
274 | c->style); |
275 | b.color = css_computed_border_bottom_color( |
276 | c->style, &b.c); |
277 | css_computed_border_bottom_width(c->style, |
278 | &b.width, &b.unit); |
279 | b.width = css_unit_len2device_px( |
280 | c->style, unit_len_ctx, |
281 | b.width, b.unit); |
282 | b.unit = CSS_UNIT_PX; |
283 | b_src = BOX_TABLE_CELL; |
284 | |
285 | if (table_border_is_more_eyecatching(unit_len_ctx, |
286 | a, |
287 | *a_src, |
288 | &b, |
289 | b_src)) { |
290 | *a = b; |
291 | *a_src = b_src; |
292 | } |
293 | } |
294 | |
295 | if (processed == false0) { |
296 | /* There must be a preceding row */ |
297 | assert(row->prev != NULL)((row->prev != ((void*)0)) ? (void) (0) : __assert_fail ("row->prev != NULL" , "content/handlers/html/table.c", 297, __extension__ __PRETTY_FUNCTION__ )); |
298 | |
299 | row = row->prev; |
300 | } |
301 | } |
302 | } |
303 | |
304 | return true1; |
305 | } |
306 | |
307 | |
308 | /** |
309 | * Process a group |
310 | * |
311 | * \param unit_len_ctx Length conversion context |
312 | * \param cell Cell being considered |
313 | * \param group Group to process |
314 | * \param a Current border style for cell |
315 | * \param a_src Source of \a a |
316 | * \return true if group has non-empty rows, false otherwise |
317 | * |
318 | * \post \a a will be updated with most eyecatching style |
319 | * \post \a a_src will be updated also |
320 | */ |
321 | static bool_Bool |
322 | table_cell_top_process_group(const css_unit_ctx *unit_len_ctx, |
323 | struct box *cell, |
324 | struct box *group, |
325 | struct border *a, |
326 | box_type *a_src) |
327 | { |
328 | struct border b; |
329 | box_type b_src; |
330 | |
331 | /* Bottom border of group */ |
332 | b.style = css_computed_border_bottom_style(group->style); |
333 | b.color = css_computed_border_bottom_color(group->style, &b.c); |
334 | css_computed_border_bottom_width(group->style, &b.width, &b.unit); |
335 | b.width = css_unit_len2device_px(group->style, unit_len_ctx, |
336 | b.width, b.unit); |
337 | b.unit = CSS_UNIT_PX; |
338 | b_src = BOX_TABLE_ROW_GROUP; |
339 | |
340 | if (table_border_is_more_eyecatching(unit_len_ctx, a, *a_src, &b, b_src)) { |
341 | *a = b; |
342 | *a_src = b_src; |
343 | } |
344 | |
345 | if (group->last != NULL((void*)0)) { |
346 | /* Process rows in group, starting with last */ |
347 | struct box *row = group->last; |
348 | |
349 | while (table_cell_top_process_row(unit_len_ctx, cell, row, |
350 | a, a_src) == false0) { |
351 | if (row->prev == NULL((void*)0)) { |
352 | return false0; |
353 | } else { |
354 | row = row->prev; |
355 | } |
356 | } |
357 | } else { |
358 | /* Group is empty, so consider its top border */ |
359 | b.style = css_computed_border_top_style(group->style); |
360 | b.color = css_computed_border_top_color(group->style, &b.c); |
361 | css_computed_border_top_width(group->style, &b.width, &b.unit); |
362 | b.width = css_unit_len2device_px(group->style, unit_len_ctx, |
363 | b.width, b.unit); |
364 | b.unit = CSS_UNIT_PX; |
365 | b_src = BOX_TABLE_ROW_GROUP; |
366 | |
367 | if (table_border_is_more_eyecatching(unit_len_ctx, |
368 | a, *a_src, &b, b_src)) { |
369 | *a = b; |
370 | *a_src = b_src; |
371 | } |
372 | |
373 | return false0; |
374 | } |
375 | |
376 | return true1; |
377 | } |
378 | |
379 | |
380 | /** |
381 | * Calculate used values of border-left-{style,color,width} |
382 | * |
383 | * \param unit_len_ctx Length conversion context |
384 | * \param cell Table cell to consider |
385 | */ |
386 | static void |
387 | table_used_left_border_for_cell(const css_unit_ctx *unit_len_ctx, struct box *cell) |
388 | { |
389 | struct border a, b; |
390 | box_type a_src, b_src; |
391 | |
392 | /** \todo Need column and column_group, too */ |
393 | |
394 | /* Initialise to computed left border for cell */ |
395 | a.style = css_computed_border_left_style(cell->style); |
396 | a.color = css_computed_border_left_color(cell->style, &a.c); |
397 | css_computed_border_left_width(cell->style, &a.width, &a.unit); |
398 | a.width = css_unit_len2device_px(cell->style, unit_len_ctx, |
399 | a.width, a.unit); |
400 | a.unit = CSS_UNIT_PX; |
401 | a_src = BOX_TABLE_CELL; |
402 | |
403 | if (cell->prev != NULL((void*)0) || cell->start_column != 0) { |
404 | /* Cell to the left -- consider its right border */ |
405 | struct box *prev = NULL((void*)0); |
406 | |
407 | if (cell->prev == NULL((void*)0)) { |
408 | struct box *row; |
409 | |
410 | /* Spanned from a previous row in current row group */ |
411 | for (row = cell->parent; row != NULL((void*)0); row = row->prev) { |
412 | for (prev = row->children; prev != NULL((void*)0); |
413 | prev = prev->next) { |
414 | if (prev->start_column + |
415 | prev->columns == |
416 | cell->start_column) |
417 | break; |
418 | } |
419 | |
420 | if (prev != NULL((void*)0)) |
421 | break; |
422 | } |
423 | |
424 | assert(prev != NULL)((prev != ((void*)0)) ? (void) (0) : __assert_fail ("prev != NULL" , "content/handlers/html/table.c", 424, __extension__ __PRETTY_FUNCTION__ )); |
425 | } else { |
426 | prev = cell->prev; |
427 | } |
428 | |
429 | b.style = css_computed_border_right_style(prev->style); |
430 | b.color = css_computed_border_right_color(prev->style, &b.c); |
431 | css_computed_border_right_width(prev->style, &b.width, &b.unit); |
432 | b.width = css_unit_len2device_px(prev->style, unit_len_ctx, |
433 | b.width, b.unit); |
434 | b.unit = CSS_UNIT_PX; |
435 | b_src = BOX_TABLE_CELL; |
436 | |
437 | if (table_border_is_more_eyecatching(unit_len_ctx, |
438 | &a, a_src, &b, b_src)) { |
439 | a = b; |
440 | a_src = b_src; |
Value stored to 'a_src' is never read | |
441 | } |
442 | } else { |
443 | /* First cell in row, so consider rows and row group */ |
444 | struct box *row = cell->parent; |
445 | struct box *group = row->parent; |
446 | struct box *table = group->parent; |
447 | unsigned int rows = cell->rows; |
448 | |
449 | while (rows-- > 0 && row != NULL((void*)0)) { |
450 | /* Spanned rows -- consider their left border */ |
451 | b.style = css_computed_border_left_style(row->style); |
452 | b.color = css_computed_border_left_color( |
453 | row->style, &b.c); |
454 | css_computed_border_left_width( |
455 | row->style, &b.width, &b.unit); |
456 | b.width = css_unit_len2device_px( |
457 | row->style, unit_len_ctx, |
458 | b.width, b.unit); |
459 | b.unit = CSS_UNIT_PX; |
460 | b_src = BOX_TABLE_ROW; |
461 | |
462 | if (table_border_is_more_eyecatching(unit_len_ctx, |
463 | &a, a_src, &b, b_src)) { |
464 | a = b; |
465 | a_src = b_src; |
466 | } |
467 | |
468 | row = row->next; |
469 | } |
470 | |
471 | /** \todo can cells span row groups? */ |
472 | |
473 | /* Row group -- consider its left border */ |
474 | b.style = css_computed_border_left_style(group->style); |
475 | b.color = css_computed_border_left_color(group->style, &b.c); |
476 | css_computed_border_left_width(group->style, &b.width, &b.unit); |
477 | b.width = css_unit_len2device_px(group->style, unit_len_ctx, |
478 | b.width, b.unit); |
479 | b.unit = CSS_UNIT_PX; |
480 | b_src = BOX_TABLE_ROW_GROUP; |
481 | |
482 | if (table_border_is_more_eyecatching(unit_len_ctx, |
483 | &a, a_src, &b, b_src)) { |
484 | a = b; |
485 | a_src = b_src; |
486 | } |
487 | |
488 | /* The table itself -- consider its left border */ |
489 | b.style = css_computed_border_left_style(table->style); |
490 | b.color = css_computed_border_left_color(table->style, &b.c); |
491 | css_computed_border_left_width(table->style, &b.width, &b.unit); |
492 | b.width = css_unit_len2device_px(table->style, unit_len_ctx, |
493 | b.width, b.unit); |
494 | b.unit = CSS_UNIT_PX; |
495 | b_src = BOX_TABLE; |
496 | |
497 | if (table_border_is_more_eyecatching(unit_len_ctx, |
498 | &a, a_src, &b, b_src)) { |
499 | a = b; |
500 | a_src = b_src; |
501 | } |
502 | } |
503 | |
504 | /* a now contains the used left border for the cell */ |
505 | cell->border[LEFT].style = a.style; |
506 | cell->border[LEFT].c = a.c; |
507 | cell->border[LEFT].width = FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( cell->style, unit_len_ctx, a.width , a.unit)) >> 10) |
508 | cell->style, unit_len_ctx, a.width, a.unit))((css_unit_len2device_px( cell->style, unit_len_ctx, a.width , a.unit)) >> 10); |
509 | } |
510 | |
511 | |
512 | /** |
513 | * Calculate used values of border-top-{style,color,width} |
514 | * |
515 | * \param unit_len_ctx Length conversion context |
516 | * \param cell Table cell to consider |
517 | */ |
518 | static void |
519 | table_used_top_border_for_cell(const css_unit_ctx *unit_len_ctx, struct box *cell) |
520 | { |
521 | struct border a, b; |
522 | box_type a_src, b_src; |
523 | struct box *row = cell->parent; |
524 | bool_Bool process_group = false0; |
525 | |
526 | /* Initialise to computed top border for cell */ |
527 | a.style = css_computed_border_top_style(cell->style); |
528 | css_computed_border_top_color(cell->style, &a.c); |
529 | css_computed_border_top_width(cell->style, &a.width, &a.unit); |
530 | a.width = css_unit_len2device_px(cell->style, unit_len_ctx, |
531 | a.width, a.unit); |
532 | a.unit = CSS_UNIT_PX; |
533 | a_src = BOX_TABLE_CELL; |
534 | |
535 | /* Top border of row */ |
536 | b.style = css_computed_border_top_style(row->style); |
537 | css_computed_border_top_color(row->style, &b.c); |
538 | css_computed_border_top_width(row->style, &b.width, &b.unit); |
539 | b.width = css_unit_len2device_px(row->style, unit_len_ctx, |
540 | b.width, b.unit); |
541 | b.unit = CSS_UNIT_PX; |
542 | b_src = BOX_TABLE_ROW; |
543 | |
544 | if (table_border_is_more_eyecatching(unit_len_ctx, &a, a_src, &b, b_src)) { |
545 | a = b; |
546 | a_src = b_src; |
547 | } |
548 | |
549 | if (row->prev != NULL((void*)0)) { |
550 | /* Consider row(s) above */ |
551 | while (table_cell_top_process_row(unit_len_ctx, cell, row->prev, |
552 | &a, &a_src) == false0) { |
553 | if (row->prev->prev == NULL((void*)0)) { |
554 | /* Consider row group */ |
555 | process_group = true1; |
556 | break; |
557 | } else { |
558 | row = row->prev; |
559 | } |
560 | } |
561 | } else { |
562 | process_group = true1; |
563 | } |
564 | |
565 | if (process_group) { |
566 | struct box *group = row->parent; |
567 | |
568 | /* Top border of row group */ |
569 | b.style = css_computed_border_top_style(group->style); |
570 | b.color = css_computed_border_top_color(group->style, &b.c); |
571 | css_computed_border_top_width(group->style, &b.width, &b.unit); |
572 | b.width = css_unit_len2device_px(group->style, unit_len_ctx, |
573 | b.width, b.unit); |
574 | b.unit = CSS_UNIT_PX; |
575 | b_src = BOX_TABLE_ROW_GROUP; |
576 | |
577 | if (table_border_is_more_eyecatching(unit_len_ctx, |
578 | &a, a_src, &b, b_src)) { |
579 | a = b; |
580 | a_src = b_src; |
581 | } |
582 | |
583 | if (group->prev == NULL((void*)0)) { |
584 | /* Top border of table */ |
585 | table_cell_top_process_table(unit_len_ctx, |
586 | group->parent, &a, &a_src); |
587 | } else { |
588 | /* Process previous group(s) */ |
589 | while (table_cell_top_process_group(unit_len_ctx, |
590 | cell, group->prev, |
591 | &a, &a_src) == false0) { |
592 | if (group->prev->prev == NULL((void*)0)) { |
593 | /* Top border of table */ |
594 | table_cell_top_process_table(unit_len_ctx, |
595 | group->parent, |
596 | &a, &a_src); |
597 | break; |
598 | } else { |
599 | group = group->prev; |
600 | } |
601 | } |
602 | } |
603 | } |
604 | |
605 | /* a now contains the used top border for the cell */ |
606 | cell->border[TOP].style = a.style; |
607 | cell->border[TOP].c = a.c; |
608 | cell->border[TOP].width = FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( cell->style, unit_len_ctx, a.width , a.unit)) >> 10) |
609 | cell->style, unit_len_ctx, a.width, a.unit))((css_unit_len2device_px( cell->style, unit_len_ctx, a.width , a.unit)) >> 10); |
610 | } |
611 | |
612 | /** |
613 | * Calculate used values of border-right-{style,color,width} |
614 | * |
615 | * \param unit_len_ctx Length conversion context |
616 | * \param cell Table cell to consider |
617 | */ |
618 | static void |
619 | table_used_right_border_for_cell(const css_unit_ctx *unit_len_ctx, struct box *cell) |
620 | { |
621 | struct border a, b; |
622 | box_type a_src, b_src; |
623 | |
624 | /** \todo Need column and column_group, too */ |
625 | |
626 | /* Initialise to computed right border for cell */ |
627 | a.style = css_computed_border_right_style(cell->style); |
628 | css_computed_border_right_color(cell->style, &a.c); |
629 | css_computed_border_right_width(cell->style, &a.width, &a.unit); |
630 | a.width = css_unit_len2device_px(cell->style, unit_len_ctx, |
631 | a.width, a.unit); |
632 | a.unit = CSS_UNIT_PX; |
633 | a_src = BOX_TABLE_CELL; |
634 | |
635 | if (cell->next != NULL((void*)0) || cell->start_column + cell->columns != |
636 | cell->parent->parent->parent->columns) { |
637 | /* Cell is not at right edge of table -- no right border */ |
638 | a.style = CSS_BORDER_STYLE_NONE; |
639 | a.width = 0; |
640 | a.unit = CSS_UNIT_PX; |
641 | } else { |
642 | /* Last cell in row, so consider rows and row group */ |
643 | struct box *row = cell->parent; |
644 | struct box *group = row->parent; |
645 | struct box *table = group->parent; |
646 | unsigned int rows = cell->rows; |
647 | |
648 | while (rows-- > 0 && row != NULL((void*)0)) { |
649 | /* Spanned rows -- consider their right border */ |
650 | b.style = css_computed_border_right_style(row->style); |
651 | b.color = css_computed_border_right_color(row->style, |
652 | &b.c); |
653 | css_computed_border_right_width(row->style, |
654 | &b.width, |
655 | &b.unit); |
656 | b.width = css_unit_len2device_px( |
657 | row->style, unit_len_ctx, |
658 | b.width, b.unit); |
659 | b.unit = CSS_UNIT_PX; |
660 | b_src = BOX_TABLE_ROW; |
661 | |
662 | if (table_border_is_more_eyecatching(unit_len_ctx, |
663 | &a, a_src, |
664 | &b, b_src)) { |
665 | a = b; |
666 | a_src = b_src; |
667 | } |
668 | |
669 | row = row->next; |
670 | } |
671 | |
672 | /** \todo can cells span row groups? */ |
673 | |
674 | /* Row group -- consider its right border */ |
675 | b.style = css_computed_border_right_style(group->style); |
676 | b.color = css_computed_border_right_color(group->style, &b.c); |
677 | css_computed_border_right_width(group->style, |
678 | &b.width, &b.unit); |
679 | b.width = css_unit_len2device_px(group->style, unit_len_ctx, |
680 | b.width, b.unit); |
681 | b.unit = CSS_UNIT_PX; |
682 | b_src = BOX_TABLE_ROW_GROUP; |
683 | |
684 | if (table_border_is_more_eyecatching(unit_len_ctx, |
685 | &a, a_src, &b, b_src)) { |
686 | a = b; |
687 | a_src = b_src; |
688 | } |
689 | |
690 | /* The table itself -- consider its right border */ |
691 | b.style = css_computed_border_right_style(table->style); |
692 | b.color = css_computed_border_right_color(table->style, &b.c); |
693 | css_computed_border_right_width(table->style, |
694 | &b.width, &b.unit); |
695 | b.width = css_unit_len2device_px(table->style, unit_len_ctx, |
696 | b.width, b.unit); |
697 | b.unit = CSS_UNIT_PX; |
698 | b_src = BOX_TABLE; |
699 | |
700 | if (table_border_is_more_eyecatching(unit_len_ctx, |
701 | &a, a_src, |
702 | &b, b_src)) { |
703 | a = b; |
704 | a_src = b_src; |
705 | } |
706 | } |
707 | |
708 | /* a now contains the used right border for the cell */ |
709 | cell->border[RIGHT].style = a.style; |
710 | cell->border[RIGHT].c = a.c; |
711 | cell->border[RIGHT].width = FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( cell->style, unit_len_ctx, a.width , a.unit)) >> 10) |
712 | cell->style, unit_len_ctx, a.width, a.unit))((css_unit_len2device_px( cell->style, unit_len_ctx, a.width , a.unit)) >> 10); |
713 | } |
714 | |
715 | |
716 | /** |
717 | * Calculate used values of border-bottom-{style,color,width} |
718 | * |
719 | * \param unit_len_ctx Length conversion context |
720 | * \param cell Table cell to consider |
721 | */ |
722 | static void |
723 | table_used_bottom_border_for_cell(const css_unit_ctx *unit_len_ctx, |
724 | struct box *cell) |
725 | { |
726 | struct border a, b; |
727 | box_type a_src, b_src; |
728 | struct box *row = cell->parent; |
729 | unsigned int rows = cell->rows; |
730 | |
731 | /* Initialise to computed bottom border for cell */ |
732 | a.style = css_computed_border_bottom_style(cell->style); |
733 | css_computed_border_bottom_color(cell->style, &a.c); |
734 | css_computed_border_bottom_width(cell->style, &a.width, &a.unit); |
735 | a.width = css_unit_len2device_px(cell->style, unit_len_ctx, |
736 | a.width, a.unit); |
737 | a.unit = CSS_UNIT_PX; |
738 | a_src = BOX_TABLE_CELL; |
739 | |
740 | while (rows-- > 0 && row != NULL((void*)0)) |
741 | row = row->next; |
742 | |
743 | /** \todo Can cells span row groups? */ |
744 | |
745 | if (row != NULL((void*)0)) { |
746 | /* Cell is not at bottom edge of table -- no bottom border */ |
747 | a.style = CSS_BORDER_STYLE_NONE; |
748 | a.width = 0; |
749 | a.unit = CSS_UNIT_PX; |
750 | } else { |
751 | /* Cell at bottom of table, so consider row and row group */ |
752 | struct box *row = cell->parent; |
753 | struct box *group = row->parent; |
754 | struct box *table = group->parent; |
755 | |
756 | /* Bottom border of row */ |
757 | b.style = css_computed_border_bottom_style(row->style); |
758 | b.color = css_computed_border_bottom_color(row->style, &b.c); |
759 | css_computed_border_bottom_width(row->style, &b.width, &b.unit); |
760 | b.width = css_unit_len2device_px(row->style, unit_len_ctx, |
761 | b.width, b.unit); |
762 | b.unit = CSS_UNIT_PX; |
763 | b_src = BOX_TABLE_ROW; |
764 | |
765 | if (table_border_is_more_eyecatching(unit_len_ctx, |
766 | &a, a_src, &b, b_src)) { |
767 | a = b; |
768 | a_src = b_src; |
769 | } |
770 | |
771 | /* Row group -- consider its bottom border */ |
772 | b.style = css_computed_border_bottom_style(group->style); |
773 | b.color = css_computed_border_bottom_color(group->style, &b.c); |
774 | css_computed_border_bottom_width(group->style, |
775 | &b.width, &b.unit); |
776 | b.width = css_unit_len2device_px(group->style, unit_len_ctx, |
777 | b.width, b.unit); |
778 | b.unit = CSS_UNIT_PX; |
779 | b_src = BOX_TABLE_ROW_GROUP; |
780 | |
781 | if (table_border_is_more_eyecatching(unit_len_ctx, |
782 | &a, a_src, &b, b_src)) { |
783 | a = b; |
784 | a_src = b_src; |
785 | } |
786 | |
787 | /* The table itself -- consider its bottom border */ |
788 | b.style = css_computed_border_bottom_style(table->style); |
789 | b.color = css_computed_border_bottom_color(table->style, &b.c); |
790 | css_computed_border_bottom_width(table->style, |
791 | &b.width, &b.unit); |
792 | b.width = css_unit_len2device_px(table->style, unit_len_ctx, |
793 | b.width, b.unit); |
794 | b.unit = CSS_UNIT_PX; |
795 | b_src = BOX_TABLE; |
796 | |
797 | if (table_border_is_more_eyecatching(unit_len_ctx, |
798 | &a, a_src, &b, b_src)) { |
799 | a = b; |
800 | } |
801 | } |
802 | |
803 | /* a now contains the used bottom border for the cell */ |
804 | cell->border[BOTTOM].style = a.style; |
805 | cell->border[BOTTOM].c = a.c; |
806 | cell->border[BOTTOM].width = FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( cell->style, unit_len_ctx, a.width , a.unit)) >> 10) |
807 | cell->style, unit_len_ctx, a.width, a.unit))((css_unit_len2device_px( cell->style, unit_len_ctx, a.width , a.unit)) >> 10); |
808 | } |
809 | |
810 | |
811 | /* exported interface documented in html/table.h */ |
812 | bool_Bool |
813 | table_calculate_column_types(const css_unit_ctx *unit_len_ctx, struct box *table) |
814 | { |
815 | unsigned int i, j; |
816 | struct column *col; |
817 | struct box *row_group, *row, *cell; |
818 | |
819 | if (table->col) |
820 | /* table->col already constructed, for example frameset table */ |
821 | return true1; |
822 | |
823 | table->col = col = talloc_array(table, struct column, table->columns)(struct column *)_talloc_array(table, sizeof(struct column), table ->columns, "struct column"); |
824 | if (!col) |
825 | return false0; |
826 | |
827 | for (i = 0; i != table->columns; i++) { |
828 | col[i].type = COLUMN_WIDTH_UNKNOWN; |
829 | col[i].width = 0; |
830 | col[i].positioned = true1; |
831 | } |
832 | |
833 | /* 1st pass: cells with colspan 1 only */ |
834 | for (row_group = table->children; row_group; row_group =row_group->next) |
835 | for (row = row_group->children; row; row = row->next) |
836 | for (cell = row->children; cell; cell = cell->next) { |
837 | enum css_width_e type; |
838 | css_fixed value = 0; |
839 | css_unit unit = CSS_UNIT_PX; |
840 | |
841 | assert(cell->type == BOX_TABLE_CELL)((cell->type == BOX_TABLE_CELL) ? (void) (0) : __assert_fail ("cell->type == BOX_TABLE_CELL", "content/handlers/html/table.c" , 841, __extension__ __PRETTY_FUNCTION__)); |
842 | assert(cell->style)((cell->style) ? (void) (0) : __assert_fail ("cell->style" , "content/handlers/html/table.c", 842, __extension__ __PRETTY_FUNCTION__ )); |
843 | |
844 | if (cell->columns != 1) |
845 | continue; |
846 | i = cell->start_column; |
847 | |
848 | if (css_computed_position(cell->style) != |
849 | CSS_POSITION_ABSOLUTE && |
850 | css_computed_position(cell->style) != |
851 | CSS_POSITION_FIXED) { |
852 | col[i].positioned = false0; |
853 | } |
854 | |
855 | type = css_computed_width(cell->style, &value, &unit); |
856 | |
857 | /* fixed width takes priority over any other width type */ |
858 | if (col[i].type != COLUMN_WIDTH_FIXED && |
859 | type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) { |
860 | col[i].type = COLUMN_WIDTH_FIXED; |
861 | col[i].width = FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( cell->style, unit_len_ctx, value , unit)) >> 10) |
862 | cell->style,((css_unit_len2device_px( cell->style, unit_len_ctx, value , unit)) >> 10) |
863 | unit_len_ctx,((css_unit_len2device_px( cell->style, unit_len_ctx, value , unit)) >> 10) |
864 | value, unit))((css_unit_len2device_px( cell->style, unit_len_ctx, value , unit)) >> 10); |
865 | if (col[i].width < 0) |
866 | col[i].width = 0; |
867 | continue; |
868 | } |
869 | |
870 | if (col[i].type != COLUMN_WIDTH_UNKNOWN) |
871 | continue; |
872 | |
873 | if (type == CSS_WIDTH_SET && unit == CSS_UNIT_PCT) { |
874 | col[i].type = COLUMN_WIDTH_PERCENT; |
875 | col[i].width = FIXTOINT(value)((value) >> 10); |
876 | if (col[i].width < 0) |
877 | col[i].width = 0; |
878 | } else if (type == CSS_WIDTH_AUTO) { |
879 | col[i].type = COLUMN_WIDTH_AUTO; |
880 | } |
881 | } |
882 | |
883 | /* 2nd pass: cells which span multiple columns */ |
884 | for (row_group = table->children; row_group; row_group =row_group->next) |
885 | for (row = row_group->children; row; row = row->next) |
886 | for (cell = row->children; cell; cell = cell->next) { |
887 | unsigned int fixed_columns = 0, |
888 | percent_columns = 0, |
889 | auto_columns = 0, |
890 | unknown_columns = 0; |
891 | int fixed_width = 0, percent_width = 0; |
892 | enum css_width_e type; |
893 | css_fixed value = 0; |
894 | css_unit unit = CSS_UNIT_PX; |
895 | |
896 | if (cell->columns == 1) |
897 | continue; |
898 | i = cell->start_column; |
899 | |
900 | for (j = i; j < i + cell->columns; j++) { |
901 | col[j].positioned = false0; |
902 | } |
903 | |
904 | /* count column types in spanned cells */ |
905 | for (j = 0; j != cell->columns; j++) { |
906 | if (col[i + j].type == COLUMN_WIDTH_FIXED) { |
907 | fixed_width += col[i + j].width; |
908 | fixed_columns++; |
909 | } else if (col[i + j].type == COLUMN_WIDTH_PERCENT) { |
910 | percent_width += col[i + j].width; |
911 | percent_columns++; |
912 | } else if (col[i + j].type == COLUMN_WIDTH_AUTO) { |
913 | auto_columns++; |
914 | } else { |
915 | unknown_columns++; |
916 | } |
917 | } |
918 | |
919 | if (!unknown_columns) |
920 | continue; |
921 | |
922 | type = css_computed_width(cell->style, &value, &unit); |
923 | |
924 | /* if cell is fixed width, and all spanned columns are fixed |
925 | * or unknown width, split extra width among unknown columns */ |
926 | if (type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT && |
927 | fixed_columns + unknown_columns == |
928 | cell->columns) { |
929 | int width = (FIXTOFLT(css_unit_len2device_px(((float) (css_unit_len2device_px( cell->style, unit_len_ctx , value, unit)) / (float) (1 << 10)) |
930 | cell->style,((float) (css_unit_len2device_px( cell->style, unit_len_ctx , value, unit)) / (float) (1 << 10)) |
931 | unit_len_ctx,((float) (css_unit_len2device_px( cell->style, unit_len_ctx , value, unit)) / (float) (1 << 10)) |
932 | value, unit))((float) (css_unit_len2device_px( cell->style, unit_len_ctx , value, unit)) / (float) (1 << 10)) - |
933 | fixed_width) / unknown_columns; |
934 | if (width < 0) |
935 | width = 0; |
936 | for (j = 0; j != cell->columns; j++) { |
937 | if (col[i + j].type == COLUMN_WIDTH_UNKNOWN) { |
938 | col[i + j].type = COLUMN_WIDTH_FIXED; |
939 | col[i + j].width = width; |
940 | } |
941 | } |
942 | } |
943 | |
944 | /* as above for percentage width */ |
945 | if (type == CSS_WIDTH_SET && unit == CSS_UNIT_PCT && |
946 | percent_columns + unknown_columns == |
947 | cell->columns) { |
948 | int width = (FIXTOFLT(value)((float) (value) / (float) (1 << 10)) - |
949 | percent_width) / unknown_columns; |
950 | if (width < 0) |
951 | width = 0; |
952 | for (j = 0; j != cell->columns; j++) { |
953 | if (col[i + j].type == COLUMN_WIDTH_UNKNOWN) { |
954 | col[i + j].type = COLUMN_WIDTH_PERCENT; |
955 | col[i + j].width = width; |
956 | } |
957 | } |
958 | } |
959 | } |
960 | |
961 | /* use AUTO if no width type was specified */ |
962 | for (i = 0; i != table->columns; i++) { |
963 | if (col[i].type == COLUMN_WIDTH_UNKNOWN) |
964 | col[i].type = COLUMN_WIDTH_AUTO; |
965 | } |
966 | |
967 | #ifdef TABLE_DEBUG |
968 | for (i = 0; i != table->columns; i++) |
969 | NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/html/table.c", sizeof("content/handlers/html/table.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 980 , }; nslog__log(&_nslog_ctx, "table %p, column %u: type %s, width %i" , table, i, ((const char *[]){ "UNKNOWN", "FIXED", "AUTO", "PERCENT" , "RELATIVE", })[col[i].type], col[i].width); } } while(0) |
970 | "table %p, column %u: type %s, width %i",do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/html/table.c", sizeof("content/handlers/html/table.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 980 , }; nslog__log(&_nslog_ctx, "table %p, column %u: type %s, width %i" , table, i, ((const char *[]){ "UNKNOWN", "FIXED", "AUTO", "PERCENT" , "RELATIVE", })[col[i].type], col[i].width); } } while(0) |
971 | table,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/html/table.c", sizeof("content/handlers/html/table.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 980 , }; nslog__log(&_nslog_ctx, "table %p, column %u: type %s, width %i" , table, i, ((const char *[]){ "UNKNOWN", "FIXED", "AUTO", "PERCENT" , "RELATIVE", })[col[i].type], col[i].width); } } while(0) |
972 | i,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/html/table.c", sizeof("content/handlers/html/table.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 980 , }; nslog__log(&_nslog_ctx, "table %p, column %u: type %s, width %i" , table, i, ((const char *[]){ "UNKNOWN", "FIXED", "AUTO", "PERCENT" , "RELATIVE", })[col[i].type], col[i].width); } } while(0) |
973 | ((const char *[]){do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/html/table.c", sizeof("content/handlers/html/table.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 980 , }; nslog__log(&_nslog_ctx, "table %p, column %u: type %s, width %i" , table, i, ((const char *[]){ "UNKNOWN", "FIXED", "AUTO", "PERCENT" , "RELATIVE", })[col[i].type], col[i].width); } } while(0) |
974 | "UNKNOWN",do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/html/table.c", sizeof("content/handlers/html/table.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 980 , }; nslog__log(&_nslog_ctx, "table %p, column %u: type %s, width %i" , table, i, ((const char *[]){ "UNKNOWN", "FIXED", "AUTO", "PERCENT" , "RELATIVE", })[col[i].type], col[i].width); } } while(0) |
975 | "FIXED",do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/html/table.c", sizeof("content/handlers/html/table.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 980 , }; nslog__log(&_nslog_ctx, "table %p, column %u: type %s, width %i" , table, i, ((const char *[]){ "UNKNOWN", "FIXED", "AUTO", "PERCENT" , "RELATIVE", })[col[i].type], col[i].width); } } while(0) |
976 | "AUTO",do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/html/table.c", sizeof("content/handlers/html/table.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 980 , }; nslog__log(&_nslog_ctx, "table %p, column %u: type %s, width %i" , table, i, ((const char *[]){ "UNKNOWN", "FIXED", "AUTO", "PERCENT" , "RELATIVE", })[col[i].type], col[i].width); } } while(0) |
977 | "PERCENT",do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/html/table.c", sizeof("content/handlers/html/table.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 980 , }; nslog__log(&_nslog_ctx, "table %p, column %u: type %s, width %i" , table, i, ((const char *[]){ "UNKNOWN", "FIXED", "AUTO", "PERCENT" , "RELATIVE", })[col[i].type], col[i].width); } } while(0) |
978 | "RELATIVE",do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/html/table.c", sizeof("content/handlers/html/table.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 980 , }; nslog__log(&_nslog_ctx, "table %p, column %u: type %s, width %i" , table, i, ((const char *[]){ "UNKNOWN", "FIXED", "AUTO", "PERCENT" , "RELATIVE", })[col[i].type], col[i].width); } } while(0) |
979 | })[col[i].type],do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/html/table.c", sizeof("content/handlers/html/table.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 980 , }; nslog__log(&_nslog_ctx, "table %p, column %u: type %s, width %i" , table, i, ((const char *[]){ "UNKNOWN", "FIXED", "AUTO", "PERCENT" , "RELATIVE", })[col[i].type], col[i].width); } } while(0) |
980 | col[i].width)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf , NSLOG_LEVEL_INFO, "content/handlers/html/table.c", sizeof("content/handlers/html/table.c" ) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 980 , }; nslog__log(&_nslog_ctx, "table %p, column %u: type %s, width %i" , table, i, ((const char *[]){ "UNKNOWN", "FIXED", "AUTO", "PERCENT" , "RELATIVE", })[col[i].type], col[i].width); } } while(0); |
981 | #endif |
982 | |
983 | return true1; |
984 | } |
985 | |
986 | |
987 | /* exported interface documented in html/table.h */ |
988 | void table_used_border_for_cell(const css_unit_ctx *unit_len_ctx, struct box *cell) |
989 | { |
990 | int side; |
991 | |
992 | assert(cell->type == BOX_TABLE_CELL)((cell->type == BOX_TABLE_CELL) ? (void) (0) : __assert_fail ("cell->type == BOX_TABLE_CELL", "content/handlers/html/table.c" , 992, __extension__ __PRETTY_FUNCTION__)); |
993 | |
994 | if (css_computed_border_collapse(cell->style) == |
995 | CSS_BORDER_COLLAPSE_SEPARATE) { |
996 | css_fixed width = 0; |
997 | css_unit unit = CSS_UNIT_PX; |
998 | |
999 | /* Left border */ |
1000 | cell->border[LEFT].style = |
1001 | css_computed_border_left_style(cell->style); |
1002 | css_computed_border_left_color(cell->style, |
1003 | &cell->border[LEFT].c); |
1004 | css_computed_border_left_width(cell->style, &width, &unit); |
1005 | cell->border[LEFT].width = |
1006 | FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( cell->style, unit_len_ctx, width , unit)) >> 10) |
1007 | cell->style, unit_len_ctx,((css_unit_len2device_px( cell->style, unit_len_ctx, width , unit)) >> 10) |
1008 | width, unit))((css_unit_len2device_px( cell->style, unit_len_ctx, width , unit)) >> 10); |
1009 | |
1010 | /* Top border */ |
1011 | cell->border[TOP].style = |
1012 | css_computed_border_top_style(cell->style); |
1013 | css_computed_border_top_color(cell->style, |
1014 | &cell->border[TOP].c); |
1015 | css_computed_border_top_width(cell->style, &width, &unit); |
1016 | cell->border[TOP].width = |
1017 | FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( cell->style, unit_len_ctx, width , unit)) >> 10) |
1018 | cell->style, unit_len_ctx,((css_unit_len2device_px( cell->style, unit_len_ctx, width , unit)) >> 10) |
1019 | width, unit))((css_unit_len2device_px( cell->style, unit_len_ctx, width , unit)) >> 10); |
1020 | |
1021 | /* Right border */ |
1022 | cell->border[RIGHT].style = |
1023 | css_computed_border_right_style(cell->style); |
1024 | css_computed_border_right_color(cell->style, |
1025 | &cell->border[RIGHT].c); |
1026 | css_computed_border_right_width(cell->style, &width, &unit); |
1027 | cell->border[RIGHT].width = |
1028 | FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( cell->style, unit_len_ctx, width , unit)) >> 10) |
1029 | cell->style, unit_len_ctx,((css_unit_len2device_px( cell->style, unit_len_ctx, width , unit)) >> 10) |
1030 | width, unit))((css_unit_len2device_px( cell->style, unit_len_ctx, width , unit)) >> 10); |
1031 | |
1032 | /* Bottom border */ |
1033 | cell->border[BOTTOM].style = |
1034 | css_computed_border_bottom_style(cell->style); |
1035 | css_computed_border_bottom_color(cell->style, |
1036 | &cell->border[BOTTOM].c); |
1037 | css_computed_border_bottom_width(cell->style, &width, &unit); |
1038 | cell->border[BOTTOM].width = |
1039 | FIXTOINT(css_unit_len2device_px(((css_unit_len2device_px( cell->style, unit_len_ctx, width , unit)) >> 10) |
1040 | cell->style, unit_len_ctx,((css_unit_len2device_px( cell->style, unit_len_ctx, width , unit)) >> 10) |
1041 | width, unit))((css_unit_len2device_px( cell->style, unit_len_ctx, width , unit)) >> 10); |
1042 | } else { |
1043 | /* Left border */ |
1044 | table_used_left_border_for_cell(unit_len_ctx, cell); |
1045 | |
1046 | /* Top border */ |
1047 | table_used_top_border_for_cell(unit_len_ctx, cell); |
1048 | |
1049 | /* Right border */ |
1050 | table_used_right_border_for_cell(unit_len_ctx, cell); |
1051 | |
1052 | /* Bottom border */ |
1053 | table_used_bottom_border_for_cell(unit_len_ctx, cell); |
1054 | } |
1055 | |
1056 | /* Finally, ensure that any borders configured as |
1057 | * hidden or none have zero width. (c.f. layout_find_dimensions) */ |
1058 | for (side = 0; side != 4; side++) { |
1059 | if (cell->border[side].style == CSS_BORDER_STYLE_HIDDEN || |
1060 | cell->border[side].style == |
1061 | CSS_BORDER_STYLE_NONE) |
1062 | cell->border[side].width = 0; |
1063 | } |
1064 | } |