NetSurf
html_redraw.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2008 James Bursa <bursa@users.sourceforge.net>
3  * Copyright 2004-2007 John M Bell <jmb202@ecs.soton.ac.uk>
4  * Copyright 2004-2007 Richard Wilson <info@tinct.net>
5  * Copyright 2005-2006 Adrian Lees <adrianl@users.sourceforge.net>
6  * Copyright 2006 Rob Kendrick <rjek@netsurf-browser.org>
7  * Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
8  * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
9  *
10  * This file is part of NetSurf, http://www.netsurf-browser.org/
11  *
12  * NetSurf is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; version 2 of the License.
15  *
16  * NetSurf is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <http://www.gnu.org/licenses/>.
23  */
24 
25 /**
26  * \file
27  *
28  * Redrawing CONTENT_HTML implementation.
29  */
30 
31 #include "utils/config.h"
32 #include <assert.h>
33 #include <stdbool.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <math.h>
37 #include <dom/dom.h>
38 
39 #include "utils/log.h"
40 #include "utils/messages.h"
41 #include "utils/utils.h"
42 #include "utils/nsoption.h"
43 #include "netsurf/content.h"
44 #include "netsurf/browser_window.h"
45 #include "netsurf/plotters.h"
46 #include "netsurf/bitmap.h"
47 #include "netsurf/layout.h"
49 #include "css/utils.h"
50 #include "desktop/selection.h"
51 #include "desktop/print.h"
52 #include "desktop/scrollbar.h"
53 #include "desktop/textarea.h"
54 #include "desktop/gui_internal.h"
55 
56 #include "html/box.h"
57 #include "html/box_inspect.h"
58 #include "html/box_manipulate.h"
59 #include "html/font.h"
60 #include "html/form_internal.h"
61 #include "html/html_internal.h"
62 #include "html/layout.h"
63 #include "html/search.h"
64 
65 
66 bool html_redraw_debug = false;
67 
68 /**
69  * Determine if a box has a background that needs drawing
70  *
71  * \param box Box to consider
72  * \return True if box has a background, false otherwise.
73  */
75 {
76  if (box->background != NULL)
77  return true;
78 
79  if (box->style != NULL) {
80  css_color colour;
81 
82  css_computed_background_color(box->style, &colour);
83 
84  if (nscss_color_is_transparent(colour) == false)
85  return true;
86  }
87 
88  return false;
89 }
90 
91 /**
92  * Find the background box for a box
93  *
94  * \param box Box to find background box for
95  * \return Pointer to background box, or NULL if there is none
96  */
97 static struct box *html_redraw_find_bg_box(struct box *box)
98 {
99  /* Thanks to backwards compatibility, CSS defines the following:
100  *
101  * + If the box is for the root element and it has a background,
102  * use that (and then process the body box with no special case)
103  * + If the box is for the root element and it has no background,
104  * then use the background (if any) from the body element as if
105  * it were specified on the root. Then, when the box for the body
106  * element is processed, ignore the background.
107  * + For any other box, just use its own styling.
108  */
109  if (box->parent == NULL) {
110  /* Root box */
112  return box;
113 
114  /* No background on root box: consider body box, if any */
115  if (box->children != NULL) {
117  return box->children;
118  }
119  } else if (box->parent != NULL && box->parent->parent == NULL) {
120  /* Body box: only render background if root has its own */
123  return box;
124  } else {
125  /* Any other box */
127  return box;
128  }
129 
130  return NULL;
131 }
132 
133 /**
134  * Redraw a short text string, complete with highlighting
135  * (for selection/search)
136  *
137  * \param utf8_text pointer to UTF-8 text string
138  * \param utf8_len length of string, in bytes
139  * \param offset byte offset within textual representation
140  * \param space width of space that follows string (0 = no space)
141  * \param fstyle text style to use (pass text size unscaled)
142  * \param x x ordinate at which to plot text
143  * \param y y ordinate at which to plot text
144  * \param clip pointer to current clip rectangle
145  * \param height height of text string
146  * \param scale current display scale (1.0 = 100%)
147  * \param excluded exclude this text string from the selection
148  * \param c Content being redrawn.
149  * \param sel Selection context
150  * \param search Search context
151  * \param ctx current redraw context
152  * \return true iff successful and redraw should proceed
153  */
154 
155 static bool
156 text_redraw(const char *utf8_text,
157  size_t utf8_len,
158  size_t offset,
159  int space,
160  const plot_font_style_t *fstyle,
161  int x,
162  int y,
163  const struct rect *clip,
164  int height,
165  float scale,
166  bool excluded,
167  struct content *c,
168  const struct selection *sel,
169  struct search_context *search,
170  const struct redraw_context *ctx)
171 {
172  bool highlighted = false;
173  plot_font_style_t plot_fstyle = *fstyle;
174  nserror res;
175 
176  /* Need scaled text size to pass to plotters */
177  plot_fstyle.size *= scale;
178 
179  /* is this box part of a selection? */
180  if (!excluded && ctx->interactive == true) {
181  unsigned len = utf8_len + (space ? 1 : 0);
182  unsigned start_idx;
183  unsigned end_idx;
184 
185  /* first try the browser window's current selection */
187  offset, offset + len,
188  &start_idx, &end_idx)) {
189  highlighted = true;
190  }
191 
192  /* what about the current search operation, if any? */
193  if (!highlighted && (search != NULL) &&
195  offset, offset + len,
196  &start_idx, &end_idx,
197  search)) {
198  highlighted = true;
199  }
200 
201  /* \todo make search terms visible within selected text */
202  if (highlighted) {
203  struct rect r;
204  unsigned endtxt_idx = end_idx;
205  bool clip_changed = false;
206  bool text_visible = true;
207  int startx, endx;
208  plot_style_t pstyle_fill_hback = *plot_style_fill_white;
209  plot_font_style_t fstyle_hback = plot_fstyle;
210 
211  if (end_idx > utf8_len) {
212  /* adjust for trailing space, not present in
213  * utf8_text */
214  assert(end_idx == utf8_len + 1);
215  endtxt_idx = utf8_len;
216  }
217 
218  res = guit->layout->width(fstyle,
219  utf8_text, start_idx,
220  &startx);
221  if (res != NSERROR_OK) {
222  startx = 0;
223  }
224 
225  res = guit->layout->width(fstyle,
226  utf8_text, endtxt_idx,
227  &endx);
228  if (res != NSERROR_OK) {
229  endx = 0;
230  }
231 
232  /* is there a trailing space that should be highlighted
233  * as well? */
234  if (end_idx > utf8_len) {
235  endx += space;
236  }
237 
238  if (scale != 1.0) {
239  startx *= scale;
240  endx *= scale;
241  }
242 
243  /* draw any text preceding highlighted portion */
244  if ((start_idx > 0) &&
245  (ctx->plot->text(ctx,
246  &plot_fstyle,
247  x,
248  y + (int)(height * 0.75 * scale),
249  utf8_text,
250  start_idx) != NSERROR_OK))
251  return false;
252 
253  pstyle_fill_hback.fill_colour = fstyle->foreground;
254 
255  /* highlighted portion */
256  r.x0 = x + startx;
257  r.y0 = y;
258  r.x1 = x + endx;
259  r.y1 = y + height * scale;
260  res = ctx->plot->rectangle(ctx, &pstyle_fill_hback, &r);
261  if (res != NSERROR_OK) {
262  return false;
263  }
264 
265  if (start_idx > 0) {
266  int px0 = max(x + startx, clip->x0);
267  int px1 = min(x + endx, clip->x1);
268 
269  if (px0 < px1) {
270  r.x0 = px0;
271  r.y0 = clip->y0;
272  r.x1 = px1;
273  r.y1 = clip->y1;
274  res = ctx->plot->clip(ctx, &r);
275  if (res != NSERROR_OK) {
276  return false;
277  }
278 
279  clip_changed = true;
280  } else {
281  text_visible = false;
282  }
283  }
284 
285  fstyle_hback.background =
286  pstyle_fill_hback.fill_colour;
287  fstyle_hback.foreground = colour_to_bw_furthest(
288  pstyle_fill_hback.fill_colour);
289 
290  if (text_visible &&
291  (ctx->plot->text(ctx,
292  &fstyle_hback,
293  x,
294  y + (int)(height * 0.75 * scale),
295  utf8_text,
296  endtxt_idx) != NSERROR_OK)) {
297  return false;
298  }
299 
300  /* draw any text succeeding highlighted portion */
301  if (endtxt_idx < utf8_len) {
302  int px0 = max(x + endx, clip->x0);
303  if (px0 < clip->x1) {
304 
305  r.x0 = px0;
306  r.y0 = clip->y0;
307  r.x1 = clip->x1;
308  r.y1 = clip->y1;
309  res = ctx->plot->clip(ctx, &r);
310  if (res != NSERROR_OK) {
311  return false;
312  }
313 
314  clip_changed = true;
315 
316  res = ctx->plot->text(ctx,
317  &plot_fstyle,
318  x,
319  y + (int)(height * 0.75 * scale),
320  utf8_text,
321  utf8_len);
322  if (res != NSERROR_OK) {
323  return false;
324  }
325  }
326  }
327 
328  if (clip_changed &&
329  (ctx->plot->clip(ctx, clip) != NSERROR_OK)) {
330  return false;
331  }
332  }
333  }
334 
335  if (!highlighted) {
336  res = ctx->plot->text(ctx,
337  &plot_fstyle,
338  x,
339  y + (int) (height * 0.75 * scale),
340  utf8_text,
341  utf8_len);
342  if (res != NSERROR_OK) {
343  return false;
344  }
345  }
346  return true;
347 }
348 
349 
350 /**
351  * Plot a checkbox.
352  *
353  * \param x left coordinate
354  * \param y top coordinate
355  * \param width dimensions of checkbox
356  * \param height dimensions of checkbox
357  * \param selected the checkbox is selected
358  * \param ctx current redraw context
359  * \return true if successful, false otherwise
360  */
361 
362 static bool html_redraw_checkbox(int x, int y, int width, int height,
363  bool selected, const struct redraw_context *ctx)
364 {
365  double z;
366  nserror res;
367  struct rect rect;
368 
369  z = width * 0.15;
370  if (z == 0) {
371  z = 1;
372  }
373 
374  rect.x0 = x;
375  rect.y0 = y ;
376  rect.x1 = x + width;
377  rect.y1 = y + height;
378  res = ctx->plot->rectangle(ctx, plot_style_fill_wbasec, &rect);
379  if (res != NSERROR_OK) {
380  return false;
381  }
382 
383  /* dark line across top */
384  rect.y1 = y;
385  res = ctx->plot->line(ctx, plot_style_stroke_darkwbasec, &rect);
386  if (res != NSERROR_OK) {
387  return false;
388  }
389 
390  /* dark line across left */
391  rect.x1 = x;
392  rect.y1 = y + height;
393  res = ctx->plot->line(ctx, plot_style_stroke_darkwbasec, &rect);
394  if (res != NSERROR_OK) {
395  return false;
396  }
397 
398  /* light line across right */
399  rect.x0 = x + width;
400  rect.x1 = x + width;
401  res = ctx->plot->line(ctx, plot_style_stroke_lightwbasec, &rect);
402  if (res != NSERROR_OK) {
403  return false;
404  }
405 
406  /* light line across bottom */
407  rect.x0 = x;
408  rect.y0 = y + height;
409  res = ctx->plot->line(ctx, plot_style_stroke_lightwbasec, &rect);
410  if (res != NSERROR_OK) {
411  return false;
412  }
413 
414  if (selected) {
415  if (width < 12 || height < 12) {
416  /* render a solid box instead of a tick */
417  rect.x0 = x + z + z;
418  rect.y0 = y + z + z;
419  rect.x1 = x + width - z;
420  rect.y1 = y + height - z;
421  res = ctx->plot->rectangle(ctx, plot_style_fill_wblobc, &rect);
422  if (res != NSERROR_OK) {
423  return false;
424  }
425  } else {
426  /* render a tick, as it'll fit comfortably */
427  rect.x0 = x + width - z;
428  rect.y0 = y + z;
429  rect.x1 = x + (z * 3);
430  rect.y1 = y + height - z;
431  res = ctx->plot->line(ctx, plot_style_stroke_wblobc, &rect);
432  if (res != NSERROR_OK) {
433  return false;
434  }
435 
436  rect.x0 = x + (z * 3);
437  rect.y0 = y + height - z;
438  rect.x1 = x + z + z;
439  rect.y1 = y + (height / 2);
440  res = ctx->plot->line(ctx, plot_style_stroke_wblobc, &rect);
441  if (res != NSERROR_OK) {
442  return false;
443  }
444  }
445  }
446  return true;
447 }
448 
449 
450 /**
451  * Plot a radio icon.
452  *
453  * \param x left coordinate
454  * \param y top coordinate
455  * \param width dimensions of radio icon
456  * \param height dimensions of radio icon
457  * \param selected the radio icon is selected
458  * \param ctx current redraw context
459  * \return true if successful, false otherwise
460  */
461 static bool html_redraw_radio(int x, int y, int width, int height,
462  bool selected, const struct redraw_context *ctx)
463 {
464  nserror res;
465 
466  /* plot background of radio button */
467  res = ctx->plot->disc(ctx,
469  x + width * 0.5,
470  y + height * 0.5,
471  width * 0.5 - 1);
472  if (res != NSERROR_OK) {
473  return false;
474  }
475 
476  /* plot dark arc */
477  res = ctx->plot->arc(ctx,
479  x + width * 0.5,
480  y + height * 0.5,
481  width * 0.5 - 1,
482  45,
483  225);
484  if (res != NSERROR_OK) {
485  return false;
486  }
487 
488  /* plot light arc */
489  res = ctx->plot->arc(ctx,
491  x + width * 0.5,
492  y + height * 0.5,
493  width * 0.5 - 1,
494  225,
495  45);
496  if (res != NSERROR_OK) {
497  return false;
498  }
499 
500  if (selected) {
501  /* plot selection blob */
502  res = ctx->plot->disc(ctx,
504  x + width * 0.5,
505  y + height * 0.5,
506  width * 0.3 - 1);
507  if (res != NSERROR_OK) {
508  return false;
509  }
510  }
511 
512  return true;
513 }
514 
515 
516 /**
517  * Plot a file upload input.
518  *
519  * \param x left coordinate
520  * \param y top coordinate
521  * \param width dimensions of input
522  * \param height dimensions of input
523  * \param box box of input
524  * \param scale scale for redraw
525  * \param background_colour current background colour
526  * \param len_ctx Length conversion context
527  * \param ctx current redraw context
528  * \return true if successful, false otherwise
529  */
530 
531 static bool html_redraw_file(int x, int y, int width, int height,
532  struct box *box, float scale, colour background_colour,
533  const nscss_len_ctx *len_ctx,
534  const struct redraw_context *ctx)
535 {
536  int text_width;
537  const char *text;
538  size_t length;
539  plot_font_style_t fstyle;
540  nserror res;
541 
542  font_plot_style_from_css(len_ctx, box->style, &fstyle);
543  fstyle.background = background_colour;
544 
545  if (box->gadget->value) {
546  text = box->gadget->value;
547  } else {
548  text = messages_get("Form_Drop");
549  }
550  length = strlen(text);
551 
552  res = guit->layout->width(&fstyle, text, length, &text_width);
553  if (res != NSERROR_OK) {
554  return false;
555  }
556  text_width *= scale;
557  if (width < text_width + 8) {
558  x = x + width - text_width - 4;
559  } else {
560  x = x + 4;
561  }
562 
563  res = ctx->plot->text(ctx, &fstyle, x, y + height * 0.75, text, length);
564  if (res != NSERROR_OK) {
565  return false;
566  }
567  return true;
568 }
569 
570 
571 /**
572  * Plot background images.
573  *
574  * The reason for the presence of \a background is the backwards compatibility
575  * mess that is backgrounds on &lt;body&gt;. The background will be drawn relative
576  * to \a box, using the background information contained within \a background.
577  *
578  * \param x coordinate of box
579  * \param y coordinate of box
580  * \param box box to draw background image of
581  * \param scale scale for redraw
582  * \param clip current clip rectangle
583  * \param background_colour current background colour
584  * \param background box containing background details (usually \a box)
585  * \param len_ctx Length conversion context
586  * \param ctx current redraw context
587  * \return true if successful, false otherwise
588  */
589 
590 static bool html_redraw_background(int x, int y, struct box *box, float scale,
591  const struct rect *clip, colour *background_colour,
592  struct box *background,
593  const nscss_len_ctx *len_ctx,
594  const struct redraw_context *ctx)
595 {
596  bool repeat_x = false;
597  bool repeat_y = false;
598  bool plot_colour = true;
599  bool plot_content;
600  bool clip_to_children = false;
601  struct box *clip_box = box;
602  int ox = x, oy = y;
603  int width, height;
604  css_fixed hpos = 0, vpos = 0;
605  css_unit hunit = CSS_UNIT_PX, vunit = CSS_UNIT_PX;
606  struct box *parent;
607  struct rect r = *clip;
608  css_color bgcol;
609  plot_style_t pstyle_fill_bg = {
611  .fill_colour = *background_colour,
612  };
613  nserror res;
614 
615  if (ctx->background_images == false)
616  return true;
617 
618  plot_content = (background->background != NULL);
619 
620  if (plot_content) {
621  if (!box->parent) {
622  /* Root element, special case:
623  * background origin calc. is based on margin box */
624  x -= box->margin[LEFT] * scale;
625  y -= box->margin[TOP] * scale;
626  width = box->margin[LEFT] + box->padding[LEFT] +
627  box->width + box->padding[RIGHT] +
628  box->margin[RIGHT];
629  height = box->margin[TOP] + box->padding[TOP] +
630  box->height + box->padding[BOTTOM] +
631  box->margin[BOTTOM];
632  } else {
633  width = box->padding[LEFT] + box->width +
634  box->padding[RIGHT];
635  height = box->padding[TOP] + box->height +
636  box->padding[BOTTOM];
637  }
638  /* handle background-repeat */
639  switch (css_computed_background_repeat(background->style)) {
640  case CSS_BACKGROUND_REPEAT_REPEAT:
641  repeat_x = repeat_y = true;
642  /* optimisation: only plot the colour if
643  * bitmap is not opaque */
644  plot_colour = !content_get_opaque(background->background);
645  break;
646 
647  case CSS_BACKGROUND_REPEAT_REPEAT_X:
648  repeat_x = true;
649  break;
650 
651  case CSS_BACKGROUND_REPEAT_REPEAT_Y:
652  repeat_y = true;
653  break;
654 
655  case CSS_BACKGROUND_REPEAT_NO_REPEAT:
656  break;
657 
658  default:
659  break;
660  }
661 
662  /* handle background-position */
663  css_computed_background_position(background->style,
664  &hpos, &hunit, &vpos, &vunit);
665  if (hunit == CSS_UNIT_PCT) {
666  x += (width -
667  content_get_width(background->background)) *
668  scale * FIXTOFLT(hpos) / 100.;
669  } else {
670  x += (int) (FIXTOFLT(nscss_len2px(len_ctx, hpos, hunit,
671  background->style)) * scale);
672  }
673 
674  if (vunit == CSS_UNIT_PCT) {
675  y += (height -
676  content_get_height(background->background)) *
677  scale * FIXTOFLT(vpos) / 100.;
678  } else {
679  y += (int) (FIXTOFLT(nscss_len2px(len_ctx, vpos, vunit,
680  background->style)) * scale);
681  }
682  }
683 
684  /* special case for table rows as their background needs
685  * to be clipped to all the cells */
686  if (box->type == BOX_TABLE_ROW) {
687  css_fixed h = 0, v = 0;
688  css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
689 
690  for (parent = box->parent;
691  ((parent) && (parent->type != BOX_TABLE));
692  parent = parent->parent);
693  assert(parent && (parent->style));
694 
695  css_computed_border_spacing(parent->style, &h, &hu, &v, &vu);
696 
697  clip_to_children = (h > 0) || (v > 0);
698 
699  if (clip_to_children)
700  clip_box = box->children;
701  }
702 
703  for (; clip_box; clip_box = clip_box->next) {
704  /* clip to child boxes if needed */
705  if (clip_to_children) {
706  assert(clip_box->type == BOX_TABLE_CELL);
707 
708  /* update clip.* to the child cell */
709  r.x0 = ox + (clip_box->x * scale);
710  r.y0 = oy + (clip_box->y * scale);
711  r.x1 = r.x0 + (clip_box->padding[LEFT] +
712  clip_box->width +
713  clip_box->padding[RIGHT]) * scale;
714  r.y1 = r.y0 + (clip_box->padding[TOP] +
715  clip_box->height +
716  clip_box->padding[BOTTOM]) * scale;
717 
718  if (r.x0 < clip->x0) r.x0 = clip->x0;
719  if (r.y0 < clip->y0) r.y0 = clip->y0;
720  if (r.x1 > clip->x1) r.x1 = clip->x1;
721  if (r.y1 > clip->y1) r.y1 = clip->y1;
722 
723  css_computed_background_color(clip_box->style, &bgcol);
724 
725  /* <td> attributes override <tr> */
726  /* if the background content is opaque there
727  * is no need to plot underneath it.
728  */
729  if ((r.x0 >= r.x1) ||
730  (r.y0 >= r.y1) ||
731  (nscss_color_is_transparent(bgcol) == false) ||
732  ((clip_box->background != NULL) &&
733  content_get_opaque(clip_box->background)))
734  continue;
735  }
736 
737  /* plot the background colour */
738  css_computed_background_color(background->style, &bgcol);
739 
740  if (nscss_color_is_transparent(bgcol) == false) {
741  *background_colour = nscss_color_to_ns(bgcol);
742  pstyle_fill_bg.fill_colour = *background_colour;
743  if (plot_colour) {
744  res = ctx->plot->rectangle(ctx, &pstyle_fill_bg, &r);
745  if (res != NSERROR_OK) {
746  return false;
747  }
748  }
749  }
750  /* and plot the image */
751  if (plot_content) {
752  width = content_get_width(background->background);
753  height = content_get_height(background->background);
754 
755  /* ensure clip area only as large as required */
756  if (!repeat_x) {
757  if (r.x0 < x)
758  r.x0 = x;
759  if (r.x1 > x + width * scale)
760  r.x1 = x + width * scale;
761  }
762  if (!repeat_y) {
763  if (r.y0 < y)
764  r.y0 = y;
765  if (r.y1 > y + height * scale)
766  r.y1 = y + height * scale;
767  }
768  /* valid clipping rectangles only */
769  if ((r.x0 < r.x1) && (r.y0 < r.y1)) {
770  struct content_redraw_data bg_data;
771 
772  res = ctx->plot->clip(ctx, &r);
773  if (res != NSERROR_OK) {
774  return false;
775  }
776 
777  bg_data.x = x;
778  bg_data.y = y;
779  bg_data.width = ceilf(width * scale);
780  bg_data.height = ceilf(height * scale);
782  bg_data.scale = scale;
783  bg_data.repeat_x = repeat_x;
784  bg_data.repeat_y = repeat_y;
785 
786  /* We just continue if redraw fails */
787  content_redraw(background->background,
788  &bg_data, &r, ctx);
789  }
790  }
791 
792  /* only <tr> rows being clipped to child boxes loop */
793  if (!clip_to_children)
794  return true;
795  }
796  return true;
797 }
798 
799 
800 /**
801  * Plot an inline's background and/or background image.
802  *
803  * \param x coordinate of box
804  * \param y coordinate of box
805  * \param box BOX_INLINE which created the background
806  * \param scale scale for redraw
807  * \param clip coordinates of clip rectangle
808  * \param b coordinates of border edge rectangle
809  * \param first true if this is the first rectangle associated with the inline
810  * \param last true if this is the last rectangle associated with the inline
811  * \param background_colour updated to current background colour if plotted
812  * \param len_ctx Length conversion context
813  * \param ctx current redraw context
814  * \return true if successful, false otherwise
815  */
816 
817 static bool html_redraw_inline_background(int x, int y, struct box *box,
818  float scale, const struct rect *clip, struct rect b,
819  bool first, bool last, colour *background_colour,
820  const nscss_len_ctx *len_ctx,
821  const struct redraw_context *ctx)
822 {
823  struct rect r = *clip;
824  bool repeat_x = false;
825  bool repeat_y = false;
826  bool plot_colour = true;
827  bool plot_content;
828  css_fixed hpos = 0, vpos = 0;
829  css_unit hunit = CSS_UNIT_PX, vunit = CSS_UNIT_PX;
830  css_color bgcol;
831  plot_style_t pstyle_fill_bg = {
833  .fill_colour = *background_colour,
834  };
835  nserror res;
836 
837  plot_content = (box->background != NULL);
838 
839  if (html_redraw_printing && nsoption_bool(remove_backgrounds))
840  return true;
841 
842  if (plot_content) {
843  /* handle background-repeat */
844  switch (css_computed_background_repeat(box->style)) {
845  case CSS_BACKGROUND_REPEAT_REPEAT:
846  repeat_x = repeat_y = true;
847  /* optimisation: only plot the colour if
848  * bitmap is not opaque
849  */
850  plot_colour = !content_get_opaque(box->background);
851  break;
852 
853  case CSS_BACKGROUND_REPEAT_REPEAT_X:
854  repeat_x = true;
855  break;
856 
857  case CSS_BACKGROUND_REPEAT_REPEAT_Y:
858  repeat_y = true;
859  break;
860 
861  case CSS_BACKGROUND_REPEAT_NO_REPEAT:
862  break;
863 
864  default:
865  break;
866  }
867 
868  /* handle background-position */
869  css_computed_background_position(box->style,
870  &hpos, &hunit, &vpos, &vunit);
871  if (hunit == CSS_UNIT_PCT) {
872  x += (b.x1 - b.x0 -
874  scale) * FIXTOFLT(hpos) / 100.;
875 
876  if (!repeat_x && ((hpos < 2 && !first) ||
877  (hpos > 98 && !last))){
878  plot_content = false;
879  }
880  } else {
881  x += (int) (FIXTOFLT(nscss_len2px(len_ctx, hpos, hunit,
882  box->style)) * scale);
883  }
884 
885  if (vunit == CSS_UNIT_PCT) {
886  y += (b.y1 - b.y0 -
888  scale) * FIXTOFLT(vpos) / 100.;
889  } else {
890  y += (int) (FIXTOFLT(nscss_len2px(len_ctx, vpos, vunit,
891  box->style)) * scale);
892  }
893  }
894 
895  /* plot the background colour */
896  css_computed_background_color(box->style, &bgcol);
897 
898  if (nscss_color_is_transparent(bgcol) == false) {
899  *background_colour = nscss_color_to_ns(bgcol);
900  pstyle_fill_bg.fill_colour = *background_colour;
901 
902  if (plot_colour) {
903  res = ctx->plot->rectangle(ctx, &pstyle_fill_bg, &r);
904  if (res != NSERROR_OK) {
905  return false;
906  }
907  }
908  }
909  /* and plot the image */
910  if (plot_content) {
911  int width = content_get_width(box->background);
913 
914  if (!repeat_x) {
915  if (r.x0 < x)
916  r.x0 = x;
917  if (r.x1 > x + width * scale)
918  r.x1 = x + width * scale;
919  }
920  if (!repeat_y) {
921  if (r.y0 < y)
922  r.y0 = y;
923  if (r.y1 > y + height * scale)
924  r.y1 = y + height * scale;
925  }
926  /* valid clipping rectangles only */
927  if ((r.x0 < r.x1) && (r.y0 < r.y1)) {
928  struct content_redraw_data bg_data;
929 
930  res = ctx->plot->clip(ctx, &r);
931  if (res != NSERROR_OK) {
932  return false;
933  }
934 
935  bg_data.x = x;
936  bg_data.y = y;
937  bg_data.width = ceilf(width * scale);
938  bg_data.height = ceilf(height * scale);
940  bg_data.scale = scale;
941  bg_data.repeat_x = repeat_x;
942  bg_data.repeat_y = repeat_y;
943 
944  /* We just continue if redraw fails */
945  content_redraw(box->background, &bg_data, &r, ctx);
946  }
947  }
948 
949  return true;
950 }
951 
952 
953 /**
954  * Plot text decoration for an inline box.
955  *
956  * \param box box to plot decorations for, of type BOX_INLINE
957  * \param x x coordinate of parent of box
958  * \param y y coordinate of parent of box
959  * \param scale scale for redraw
960  * \param colour colour for decorations
961  * \param ratio position of line as a ratio of line height
962  * \param ctx current redraw context
963  * \return true if successful, false otherwise
964  */
965 
966 static bool
968  int x, int y,
969  float scale,
970  colour colour,
971  float ratio,
972  const struct redraw_context *ctx)
973 {
974  struct box *c;
975  plot_style_t plot_style_box = {
977  .stroke_colour = colour,
978  };
979  nserror res;
980  struct rect rect;
981 
982  for (c = box->next;
983  c && c != box->inline_end;
984  c = c->next) {
985  if (c->type != BOX_TEXT) {
986  continue;
987  }
988  rect.x0 = (x + c->x) * scale;
989  rect.y0 = (y + c->y + c->height * ratio) * scale;
990  rect.x1 = (x + c->x + c->width) * scale;
991  rect.y1 = (y + c->y + c->height * ratio) * scale;
992  res = ctx->plot->line(ctx, &plot_style_box, &rect);
993  if (res != NSERROR_OK) {
994  return false;
995  }
996  }
997  return true;
998 }
999 
1000 
1001 /**
1002  * Plot text decoration for an non-inline box.
1003  *
1004  * \param box box to plot decorations for, of type other than BOX_INLINE
1005  * \param x x coordinate of box
1006  * \param y y coordinate of box
1007  * \param scale scale for redraw
1008  * \param colour colour for decorations
1009  * \param ratio position of line as a ratio of line height
1010  * \param ctx current redraw context
1011  * \return true if successful, false otherwise
1012  */
1013 
1014 static bool
1016  int x, int y,
1017  float scale,
1018  colour colour,
1019  float ratio,
1020  const struct redraw_context *ctx)
1021 {
1022  struct box *c;
1023  plot_style_t plot_style_box = {
1025  .stroke_colour = colour,
1026  };
1027  nserror res;
1028  struct rect rect;
1029 
1030  /* draw through text descendants */
1031  for (c = box->children; c; c = c->next) {
1032  if (c->type == BOX_TEXT) {
1033  rect.x0 = (x + c->x) * scale;
1034  rect.y0 = (y + c->y + c->height * ratio) * scale;
1035  rect.x1 = (x + c->x + c->width) * scale;
1036  rect.y1 = (y + c->y + c->height * ratio) * scale;
1037  res = ctx->plot->line(ctx, &plot_style_box, &rect);
1038  if (res != NSERROR_OK) {
1039  return false;
1040  }
1041  } else if ((c->type == BOX_INLINE_CONTAINER) || (c->type == BOX_BLOCK)) {
1043  x + c->x, y + c->y,
1044  scale, colour, ratio, ctx))
1045  return false;
1046  }
1047  }
1048  return true;
1049 }
1050 
1051 
1052 /**
1053  * Plot text decoration for a box.
1054  *
1055  * \param box box to plot decorations for
1056  * \param x_parent x coordinate of parent of box
1057  * \param y_parent y coordinate of parent of box
1058  * \param scale scale for redraw
1059  * \param background_colour current background colour
1060  * \param ctx current redraw context
1061  * \return true if successful, false otherwise
1062  */
1063 
1065  int x_parent, int y_parent, float scale,
1066  colour background_colour, const struct redraw_context *ctx)
1067 {
1068  static const enum css_text_decoration_e decoration[] = {
1069  CSS_TEXT_DECORATION_UNDERLINE, CSS_TEXT_DECORATION_OVERLINE,
1070  CSS_TEXT_DECORATION_LINE_THROUGH };
1071  static const float line_ratio[] = { 0.9, 0.1, 0.5 };
1072  colour fgcol;
1073  unsigned int i;
1074  css_color col;
1075 
1076  css_computed_color(box->style, &col);
1077  fgcol = nscss_color_to_ns(col);
1078 
1079  /* antialias colour for under/overline */
1080  if (html_redraw_printing == false)
1081  fgcol = blend_colour(background_colour, fgcol);
1082 
1083  if (box->type == BOX_INLINE) {
1084  if (!box->inline_end)
1085  return true;
1086  for (i = 0; i != NOF_ELEMENTS(decoration); i++)
1087  if (css_computed_text_decoration(box->style) &
1088  decoration[i])
1090  x_parent, y_parent, scale,
1091  fgcol, line_ratio[i], ctx))
1092  return false;
1093  } else {
1094  for (i = 0; i != NOF_ELEMENTS(decoration); i++)
1095  if (css_computed_text_decoration(box->style) &
1096  decoration[i])
1098  x_parent + box->x,
1099  y_parent + box->y,
1100  scale,
1101  fgcol, line_ratio[i], ctx))
1102  return false;
1103  }
1104 
1105  return true;
1106 }
1107 
1108 
1109 /**
1110  * Redraw the text content of a box, possibly partially highlighted
1111  * because the text has been selected, or matches a search operation.
1112  *
1113  * \param html The html content to redraw text within.
1114  * \param box box with text content
1115  * \param x x co-ord of box
1116  * \param y y co-ord of box
1117  * \param clip current clip rectangle
1118  * \param scale current scale setting (1.0 = 100%)
1119  * \param current_background_color
1120  * \param ctx current redraw context
1121  * \return true iff successful and redraw should proceed
1122  */
1123 
1124 static bool html_redraw_text_box(const html_content *html, struct box *box,
1125  int x, int y, const struct rect *clip, float scale,
1126  colour current_background_color,
1127  const struct redraw_context *ctx)
1128 {
1129  bool excluded = (box->object != NULL);
1130  plot_font_style_t fstyle;
1131 
1132  font_plot_style_from_css(&html->len_ctx, box->style, &fstyle);
1133  fstyle.background = current_background_color;
1134 
1135  if (!text_redraw(box->text, box->length, box->byte_offset,
1136  box->space, &fstyle, x, y,
1137  clip, box->height, scale, excluded,
1138  (struct content *)html, &html->sel,
1139  html->search, ctx))
1140  return false;
1141 
1142  return true;
1143 }
1144 
1145 bool html_redraw_box(const html_content *html, struct box *box,
1146  int x_parent, int y_parent,
1147  const struct rect *clip, float scale,
1148  colour current_background_color,
1149  const struct redraw_context *ctx);
1150 
1151 /**
1152  * Draw the various children of a box.
1153  *
1154  * \param html html content
1155  * \param box box to draw children of
1156  * \param x_parent coordinate of parent box
1157  * \param y_parent coordinate of parent box
1158  * \param clip clip rectangle
1159  * \param scale scale for redraw
1160  * \param current_background_color background colour under this box
1161  * \param ctx current redraw context
1162  * \return true if successful, false otherwise
1163  */
1164 
1165 static bool html_redraw_box_children(const html_content *html, struct box *box,
1166  int x_parent, int y_parent,
1167  const struct rect *clip, float scale,
1168  colour current_background_color,
1169  const struct redraw_context *ctx)
1170 {
1171  struct box *c;
1172 
1173  for (c = box->children; c; c = c->next) {
1174 
1175  if (c->type != BOX_FLOAT_LEFT && c->type != BOX_FLOAT_RIGHT)
1176  if (!html_redraw_box(html, c,
1177  x_parent + box->x -
1179  y_parent + box->y -
1181  clip, scale, current_background_color,
1182  ctx))
1183  return false;
1184  }
1185  for (c = box->float_children; c; c = c->next_float)
1186  if (!html_redraw_box(html, c,
1187  x_parent + box->x -
1189  y_parent + box->y -
1191  clip, scale, current_background_color,
1192  ctx))
1193  return false;
1194 
1195  return true;
1196 }
1197 
1198 /**
1199  * Recursively draw a box.
1200  *
1201  * \param html html content
1202  * \param box box to draw
1203  * \param x_parent coordinate of parent box
1204  * \param y_parent coordinate of parent box
1205  * \param clip clip rectangle
1206  * \param scale scale for redraw
1207  * \param current_background_color background colour under this box
1208  * \param ctx current redraw context
1209  * \return true if successful, false otherwise
1210  *
1211  * x, y, clip_[xy][01] are in target coordinates.
1212  */
1213 
1214 bool html_redraw_box(const html_content *html, struct box *box,
1215  int x_parent, int y_parent,
1216  const struct rect *clip, const float scale,
1217  colour current_background_color,
1218  const struct redraw_context *ctx)
1219 {
1220  const struct plotter_table *plot = ctx->plot;
1221  int x, y;
1222  int width, height;
1223  int padding_left, padding_top, padding_width, padding_height;
1224  int border_left, border_top, border_right, border_bottom;
1225  struct rect r;
1226  struct rect rect;
1227  int x_scrolled, y_scrolled;
1228  struct box *bg_box = NULL;
1229  css_computed_clip_rect css_rect;
1230  enum css_overflow_e overflow_x = CSS_OVERFLOW_VISIBLE;
1231  enum css_overflow_e overflow_y = CSS_OVERFLOW_VISIBLE;
1232 
1233  if (html_redraw_printing && (box->flags & PRINTED))
1234  return true;
1235 
1236  if (box->style != NULL) {
1237  overflow_x = css_computed_overflow_x(box->style);
1238  overflow_y = css_computed_overflow_y(box->style);
1239  }
1240 
1241  /* avoid trivial FP maths */
1242  if (scale == 1.0) {
1243  x = x_parent + box->x;
1244  y = y_parent + box->y;
1245  width = box->width;
1246  height = box->height;
1247  padding_left = box->padding[LEFT];
1248  padding_top = box->padding[TOP];
1249  padding_width = padding_left + box->width + box->padding[RIGHT];
1250  padding_height = padding_top + box->height +
1251  box->padding[BOTTOM];
1252  border_left = box->border[LEFT].width;
1253  border_top = box->border[TOP].width;
1254  border_right = box->border[RIGHT].width;
1255  border_bottom = box->border[BOTTOM].width;
1256  } else {
1257  x = (x_parent + box->x) * scale;
1258  y = (y_parent + box->y) * scale;
1259  width = box->width * scale;
1260  height = box->height * scale;
1261  /* left and top padding values are normally zero,
1262  * so avoid trivial FP maths */
1263  padding_left = box->padding[LEFT] ? box->padding[LEFT] * scale
1264  : 0;
1265  padding_top = box->padding[TOP] ? box->padding[TOP] * scale
1266  : 0;
1267  padding_width = (box->padding[LEFT] + box->width +
1268  box->padding[RIGHT]) * scale;
1269  padding_height = (box->padding[TOP] + box->height +
1270  box->padding[BOTTOM]) * scale;
1271  border_left = box->border[LEFT].width * scale;
1272  border_top = box->border[TOP].width * scale;
1273  border_right = box->border[RIGHT].width * scale;
1274  border_bottom = box->border[BOTTOM].width * scale;
1275  }
1276 
1277  /* calculate rectangle covering this box and descendants */
1278  if (box->style && overflow_x != CSS_OVERFLOW_VISIBLE &&
1279  box->parent != NULL) {
1280  /* box contents clipped to box size */
1281  r.x0 = x - border_left;
1282  r.x1 = x + padding_width + border_right;
1283  } else {
1284  /* box contents can hang out of the box; use descendant box */
1285  if (scale == 1.0) {
1286  r.x0 = x + box->descendant_x0;
1287  r.x1 = x + box->descendant_x1 + 1;
1288  } else {
1289  r.x0 = x + box->descendant_x0 * scale;
1290  r.x1 = x + box->descendant_x1 * scale + 1;
1291  }
1292  if (!box->parent) {
1293  /* root element */
1294  int margin_left, margin_right;
1295  if (scale == 1.0) {
1296  margin_left = box->margin[LEFT];
1297  margin_right = box->margin[RIGHT];
1298  } else {
1299  margin_left = box->margin[LEFT] * scale;
1300  margin_right = box->margin[RIGHT] * scale;
1301  }
1302  r.x0 = x - border_left - margin_left < r.x0 ?
1303  x - border_left - margin_left : r.x0;
1304  r.x1 = x + padding_width + border_right +
1305  margin_right > r.x1 ?
1306  x + padding_width + border_right +
1307  margin_right : r.x1;
1308  }
1309  }
1310 
1311  /* calculate rectangle covering this box and descendants */
1312  if (box->style && overflow_y != CSS_OVERFLOW_VISIBLE &&
1313  box->parent != NULL) {
1314  /* box contents clipped to box size */
1315  r.y0 = y - border_top;
1316  r.y1 = y + padding_height + border_bottom;
1317  } else {
1318  /* box contents can hang out of the box; use descendant box */
1319  if (scale == 1.0) {
1320  r.y0 = y + box->descendant_y0;
1321  r.y1 = y + box->descendant_y1 + 1;
1322  } else {
1323  r.y0 = y + box->descendant_y0 * scale;
1324  r.y1 = y + box->descendant_y1 * scale + 1;
1325  }
1326  if (!box->parent) {
1327  /* root element */
1328  int margin_top, margin_bottom;
1329  if (scale == 1.0) {
1330  margin_top = box->margin[TOP];
1331  margin_bottom = box->margin[BOTTOM];
1332  } else {
1333  margin_top = box->margin[TOP] * scale;
1334  margin_bottom = box->margin[BOTTOM] * scale;
1335  }
1336  r.y0 = y - border_top - margin_top < r.y0 ?
1337  y - border_top - margin_top : r.y0;
1338  r.y1 = y + padding_height + border_bottom +
1339  margin_bottom > r.y1 ?
1340  y + padding_height + border_bottom +
1341  margin_bottom : r.y1;
1342  }
1343  }
1344 
1345  /* return if the rectangle is completely outside the clip rectangle */
1346  if (clip->y1 < r.y0 || r.y1 < clip->y0 ||
1347  clip->x1 < r.x0 || r.x1 < clip->x0)
1348  return true;
1349 
1350  /*if the rectangle is under the page bottom but it can fit in a page,
1351  don't print it now*/
1352  if (html_redraw_printing) {
1353  if (r.y1 > html_redraw_printing_border) {
1354  if (r.y1 - r.y0 <= html_redraw_printing_border &&
1355  (box->type == BOX_TEXT ||
1356  box->type == BOX_TABLE_CELL
1357  || box->object || box->gadget)) {
1358  /*remember the highest of all points from the
1359  not printed elements*/
1362  return true;
1363  }
1364  }
1365  else box->flags |= PRINTED; /*it won't be printed anymore*/
1366  }
1367 
1368  /* if visibility is hidden render children only */
1369  if (box->style && css_computed_visibility(box->style) ==
1370  CSS_VISIBILITY_HIDDEN) {
1371  if ((ctx->plot->group_start) &&
1372  (ctx->plot->group_start(ctx, "hidden box") != NSERROR_OK))
1373  return false;
1374  if (!html_redraw_box_children(html, box, x_parent, y_parent,
1375  &r, scale, current_background_color, ctx))
1376  return false;
1377  return ((!ctx->plot->group_end) || (ctx->plot->group_end(ctx) == NSERROR_OK));
1378  }
1379 
1380  if ((ctx->plot->group_start) &&
1381  (ctx->plot->group_start(ctx,"vis box") != NSERROR_OK)) {
1382  return false;
1383  }
1384 
1385  if (box->style != NULL &&
1386  css_computed_position(box->style) ==
1387  CSS_POSITION_ABSOLUTE &&
1388  css_computed_clip(box->style, &css_rect) ==
1389  CSS_CLIP_RECT) {
1390  /* We have an absolutly positioned box with a clip rect */
1391  if (css_rect.left_auto == false)
1392  r.x0 = x - border_left + FIXTOINT(nscss_len2px(
1393  &html->len_ctx,
1394  css_rect.left, css_rect.lunit,
1395  box->style));
1396 
1397  if (css_rect.top_auto == false)
1398  r.y0 = y - border_top + FIXTOINT(nscss_len2px(
1399  &html->len_ctx,
1400  css_rect.top, css_rect.tunit,
1401  box->style));
1402 
1403  if (css_rect.right_auto == false)
1404  r.x1 = x - border_left + FIXTOINT(nscss_len2px(
1405  &html->len_ctx,
1406  css_rect.right, css_rect.runit,
1407  box->style));
1408 
1409  if (css_rect.bottom_auto == false)
1410  r.y1 = y - border_top + FIXTOINT(nscss_len2px(
1411  &html->len_ctx,
1412  css_rect.bottom, css_rect.bunit,
1413  box->style));
1414 
1415  /* find intersection of clip rectangle and box */
1416  if (r.x0 < clip->x0) r.x0 = clip->x0;
1417  if (r.y0 < clip->y0) r.y0 = clip->y0;
1418  if (clip->x1 < r.x1) r.x1 = clip->x1;
1419  if (clip->y1 < r.y1) r.y1 = clip->y1;
1420  /* Nothing to do for invalid rectangles */
1421  if (r.x0 >= r.x1 || r.y0 >= r.y1)
1422  /* not an error */
1423  return ((!ctx->plot->group_end) ||
1424  (ctx->plot->group_end(ctx) == NSERROR_OK));
1425  /* clip to it */
1426  if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
1427  return false;
1428 
1429  } else if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
1430  box->type == BOX_TABLE_CELL || box->object) {
1431  /* find intersection of clip rectangle and box */
1432  if (r.x0 < clip->x0) r.x0 = clip->x0;
1433  if (r.y0 < clip->y0) r.y0 = clip->y0;
1434  if (clip->x1 < r.x1) r.x1 = clip->x1;
1435  if (clip->y1 < r.y1) r.y1 = clip->y1;
1436  /* no point trying to draw 0-width/height boxes */
1437  if (r.x0 == r.x1 || r.y0 == r.y1)
1438  /* not an error */
1439  return ((!ctx->plot->group_end) ||
1440  (ctx->plot->group_end(ctx) == NSERROR_OK));
1441  /* clip to it */
1442  if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
1443  return false;
1444  } else {
1445  /* clip box is fine, clip to it */
1446  r = *clip;
1447  if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
1448  return false;
1449  }
1450 
1451  /* background colour and image for block level content and replaced
1452  * inlines */
1453 
1454  bg_box = html_redraw_find_bg_box(box);
1455 
1456  /* bg_box == NULL implies that this box should not have
1457  * its background rendered. Otherwise filter out linebreaks,
1458  * optimize away non-differing inlines, only plot background
1459  * for BOX_TEXT it's in an inline */
1460  if (bg_box && bg_box->type != BOX_BR &&
1461  bg_box->type != BOX_TEXT &&
1462  bg_box->type != BOX_INLINE_END &&
1463  (bg_box->type != BOX_INLINE || bg_box->object ||
1464  bg_box->flags & IFRAME || box->flags & REPLACE_DIM ||
1465  (bg_box->gadget != NULL &&
1466  (bg_box->gadget->type == GADGET_TEXTAREA ||
1467  bg_box->gadget->type == GADGET_TEXTBOX ||
1468  bg_box->gadget->type == GADGET_PASSWORD)))) {
1469  /* find intersection of clip box and border edge */
1470  struct rect p;
1471  p.x0 = x - border_left < r.x0 ? r.x0 : x - border_left;
1472  p.y0 = y - border_top < r.y0 ? r.y0 : y - border_top;
1473  p.x1 = x + padding_width + border_right < r.x1 ?
1474  x + padding_width + border_right : r.x1;
1475  p.y1 = y + padding_height + border_bottom < r.y1 ?
1476  y + padding_height + border_bottom : r.y1;
1477  if (!box->parent) {
1478  /* Root element, special case:
1479  * background covers margins too */
1480  int m_left, m_top, m_right, m_bottom;
1481  if (scale == 1.0) {
1482  m_left = box->margin[LEFT];
1483  m_top = box->margin[TOP];
1484  m_right = box->margin[RIGHT];
1485  m_bottom = box->margin[BOTTOM];
1486  } else {
1487  m_left = box->margin[LEFT] * scale;
1488  m_top = box->margin[TOP] * scale;
1489  m_right = box->margin[RIGHT] * scale;
1490  m_bottom = box->margin[BOTTOM] * scale;
1491  }
1492  p.x0 = p.x0 - m_left < r.x0 ? r.x0 : p.x0 - m_left;
1493  p.y0 = p.y0 - m_top < r.y0 ? r.y0 : p.y0 - m_top;
1494  p.x1 = p.x1 + m_right < r.x1 ? p.x1 + m_right : r.x1;
1495  p.y1 = p.y1 + m_bottom < r.y1 ? p.y1 + m_bottom : r.y1;
1496  }
1497  /* valid clipping rectangles only */
1498  if ((p.x0 < p.x1) && (p.y0 < p.y1)) {
1499  /* plot background */
1500  if (!html_redraw_background(x, y, box, scale, &p,
1501  &current_background_color, bg_box,
1502  &html->len_ctx, ctx))
1503  return false;
1504  /* restore previous graphics window */
1505  if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
1506  return false;
1507  }
1508  }
1509 
1510  /* borders for block level content and replaced inlines */
1511  if (box->style &&
1512  box->type != BOX_TEXT &&
1513  box->type != BOX_INLINE_END &&
1514  (box->type != BOX_INLINE || box->object ||
1515  box->flags & IFRAME || box->flags & REPLACE_DIM ||
1516  (box->gadget != NULL &&
1517  (box->gadget->type == GADGET_TEXTAREA ||
1518  box->gadget->type == GADGET_TEXTBOX ||
1519  box->gadget->type == GADGET_PASSWORD))) &&
1520  (border_top || border_right || border_bottom || border_left)) {
1521  if (!html_redraw_borders(box, x_parent, y_parent,
1522  padding_width, padding_height, &r,
1523  scale, ctx))
1524  return false;
1525  }
1526 
1527  /* backgrounds and borders for non-replaced inlines */
1528  if (box->style && box->type == BOX_INLINE && box->inline_end &&
1530  border_top || border_right ||
1531  border_bottom || border_left)) {
1532  /* inline backgrounds and borders span other boxes and may
1533  * wrap onto separate lines */
1534  struct box *ib;
1535  struct rect b; /* border edge rectangle */
1536  struct rect p; /* clipped rect */
1537  bool first = true;
1538  int ib_x;
1539  int ib_y = y;
1540  int ib_p_width;
1541  int ib_b_left, ib_b_right;
1542 
1543  b.x0 = x - border_left;
1544  b.x1 = x + padding_width + border_right;
1545  b.y0 = y - border_top;
1546  b.y1 = y + padding_height + border_bottom;
1547 
1548  p.x0 = b.x0 < r.x0 ? r.x0 : b.x0;
1549  p.x1 = b.x1 < r.x1 ? b.x1 : r.x1;
1550  p.y0 = b.y0 < r.y0 ? r.y0 : b.y0;
1551  p.y1 = b.y1 < r.y1 ? b.y1 : r.y1;
1552  for (ib = box; ib; ib = ib->next) {
1553  /* to get extents of rectangle(s) associated with
1554  * inline, cycle though all boxes in inline, skipping
1555  * over floats */
1556  if (ib->type == BOX_FLOAT_LEFT ||
1557  ib->type == BOX_FLOAT_RIGHT)
1558  continue;
1559  if (scale == 1.0) {
1560  ib_x = x_parent + ib->x;
1561  ib_y = y_parent + ib->y;
1562  ib_p_width = ib->padding[LEFT] + ib->width +
1563  ib->padding[RIGHT];
1564  ib_b_left = ib->border[LEFT].width;
1565  ib_b_right = ib->border[RIGHT].width;
1566  } else {
1567  ib_x = (x_parent + ib->x) * scale;
1568  ib_y = (y_parent + ib->y) * scale;
1569  ib_p_width = (ib->padding[LEFT] + ib->width +
1570  ib->padding[RIGHT]) * scale;
1571  ib_b_left = ib->border[LEFT].width * scale;
1572  ib_b_right = ib->border[RIGHT].width * scale;
1573  }
1574 
1575  if ((ib->flags & NEW_LINE) && ib != box) {
1576  /* inline element has wrapped, plot background
1577  * and borders */
1579  x, y, box, scale, &p, b,
1580  first, false,
1581  &current_background_color,
1582  &html->len_ctx, ctx))
1583  return false;
1584  /* restore previous graphics window */
1585  if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
1586  return false;
1587  if (!html_redraw_inline_borders(box, b, &r,
1588  scale, first, false, ctx))
1589  return false;
1590  /* reset coords */
1591  b.x0 = ib_x - ib_b_left;
1592  b.y0 = ib_y - border_top - padding_top;
1593  b.y1 = ib_y + padding_height - padding_top +
1594  border_bottom;
1595 
1596  p.x0 = b.x0 < r.x0 ? r.x0 : b.x0;
1597  p.y0 = b.y0 < r.y0 ? r.y0 : b.y0;
1598  p.y1 = b.y1 < r.y1 ? b.y1 : r.y1;
1599 
1600  first = false;
1601  }
1602 
1603  /* increase width for current box */
1604  b.x1 = ib_x + ib_p_width + ib_b_right;
1605  p.x1 = b.x1 < r.x1 ? b.x1 : r.x1;
1606 
1607  if (ib == box->inline_end)
1608  /* reached end of BOX_INLINE span */
1609  break;
1610  }
1611  /* plot background and borders for last rectangle of
1612  * the inline */
1613  if (!html_redraw_inline_background(x, ib_y, box, scale, &p, b,
1614  first, true, &current_background_color,
1615  &html->len_ctx, ctx))
1616  return false;
1617  /* restore previous graphics window */
1618  if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
1619  return false;
1620  if (!html_redraw_inline_borders(box, b, &r, scale, first, true,
1621  ctx))
1622  return false;
1623 
1624  }
1625 
1626  /* Debug outlines */
1627  if (html_redraw_debug) {
1628  int margin_left, margin_right;
1629  int margin_top, margin_bottom;
1630  if (scale == 1.0) {
1631  /* avoid trivial fp maths */
1632  margin_left = box->margin[LEFT];
1633  margin_top = box->margin[TOP];
1634  margin_right = box->margin[RIGHT];
1635  margin_bottom = box->margin[BOTTOM];
1636  } else {
1637  margin_left = box->margin[LEFT] * scale;
1638  margin_top = box->margin[TOP] * scale;
1639  margin_right = box->margin[RIGHT] * scale;
1640  margin_bottom = box->margin[BOTTOM] * scale;
1641  }
1642  /* Content edge -- blue */
1643  rect.x0 = x + padding_left;
1644  rect.y0 = y + padding_top;
1645  rect.x1 = x + padding_left + width;
1646  rect.y1 = y + padding_top + height;
1647  if (ctx->plot->rectangle(ctx, plot_style_content_edge, &rect) != NSERROR_OK)
1648  return false;
1649 
1650  /* Padding edge -- red */
1651  rect.x0 = x;
1652  rect.y0 = y;
1653  rect.x1 = x + padding_width;
1654  rect.y1 = y + padding_height;
1655  if (ctx->plot->rectangle(ctx, plot_style_padding_edge, &rect) != NSERROR_OK)
1656  return false;
1657 
1658  /* Margin edge -- yellow */
1659  rect.x0 = x - border_left - margin_left;
1660  rect.y0 = y - border_top - margin_top;
1661  rect.x1 = x + padding_width + border_right + margin_right;
1662  rect.y1 = y + padding_height + border_bottom + margin_bottom;
1663  if (ctx->plot->rectangle(ctx, plot_style_margin_edge, &rect) != NSERROR_OK)
1664  return false;
1665  }
1666 
1667  /* clip to the padding edge for objects, or boxes with overflow hidden
1668  * or scroll, unless it's the root element */
1669  if (box->parent != NULL) {
1670  bool need_clip = false;
1671  if (box->object || box->flags & IFRAME ||
1672  (overflow_x != CSS_OVERFLOW_VISIBLE &&
1673  overflow_y != CSS_OVERFLOW_VISIBLE)) {
1674  r.x0 = x;
1675  r.y0 = y;
1676  r.x1 = x + padding_width;
1677  r.y1 = y + padding_height;
1678  if (r.x0 < clip->x0) r.x0 = clip->x0;
1679  if (r.y0 < clip->y0) r.y0 = clip->y0;
1680  if (clip->x1 < r.x1) r.x1 = clip->x1;
1681  if (clip->y1 < r.y1) r.y1 = clip->y1;
1682  if (r.x1 <= r.x0 || r.y1 <= r.y0) {
1683  return (!ctx->plot->group_end ||
1684  (ctx->plot->group_end(ctx) == NSERROR_OK));
1685  }
1686  need_clip = true;
1687 
1688  } else if (overflow_x != CSS_OVERFLOW_VISIBLE) {
1689  r.x0 = x;
1690  r.y0 = clip->y0;
1691  r.x1 = x + padding_width;
1692  r.y1 = clip->y1;
1693  if (r.x0 < clip->x0) r.x0 = clip->x0;
1694  if (clip->x1 < r.x1) r.x1 = clip->x1;
1695  if (r.x1 <= r.x0) {
1696  return (!ctx->plot->group_end ||
1697  (ctx->plot->group_end(ctx) == NSERROR_OK));
1698  }
1699  need_clip = true;
1700 
1701  } else if (overflow_y != CSS_OVERFLOW_VISIBLE) {
1702  r.x0 = clip->x0;
1703  r.y0 = y;
1704  r.x1 = clip->x1;
1705  r.y1 = y + padding_height;
1706  if (r.y0 < clip->y0) r.y0 = clip->y0;
1707  if (clip->y1 < r.y1) r.y1 = clip->y1;
1708  if (r.y1 <= r.y0) {
1709  return (!ctx->plot->group_end ||
1710  (ctx->plot->group_end(ctx) == NSERROR_OK));
1711  }
1712  need_clip = true;
1713  }
1714 
1715  if (need_clip &&
1716  (box->type == BOX_BLOCK ||
1717  box->type == BOX_INLINE_BLOCK ||
1718  box->type == BOX_TABLE_CELL || box->object)) {
1719  if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
1720  return false;
1721  }
1722  }
1723 
1724  /* text decoration */
1725  if ((box->type != BOX_TEXT) &&
1726  box->style &&
1727  css_computed_text_decoration(box->style) != CSS_TEXT_DECORATION_NONE) {
1728  if (!html_redraw_text_decoration(box, x_parent, y_parent,
1729  scale, current_background_color, ctx))
1730  return false;
1731  }
1732 
1733  if (box->object && width != 0 && height != 0) {
1734  struct content_redraw_data obj_data;
1735 
1736  x_scrolled = x - scrollbar_get_offset(box->scroll_x) * scale;
1737  y_scrolled = y - scrollbar_get_offset(box->scroll_y) * scale;
1738 
1739  obj_data.x = x_scrolled + padding_left;
1740  obj_data.y = y_scrolled + padding_top;
1741  obj_data.width = width;
1742  obj_data.height = height;
1743  obj_data.background_colour = current_background_color;
1744  obj_data.scale = scale;
1745  obj_data.repeat_x = false;
1746  obj_data.repeat_y = false;
1747 
1748  if (content_get_type(box->object) == CONTENT_HTML) {
1749  obj_data.x /= scale;
1750  obj_data.y /= scale;
1751  }
1752 
1753  if (!content_redraw(box->object, &obj_data, &r, ctx)) {
1754  /* Show image fail */
1755  /* Unicode (U+FFFC) 'OBJECT REPLACEMENT CHARACTER' */
1756  const char *obj = "\xef\xbf\xbc";
1757  int obj_width;
1758  int obj_x = x + padding_left;
1759  nserror res;
1760 
1761  rect.x0 = x + padding_left;
1762  rect.y0 = y + padding_top;
1763  rect.x1 = x + padding_left + width - 1;
1764  rect.y1 = y + padding_top + height - 1;
1765  res = ctx->plot->rectangle(ctx, plot_style_broken_object, &rect);
1766  if (res != NSERROR_OK) {
1767  return false;
1768  }
1769 
1771  obj,
1772  sizeof(obj) - 1,
1773  &obj_width);
1774  if (res != NSERROR_OK) {
1775  obj_x += 1;
1776  } else {
1777  obj_x += width / 2 - obj_width / 2;
1778  }
1779 
1780  if (ctx->plot->text(ctx,
1782  obj_x, y + padding_top + (int)(height * 0.75),
1783  obj, sizeof(obj) - 1) != NSERROR_OK)
1784  return false;
1785  }
1786 
1787  } else if (box->iframe) {
1788  /* Offset is passed to browser window redraw unscaled */
1790  x + padding_left,
1791  y + padding_top, &r, ctx);
1792 
1793  } else if (box->gadget && box->gadget->type == GADGET_CHECKBOX) {
1794  if (!html_redraw_checkbox(x + padding_left, y + padding_top,
1795  width, height, box->gadget->selected, ctx))
1796  return false;
1797 
1798  } else if (box->gadget && box->gadget->type == GADGET_RADIO) {
1799  if (!html_redraw_radio(x + padding_left, y + padding_top,
1800  width, height, box->gadget->selected, ctx))
1801  return false;
1802 
1803  } else if (box->gadget && box->gadget->type == GADGET_FILE) {
1804  if (!html_redraw_file(x + padding_left, y + padding_top,
1805  width, height, box, scale,
1806  current_background_color, &html->len_ctx, ctx))
1807  return false;
1808 
1809  } else if (box->gadget &&
1810  (box->gadget->type == GADGET_TEXTAREA ||
1811  box->gadget->type == GADGET_PASSWORD ||
1812  box->gadget->type == GADGET_TEXTBOX)) {
1813  textarea_redraw(box->gadget->data.text.ta, x, y,
1814  current_background_color, scale, &r, ctx);
1815 
1816  } else if (box->text) {
1817  if (!html_redraw_text_box(html, box, x, y, &r, scale,
1818  current_background_color, ctx))
1819  return false;
1820 
1821  } else {
1822  if (!html_redraw_box_children(html, box, x_parent, y_parent, &r,
1823  scale, current_background_color, ctx))
1824  return false;
1825  }
1826 
1827  if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
1828  box->type == BOX_TABLE_CELL || box->type == BOX_INLINE)
1829  if (ctx->plot->clip(ctx, clip) != NSERROR_OK)
1830  return false;
1831 
1832  /* list marker */
1833  if (box->list_marker) {
1834  if (!html_redraw_box(html, box->list_marker,
1835  x_parent + box->x -
1837  y_parent + box->y -
1839  clip, scale, current_background_color, ctx))
1840  return false;
1841  }
1842 
1843  /* scrollbars */
1844  if (((box->style && box->type != BOX_BR &&
1845  box->type != BOX_TABLE && box->type != BOX_INLINE &&
1846  (box->gadget == NULL || box->gadget->type != GADGET_TEXTAREA) &&
1847  (overflow_x == CSS_OVERFLOW_SCROLL ||
1848  overflow_x == CSS_OVERFLOW_AUTO ||
1849  overflow_y == CSS_OVERFLOW_SCROLL ||
1850  overflow_y == CSS_OVERFLOW_AUTO)) ||
1851  (box->object && content_get_type(box->object) ==
1852  CONTENT_HTML)) && box->parent != NULL) {
1853  nserror res;
1854  bool has_x_scroll = (overflow_x == CSS_OVERFLOW_SCROLL);
1855  bool has_y_scroll = (overflow_y == CSS_OVERFLOW_SCROLL);
1856 
1857  has_x_scroll |= (overflow_x == CSS_OVERFLOW_AUTO) &&
1859  has_y_scroll |= (overflow_y == CSS_OVERFLOW_AUTO) &&
1861 
1862  res = box_handle_scrollbars((struct content *)html,
1863  box, has_x_scroll, has_y_scroll);
1864  if (res != NSERROR_OK) {
1865  NSLOG(netsurf, INFO, "%s", messages_get_errorcode(res));
1866  return false;
1867  }
1868 
1869  if (box->scroll_x != NULL)
1871  x_parent + box->x,
1872  y_parent + box->y + box->padding[TOP] +
1873  box->height + box->padding[BOTTOM] -
1874  SCROLLBAR_WIDTH, clip, scale, ctx);
1875  if (box->scroll_y != NULL)
1877  x_parent + box->x + box->padding[LEFT] +
1878  box->width + box->padding[RIGHT] -
1880  y_parent + box->y, clip, scale, ctx);
1881  }
1882 
1883  if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
1884  box->type == BOX_TABLE_CELL || box->type == BOX_INLINE) {
1885  if (ctx->plot->clip(ctx, clip) != NSERROR_OK)
1886  return false;
1887  }
1888 
1889  return ((!plot->group_end) || (ctx->plot->group_end(ctx) == NSERROR_OK));
1890 }
1891 
1892 /**
1893  * Draw a CONTENT_HTML using the current set of plotters (plot).
1894  *
1895  * \param c content of type CONTENT_HTML
1896  * \param data redraw data for this content redraw
1897  * \param clip current clip region
1898  * \param ctx current redraw context
1899  * \return true if successful, false otherwise
1900  *
1901  * x, y, clip_[xy][01] are in target coordinates.
1902  */
1903 
1904 bool html_redraw(struct content *c, struct content_redraw_data *data,
1905  const struct rect *clip, const struct redraw_context *ctx)
1906 {
1907  html_content *html = (html_content *) c;
1908  struct box *box;
1909  bool result = true;
1910  bool select, select_only;
1911  plot_style_t pstyle_fill_bg = {
1913  .fill_colour = data->background_colour,
1914  };
1915 
1916  box = html->layout;
1917  assert(box);
1918 
1919  /* The select menu needs special treating because, when opened, it
1920  * reaches beyond its layout box.
1921  */
1922  select = false;
1923  select_only = false;
1924  if (ctx->interactive && html->visible_select_menu != NULL) {
1925  struct form_control *control = html->visible_select_menu;
1926  select = true;
1927  /* check if the redraw rectangle is completely inside of the
1928  select menu */
1929  select_only = form_clip_inside_select_menu(control,
1930  data->scale, clip);
1931  }
1932 
1933  if (!select_only) {
1934  /* clear to background colour */
1935  result = (ctx->plot->clip(ctx, clip) == NSERROR_OK);
1936 
1937  if (html->background_colour != NS_TRANSPARENT)
1938  pstyle_fill_bg.fill_colour = html->background_colour;
1939 
1940  result &= (ctx->plot->rectangle(ctx, &pstyle_fill_bg, clip) == NSERROR_OK);
1941 
1942  result &= html_redraw_box(html, box, data->x, data->y, clip,
1943  data->scale, pstyle_fill_bg.fill_colour, ctx);
1944  }
1945 
1946  if (select) {
1947  int menu_x, menu_y;
1948  box = html->visible_select_menu->box;
1949  box_coords(box, &menu_x, &menu_y);
1950 
1951  menu_x -= box->border[LEFT].width;
1952  menu_y += box->height + box->border[BOTTOM].width +
1953  box->padding[BOTTOM] + box->padding[TOP];
1955  data->x + menu_x, data->y + menu_y,
1956  data->scale, clip, ctx);
1957  }
1958 
1959  return result;
1960 
1961 }
struct form_control * gadget
Form control data, or NULL if not a form control.
Definition: box.h:417
Target independent plotting interface.
Definition: box.h:96
bool box_hscrollbar_present(const struct box *const box)
Determine if a box has a horizontal scrollbar.
Definition: box_inspect.c:826
Definition: box.h:96
STATIC char result[100]
Definition: arexx.c:77
nserror scrollbar_redraw(struct scrollbar *s, int x, int y, const struct rect *clip, float scale, const struct redraw_context *ctx)
Redraw a part of the scrollbar.
Definition: scrollbar.c:239
int y1
Bottom right.
Definition: types.h:42
static bool html_redraw_text_decoration(struct box *box, int x_parent, int y_parent, float scale, colour background_colour, const struct redraw_context *ctx)
Plot text decoration for a box.
Definition: html_redraw.c:1064
bool content_redraw(struct hlcache_handle *h, struct content_redraw_data *data, const struct rect *clip, const struct redraw_context *ctx)
Display content on screen with optional tiling.
Definition: content.c:625
int descendant_x1
right edge of descendants
Definition: box.h:309
const struct plotter_table * plot
Current plot operation table.
Definition: plotters.h:73
bool browser_window_redraw(struct browser_window *bw, int x, int y, const struct rect *clip, const struct redraw_context *ctx)
Redraw an area of a window.
plot_style_t * plot_style_stroke_lightwbasec
Definition: plot_style.c:153
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 struct box * html_redraw_find_bg_box(struct box *box)
Find the background box for a box.
Definition: html_redraw.c:97
Interface to utility string handling.
nserror(* disc)(const struct redraw_context *ctx, const plot_style_t *pstyle, int x, int y, int radius)
Plots a circle.
Definition: plotters.h:152
Localised message support (interface).
plot_style_t const *const plot_style_broken_object
Definition: plot_style.c:79
#define SCROLLBAR_WIDTH
Definition: scrollbar.h:32
box_flags flags
Box flags.
Definition: box.h:184
Interface to form handling functions internal to HTML content handler.
Interface to platform-specific layout operation table.
struct form_textarea_data data
Public content interface.
bool html_redraw(struct content *c, struct content_redraw_data *data, const struct rect *clip, const struct redraw_context *ctx)
Draw a CONTENT_HTML using the current set of plotters (plot).
Definition: html_redraw.c:1904
int padding[4]
Padding: TOP, RIGHT, BOTTOM, LEFT.
Definition: box.h:320
struct form_control * visible_select_menu
Open core-handled form SELECT menu, or NULL if none currently open.
nserror(* group_end)(const struct redraw_context *ctx)
End of the most recently started group.
Definition: plotters.h:307
static bool html_redraw_background(int x, int y, struct box *box, float scale, const struct rect *clip, colour *background_colour, struct box *background, const nscss_len_ctx *len_ctx, const struct redraw_context *ctx)
Plot background images.
Definition: html_redraw.c:590
size_t byte_offset
Byte offset within a textual representation of this content.
Definition: box.h:368
int descendant_y0
top edge of descendants
Definition: box.h:308
struct scrollbar * scroll_x
Horizontal scroll.
Definition: box.h:330
#define selection_defined(s)
Definition: selection.h:75
Definition: box.h:96
int descendant_x0
left edge of descendants
Definition: box.h:307
bool html_redraw_debug
Render padding and margin box outlines in html_redraw().
Definition: html_redraw.c:66
nserror(* clip)(const struct redraw_context *ctx, const struct rect *clip)
Sets a clip rectangle for subsequent plot operations.
Definition: plotters.h:111
void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale, const struct rect *clip, const struct redraw_context *ctx)
Handle redraw requests for text areas.
Definition: textarea.c:2131
void box_coords(struct box *box, int *x, int *y)
Find the absolute coordinates of a box.
Definition: box_inspect.c:544
#define min(x, y)
Definition: utils.h:46
int x
Coordinate of left padding edge relative to parent box, or relative to ancestor that contains this bo...
Definition: box.h:278
struct box * layout
Box tree, or NULL.
Length conversion context data.
Definition: utils.h:35
Definition: box.h:58
HTML Box tree inspection interface.
struct box * float_children
First float child box, or NULL.
Definition: box.h:249
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
struct scrollbar * scroll_y
Vertical scroll.
Definition: box.h:335
bool html_redraw_printing
Definition: print.c:51
#define colour_to_bw_furthest(c0)
Definition: plot_style.h:175
bool background_images
Render background images.
Definition: plotters.h:66
plot_style_t * plot_style_fill_white
Definition: plot_style.c:32
plot_font_style_t const *const plot_fstyle_broken_object
Definition: plot_style.c:90
Solid colour.
Definition: plot_style.h:67
bool interactive
Redraw to show interactive features.
Definition: plotters.h:59
Option reading and saving interface.
int scrollbar_get_offset(struct scrollbar *s)
Get the current scroll offset to the visible part of the full area.
Definition: scrollbar.c:627
static bool text_redraw(const char *utf8_text, size_t utf8_len, size_t offset, int space, const plot_font_style_t *fstyle, int x, int y, const struct rect *clip, int height, float scale, bool excluded, struct content *c, const struct selection *sel, struct search_context *search, const struct redraw_context *ctx)
Redraw a short text string, complete with highlighting (for selection/search)
Definition: html_redraw.c:156
form_control_type type
Type of control.
Definition: form_internal.h:79
int space
Width of space after current text (depends on font and size).
Definition: box.h:363
int y
coordinate for top-left of redraw
Definition: content.h:42
colour foreground
Colour of text.
Definition: plot_style.h:123
nserror
Enumeration of error codes.
Definition: errors.h:29
struct box * next_float
Next sibling float box.
Definition: box.h:254
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.
size_t length
Length of text.
Definition: box.h:358
bool form_redraw_select_menu(struct form_control *control, int x, int y, float scale, const struct rect *clip, const struct redraw_context *ctx)
Redraw an opened select menu.
Definition: form.c:1577
plot_style_t * plot_style_fill_wbasec
Definition: plot_style.c:109
Corresponds to a single URL.
Private data for text/html content.
#define NS_TRANSPARENT
Transparent colour value.
Definition: plot_style.h:39
static bool html_redraw_checkbox(int x, int y, int width, int height, bool selected, const struct redraw_context *ctx)
Plot a checkbox.
Definition: html_redraw.c:362
plot_style_t const *const plot_style_padding_edge
Definition: plot_style.c:60
No error.
Definition: errors.h:30
Font style for plotting.
Definition: plot_style.h:111
plot_style_t * plot_style_fill_darkwbasec
Definition: plot_style.c:116
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:115
Internal font handling interfaces.
Conception: Generalized output-in-pages.
Single/Multi-line UTF-8 text area interface.
Definition: box.h:87
static bool html_redraw_radio(int x, int y, int width, int height, bool selected, const struct redraw_context *ctx)
Plot a radio icon.
Definition: html_redraw.c:461
static bool html_redraw_box_has_background(struct box *box)
Determine if a box has a background that needs drawing.
Definition: html_redraw.c:74
uint32_t colour
Colour type: XBGR.
Definition: types.h:35
struct box * list_marker
List marker box if this is a list-item, or NULL.
Definition: box.h:411
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.
int x1
Definition: types.h:42
Box interface.
int height
vertical dimension
Definition: content.h:48
wimp_w parent
Definition: dialog.c:87
int content_get_height(struct hlcache_handle *h)
Retrieve height of content.
Definition: content.c:1291
int y0
Top left.
Definition: types.h:41
bool html_redraw_box(const html_content *html, struct box *box, int x_parent, int y_parent, const struct rect *clip, float scale, colour current_background_color, const struct redraw_context *ctx)
Recursively draw a box.
Definition: html_redraw.c:1214
interface to HTML layout.
int html_redraw_printing_top_cropped
Definition: print.c:53
int width
dimensions to render content at (for scaling contents with intrinsic dimensions)
Definition: content.h:47
plot_style_t * plot_style_stroke_wblobc
Definition: plot_style.c:139
Definition: box.h:59
static nserror text(const struct redraw_context *ctx, const struct plot_font_style *fstyle, int x, int y, const char *text, size_t length)
Text plotting.
Definition: plot.c:978
bool selection_highlighted(const struct selection *s, unsigned start, unsigned end, unsigned *start_idx, unsigned *end_idx)
Tests whether a text range lies partially within the selection, if there is a selection defined...
Definition: selection.c:990
colour background
Background colour to blend to, if appropriate.
Definition: plot_style.h:122
Definition: box.h:96
Box tree manipulation interface.
static bool html_redraw_inline_background(int x, int y, struct box *box, float scale, const struct rect *clip, struct rect b, bool first, bool last, colour *background_colour, const nscss_len_ctx *len_ctx, const struct redraw_context *ctx)
Plot an inline&#39;s background and/or background image.
Definition: html_redraw.c:817
bool box_vscrollbar_present(const struct box *const box)
Determine if a box has a vertical scrollbar.
Definition: box_inspect.c:816
Redraw context.
Definition: plotters.h:51
Form control.
Definition: form_internal.h:73
Definition: box.h:56
plot_operation_type_t fill_type
Fill plot type.
Definition: plot_style.h:80
parameters to content redraw
Definition: content.h:40
const char * messages_get(const char *key)
Fast lookup of a message by key from the standard Messages hash.
Definition: messages.c:241
struct box * children
First child box, or NULL.
Definition: box.h:224
colour background_colour
The background colour.
Definition: content.h:51
Plotter operations table.
Definition: plotters.h:102
Definition: box.h:79
int height
Definition: gui.c:180
Plot style for stroke/fill plotters.
Definition: plot_style.h:76
int width
border-width (pixels)
Definition: box.h:105
int height
Height of content box (excluding padding etc.).
Definition: box.h:291
box_type type
Type of box.
Definition: box.h:179
css_fixed nscss_len2px(const nscss_len_ctx *ctx, css_fixed length, css_unit unit, const css_computed_style *style)
Convert a CSS length to pixels.
Definition: utils.c:129
int descendant_y1
bottom edge of descendants
Definition: box.h:310
Rectangle coordinates.
Definition: types.h:40
static bool html_redraw_text_decoration_inline(struct box *box, int x, int y, float scale, colour colour, float ratio, const struct redraw_context *ctx)
Plot text decoration for an inline box.
Definition: html_redraw.c:967
plot_style_fixed size
Font size, in pt.
Definition: plot_style.h:119
struct hlcache_handle * background
Background image for this box, or NULL if none.
Definition: box.h:429
char * text
Text, or NULL if none.
Definition: box.h:353
content_type content_get_type(struct hlcache_handle *h)
Retrieve computed type of content.
Definition: content.c:1182
int width
Width of content box (excluding padding etc.).
Definition: box.h:287
struct hlcache_handle * object
Object in this box (usually an image), or NULL if none.
Definition: box.h:435
Interface to HTML searching.
bool form_clip_inside_select_menu(struct form_control *control, float scale, const struct rect *clip)
Check whether a clipping rectangle is completely contained in the select menu.
Definition: form.c:1732
int x0
Definition: types.h:41
int content_get_width(struct hlcache_handle *h)
Retrieve width of content.
Definition: content.c:1275
#define nscss_color_to_ns(c)
Convert a CSS color to a NetSurf colour primitive.
Definition: css.h:35
Interface to a number of general purpose functionality.
Browser window creation and manipulation interface.
Definition: box.h:67
#define blend_colour(c0, c1)
Definition: plot_style.h:163
Generic bitmap handling interface.
content is HTML
Definition: content_type.h:48
static bool html_redraw_box_children(const html_content *html, struct box *box, int x_parent, int y_parent, const struct rect *clip, float scale, colour current_background_color, const struct redraw_context *ctx)
Draw the various children of a box.
Definition: html_redraw.c:1165
nserror(* width)(const struct plot_font_style *fstyle, const char *string, size_t length, int *width)
Measure the width of a string.
Definition: layout.h:49
struct box * box
Box for control.
Definition: form_internal.h:89
nserror(* group_start)(const struct redraw_context *ctx, const char *name)
Start of a group of objects.
Definition: plotters.h:295
int margin[4]
Margin: TOP, RIGHT, BOTTOM, LEFT.
Definition: box.h:315
bool search_term_highlighted(struct content *c, unsigned start_offset, unsigned end_offset, unsigned *start_idx, unsigned *end_idx, struct search_context *context)
Determines whether any portion of the given text box should be selected because it matches the curren...
Definition: search.c:626
Text selection within browser windows (interface).
struct box * next
Next sibling box, or NULL.
Definition: box.h:214
bool selected
Whether control is selected.
Definition: form_internal.h:94
struct box * parent
Parent box, or NULL.
Definition: box.h:234
nscss_len_ctx len_ctx
CSS length conversion context for document.
nserror(* rectangle)(const struct redraw_context *ctx, const plot_style_t *pstyle, const struct rect *rectangle)
Plots a rectangle.
Definition: plotters.h:188
int x
coordinate for top-left of redraw
Definition: content.h:41
plot_style_t * plot_style_stroke_darkwbasec
Definition: plot_style.c:146
nserror(* line)(const struct redraw_context *ctx, const plot_style_t *pstyle, const struct rect *line)
Plots a line.
Definition: plotters.h:170
plot_style_t const *const plot_style_margin_edge
Definition: plot_style.c:68
Scrollbar widget interface.
const char * messages_get_errorcode(nserror code)
lookup of a message by errorcode from the standard Messages hash.
Definition: messages.c:248
nserror box_handle_scrollbars(struct content *c, struct box *box, bool bottom, bool right)
Applies the given scroll setup to a box.
bool content_get_opaque(hlcache_handle *h)
Determine if a content is opaque from handle.
Definition: content.c:1397
plot_style_t const *const plot_style_content_edge
Definition: plot_style.c:52
plot_style_t * plot_style_fill_lightwbasec
Definition: plot_style.c:123
bool repeat_x
whether content is tiled in x direction
Definition: content.h:58
int html_redraw_printing_border
Definition: print.c:52
nserror(* arc)(const struct redraw_context *ctx, const plot_style_t *pstyle, int x, int y, int radius, int angle1, int angle2)
Plots an arc.
Definition: plotters.h:131
plot_style_t * plot_style_fill_wblobc
Definition: plot_style.c:131
Definition: box.h:66
static bool html_redraw_file(int x, int y, int width, int height, struct box *box, float scale, colour background_colour, const nscss_len_ctx *len_ctx, const struct redraw_context *ctx)
Plot a file upload input.
Definition: html_redraw.c:531
#define max(x, y)
Definition: utils.h:50
Data specific to CONTENT_HTML.
Definition: html_internal.h:93
int width
Definition: gui.c:179
static nserror clip(const struct redraw_context *ctx, const struct rect *clip)
Sets a clip rectangle for subsequent plot operations.
Definition: plot.c:357
Interface to core interface table.
nserror(* text)(const struct redraw_context *ctx, const plot_font_style_t *fstyle, int x, int y, const char *text, size_t length)
Text plotting.
Definition: plotters.h:278
css_computed_style * style
Style for this box.
Definition: box.h:203
float scale
Scale for redraw (for scaling contents without intrinsic dimensions)
Definition: content.h:56
colour background_colour
Document background colour.
struct netsurf_table * guit
The global interface table.
Definition: gui_factory.c:46
#define NOF_ELEMENTS(array)
Definition: search.c:67
Protected interface to Content handling.
static bool html_redraw_text_decoration_block(struct box *box, int x, int y, float scale, colour colour, float ratio, const struct redraw_context *ctx)
Plot text decoration for an non-inline box.
Definition: html_redraw.c:1015
bool repeat_y
whether content is tiled in y direction
Definition: content.h:59
struct box * inline_end
INLINE_END box corresponding to this INLINE box, or INLINE box corresponding to this INLINE_END box...
Definition: box.h:240
#define nsoption_bool(OPTION)
Get the value of a boolean option.
Definition: nsoption.h:270
char * value
Current value of control.
Definition: form_internal.h:84
void font_plot_style_from_css(const nscss_len_ctx *len_ctx, const css_computed_style *css, plot_font_style_t *fstyle)
Populate a font style using data from a computed CSS style.
Definition: font.c:135
static bool html_redraw_text_box(const html_content *html, struct box *box, int x, int y, const struct rect *clip, float scale, colour current_background_color, const struct redraw_context *ctx)
Redraw the text content of a box, possibly partially highlighted because the text has been selected...
Definition: html_redraw.c:1124
struct browser_window * iframe
Iframe&#39;s browser_window, or NULL if none.
Definition: box.h:446
struct gui_layout_table * layout
Layout table.
Definition: gui_table.h:154
Definition: box.h:77
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