NetSurf
box.c
Go to the documentation of this file.
1 /*
2  * Copyright 2005-2007 James Bursa <bursa@users.sourceforge.net>
3  * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
4  * Copyright 2005 John M Bell <jmb202@ecs.soton.ac.uk>
5  * Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
6  *
7  * This file is part of NetSurf, http://www.netsurf-browser.org/
8  *
9  * NetSurf is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; version 2 of the License.
12  *
13  * NetSurf is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 /**
23  * \file
24  * implementation of box tree manipulation.
25  */
26 
27 #include <assert.h>
28 #include <stdbool.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <dom/dom.h>
32 
33 #include "utils/nsoption.h"
34 #include "utils/log.h"
35 #include "utils/talloc.h"
36 #include "utils/nsurl.h"
37 #include "netsurf/misc.h"
38 #include "netsurf/content.h"
39 #include "netsurf/mouse.h"
40 #include "css/utils.h"
41 #include "css/dump.h"
42 #include "desktop/scrollbar.h"
43 #include "desktop/gui_internal.h"
44 #include "desktop/search.h"
45 
46 #include "html/box.h"
47 #include "html/form_internal.h"
48 #include "html/html_internal.h"
49 #include "html/interaction.h"
50 
51 #define box_is_float(box) (box->type == BOX_FLOAT_LEFT || \
52  box->type == BOX_FLOAT_RIGHT)
53 
54 /**
55  * Destructor for box nodes which own styles
56  *
57  * \param b The box being destroyed.
58  * \return 0 to allow talloc to continue destroying the tree.
59  */
60 static int box_talloc_destructor(struct box *b)
61 {
62  struct html_scrollbar_data *data;
63 
64  if ((b->flags & STYLE_OWNED) && b->style != NULL) {
65  css_computed_style_destroy(b->style);
66  b->style = NULL;
67  }
68 
69  if (b->styles != NULL) {
70  css_select_results_destroy(b->styles);
71  b->styles = NULL;
72  }
73 
74  if (b->href != NULL)
75  nsurl_unref(b->href);
76 
77  if (b->id != NULL) {
78  lwc_string_unref(b->id);
79  }
80 
81  if (b->node != NULL) {
82  dom_node_unref(b->node);
83  }
84 
85  if (b->scroll_x != NULL) {
86  data = scrollbar_get_data(b->scroll_x);
88  free(data);
89  }
90 
91  if (b->scroll_y != NULL) {
92  data = scrollbar_get_data(b->scroll_y);
94  free(data);
95  }
96 
97  return 0;
98 }
99 
100 
101 /* Exported function documented in html/box.h */
102 struct box *
103 box_create(css_select_results *styles,
104  css_computed_style *style,
105  bool style_owned,
106  nsurl *href,
107  const char *target,
108  const char *title,
109  lwc_string *id,
110  void *context)
111 {
112  unsigned int i;
113  struct box *box;
114 
115  box = talloc(context, struct box);
116  if (!box) {
117  return 0;
118  }
119 
121 
122  box->type = BOX_INLINE;
123  box->flags = 0;
124  box->flags = style_owned ? (box->flags | STYLE_OWNED) : box->flags;
125  box->styles = styles;
126  box->style = style;
127  box->x = box->y = 0;
128  box->width = UNKNOWN_WIDTH;
129  box->height = 0;
130  box->descendant_x0 = box->descendant_y0 = 0;
131  box->descendant_x1 = box->descendant_y1 = 0;
132  for (i = 0; i != 4; i++)
133  box->margin[i] = box->padding[i] = box->border[i].width = 0;
134  box->scroll_x = box->scroll_y = NULL;
135  box->min_width = 0;
137  box->byte_offset = 0;
138  box->text = NULL;
139  box->length = 0;
140  box->space = 0;
141  box->href = (href == NULL) ? NULL : nsurl_ref(href);
142  box->target = target;
143  box->title = title;
144  box->columns = 1;
145  box->rows = 1;
146  box->start_column = 0;
147  box->next = NULL;
148  box->prev = NULL;
149  box->children = NULL;
150  box->last = NULL;
151  box->parent = NULL;
152  box->inline_end = NULL;
153  box->float_children = NULL;
154  box->float_container = NULL;
155  box->next_float = NULL;
156  box->cached_place_below_level = 0;
157  box->list_marker = NULL;
158  box->col = NULL;
159  box->gadget = NULL;
160  box->usemap = NULL;
161  box->id = id;
162  box->background = NULL;
163  box->object = NULL;
164  box->object_params = NULL;
165  box->iframe = NULL;
166  box->node = NULL;
167 
168  return box;
169 }
170 
171 
172 /* Exported function documented in html/box.h */
173 void box_add_child(struct box *parent, struct box *child)
174 {
175  assert(parent);
176  assert(child);
177 
178  if (parent->children != 0) { /* has children already */
179  parent->last->next = child;
180  child->prev = parent->last;
181  } else { /* this is the first child */
182  parent->children = child;
183  child->prev = 0;
184  }
185 
186  parent->last = child;
187  child->parent = parent;
188 }
189 
190 
191 /* Exported function documented in html/box.h */
192 void box_insert_sibling(struct box *box, struct box *new_box)
193 {
194  new_box->parent = box->parent;
195  new_box->prev = box;
196  new_box->next = box->next;
197  box->next = new_box;
198  if (new_box->next)
199  new_box->next->prev = new_box;
200  else if (new_box->parent)
201  new_box->parent->last = new_box;
202 }
203 
204 
205 /* Exported function documented in html/box.h */
207 {
208  struct box *parent = box->parent;
209  struct box *next = box->next;
210  struct box *prev = box->prev;
211 
212  if (parent) {
213  if (parent->children == box)
214  parent->children = next;
215  if (parent->last == box)
216  parent->last = next ? next : prev;
217  }
218 
219  if (prev)
220  prev->next = next;
221  if (next)
222  next->prev = prev;
223 
224  box_free(box);
225 }
226 
227 
228 /* Exported function documented in html/box.h */
229 void box_free(struct box *box)
230 {
231  struct box *child, *next;
232 
233  /* free children first */
234  for (child = box->children; child; child = next) {
235  next = child->next;
236  box_free(child);
237  }
238 
239  /* last this box */
240  box_free_box(box);
241 }
242 
243 
244 /* Exported function documented in html/box.h */
245 void box_free_box(struct box *box)
246 {
247  if (!(box->flags & CLONE)) {
248  if (box->gadget)
250  if (box->scroll_x != NULL)
252  if (box->scroll_y != NULL)
254  if (box->styles != NULL)
255  css_select_results_destroy(box->styles);
256  }
257 
258  talloc_free(box);
259 }
260 
261 
262 /* Exported function documented in html/box.h */
263 void box_coords(struct box *box, int *x, int *y)
264 {
265  *x = box->x;
266  *y = box->y;
267  while (box->parent) {
268  if (box_is_float(box)) {
269  assert(box->float_container);
270  box = box->float_container;
271  } else {
272  box = box->parent;
273  }
274  *x += box->x - scrollbar_get_offset(box->scroll_x);
275  *y += box->y - scrollbar_get_offset(box->scroll_y);
276  }
277 }
278 
279 
280 /* Exported function documented in html/box.h */
281 void box_bounds(struct box *box, struct rect *r)
282 {
283  int width, height;
284 
285  box_coords(box, &r->x0, &r->y0);
286 
287  width = box->padding[LEFT] + box->width + box->padding[RIGHT];
288  height = box->padding[TOP] + box->height + box->padding[BOTTOM];
289 
290  r->x1 = r->x0 + width;
291  r->y1 = r->y0 + height;
292 }
293 
294 
295 /**
296  * Determine if a point lies within a box.
297  *
298  * \param[in] len_ctx CSS length conversion context to use.
299  * \param[in] box Box to consider
300  * \param[in] x Coordinate relative to box
301  * \param[in] y Coordinate relative to box
302  * \param[out] physically If function returning true, physically is set true
303  * iff point is within the box's physical dimensions and
304  * false if the point is not within the box's physical
305  * dimensions but is in the area defined by the box's
306  * descendants. If function returns false, physically
307  * is undefined.
308  * \return true if the point is within the box or a descendant box
309  *
310  * This is a helper function for box_at_point().
311  */
312 static bool box_contains_point(
313  const nscss_len_ctx *len_ctx,
314  const struct box *box,
315  int x,
316  int y,
317  bool *physically)
318 {
319  css_computed_clip_rect css_rect;
320 
321  if (box->style != NULL &&
322  css_computed_position(box->style) ==
323  CSS_POSITION_ABSOLUTE &&
324  css_computed_clip(box->style, &css_rect) ==
325  CSS_CLIP_RECT) {
326  /* We have an absolutly positioned box with a clip rect */
327  struct rect r = {
328  .x0 = box->border[LEFT].width,
329  .y0 = box->border[TOP].width,
330  .x1 = box->padding[LEFT] + box->width +
331  box->border[RIGHT].width +
332  box->padding[RIGHT],
333  .y1 = box->padding[TOP] + box->height +
334  box->border[BOTTOM].width +
335  box->padding[BOTTOM]
336  };
337  if (x >= r.x0 && x < r.x1 && y >= r.y0 && y < r.y1)
338  *physically = true;
339  else
340  *physically = false;
341 
342  /* Adjust rect to css clip region */
343  if (css_rect.left_auto == false) {
344  r.x0 += FIXTOINT(nscss_len2px(len_ctx,
345  css_rect.left, css_rect.lunit,
346  box->style));
347  }
348  if (css_rect.top_auto == false) {
349  r.y0 += FIXTOINT(nscss_len2px(len_ctx,
350  css_rect.top, css_rect.tunit,
351  box->style));
352  }
353  if (css_rect.right_auto == false) {
354  r.x1 = box->border[LEFT].width +
355  FIXTOINT(nscss_len2px(len_ctx,
356  css_rect.right,
357  css_rect.runit,
358  box->style));
359  }
360  if (css_rect.bottom_auto == false) {
361  r.y1 = box->border[TOP].width +
362  FIXTOINT(nscss_len2px(len_ctx,
363  css_rect.bottom,
364  css_rect.bunit,
365  box->style));
366  }
367 
368  /* Test if point is in clipped box */
369  if (x >= r.x0 && x < r.x1 && y >= r.y0 && y < r.y1) {
370  /* inside clip area */
371  return true;
372  }
373 
374  /* Not inside clip area */
375  return false;
376  }
377  if (x >= -box->border[LEFT].width &&
378  x < box->padding[LEFT] + box->width +
379  box->padding[RIGHT] + box->border[RIGHT].width &&
380  y >= -box->border[TOP].width &&
381  y < box->padding[TOP] + box->height +
382  box->padding[BOTTOM] + box->border[BOTTOM].width) {
383  *physically = true;
384  return true;
385  }
386  if (box->list_marker && box->list_marker->x - box->x <= x +
387  box->list_marker->border[LEFT].width &&
388  x < box->list_marker->x - box->x +
389  box->list_marker->padding[LEFT] +
390  box->list_marker->width +
391  box->list_marker->border[RIGHT].width +
392  box->list_marker->padding[RIGHT] &&
393  box->list_marker->y - box->y <= y +
394  box->list_marker->border[TOP].width &&
395  y < box->list_marker->y - box->y +
396  box->list_marker->padding[TOP] +
397  box->list_marker->height +
398  box->list_marker->border[BOTTOM].width +
399  box->list_marker->padding[BOTTOM]) {
400  *physically = true;
401  return true;
402  }
403  if ((box->style && css_computed_overflow_x(box->style) ==
404  CSS_OVERFLOW_VISIBLE) || !box->style) {
405  if (box->descendant_x0 <= x &&
406  x < box->descendant_x1) {
407  *physically = false;
408  return true;
409  }
410  }
411  if ((box->style && css_computed_overflow_y(box->style) ==
412  CSS_OVERFLOW_VISIBLE) || !box->style) {
413  if (box->descendant_y0 <= y &&
414  y < box->descendant_y1) {
415  *physically = false;
416  return true;
417  }
418  }
419  return false;
420 }
421 
422 
423 /**
424  * Direction to move in a box-tree walk
425  */
433 };
434 
435 
436 /**
437  * Move from box to next box in given direction, adjusting for box coord change
438  *
439  * \param b box to move from from
440  * \param dir direction to move in
441  * \param x box's global x-coord, updated to position of next box
442  * \param y box's global y-coord, updated to position of next box
443  *
444  * If no box can be found in given direction, NULL is returned.
445  */
446 static inline struct box *
447 box_move_xy(struct box *b, enum box_walk_dir dir, int *x, int *y)
448 {
449  struct box *rb = NULL;
450 
451  switch (dir) {
452  case BOX_WALK_CHILDREN:
453  b = b->children;
454  if (b == NULL)
455  break;
456  *x += b->x;
457  *y += b->y;
458  if (!box_is_float(b)) {
459  rb = b;
460  break;
461  }
462  /* fall through */
463 
465  do {
466  *x -= b->x;
467  *y -= b->y;
468  b = b->next;
469  if (b == NULL)
470  break;
471  *x += b->x;
472  *y += b->y;
473  } while (box_is_float(b));
474  rb = b;
475  break;
476 
477  case BOX_WALK_PARENT:
478  *x -= b->x;
479  *y -= b->y;
480  rb = b->parent;
481  break;
482 
484  b = b->float_children;
485  if (b == NULL)
486  break;
487  *x += b->x;
488  *y += b->y;
489  rb = b;
490  break;
491 
493  *x -= b->x;
494  *y -= b->y;
495  b = b->next_float;
496  if (b == NULL)
497  break;
498  *x += b->x;
499  *y += b->y;
500  rb = b;
501  break;
502 
504  *x -= b->x;
505  *y -= b->y;
506  rb = b->float_container;
507  break;
508 
509  default:
510  assert(0 && "Bad box walk type.");
511  }
512 
513  return rb;
514 }
515 
516 
517 /**
518  * Itterator for walking to next box in interaction order
519  *
520  * \param b box to find next box from
521  * \param x box's global x-coord, updated to position of next box
522  * \param y box's global y-coord, updated to position of next box
523  * \param skip_children whether to skip box's children
524  *
525  * This walks to a boxes float children before its children. When walking
526  * children, floating boxes are skipped.
527  */
528 static inline struct box *box_next_xy(struct box *b, int *x, int *y,
529  bool skip_children)
530 {
531  struct box *n;
532  int tx, ty;
533 
534  assert(b != NULL);
535 
536  if (skip_children) {
537  /* Caller is not interested in any kind of children */
538  goto skip_children;
539  }
540 
541  tx = *x; ty = *y;
542  n = box_move_xy(b, BOX_WALK_FLOAT_CHILDREN, &tx, &ty);
543  if (n) {
544  /* Next node is float child */
545  *x = tx;
546  *y = ty;
547  return n;
548  }
549 done_float_children:
550 
551  tx = *x; ty = *y;
552  n = box_move_xy(b, BOX_WALK_CHILDREN, &tx, &ty);
553  if (n) {
554  /* Next node is child */
555  *x = tx;
556  *y = ty;
557  return n;
558  }
559 
560 skip_children:
561  tx = *x; ty = *y;
562  n = box_move_xy(b, BOX_WALK_NEXT_FLOAT_SIBLING, &tx, &ty);
563  if (n) {
564  /* Go to next float sibling */
565  *x = tx;
566  *y = ty;
567  return n;
568  }
569 
570  if (box_is_float(b)) {
571  /* Done floats, but the float container may have children,
572  * or siblings, or ansestors with siblings. Change to
573  * float container and move past handling its float children.
574  */
576  goto done_float_children;
577  }
578 
579  /* Go to next sibling, or nearest ancestor with next sibling. */
580  while (b) {
581  while (!b->next && b->parent) {
582  b = box_move_xy(b, BOX_WALK_PARENT, x, y);
583  if (box_is_float(b)) {
584  /* Go on to next float, if there is one */
585  goto skip_children;
586  }
587  }
588  if (!b->next) {
589  /* No more boxes */
590  return NULL;
591  }
592 
593  tx = *x; ty = *y;
594  n = box_move_xy(b, BOX_WALK_NEXT_SIBLING, &tx, &ty);
595  if (n) {
596  /* Go to non-float (ancestor) sibling */
597  *x = tx;
598  *y = ty;
599  return n;
600 
601  } else if (b->parent) {
602  b = box_move_xy(b, BOX_WALK_PARENT, x, y);
603  if (box_is_float(b)) {
604  /* Go on to next float, if there is one */
605  goto skip_children;
606  }
607 
608  } else {
609  /* No more boxes */
610  return NULL;
611  }
612  }
613 
614  assert(b != NULL);
615  return NULL;
616 }
617 
618 
619 /* Exported function documented in html/box.h */
620 struct box *
622  struct box *box,
623  const int x, const int y,
624  int *box_x, int *box_y)
625 {
626  bool skip_children;
627  bool physically;
628 
629  assert(box);
630 
631  skip_children = false;
632  while ((box = box_next_xy(box, box_x, box_y, skip_children))) {
633  if (box_contains_point(len_ctx, box, x - *box_x, y - *box_y,
634  &physically)) {
635  *box_x -= scrollbar_get_offset(box->scroll_x);
636  *box_y -= scrollbar_get_offset(box->scroll_y);
637 
638  if (physically)
639  return box;
640 
641  skip_children = false;
642  } else {
643  skip_children = true;
644  }
645  }
646 
647  return NULL;
648 }
649 
650 
651 /**
652  * Check whether box is nearer mouse coordinates than current nearest box
653  *
654  * \param box box to test
655  * \param bx position of box, in global document coordinates
656  * \param by position of box, in global document coordinates
657  * \param x mouse point, in global document coordinates
658  * \param y mouse point, in global document coordinates
659  * \param dir direction in which to search (-1 = above-left,
660  * +1 = below-right)
661  * \param nearest nearest text box found, or NULL if none
662  * updated if box is nearer than existing nearest
663  * \param tx position of text_box, in global document coordinates
664  * updated if box is nearer than existing nearest
665  * \param ty position of text_box, in global document coordinates
666  * updated if box is nearer than existing nearest
667  * \param nr_xd distance to nearest text box found
668  * updated if box is nearer than existing nearest
669  * \param nr_yd distance to nearest text box found
670  * updated if box is nearer than existing nearest
671  * \return true if mouse point is inside box
672  */
673 static bool
675  int bx, int by,
676  int x, int y,
677  int dir,
678  struct box **nearest,
679  int *tx, int *ty,
680  int *nr_xd, int *nr_yd)
681 {
682  int w = box->padding[LEFT] + box->width + box->padding[RIGHT];
683  int h = box->padding[TOP] + box->height + box->padding[BOTTOM];
684  int y1 = by + h;
685  int x1 = bx + w;
686  int yd = INT_MAX;
687  int xd = INT_MAX;
688 
689  if (x >= bx && x1 > x && y >= by && y1 > y) {
690  *nearest = box;
691  *tx = bx;
692  *ty = by;
693  return true;
694  }
695 
696  if (box->parent->list_marker != box) {
697  if (dir < 0) {
698  /* consider only those children (partly) above-left */
699  if (by <= y && bx < x) {
700  yd = y <= y1 ? 0 : y - y1;
701  xd = x <= x1 ? 0 : x - x1;
702  }
703  } else {
704  /* consider only those children (partly) below-right */
705  if (y1 > y && x1 > x) {
706  yd = y > by ? 0 : by - y;
707  xd = x > bx ? 0 : bx - x;
708  }
709  }
710 
711  /* give y displacement precedence over x */
712  if (yd < *nr_yd || (yd == *nr_yd && xd <= *nr_xd)) {
713  *nr_yd = yd;
714  *nr_xd = xd;
715  *nearest = box;
716  *tx = bx;
717  *ty = by;
718  }
719  }
720  return false;
721 }
722 
723 
724 /**
725  * Pick the text box child of 'box' that is closest to and above-left
726  * (dir -ve) or below-right (dir +ve) of the point 'x,y'
727  *
728  * \param box parent box
729  * \param bx position of box, in global document coordinates
730  * \param by position of box, in global document coordinates
731  * \param fx position of float parent, in global document coordinates
732  * \param fy position of float parent, in global document coordinates
733  * \param x mouse point, in global document coordinates
734  * \param y mouse point, in global document coordinates
735  * \param dir direction in which to search (-1 = above-left,
736  * +1 = below-right)
737  * \param nearest nearest text box found, or NULL if none
738  * updated if a descendant of box is nearer than old nearest
739  * \param tx position of nearest, in global document coordinates
740  * updated if a descendant of box is nearer than old nearest
741  * \param ty position of nearest, in global document coordinates
742  * updated if a descendant of box is nearer than old nearest
743  * \param nr_xd distance to nearest text box found
744  * updated if a descendant of box is nearer than old nearest
745  * \param nr_yd distance to nearest text box found
746  * updated if a descendant of box is nearer than old nearest
747  * \return true if mouse point is inside text_box
748  */
749 static bool box_nearest_text_box(struct box *box, int bx, int by,
750  int fx, int fy, int x, int y, int dir, struct box **nearest,
751  int *tx, int *ty, int *nr_xd, int *nr_yd)
752 {
753  struct box *child = box->children;
754  int c_bx, c_by;
755  int c_fx, c_fy;
756  bool in_box = false;
757 
758  if (*nearest == NULL) {
759  *nr_xd = INT_MAX / 2; /* displacement of 'nearest so far' */
760  *nr_yd = INT_MAX / 2;
761  }
762  if (box->type == BOX_INLINE_CONTAINER) {
763  int bw = box->padding[LEFT] + box->width + box->padding[RIGHT];
764  int bh = box->padding[TOP] + box->height + box->padding[BOTTOM];
765  int b_y1 = by + bh;
766  int b_x1 = bx + bw;
767  if (x >= bx && b_x1 > x && y >= by && b_y1 > y) {
768  in_box = true;
769  }
770  }
771 
772  while (child) {
773  if (child->type == BOX_FLOAT_LEFT ||
774  child->type == BOX_FLOAT_RIGHT) {
775  c_bx = fx + child->x -
777  c_by = fy + child->y -
779  } else {
780  c_bx = bx + child->x -
782  c_by = by + child->y -
784  }
785  if (child->float_children) {
786  c_fx = c_bx;
787  c_fy = c_by;
788  } else {
789  c_fx = fx;
790  c_fy = fy;
791  }
792  if (in_box && child->text && !child->object) {
793  if (box_nearer_text_box(child,
794  c_bx, c_by, x, y, dir, nearest,
795  tx, ty, nr_xd, nr_yd))
796  return true;
797  } else {
798  if (child->list_marker) {
800  child->list_marker,
801  c_bx + child->list_marker->x,
802  c_by + child->list_marker->y,
803  x, y, dir, nearest,
804  tx, ty, nr_xd, nr_yd))
805  return true;
806  }
807  if (box_nearest_text_box(child, c_bx, c_by,
808  c_fx, c_fy, x, y, dir, nearest, tx, ty,
809  nr_xd, nr_yd))
810  return true;
811  }
812  child = child->next;
813  }
814 
815  return false;
816 }
817 
818 
819 /* Exported function documented in html/box.h */
820 struct box *
822  int x, int y,
823  int dir,
824  int *dx, int *dy)
825 {
826  struct box *text_box = NULL;
827  struct box *box;
828  int nr_xd, nr_yd;
829  int bx, by;
830  int fx, fy;
831  int tx, ty;
832 
833  if (html == NULL)
834  return NULL;
835 
836  box = html->layout;
837  bx = box->margin[LEFT];
838  by = box->margin[TOP];
839  fx = bx;
840  fy = by;
841 
842  if (!box_nearest_text_box(box, bx, by, fx, fy, x, y,
843  dir, &text_box, &tx, &ty, &nr_xd, &nr_yd)) {
844  if (text_box && text_box->text && !text_box->object) {
845  int w = (text_box->padding[LEFT] +
846  text_box->width +
847  text_box->padding[RIGHT]);
848  int h = (text_box->padding[TOP] +
849  text_box->height +
850  text_box->padding[BOTTOM]);
851  int x1, y1;
852 
853  y1 = ty + h;
854  x1 = tx + w;
855 
856  /* ensure point lies within the text box */
857  if (x < tx) x = tx;
858  if (y < ty) y = ty;
859  if (y > y1) y = y1;
860  if (x > x1) x = x1;
861  }
862  }
863 
864  /* return coordinates relative to box */
865  *dx = x - tx;
866  *dy = y - ty;
867 
868  return text_box;
869 }
870 
871 
872 /* Exported function documented in html/box.h */
873 struct box *box_find_by_id(struct box *box, lwc_string *id)
874 {
875  struct box *a, *b;
876  bool m;
877 
878  if (box->id != NULL &&
879  lwc_string_isequal(id, box->id, &m) == lwc_error_ok &&
880  m == true)
881  return box;
882 
883  for (a = box->children; a; a = a->next) {
884  if ((b = box_find_by_id(a, id)) != NULL)
885  return b;
886  }
887 
888  return NULL;
889 }
890 
891 
892 /* Exported function documented in html/box.h */
893 bool box_visible(struct box *box)
894 {
895  /* visibility: hidden */
896  if (box->style && css_computed_visibility(box->style) ==
897  CSS_VISIBILITY_HIDDEN)
898  return false;
899 
900  return true;
901 }
902 
903 
904 /* Exported function documented in html/box.h */
905 void box_dump(FILE *stream, struct box *box, unsigned int depth, bool style)
906 {
907  unsigned int i;
908  struct box *c, *prev;
909 
910  for (i = 0; i != depth; i++)
911  fprintf(stream, " ");
912 
913  fprintf(stream, "%p ", box);
914  fprintf(stream, "x%i y%i w%i h%i ", box->x, box->y,
915  box->width, box->height);
916  if (box->max_width != UNKNOWN_MAX_WIDTH)
917  fprintf(stream, "min%i max%i ", box->min_width, box->max_width);
918  fprintf(stream, "(%i %i %i %i) ",
919  box->descendant_x0, box->descendant_y0,
920  box->descendant_x1, box->descendant_y1);
921 
922  fprintf(stream, "m(%i %i %i %i) ",
923  box->margin[TOP], box->margin[LEFT],
924  box->margin[BOTTOM], box->margin[RIGHT]);
925 
926  switch (box->type) {
927  case BOX_BLOCK: fprintf(stream, "BLOCK "); break;
928  case BOX_INLINE_CONTAINER: fprintf(stream, "INLINE_CONTAINER "); break;
929  case BOX_INLINE: fprintf(stream, "INLINE "); break;
930  case BOX_INLINE_END: fprintf(stream, "INLINE_END "); break;
931  case BOX_INLINE_BLOCK: fprintf(stream, "INLINE_BLOCK "); break;
932  case BOX_TABLE: fprintf(stream, "TABLE [columns %i] ",
933  box->columns); break;
934  case BOX_TABLE_ROW: fprintf(stream, "TABLE_ROW "); break;
935  case BOX_TABLE_CELL: fprintf(stream, "TABLE_CELL [columns %i, "
936  "start %i, rows %i] ", box->columns,
937  box->start_column, box->rows); break;
938  case BOX_TABLE_ROW_GROUP: fprintf(stream, "TABLE_ROW_GROUP "); break;
939  case BOX_FLOAT_LEFT: fprintf(stream, "FLOAT_LEFT "); break;
940  case BOX_FLOAT_RIGHT: fprintf(stream, "FLOAT_RIGHT "); break;
941  case BOX_BR: fprintf(stream, "BR "); break;
942  case BOX_TEXT: fprintf(stream, "TEXT "); break;
943  default: fprintf(stream, "Unknown box type ");
944  }
945 
946  if (box->text)
947  fprintf(stream, "%li '%.*s' ", (unsigned long) box->byte_offset,
948  (int) box->length, box->text);
949  if (box->space)
950  fprintf(stream, "space ");
951  if (box->object) {
952  fprintf(stream, "(object '%s') ",
954  }
955  if (box->iframe) {
956  fprintf(stream, "(iframe) ");
957  }
958  if (box->gadget)
959  fprintf(stream, "(gadget) ");
960  if (style && box->style)
961  nscss_dump_computed_style(stream, box->style);
962  if (box->href)
963  fprintf(stream, " -> '%s'", nsurl_access(box->href));
964  if (box->target)
965  fprintf(stream, " |%s|", box->target);
966  if (box->title)
967  fprintf(stream, " [%s]", box->title);
968  if (box->id)
969  fprintf(stream, " ID:%s", lwc_string_data(box->id));
970  if (box->type == BOX_INLINE || box->type == BOX_INLINE_END)
971  fprintf(stream, " inline_end %p", box->inline_end);
972  if (box->float_children)
973  fprintf(stream, " float_children %p", box->float_children);
974  if (box->next_float)
975  fprintf(stream, " next_float %p", box->next_float);
976  if (box->float_container)
977  fprintf(stream, " float_container %p", box->float_container);
978  if (box->col) {
979  fprintf(stream, " (columns");
980  for (i = 0; i != box->columns; i++)
981  fprintf(stream, " (%s %s %i %i %i)",
982  ((const char *[]) {"UNKNOWN", "FIXED",
983  "AUTO", "PERCENT", "RELATIVE"})
984  [box->col[i].type],
985  ((const char *[]) {"normal",
986  "positioned"})
987  [box->col[i].positioned],
988  box->col[i].width,
989  box->col[i].min, box->col[i].max);
990  fprintf(stream, ")");
991  }
992  if (box->node != NULL) {
993  dom_string *name;
994  if (dom_node_get_node_name(box->node, &name) == DOM_NO_ERR) {
995  fprintf(stream, " <%s>", dom_string_data(name));
996  dom_string_unref(name);
997  }
998  }
999  fprintf(stream, "\n");
1000 
1001  if (box->list_marker) {
1002  for (i = 0; i != depth; i++)
1003  fprintf(stream, " ");
1004  fprintf(stream, "list_marker:\n");
1005  box_dump(stream, box->list_marker, depth + 1, style);
1006  }
1007 
1008  for (c = box->children; c && c->next; c = c->next)
1009  ;
1010  if (box->last != c)
1011  fprintf(stream, "warning: box->last %p (should be %p) "
1012  "(box %p)\n", box->last, c, box);
1013  for (prev = 0, c = box->children; c; prev = c, c = c->next) {
1014  if (c->parent != box)
1015  fprintf(stream, "warning: box->parent %p (should be "
1016  "%p) (box on next line)\n",
1017  c->parent, box);
1018  if (c->prev != prev)
1019  fprintf(stream, "warning: box->prev %p (should be "
1020  "%p) (box on next line)\n",
1021  c->prev, prev);
1022  box_dump(stream, c, depth + 1, style);
1023  }
1024 }
1025 
1026 
1027 /* exported interface documented in html/box.h */
1028 nserror
1030  struct box *box,
1031  bool bottom,
1032  bool right)
1033 {
1034  struct html_scrollbar_data *data;
1035  int visible_width, visible_height;
1036  int full_width, full_height;
1037  nserror res;
1038 
1039  if (!bottom && box->scroll_x != NULL) {
1040  data = scrollbar_get_data(box->scroll_x);
1042  free(data);
1043  box->scroll_x = NULL;
1044  }
1045 
1046  if (!right && box->scroll_y != NULL) {
1047  data = scrollbar_get_data(box->scroll_y);
1049  free(data);
1050  box->scroll_y = NULL;
1051  }
1052 
1053  if (!bottom && !right) {
1054  return NSERROR_OK;
1055  }
1056 
1057  visible_width = box->width + box->padding[RIGHT] + box->padding[LEFT];
1058  visible_height = box->height + box->padding[TOP] + box->padding[BOTTOM];
1059 
1060  full_width = ((box->descendant_x1 - box->border[RIGHT].width) >
1061  visible_width) ?
1062  box->descendant_x1 + box->padding[RIGHT] :
1063  visible_width;
1064  full_height = ((box->descendant_y1 - box->border[BOTTOM].width) >
1065  visible_height) ?
1066  box->descendant_y1 + box->padding[BOTTOM] :
1067  visible_height;
1068 
1069  if (right) {
1070  if (box->scroll_y == NULL) {
1071  data = malloc(sizeof(struct html_scrollbar_data));
1072  if (data == NULL) {
1073  return NSERROR_NOMEM;
1074  }
1075  data->c = c;
1076  data->box = box;
1077  res = scrollbar_create(false,
1078  visible_height,
1079  full_height,
1080  visible_height,
1081  data,
1083  &(box->scroll_y));
1084  if (res != NSERROR_OK) {
1085  return res;
1086  }
1087  } else {
1089  visible_height,
1090  visible_height,
1091  full_height);
1092  }
1093  }
1094  if (bottom) {
1095  if (box->scroll_x == NULL) {
1096  data = malloc(sizeof(struct html_scrollbar_data));
1097  if (data == NULL) {
1098  return NSERROR_OK;
1099  }
1100  data->c = c;
1101  data->box = box;
1102  res = scrollbar_create(true,
1103  visible_width - (right ? SCROLLBAR_WIDTH : 0),
1104  full_width,
1105  visible_width,
1106  data,
1108  &box->scroll_x);
1109  if (res != NSERROR_OK) {
1110  return res;
1111  }
1112  } else {
1114  visible_width -
1115  (right ? SCROLLBAR_WIDTH : 0),
1116  visible_width, full_width);
1117  }
1118  }
1119 
1120  if (right && bottom) {
1122  }
1123 
1124  return NSERROR_OK;
1125 }
1126 
1127 
1128 /* exported interface documented in html/box.h */
1129 bool box_vscrollbar_present(const struct box * const box)
1130 {
1131  return box->padding[TOP] + box->height + box->padding[BOTTOM] +
1132  box->border[BOTTOM].width < box->descendant_y1;
1133 }
1134 
1135 
1136 /* exported interface documented in html/box.h */
1137 bool box_hscrollbar_present(const struct box * const box)
1138 {
1139  return box->padding[LEFT] + box->width + box->padding[RIGHT] +
1140  box->border[RIGHT].width < box->descendant_x1;
1141 }
struct form_control * gadget
Form control data, or NULL if not a form control.
Definition: box.h:478
struct box * prev
Previous sibling box, or NULL.
Definition: box.h:280
unsigned int start_column
Start column for TABLE_CELL only.
Definition: box.h:461
Definition: box.h:157
const char * target
Link target, or NULL.
Definition: box.h:440
Definition: box.h:157
int y1
Bottom right.
Definition: types.h:42
void nscss_dump_computed_style(FILE *stream, const css_computed_style *style)
Dump a computed style style to the give file handle stream.
Definition: dump.c:159
struct box * box_create(css_select_results *styles, css_computed_style *style, bool style_owned, nsurl *href, const char *target, const char *title, lwc_string *id, void *context)
Create a box tree node.
Definition: box.c:103
void scrollbar_make_pair(struct scrollbar *horizontal, struct scrollbar *vertical)
Connect a horizontal and a vertical scrollbar into a pair so that they co-operate during 2D drags...
Definition: scrollbar.c:989
int descendant_x1
right edge of descendants
Definition: box.h:370
struct object_params * object_params
Parameters for the object, or NULL.
Definition: box.h:501
struct box_border border[4]
Border: TOP, RIGHT, BOTTOM, LEFT.
Definition: box.h:386
Interface to utility string handling.
static bool box_nearest_text_box(struct box *box, int bx, int by, int fx, int fy, int x, int y, int dir, struct box **nearest, int *tx, int *ty, int *nr_xd, int *nr_yd)
Pick the text box child of &#39;box&#39; that is closest to and above-left (dir -ve) or below-right (dir +ve)...
Definition: box.c:749
bool box_hscrollbar_present(const struct box *const box)
Determine if a box has a horizontal scrollbar.
Definition: box.c:1137
struct nsurl * href
Link, or NULL.
Definition: box.h:435
#define SCROLLBAR_WIDTH
Definition: scrollbar.h:32
box_flags flags
Box flags.
Definition: box.h:245
int cached_place_below_level
Level below which floats have been placed.
Definition: box.h:331
Interface to form handling functions internal to HTML content handler.
Public content interface.
int min_width
Width of box taking all line breaks (including margins etc).
Definition: box.h:402
int padding[4]
Padding: TOP, RIGHT, BOTTOM, LEFT.
Definition: box.h:381
nserror scrollbar_create(bool horizontal, int length, int full_size, int visible_size, void *client_data, scrollbar_client_callback client_callback, struct scrollbar **s)
Create a scrollbar.
Definition: scrollbar.c:93
Memory exhaustion.
Definition: errors.h:32
box_walk_dir
Direction to move in a box-tree walk.
Definition: box.c:426
size_t byte_offset
Byte offset within a textual representation of this content.
Definition: box.h:429
#define talloc_set_destructor(ptr, function)
Definition: talloc.h:75
void scrollbar_set_extents(struct scrollbar *s, int length, int visible_size, int full_size)
Set the length of the scrollbar widget, the size of the visible area, and the size of the full area...
Definition: scrollbar.c:639
#define box_is_float(box)
Definition: box.c:51
int descendant_y0
top edge of descendants
Definition: box.h:369
struct scrollbar * scroll_x
Horizontal scroll.
Definition: box.h:391
Definition: box.h:157
Core mouse and pointer states.
int descendant_x0
left edge of descendants
Definition: box.h:368
void box_unlink_and_free(struct box *box)
Unlink a box from the box tree and then free it recursively.
Definition: box.c:206
Interface to platform-specific miscellaneous browser operation table.
void box_insert_sibling(struct box *box, struct box *new_box)
Insert a new box as a sibling to a box in a tree.
Definition: box.c:192
void box_add_child(struct box *parent, struct box *child)
Add a child to a box tree node.
Definition: box.c:173
struct box * last
Last child box, or NULL.
Definition: box.h:290
int min
Minimum width of content.
Definition: box.h:194
void box_free_box(struct box *box)
Free the data in a single box structure.
Definition: box.c:245
int x
Coordinate of left padding edge relative to parent box, or relative to ancestor that contains this bo...
Definition: box.h:339
struct box * layout
Box tree, or NULL.
Length conversion context data.
Definition: utils.h:35
struct box * float_children
First float child box, or NULL.
Definition: box.h:310
int y
Coordinate of top padding edge, relative as for x.
Definition: box.h:343
struct scrollbar * scroll_y
Vertical scroll.
Definition: box.h:396
unsigned int rows
Number of rows for TABLE only.
Definition: box.h:456
int talloc_free(void *ptr)
Definition: talloc.c:760
void * scrollbar_get_data(struct scrollbar *s)
Get the scrollbar&#39;s client data.
Definition: scrollbar.c:1003
#define UNKNOWN_MAX_WIDTH
Definition: box.h:107
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
void html_overflow_scroll_callback(void *client_data, struct scrollbar_msg_data *scrollbar_data)
Callback for in-page scrollbars.
Definition: interaction.c:1678
int space
Width of space after current text (depends on font and size).
Definition: box.h:424
nserror
Enumeration of error codes.
Definition: errors.h:29
struct box * next_float
Next sibling float box.
Definition: box.h:315
size_t length
Length of text.
Definition: box.h:419
lwc_string * id
value of id attribute (or name for anchors)
Definition: box.h:269
int max
Maximum width of content.
Definition: box.h:199
void scrollbar_destroy(struct scrollbar *s)
Destroy a scrollbar.
Definition: scrollbar.c:138
static struct box * box_next_xy(struct box *b, int *x, int *y, bool skip_children)
Itterator for walking to next box in interaction order.
Definition: box.c:528
struct content * c
Definition: interaction.h:31
struct box * box_at_point(const nscss_len_ctx *len_ctx, struct box *box, const int x, const int y, int *box_x, int *box_y)
Find the boxes at a point.
Definition: box.c:621
Corresponds to a single URL.
static struct box * box_move_xy(struct box *b, enum box_walk_dir dir, int *x, int *y)
Move from box to next box in given direction, adjusting for box coord change.
Definition: box.c:447
struct dom_node * node
DOM node that generated this box or NULL.
Definition: box.h:250
Private data for text/html content.
HTML content user interaction handling.
No error.
Definition: errors.h:30
static bool box_contains_point(const nscss_len_ctx *len_ctx, const struct box *box, int x, int y, bool *physically)
Determine if a point lies within a box.
Definition: box.c:312
struct nsurl * hlcache_handle_get_url(const struct hlcache_handle *handle)
Retrieve the URL associated with a high level cache handle.
nserror box_handle_scrollbars(struct content *c, struct box *box, bool bottom, bool right)
Applies the given scroll setup to a box.
Definition: box.c:1029
struct box * box_find_by_id(struct box *box, lwc_string *id)
Find a box based upon its id attribute.
Definition: box.c:873
struct box * list_marker
List marker box if this is a list-item, or NULL.
Definition: box.h:472
int x1
Definition: types.h:42
Box tree construction and manipulation interface.
struct column * col
Array of table column data for TABLE only.
Definition: box.h:466
wimp_w parent
Definition: dialog.c:87
int y0
Top left.
Definition: types.h:41
struct box * float_container
If box is a float, points to box&#39;s containing block.
Definition: box.h:320
void box_free(struct box *box)
Free a box tree recursively.
Definition: box.c:229
const char * title
Title, or NULL.
Definition: box.h:445
Definition: box.h:120
#define UNKNOWN_WIDTH
Definition: box.h:106
Definition: box.h:157
static bool box_nearer_text_box(struct box *box, int bx, int by, int x, int y, int dir, struct box **nearest, int *tx, int *ty, int *nr_xd, int *nr_yd)
Check whether box is nearer mouse coordinates than current nearest box.
Definition: box.c:674
Definition: box.h:117
struct box * box
Definition: interaction.h:32
struct box * children
First child box, or NULL.
Definition: box.h:285
css_select_results * styles
Computed styles for elements and their pseudo elements.
Definition: box.h:256
int height
Definition: gui.c:180
bool positioned
Whether all of column&#39;s cells are css positioned.
Definition: box.h:204
int width
border-width (pixels)
Definition: box.h:166
int height
Height of content box (excluding padding etc.).
Definition: box.h:352
Context for scrollbar.
Definition: interaction.h:30
box_type type
Type of box.
Definition: box.h:240
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:371
Rectangle coordinates.
Definition: types.h:40
int width
Preferred width of column.
Definition: box.h:189
struct hlcache_handle * background
Background image for this box, or NULL if none.
Definition: box.h:490
bool box_vscrollbar_present(const struct box *const box)
Determine if a box has a vertical scrollbar.
Definition: box.c:1129
bool box_visible(struct box *box)
Determine if a box is visible when the tree is rendered.
Definition: box.c:893
char * text
Text, or NULL if none.
Definition: box.h:414
nsurl * nsurl_ref(nsurl *url)
Increment the reference count to a NetSurf URL object.
int width
Width of content box (excluding padding etc.).
Definition: box.h:348
struct hlcache_handle * object
Object in this box (usually an image), or NULL if none.
Definition: box.h:496
int x0
Definition: types.h:41
static int box_talloc_destructor(struct box *b)
Destructor for box nodes which own styles.
Definition: box.c:60
Definition: box.h:128
void box_coords(struct box *box, int *x, int *y)
Find the absolute coordinates of a box.
Definition: box.c:263
const char * nsurl_access(const nsurl *url)
Access a NetSurf URL object as a string.
int margin[4]
Margin: TOP, RIGHT, BOTTOM, LEFT.
Definition: box.h:376
struct box * next
Next sibling box, or NULL.
Definition: box.h:275
struct box * parent
Parent box, or NULL.
Definition: box.h:295
int max_width
Width that would be taken with no line breaks.
Definition: box.h:408
unsigned int columns
Number of columns for TABLE / TABLE_CELL.
Definition: box.h:451
struct box * box_pick_text_box(struct html_content *html, int x, int y, int dir, int *dx, int *dy)
Peform pick text on browser window contents to locate the box under the mouse pointer, or nearest in the given direction if the pointer is not over a text box.
Definition: box.c:821
Scrollbar widget interface.
void box_dump(FILE *stream, struct box *box, unsigned int depth, bool style)
Print a box tree to a file.
Definition: box.c:905
#define talloc(ctx, type)
Definition: talloc.h:85
enum column::@132 type
Type of column.
Definition: box.h:127
Data specific to CONTENT_HTML.
Definition: html_internal.h:93
int width
Definition: gui.c:179
Interface to core interface table.
Definition: box.h:142
css_computed_style * style
Style for this box.
Definition: box.h:264
NetSurf URL handling (interface).
struct nsurl nsurl
NetSurf URL object.
Definition: nsurl.h:31
struct box * inline_end
INLINE_END box corresponding to this INLINE box, or INLINE box corresponding to this INLINE_END box...
Definition: box.h:301
void nsurl_unref(nsurl *url)
Drop a reference to a NetSurf URL object.
struct browser_window * iframe
Iframe&#39;s browser_window, or NULL if none.
Definition: box.h:507
char * usemap
(Image)map to use with this object, or NULL if none
Definition: box.h:484
Node in box tree.
Definition: box.h:236
void form_free_control(struct form_control *control)
Free a struct form_control.
Definition: form.c:216
void box_bounds(struct box *box, struct rect *r)
Find the bounds of a box.
Definition: box.c:281