NetSurf
redraw_border.c
Go to the documentation of this file.
1/*
2 * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/**
20 * \file
21 *
22 * Redrawing CONTENT_HTML borders implementation.
23 */
24
25#include <stdbool.h>
26#include <stdlib.h>
27
28#include "utils/utils.h"
29#include "utils/log.h"
30#include "netsurf/plotters.h"
31#include "netsurf/css.h"
32
33#include "html/box.h"
34#include "html/private.h"
35
36
39};
42};
45};
48};
51};
54};
55
56
57static inline nserror
59 const plot_style_t *style,
60 const struct rect *clip,
61 struct rect *rect)
62{
63 nserror res;
64
65 rect->x0 = (clip->x0 > rect->x0) ? clip->x0 : rect->x0;
66 rect->y0 = (clip->y0 > rect->y0) ? clip->y0 : rect->y0;
67 rect->x1 = (clip->x1 < rect->x1) ? clip->x1 : rect->x1;
68 rect->y1 = (clip->y1 < rect->y1) ? clip->y1 : rect->y1;
69 if ((rect->x0 < rect->x1) && (rect->y0 < rect->y1)) {
70 /* valid clip rectangles only */
71 res = ctx->plot->rectangle(ctx, style, rect);
72 } else {
73 res = NSERROR_OK;
74 }
75 return res;
76}
77
78
79/**
80 * Draw one border.
81 *
82 * \param side index of border side (TOP, RIGHT, BOTTOM, LEFT)
83 * \param p array of precomputed border vertices
84 * \param c colour for border
85 * \param style border line style
86 * \param thickness border thickness
87 * \param rectangular whether border is rectangular
88 * \param clip cliping area for redrawing border.
89 * \param ctx current redraw context
90 * \return NSERROR_OK if successful otherwise appropriate error code
91 */
92static nserror
94 const int *p,
95 colour c,
96 enum css_border_style_e style,
97 int thickness,
98 bool rectangular,
99 const struct rect *clip,
100 const struct redraw_context *ctx)
101{
102 int z[8]; /* Vertices of border part */
103 unsigned int light = side;
104 plot_style_t *plot_style_bdr_in;
105 plot_style_t *plot_style_bdr_out;
106 nserror res = NSERROR_OK;
107 struct rect rect;
108
109 if (c == NS_TRANSPARENT) {
110 return res;
111 }
112
121
122 switch (style) {
123 case CSS_BORDER_STYLE_DOTTED:
126 case CSS_BORDER_STYLE_DASHED:
127 rect.x0 = (p[0] + p[2]) / 2;
128 rect.y0 = (p[1] + p[3]) / 2;
129 rect.x1 = (p[4] + p[6]) / 2;
130 rect.y1 = (p[5] + p[7]) / 2;
131 res = ctx->plot->line(ctx, &plot_style_bdr, &rect);
132 break;
133
134 case CSS_BORDER_STYLE_SOLID:
135 /* solid is the default */
136 default:
137 if (rectangular || thickness == 1) {
138
139 if (side == TOP || side == RIGHT) {
140 rect.x0 = p[2];
141 rect.y0 = p[3];
142 if ((side == TOP) &&
143 (p[4] - p[6] != 0)) {
144 rect.x1 = p[4];
145 } else {
146 rect.x1 = p[6];
147 }
148 rect.y1 = p[7];
149 } else {
150 rect.x0 = p[6];
151 rect.y0 = p[7];
152 rect.x1 = p[2];
153 if ((side == LEFT) &&
154 (p[1] - p[3] != 0)) {
155 rect.y1 = p[1];
156 } else {
157 rect.y1 = p[3];
158 }
159 }
160 res = plot_clipped_rectangle(ctx,
162 clip,
163 &rect);
164 } else {
165 res = ctx->plot->polygon(ctx, &plot_style_fillbdr, p, 4);
166 }
167 break;
168
169 case CSS_BORDER_STYLE_DOUBLE:
170 z[0] = p[0];
171 z[1] = p[1];
172 z[2] = (p[0] * 2 + p[2]) / 3;
173 z[3] = (p[1] * 2 + p[3]) / 3;
174 z[4] = (p[6] * 2 + p[4]) / 3;
175 z[5] = (p[7] * 2 + p[5]) / 3;
176 z[6] = p[6];
177 z[7] = p[7];
178 res = ctx->plot->polygon(ctx, &plot_style_fillbdr, z, 4);
179 if (res == NSERROR_OK) {
180 z[0] = p[2];
181 z[1] = p[3];
182 z[2] = (p[2] * 2 + p[0]) / 3;
183 z[3] = (p[3] * 2 + p[1]) / 3;
184 z[4] = (p[4] * 2 + p[6]) / 3;
185 z[5] = (p[5] * 2 + p[7]) / 3;
186 z[6] = p[4];
187 z[7] = p[5];
188 res = ctx->plot->polygon(ctx, &plot_style_fillbdr, z, 4);
189 }
190 break;
191
192 case CSS_BORDER_STYLE_GROOVE:
193 light = 3 - light;
195 case CSS_BORDER_STYLE_RIDGE:
196 /* choose correct colours for each part of the border line */
197 if (light <= 1) {
198 plot_style_bdr_in = &plot_style_fillbdr_dark;
199 plot_style_bdr_out = &plot_style_fillbdr_light;
200 } else {
201 plot_style_bdr_in = &plot_style_fillbdr_light;
202 plot_style_bdr_out = &plot_style_fillbdr_dark;
203 }
204
205 /* Render border */
206 if ((rectangular || thickness == 2) && thickness != 1) {
207 /* Border made up from two parts and can be
208 * plotted with rectangles
209 */
210
211 /* First part */
212 if (side == TOP || side == RIGHT) {
213 rect.x0 = (p[0] + p[2]) / 2;
214 rect.y0 = (p[1] + p[3]) / 2;
215 rect.x1 = p[6];
216 rect.y1 = p[7];
217 } else {
218 rect.x0 = p[6];
219 rect.y0 = p[7];
220 rect.x1 = (p[0] + p[2]) / 2;
221 rect.y1 = (p[1] + p[3]) / 2;
222 }
223 res = plot_clipped_rectangle(ctx,
224 plot_style_bdr_in,
225 clip,
226 &rect);
227 if (res != NSERROR_OK) {
228 return res;
229 }
230
231 /* Second part */
232 if (side == TOP || side == RIGHT) {
233 rect.x0 = p[2];
234 rect.y0 = p[3];
235 rect.x1 = (p[6] + p[4]) / 2;
236 rect.y1 = (p[7] + p[5]) / 2;
237 } else {
238 rect.x0 = (p[6] + p[4]) / 2;
239 rect.y0 = (p[7] + p[5]) / 2;
240 rect.x1 = p[2];
241 rect.y1 = p[3];
242 }
243 res = plot_clipped_rectangle(ctx,
244 plot_style_bdr_out,
245 clip,
246 &rect);
247 } else if (thickness == 1) {
248 /* Border made up from one part which can be
249 * plotted as a rectangle
250 */
251
252 if (side == TOP || side == RIGHT) {
253 rect.x0 = p[2];
254 rect.y0 = p[3];
255 rect.x1 = p[6];
256 rect.y1 = p[7];
257 rect.x1 = ((side == TOP) && (p[4] - p[6] != 0)) ?
258 rect.x1 + p[4] - p[6] : rect.x1;
259
260 res = plot_clipped_rectangle(ctx,
261 plot_style_bdr_in,
262 clip,
263 &rect);
264 } else {
265 rect.x0 = p[6];
266 rect.y0 = p[7];
267 rect.x1 = p[2];
268 rect.y1 = p[3];
269 rect.y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ?
270 rect.y1 + p[1] - p[3] : rect.y1;
271 res = plot_clipped_rectangle(ctx,
272 plot_style_bdr_out,
273 clip,
274 &rect);
275 }
276 } else {
277 /* Border made up from two parts and can't be
278 * plotted with rectangles
279 */
280 z[0] = p[0];
281 z[1] = p[1];
282 z[2] = (p[0] + p[2]) / 2;
283 z[3] = (p[1] + p[3]) / 2;
284 z[4] = (p[6] + p[4]) / 2;
285 z[5] = (p[7] + p[5]) / 2;
286 z[6] = p[6];
287 z[7] = p[7];
288 res = ctx->plot->polygon(ctx, plot_style_bdr_in, z, 4);
289 if (res == NSERROR_OK) {
290 z[0] = p[2];
291 z[1] = p[3];
292 z[6] = p[4];
293 z[7] = p[5];
294 res = ctx->plot->polygon(ctx,
295 plot_style_bdr_out,
296 z,
297 4);
298 }
299 }
300 break;
301
302 case CSS_BORDER_STYLE_INSET:
303 light = (light + 2) % 4;
305 case CSS_BORDER_STYLE_OUTSET:
306 /* choose correct colours for each part of the border line */
307 switch (light) {
308 case 0:
309 plot_style_bdr_in = &plot_style_fillbdr_light;
310 plot_style_bdr_out = &plot_style_fillbdr_dlight;
311 break;
312 case 1:
313 plot_style_bdr_in = &plot_style_fillbdr_ddark;
314 plot_style_bdr_out = &plot_style_fillbdr_dark;
315 break;
316 case 2:
317 plot_style_bdr_in = &plot_style_fillbdr_dark;
318 plot_style_bdr_out = &plot_style_fillbdr_ddark;
319 break;
320 case 3:
321 plot_style_bdr_in = &plot_style_fillbdr_dlight;
322 plot_style_bdr_out = &plot_style_fillbdr_light;
323 break;
324 default:
325 plot_style_bdr_in = &plot_style_fillbdr;
326 plot_style_bdr_out = &plot_style_fillbdr;
327 break;
328 }
329
330 /* Render border */
331 if ((rectangular || thickness == 2) && thickness != 1) {
332 /* Border made up from two parts and can be
333 * plotted with rectangles
334 */
335
336 /* First part */
337 if (side == TOP || side == RIGHT) {
338 rect.x0 = (p[0] + p[2]) / 2;
339 rect.y0 = (p[1] + p[3]) / 2;
340 rect.x1 = p[6];
341 rect.y1 = p[7];
342 } else {
343 rect.x0 = p[6];
344 rect.y0 = p[7];
345 rect.x1 = (p[0] + p[2]) / 2;
346 rect.y1 = (p[1] + p[3]) / 2;
347 }
348 res = plot_clipped_rectangle(ctx,
349 plot_style_bdr_in,
350 clip,
351 &rect);
352 if (res != NSERROR_OK) {
353 return res;
354 }
355
356 /* Second part */
357 if (side == TOP || side == RIGHT) {
358 rect.x0 = p[2];
359 rect.y0 = p[3];
360 rect.x1 = (p[6] + p[4]) / 2;
361 rect.y1 = (p[7] + p[5]) / 2;
362 } else {
363 rect.x0 = (p[6] + p[4]) / 2;
364 rect.y0 = (p[7] + p[5]) / 2;
365 rect.x1 = p[2];
366 rect.y1 = p[3];
367 }
368 res = plot_clipped_rectangle(ctx,
369 plot_style_bdr_out,
370 clip,
371 &rect);
372 } else if (thickness == 1) {
373 /* Border made up from one part which can be
374 * plotted as a rectangle
375 */
376
377 if (side == TOP || side == RIGHT) {
378 rect.x0 = p[2];
379 rect.y0 = p[3];
380 rect.x1 = p[6];
381 rect.y1 = p[7];
382 rect.x1 = ((side == TOP) && (p[4] - p[6] != 0)) ?
383 rect.x1 + p[4] - p[6] : rect.x1;
384 res = plot_clipped_rectangle(ctx,
385 plot_style_bdr_in,
386 clip,
387 &rect);
388 } else {
389 rect.x0 = p[6];
390 rect.y0 = p[7];
391 rect.x1 = p[2];
392 rect.y1 = p[3];
393 rect.y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ?
394 rect.y1 + p[1] - p[3] : rect.y1;
395 res = plot_clipped_rectangle(ctx,
396 plot_style_bdr_out,
397 clip,
398 &rect);
399 }
400 } else {
401 /* Border made up from two parts and can't be
402 * plotted with rectangles
403 */
404
405 z[0] = p[0];
406 z[1] = p[1];
407 z[2] = (p[0] + p[2]) / 2;
408 z[3] = (p[1] + p[3]) / 2;
409 z[4] = (p[6] + p[4]) / 2;
410 z[5] = (p[7] + p[5]) / 2;
411 z[6] = p[6];
412 z[7] = p[7];
413 res = ctx->plot->polygon(ctx, plot_style_bdr_in, z, 4);
414 if (res != NSERROR_OK) {
415 return res;
416 }
417 z[0] = p[2];
418 z[1] = p[3];
419 z[6] = p[4];
420 z[7] = p[5];
421 res = ctx->plot->polygon(ctx, plot_style_bdr_out, z, 4);
422 }
423 break;
424 }
425
426 return res;
427}
428
429
430/**
431 * Draw borders for a box.
432 *
433 * \param box box to draw
434 * \param x_parent coordinate of left padding edge of parent of box
435 * \param y_parent coordinate of top padding edge of parent of box
436 * \param p_width width of padding box
437 * \param p_height height of padding box
438 * \param clip cliping area for redrawing border.
439 * \param scale scale for redraw
440 * \param ctx current redraw context
441 * \return true if successful, false otherwise
442 */
443bool
445 int x_parent,
446 int y_parent,
447 int p_width,
448 int p_height,
449 const struct rect *clip,
450 float scale,
451 const struct redraw_context *ctx)
452{
453 unsigned int sides[] = { LEFT, RIGHT, TOP, BOTTOM };
454 int top = box->border[TOP].width;
455 int right = box->border[RIGHT].width;
456 int bottom = box->border[BOTTOM].width;
457 int left = box->border[LEFT].width;
458 int x, y;
459 unsigned int i, side;
460 int p[8]; /* Box border vertices */
461 int z[8]; /* Border vertices */
462 bool square_end_1 = false;
463 bool square_end_2 = false;
464 nserror res;
465
466 x = x_parent + box->x;
467 y = y_parent + box->y;
468
469 if (scale != 1.0) {
470 top *= scale;
471 right *= scale;
472 bottom *= scale;
473 left *= scale;
474 x *= scale;
475 y *= scale;
476 }
477
478 assert(box->style);
479
480 /* Calculate border vertices
481 *
482 * A----------------------+
483 * | \ / |
484 * | B--------------+ |
485 * | | | |
486 * | +--------------C |
487 * | / \ |
488 * +----------------------D
489 */
490 p[0] = x - left; p[1] = y - top; /* A */
491 p[2] = x; p[3] = y; /* B */
492 p[4] = x + p_width; p[5] = y + p_height; /* C */
493 p[6] = x + p_width + right; p[7] = y + p_height + bottom; /* D */
494
495 for (i = 0; i != 4; i++) {
496 colour col = 0;
497 side = sides[i]; /* plot order */
498
499 if (box->border[side].width == 0 ||
501 continue;
502 }
503
504 switch (side) {
505 case LEFT:
506 square_end_1 = (top == 0);
507 square_end_2 = (bottom == 0);
508
509 z[0] = p[0]; z[1] = p[7];
510 z[2] = p[2]; z[3] = p[5];
511 z[4] = p[2]; z[5] = p[3];
512 z[6] = p[0]; z[7] = p[1];
513
514 if (nscss_color_is_transparent(box->border[TOP].c) == false &&
515 box->border[TOP].style != CSS_BORDER_STYLE_DOUBLE) {
516 /* make border overhang top corner fully,
517 * if top border is opaque
518 */
519 z[5] -= top;
520 square_end_1 = true;
521 }
522 if (nscss_color_is_transparent(box->border[BOTTOM].c) == false &&
523 box->border[BOTTOM].style != CSS_BORDER_STYLE_DOUBLE) {
524 /* make border overhang bottom corner fully,
525 * if bottom border is opaque
526 */
527 z[3] += bottom;
528 square_end_2 = true;
529 }
530
531 col = nscss_color_to_ns(box->border[side].c);
532
533 res = html_redraw_border_plot(side,
534 z,
535 col,
536 box->border[side].style,
537 box->border[side].width * scale,
538 square_end_1 && square_end_2,
539 clip,
540 ctx);
541 if (res != NSERROR_OK) {
542 return false;
543 }
544 break;
545
546 case RIGHT:
547 square_end_1 = (top == 0);
548 square_end_2 = (bottom == 0);
549
550 z[0] = p[6]; z[1] = p[1];
551 z[2] = p[4]; z[3] = p[3];
552 z[4] = p[4]; z[5] = p[5];
553 z[6] = p[6]; z[7] = p[7];
554
555 if (nscss_color_is_transparent(box->border[TOP].c) == false &&
556 box->border[TOP].style != CSS_BORDER_STYLE_DOUBLE) {
557 /* make border overhang top corner fully,
558 * if top border is opaque
559 */
560 z[3] -= top;
561 square_end_1 = true;
562 }
563 if (nscss_color_is_transparent(box->border[BOTTOM].c) == false &&
564 box->border[BOTTOM].style != CSS_BORDER_STYLE_DOUBLE) {
565 /* make border overhang bottom corner fully,
566 * if bottom border is opaque
567 */
568 z[5] += bottom;
569 square_end_2 = true;
570 }
571
572 col = nscss_color_to_ns(box->border[side].c);
573
574 res = html_redraw_border_plot(side,
575 z,
576 col,
577 box->border[side].style,
578 box->border[side].width * scale,
579 square_end_1 && square_end_2,
580 clip,
581 ctx);
582 if (res != NSERROR_OK) {
583 return false;
584 }
585 break;
586
587 case TOP:
588 if (clip->y0 > p[3]) {
589 /* clip rectangle is below border; nothing to
590 * plot
591 */
592 continue;
593 }
594
595 square_end_1 = (left == 0);
596 square_end_2 = (right == 0);
597
598 z[0] = p[2]; z[1] = p[3];
599 z[2] = p[0]; z[3] = p[1];
600 z[4] = p[6]; z[5] = p[1];
601 z[6] = p[4]; z[7] = p[3];
602
603 if (box->border[TOP].style == CSS_BORDER_STYLE_SOLID &&
604 box->border[TOP].c == box->border[LEFT].c) {
605 /* don't bother overlapping left corner if
606 * it's the same colour anyway
607 */
608 z[2] += left;
609 square_end_1 = true;
610 }
611 if (box->border[TOP].style == CSS_BORDER_STYLE_SOLID &&
612 box->border[TOP].c == box->border[RIGHT].c) {
613 /* don't bother overlapping right corner if
614 * it's the same colour anyway
615 */
616 z[4] -= right;
617 square_end_2 = true;
618 }
619
620 col = nscss_color_to_ns(box->border[side].c);
621
622 res = html_redraw_border_plot(side,
623 z,
624 col,
625 box->border[side].style,
626 box->border[side].width * scale,
627 square_end_1 && square_end_2,
628 clip,
629 ctx);
630 if (res != NSERROR_OK) {
631 return false;
632 }
633 break;
634
635 case BOTTOM:
636 if (clip->y1 < p[5]) {
637 /* clip rectangle is above border; nothing to
638 * plot
639 */
640 continue;
641 }
642
643 square_end_1 = (left == 0);
644 square_end_2 = (right == 0);
645
646 z[0] = p[4]; z[1] = p[5];
647 z[2] = p[6]; z[3] = p[7];
648 z[4] = p[0]; z[5] = p[7];
649 z[6] = p[2]; z[7] = p[5];
650
651 if (box->border[BOTTOM].style == CSS_BORDER_STYLE_SOLID &&
652 box->border[BOTTOM].c == box->border[LEFT].c) {
653 /* don't bother overlapping left corner if
654 * it's the same colour anyway
655 */
656 z[4] += left;
657 square_end_1 = true;
658 }
659 if (box->border[BOTTOM].style == CSS_BORDER_STYLE_SOLID &&
660 box->border[BOTTOM].c == box->border[RIGHT].c) {
661 /* don't bother overlapping right corner if
662 * it's the same colour anyway
663 */
664 z[2] -= right;
665 square_end_2 = true;
666 }
667
668 col = nscss_color_to_ns(box->border[side].c);
669
670 res = html_redraw_border_plot(side,
671 z,
672 col,
673 box->border[side].style,
674 box->border[side].width * scale,
675 square_end_1 && square_end_2,
676 clip,
677 ctx);
678 if (res != NSERROR_OK) {
679 return false;
680 }
681 break;
682
683 default:
684 assert(side == TOP || side == BOTTOM ||
685 side == LEFT || side == RIGHT);
686 break;
687 }
688 }
689
690 return true;
691}
692
693
694/**
695 * Draw an inline's borders.
696 *
697 * \param box BOX_INLINE which created the border
698 * \param b coordinates of border edge rectangle
699 * \param clip cliping area for redrawing border.
700 * \param scale scale for redraw
701 * \param first true if this is the first rectangle associated with the inline
702 * \param last true if this is the last rectangle associated with the inline
703 * \param ctx current redraw context
704 * \return true if successful, false otherwise
705 */
706bool
708 struct rect b,
709 const struct rect *clip,
710 float scale,
711 bool first,
712 bool last,
713 const struct redraw_context *ctx)
714{
715 int top = box->border[TOP].width;
716 int right = box->border[RIGHT].width;
717 int bottom = box->border[BOTTOM].width;
718 int left = box->border[LEFT].width;
719 colour col;
720 int p[8]; /* Box border vertices */
721 int z[8]; /* Border vertices */
722 bool square_end_1;
723 bool square_end_2;
724 nserror res;
725
726 if (scale != 1.0) {
727 top *= scale;
728 right *= scale;
729 bottom *= scale;
730 left *= scale;
731 }
732
733 /* Calculate border vertices
734 *
735 * A----------------------+
736 * | \ / |
737 * | B--------------+ |
738 * | | | |
739 * | +--------------C |
740 * | / \ |
741 * +----------------------D
742 */
743 p[0] = b.x0; p[1] = b.y0; /* A */
744 p[2] = first ? b.x0 + left : b.x0; p[3] = b.y0 + top; /* B */
745 p[4] = last ? b.x1 - right : b.x1; p[5] = b.y1 - bottom; /* C */
746 p[6] = b.x1; p[7] = b.y1; /* D */
747
748 assert(box->style);
749
750 /* Left */
751 square_end_1 = (top == 0);
752 square_end_2 = (bottom == 0);
753 if (left != 0 &&
754 first &&
757
758 z[0] = p[0]; z[1] = p[7];
759 z[2] = p[2]; z[3] = p[5];
760 z[4] = p[2]; z[5] = p[3];
761 z[6] = p[0]; z[7] = p[1];
762
763 if (nscss_color_is_transparent(box->border[TOP].c) == false &&
764 box->border[TOP].style != CSS_BORDER_STYLE_DOUBLE) {
765 /* make border overhang top corner fully,
766 * if top border is opaque
767 */
768 z[5] -= top;
769 square_end_1 = true;
770 }
771
772 if (nscss_color_is_transparent(box->border[BOTTOM].c) == false &&
773 box->border[BOTTOM].style != CSS_BORDER_STYLE_DOUBLE) {
774 /* make border overhang bottom corner fully,
775 * if bottom border is opaque
776 */
777 z[3] += bottom;
778 square_end_2 = true;
779 }
780
782 z,
783 col,
785 left,
786 square_end_1 && square_end_2,
787 clip,
788 ctx);
789 if (res != NSERROR_OK) {
790 return false;
791 }
792 }
793
794 /* Right */
795 square_end_1 = (top == 0);
796 square_end_2 = (bottom == 0);
797 if (right != 0 &&
798 last &&
801
802 z[0] = p[6]; z[1] = p[1];
803 z[2] = p[4]; z[3] = p[3];
804 z[4] = p[4]; z[5] = p[5];
805 z[6] = p[6]; z[7] = p[7];
806
807 if (nscss_color_is_transparent(box->border[TOP].c) == false &&
808 box->border[TOP].style != CSS_BORDER_STYLE_DOUBLE) {
809 /* make border overhang top corner fully,
810 * if top border is opaque
811 */
812 z[3] -= top;
813 square_end_1 = true;
814 }
815
816 if (nscss_color_is_transparent(box->border[BOTTOM].c) == false &&
817 box->border[BOTTOM].style != CSS_BORDER_STYLE_DOUBLE) {
818 /* make border overhang bottom corner fully,
819 * if bottom border is opaque
820 */
821 z[5] += bottom;
822 square_end_2 = true;
823 }
824
826 z,
827 col,
829 right,
830 square_end_1 && square_end_2,
831 clip,
832 ctx);
833 if (res != NSERROR_OK) {
834 return false;
835 }
836 }
837
838 /* Top */
839 square_end_1 = (left == 0);
840 square_end_2 = (right == 0);
841 if (top != 0 &&
844
845 z[0] = p[2]; z[1] = p[3];
846 z[2] = p[0]; z[3] = p[1];
847 z[4] = p[6]; z[5] = p[1];
848 z[6] = p[4]; z[7] = p[3];
849
850 if (first &&
851 box->border[TOP].style == CSS_BORDER_STYLE_SOLID &&
852 box->border[TOP].c == box->border[LEFT].c) {
853 /* don't bother overlapping left corner if
854 * it's the same colour anyway
855 */
856 z[2] += left;
857 square_end_1 = true;
858 }
859
860 if (last &&
861 box->border[TOP].style == CSS_BORDER_STYLE_SOLID &&
862 box->border[TOP].c == box->border[RIGHT].c) {
863 /* don't bother overlapping right corner if
864 * it's the same colour anyway
865 */
866 z[4] -= right;
867 square_end_2 = true;
868 }
869
871 z,
872 col,
874 top,
875 square_end_1 && square_end_2,
876 clip,
877 ctx);
878 if (res != NSERROR_OK) {
879 return false;
880 }
881 }
882
883 /* Bottom */
884 square_end_1 = (left == 0);
885 square_end_2 = (right == 0);
886 if (bottom != 0 &&
889
890 z[0] = p[4]; z[1] = p[5];
891 z[2] = p[6]; z[3] = p[7];
892 z[4] = p[0]; z[5] = p[7];
893 z[6] = p[2]; z[7] = p[5];
894
895 if (first &&
896 box->border[BOTTOM].style == CSS_BORDER_STYLE_SOLID &&
897 box->border[BOTTOM].c == box->border[LEFT].c) {
898 /* don't bother overlapping left corner if
899 * it's the same colour anyway
900 */
901 z[4] += left;
902 square_end_1 = true;
903 }
904
905 if (last &&
906 box->border[BOTTOM].style == CSS_BORDER_STYLE_SOLID &&
907 box->border[BOTTOM].c == box->border[RIGHT].c) {
908 /* don't bother overlapping right corner if
909 * it's the same colour anyway
910 */
911 z[2] -= right;
912 square_end_2 = true;
913 }
914
916 z,
917 col,
919 bottom,
920 square_end_1 && square_end_2,
921 clip,
922 ctx);
923 if (res != NSERROR_OK) {
924 return false;
925 }
926 }
927
928 return true;
929}
Box interface.
@ TOP
Definition: box.h:98
@ BOTTOM
Definition: box.h:98
@ LEFT
Definition: box.h:98
@ RIGHT
Definition: box.h:98
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_OK
No error.
Definition: errors.h:30
Netsurf core css API.
#define nscss_color_is_transparent(color)
Determine if a CSS color primitive is transparent.
Definition: css.h:62
#define nscss_color_to_ns(c)
Convert a CSS color to a NetSurf colour primitive.
Definition: css.h:35
Target independent plotting interface.
#define PLOT_STYLE_RADIX
22:10 fixed point
Definition: plot_style.h:42
#define lighten_colour(c1)
Definition: plot_style.h:150
#define darken_colour(c1)
Definition: plot_style.h:133
@ PLOT_OP_TYPE_DASH
Dashed plot.
Definition: plot_style.h:69
@ PLOT_OP_TYPE_DOT
Dotted plot.
Definition: plot_style.h:68
@ PLOT_OP_TYPE_SOLID
Solid colour.
Definition: plot_style.h:67
#define double_lighten_colour(c1)
Definition: plot_style.h:156
#define NS_TRANSPARENT
Transparent colour value.
Definition: plot_style.h:39
#define double_darken_colour(c1)
Definition: plot_style.h:138
Private data for text/html content.
static plot_style_t plot_style_fillbdr_dlight
Definition: redraw_border.c:52
static nserror html_redraw_border_plot(const int side, const int *p, colour c, enum css_border_style_e style, int thickness, bool rectangular, const struct rect *clip, const struct redraw_context *ctx)
Draw one border.
Definition: redraw_border.c:93
bool html_redraw_borders(struct box *box, int x_parent, int y_parent, int p_width, int p_height, const struct rect *clip, float scale, const struct redraw_context *ctx)
Draw borders for a box.
static plot_style_t plot_style_fillbdr_light
Definition: redraw_border.c:46
static plot_style_t plot_style_bdr
Definition: redraw_border.c:37
static plot_style_t plot_style_fillbdr
Definition: redraw_border.c:40
static plot_style_t plot_style_fillbdr_ddark
Definition: redraw_border.c:49
static plot_style_t plot_style_fillbdr_dark
Definition: redraw_border.c:43
bool html_redraw_inline_borders(struct box *box, struct rect b, const struct rect *clip, float scale, bool first, bool last, const struct redraw_context *ctx)
Draw an inline's borders.
static nserror plot_clipped_rectangle(const struct redraw_context *ctx, const plot_style_t *style, const struct rect *clip, struct rect *rect)
Definition: redraw_border.c:58
enum css_border_style_e style
border-style
Definition: box.h:105
css_color c
border-color value
Definition: box.h:106
int width
border-width (pixels)
Definition: box.h:107
Node in box tree.
Definition: box.h:177
struct box_border border[4]
Border: TOP, RIGHT, BOTTOM, LEFT.
Definition: box.h:327
css_computed_style * style
Style for this box.
Definition: box.h:205
int x
Coordinate of left padding edge relative to parent box, or relative to ancestor that contains this bo...
Definition: box.h:280
int y
Coordinate of top padding edge, relative as for x.
Definition: box.h:284
Plot style for stroke/fill plotters.
Definition: plot_style.h:76
colour fill_colour
Colour of fill.
Definition: plot_style.h:81
plot_style_fixed stroke_width
Width of stroke, in pixels.
Definition: plot_style.h:78
plot_operation_type_t fill_type
Fill plot type.
Definition: plot_style.h:80
colour stroke_colour
Colour of stroke.
Definition: plot_style.h:79
plot_operation_type_t stroke_type
Stroke plot type.
Definition: plot_style.h:77
nserror(* line)(const struct redraw_context *ctx, const plot_style_t *pstyle, const struct rect *line)
Plots a line.
Definition: plotters.h:170
nserror(* polygon)(const struct redraw_context *ctx, const plot_style_t *pstyle, const int *p, unsigned int n)
Plot a polygon.
Definition: plotters.h:207
nserror(* rectangle)(const struct redraw_context *ctx, const plot_style_t *pstyle, const struct rect *rectangle)
Plots a rectangle.
Definition: plotters.h:188
Rectangle coordinates.
Definition: types.h:40
int x0
Definition: types.h:41
int y0
Top left.
Definition: types.h:41
int x1
Definition: types.h:42
int y1
Bottom right.
Definition: types.h:42
Redraw context.
Definition: plotters.h:51
const struct plotter_table * plot
Current plot operation table.
Definition: plotters.h:73
uint32_t colour
Colour type: XBGR.
Definition: types.h:35
Interface to a number of general purpose functionality.
#define fallthrough
switch fall through
Definition: utils.h:119
static nserror clip(const struct redraw_context *ctx, const struct rect *clip)
Sets a clip rectangle for subsequent plot operations.
Definition: plot.c:357