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