Bug Summary

File:content/handlers/html/table.c
Warning:line 440, column 4
Value stored to 'a_src' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name table.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/var/lib/jenkins/workspace/scan-build-netsurf -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -I . -I include -I build/Linux-framebuffer -I frontends -I content/handlers -D WITH_JPEG -U WITH_PDF_EXPORT -D LIBICONV_PLUG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /usr/include/x86_64-linux-gnu -D WITH_CURL -D WITH_OPENSSL -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D UTF8PROC_EXPORTS -D WITH_UTF8PROC -D WITH_WEBP -I /usr/include/libpng16 -D WITH_PNG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include/ -D WITH_BMP -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_GIF -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NS_SVG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSSPRITE -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSPSL -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSLOG -D NETSURF_UA_FORMAT_STRING="Mozilla/5.0 (%s) NetSurf/%d.%d" -D NETSURF_HOMEPAGE="about:welcome" -D NETSURF_LOG_LEVEL=VERBOSE -D NETSURF_BUILTIN_LOG_FILTER="(level:WARNING || cat:jserrors)" -D NETSURF_BUILTIN_VERBOSE_FILTER="(level:VERBOSE || cat:jserrors)" -D STMTEXPR=1 -D nsframebuffer -D small -D NETSURF_FB_RESPATH="${HOME}/.netsurf/:${NETSURFRES}:/var/lib/jenkins/artifacts-x86_64-linux-gnu/share/netsurf:./frontends/framebuffer/res" -D NETSURF_FB_FONTPATH="/usr/share/fonts/truetype/dejavu:/usr/share/fonts/truetype/msttcorefonts" -D NETSURF_FB_FONT_SANS_SERIF="DejaVuSans.ttf" -D NETSURF_FB_FONT_SANS_SERIF_BOLD="DejaVuSans-Bold.ttf" -D NETSURF_FB_FONT_SANS_SERIF_ITALIC="DejaVuSans-Oblique.ttf" -D NETSURF_FB_FONT_SANS_SERIF_ITALIC_BOLD="DejaVuSans-BoldOblique.ttf" -D NETSURF_FB_FONT_SERIF="DejaVuSerif.ttf" -D NETSURF_FB_FONT_SERIF_BOLD="DejaVuSerif-Bold.ttf" -D NETSURF_FB_FONT_MONOSPACE="DejaVuSansMono.ttf" -D NETSURF_FB_FONT_MONOSPACE_BOLD="DejaVuSansMono-Bold.ttf" -D NETSURF_FB_FONT_CURSIVE="Comic_Sans_MS.ttf" -D NETSURF_FB_FONT_FANTASY="Impact.ttf" -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D _POSIX_C_SOURCE=200809L -D _XOPEN_SOURCE=700 -D _BSD_SOURCE -D _DEFAULT_SOURCE -D _NETBSD_SOURCE -D DUK_OPT_HAVE_CUSTOM_H -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wwrite-strings -Wno-unused-parameter -Wno-unused-but-set-variable -std=c99 -fconst-strings -fdebug-compilation-dir=/var/lib/jenkins/workspace/scan-build-netsurf -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-display-progress -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/lib/jenkins/workspace/scan-build-netsurf/clangScanBuildReports/2024-12-17-120558-2788052-1 -x c content/handlers/html/table.c
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 */
42struct 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 */
61static bool_Bool
62table_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 */
172static void
173table_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 */
210static bool_Bool
211table_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 */
321static bool_Bool
322table_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 */
386static void
387table_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 */
518static void
519table_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 */
618static void
619table_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 */
722static void
723table_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 */
812bool_Bool
813table_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 */
988void 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}