Bug Summary

File:frontends/framebuffer/fbtk/fbtk.c
Warning:line 290, column 3
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name fbtk.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/var/lib/jenkins/workspace/scan-build-netsurf -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -I . -I include -I build/Linux-framebuffer -I frontends -I content/handlers -D WITH_JPEG -U WITH_PDF_EXPORT -D LIBICONV_PLUG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /usr/include/x86_64-linux-gnu -D WITH_CURL -D WITH_OPENSSL -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D UTF8PROC_EXPORTS -D WITH_UTF8PROC -D WITH_WEBP -I /usr/include/libpng16 -D WITH_PNG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include/ -D WITH_BMP -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_GIF -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NS_SVG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSSPRITE -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSPSL -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSLOG -D NETSURF_UA_FORMAT_STRING="Mozilla/5.0 (%s) NetSurf/%d.%d" -D NETSURF_HOMEPAGE="about:welcome" -D NETSURF_LOG_LEVEL=VERBOSE -D NETSURF_BUILTIN_LOG_FILTER="(level:WARNING || cat:jserrors)" -D NETSURF_BUILTIN_VERBOSE_FILTER="(level:VERBOSE || cat:jserrors)" -D STMTEXPR=1 -D nsframebuffer -D small -D NETSURF_FB_RESPATH="${HOME}/.netsurf/:${NETSURFRES}:/var/lib/jenkins/artifacts-x86_64-linux-gnu/share/netsurf:./frontends/framebuffer/res" -D NETSURF_FB_FONTPATH="/usr/share/fonts/truetype/dejavu:/usr/share/fonts/truetype/msttcorefonts" -D NETSURF_FB_FONT_SANS_SERIF="DejaVuSans.ttf" -D NETSURF_FB_FONT_SANS_SERIF_BOLD="DejaVuSans-Bold.ttf" -D NETSURF_FB_FONT_SANS_SERIF_ITALIC="DejaVuSans-Oblique.ttf" -D NETSURF_FB_FONT_SANS_SERIF_ITALIC_BOLD="DejaVuSans-BoldOblique.ttf" -D NETSURF_FB_FONT_SERIF="DejaVuSerif.ttf" -D NETSURF_FB_FONT_SERIF_BOLD="DejaVuSerif-Bold.ttf" -D NETSURF_FB_FONT_MONOSPACE="DejaVuSansMono.ttf" -D NETSURF_FB_FONT_MONOSPACE_BOLD="DejaVuSansMono-Bold.ttf" -D NETSURF_FB_FONT_CURSIVE="Comic_Sans_MS.ttf" -D NETSURF_FB_FONT_FANTASY="Impact.ttf" -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D _POSIX_C_SOURCE=200809L -D _XOPEN_SOURCE=700 -D _BSD_SOURCE -D _DEFAULT_SOURCE -D _NETBSD_SOURCE -D DUK_OPT_HAVE_CUSTOM_H -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wwrite-strings -Wno-unused-parameter -Wno-unused-but-set-variable -std=c99 -fconst-strings -fdebug-compilation-dir=/var/lib/jenkins/workspace/scan-build-netsurf -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-display-progress -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/lib/jenkins/workspace/scan-build-netsurf/clangScanBuildReports/2024-12-17-120558-2788052-1 -x c frontends/framebuffer/fbtk/fbtk.c
1/*
2 * Copyright 2008,2010 Vincent Sanders <vince@simtec.co.uk>
3 *
4 * Framebuffer windowing toolkit core.
5 *
6 * This file is part of NetSurf, http://www.netsurf-browser.org/
7 *
8 * NetSurf is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * NetSurf is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <stdlib.h>
22#include <sys/types.h>
23#include <assert.h>
24#include <stdint.h>
25#include <string.h>
26#include <stdbool.h>
27#include <stdarg.h>
28
29#include <libnsfb.h>
30#include <libnsfb_plot.h>
31#include <libnsfb_plot_util.h>
32#include <libnsfb_event.h>
33#include <libnsfb_cursor.h>
34
35#include "utils/utils.h"
36#include "utils/log.h"
37#include "netsurf/browser_window.h"
38#include "netsurf/plotters.h"
39
40#include "framebuffer/gui.h"
41#include "framebuffer/fbtk.h"
42#include "framebuffer/image_data.h"
43
44#include "widget.h"
45
46#ifdef FBTK_LOGGING
47
48/* tree dump debug, also example of depth first tree walk */
49static void
50dump_tk_tree(fbtk_widget_t *widget)
51{
52 widget = fbtk_get_root_widget(widget);
53 int indent = 0;
54
55 while (widget != NULL((void*)0)) {
56 NSLOG(fbtk, DEBUG, "%*s%p", indent, "", widget)do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_fbtk
, NSLOG_LEVEL_DEBUG, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 56, }; nslog__log(&_nslog_ctx
, "%*s%p", indent, "", widget); } } while(0)
;
57 if (widget->first_child != NULL((void*)0)) {
58 widget = widget->first_child;
59 indent += 6;
60 } else if (widget->next != NULL((void*)0)) {
61 widget = widget->next;
62 } else {
63 while ((widget->parent != NULL((void*)0)) &&
64 (widget->parent->next == NULL((void*)0))) {
65 widget = widget->parent;
66 indent -= 6;
67 }
68 if (widget->parent != NULL((void*)0)) {
69 indent -= 6;
70 widget = widget->parent->next;
71 } else {
72 widget = NULL((void*)0);
73 }
74 }
75 }
76}
77
78#endif
79
80/* exported function documented in fbtk.h */
81void
82fbtk_request_redraw(fbtk_widget_t *widget)
83{
84 fbtk_widget_t *cwidget;
85 fbtk_widget_t *pwidget;
86
87 assert(widget != NULL)((widget != ((void*)0)) ? (void) (0) : __assert_fail ("widget != NULL"
, "frontends/framebuffer/fbtk/fbtk.c", 87, __extension__ __PRETTY_FUNCTION__
))
;
88
89 /* if widget not mapped do not try to redraw it */
90 pwidget = widget;
91 while (pwidget != NULL((void*)0)) {
92 if (pwidget->mapped == false0)
93 return;
94 pwidget = pwidget->parent;
95 }
96
97 widget->redraw.needed = true1;
98 widget->redraw.x = 0;
99 widget->redraw.y = 0;
100 widget->redraw.width = widget->width;
101 widget->redraw.height = widget->height;
102
103 NSLOG(fbtk, DEBUG,do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_fbtk
, NSLOG_LEVEL_DEBUG, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 109, }; nslog__log(&_nslog_ctx
, "redrawing %p %d,%d %d,%d", widget, widget->redraw.x, widget
->redraw.y, widget->redraw.width, widget->redraw.height
); } } while(0)
104 "redrawing %p %d,%d %d,%d",do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_fbtk
, NSLOG_LEVEL_DEBUG, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 109, }; nslog__log(&_nslog_ctx
, "redrawing %p %d,%d %d,%d", widget, widget->redraw.x, widget
->redraw.y, widget->redraw.width, widget->redraw.height
); } } while(0)
105 widget,do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_fbtk
, NSLOG_LEVEL_DEBUG, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 109, }; nslog__log(&_nslog_ctx
, "redrawing %p %d,%d %d,%d", widget, widget->redraw.x, widget
->redraw.y, widget->redraw.width, widget->redraw.height
); } } while(0)
106 widget->redraw.x,do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_fbtk
, NSLOG_LEVEL_DEBUG, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 109, }; nslog__log(&_nslog_ctx
, "redrawing %p %d,%d %d,%d", widget, widget->redraw.x, widget
->redraw.y, widget->redraw.width, widget->redraw.height
); } } while(0)
107 widget->redraw.y,do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_fbtk
, NSLOG_LEVEL_DEBUG, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 109, }; nslog__log(&_nslog_ctx
, "redrawing %p %d,%d %d,%d", widget, widget->redraw.x, widget
->redraw.y, widget->redraw.width, widget->redraw.height
); } } while(0)
108 widget->redraw.width,do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_fbtk
, NSLOG_LEVEL_DEBUG, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 109, }; nslog__log(&_nslog_ctx
, "redrawing %p %d,%d %d,%d", widget, widget->redraw.x, widget
->redraw.y, widget->redraw.width, widget->redraw.height
); } } while(0)
109 widget->redraw.height)do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_fbtk
, NSLOG_LEVEL_DEBUG, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 109, }; nslog__log(&_nslog_ctx
, "redrawing %p %d,%d %d,%d", widget, widget->redraw.x, widget
->redraw.y, widget->redraw.width, widget->redraw.height
); } } while(0)
;
110
111 cwidget = widget->last_child;
112 while (cwidget != NULL((void*)0)) {
113 fbtk_request_redraw(cwidget);
114 cwidget = cwidget->prev;
115 }
116
117 while (widget->parent != NULL((void*)0)) {
118 widget = widget->parent;
119 widget->redraw.child = true1;
120 }
121}
122
123
124
125/* exported function documented in fbtk.h */
126int
127fbtk_set_mapping(fbtk_widget_t *widget, bool_Bool map)
128{
129 NSLOG(netsurf, INFO, "setting mapping on %p to %d", widget, map)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 129, }; nslog__log(&_nslog_ctx
, "setting mapping on %p to %d", widget, map); } } while(0)
;
130 widget->mapped = map;
131 if (map) {
132 fbtk_request_redraw(widget);
133 } else {
134 fbtk_request_redraw(widget->parent);
135 }
136 return 0;
137}
138
139
140/**
141 * Swap a sibling widget with the next deepest in the hierachy
142 *
143 * \param lw The widget to swap
144 */
145static void
146swap_siblings(fbtk_widget_t *lw)
147{
148 fbtk_widget_t *rw = lw->next; /* the widget to swap lw with */
149 fbtk_widget_t *before;
150 fbtk_widget_t *after;
151
152 assert(rw != NULL)((rw != ((void*)0)) ? (void) (0) : __assert_fail ("rw != NULL"
, "frontends/framebuffer/fbtk/fbtk.c", 152, __extension__ __PRETTY_FUNCTION__
))
;
153
154 NSLOG(netsurf, INFO, "Swapping %p with %p", lw, rw)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 154, }; nslog__log(&_nslog_ctx
, "Swapping %p with %p", lw, rw); } } while(0)
;
155 before = lw->prev;
156 after = rw->next;
157
158 if (before == NULL((void*)0)) {
159 /* left widget is currently the first child */
160 lw->parent->first_child = rw;
161 } else {
162 before->next = rw;
163 }
164 rw->prev = before;
165 rw->next = lw;
166
167 if (after == NULL((void*)0)) {
168 /* right widget is currently the last child */
169 rw->parent->last_child = lw;
170 } else {
171 after->prev = lw;
172 }
173 lw->next = after;
174 lw->prev = rw;
175}
176
177
178
179/* exported function documented in fbtk.h */
180int
181fbtk_set_zorder(fbtk_widget_t *widget, int z)
182{
183 while (z != 0) {
184 if (z < 0) {
185 if (widget->prev == NULL((void*)0))
186 break; /* cannot go any shallower */
187
188 /* swap with previous entry */
189 swap_siblings(widget->prev);
190
191 z++;
192 } else {
193 if (widget->next == NULL((void*)0))
194 break; /* cannot go any deeper */
195
196 /* swap with subsequent entry */
197 swap_siblings(widget);
198
199 z--;
200 }
201 }
202
203 return z;
204}
205
206
207/* exported function documented in fbtk.h */
208bool_Bool
209fbtk_set_pos_and_size(fbtk_widget_t *widget,
210 int x, int y,
211 int width, int height)
212{
213 if (widget->parent != NULL((void*)0)) {
214 fbtk_widget_t *parent = widget->parent;
215
216 /* make new window fit inside parent */
217 if (width == 0) {
218 width = parent->width - x;
219 } else if (width < 0) {
220 width = parent->width + width - x;
221 }
222 if ((width + x) > parent->width) {
223 width = parent->width - x;
224 }
225
226 if (height == 0) {
227 height = parent->height - y;
228 } else if (height < 0) {
229 height = parent->height + height - y;
230 }
231 if ((height + y) > parent->height) {
232 height = parent->height - y;
233 }
234 }
235
236 if ((widget->x != x) ||
237 (widget->y != y) ||
238 (widget->width != width) ||
239 (widget->height != height)) {
240 widget->x = x;
241 widget->y = y;
242 widget->width = width;
243 widget->height = height;
244 return true1;
245 }
246 return false0;
247}
248
249
250/* exported function docuemnted in fbtk.h */
251void
252fbtk_set_caret(fbtk_widget_t *widget, bool_Bool set,
253 int x, int y, int height,
254 void (*remove_caret)(fbtk_widget_t *widget))
255{
256 fbtk_widget_t *root;
257
258 assert(widget != NULL)((widget != ((void*)0)) ? (void) (0) : __assert_fail ("widget != NULL"
, "frontends/framebuffer/fbtk/fbtk.c", 258, __extension__ __PRETTY_FUNCTION__
))
;
259 root = fbtk_get_root_widget(widget);
260
261 if (root->u.root.caret.owner != NULL((void*)0) &&
262 root->u.root.caret.remove_cb != NULL((void*)0))
263 root->u.root.caret.remove_cb(widget);
264
265 if (set) {
266 assert(remove_caret != NULL)((remove_caret != ((void*)0)) ? (void) (0) : __assert_fail ("remove_caret != NULL"
, "frontends/framebuffer/fbtk/fbtk.c", 266, __extension__ __PRETTY_FUNCTION__
))
;
267
268 root->u.root.caret.owner = widget;
269 root->u.root.caret.x = x;
270 root->u.root.caret.y = y;
271 root->u.root.caret.height = height;
272 root->u.root.caret.remove_cb = remove_caret;
273
274 } else {
275 root->u.root.caret.owner = NULL((void*)0);
276 root->u.root.caret.remove_cb = NULL((void*)0);
277 }
278}
279
280/* exported function documented in fbtk.h */
281int
282fbtk_destroy_widget(fbtk_widget_t *widget)
283{
284 fbtk_widget_t *parent;
285 int ret = 0;
286
287 ret = fbtk_post_callback(widget, FBTK_CBT_DESTROY);
288
289 while (widget->first_child
13.1
Field 'first_child' is not equal to NULL
!= NULL((void*)0)
) {
1
Assuming field 'first_child' is not equal to NULL
2
Loop condition is true. Entering loop body
4
Assuming field 'first_child' is equal to NULL
5
Loop condition is false. Execution continues on line 293
14
Loop condition is true. Entering loop body
290 fbtk_destroy_widget(widget->first_child);
3
Calling 'fbtk_destroy_widget'
13
Returning; memory was released via 1st parameter
15
Use of memory after it is freed
291 }
292
293 parent = widget->parent;
294 if (parent != NULL((void*)0)) {
6
Assuming 'parent' is not equal to NULL
7
Taking true branch
295
296 /* unlink from siblings */
297 if (widget->prev != NULL((void*)0)) {
8
Assuming field 'prev' is equal to NULL
9
Taking false branch
298 widget->prev->next = widget->next;
299 } else {
300 /* must be the first widget, unlink from parent */
301 parent->first_child = widget->next;
302 }
303 if (widget->next != NULL((void*)0)) {
10
Assuming field 'next' is equal to NULL
11
Taking false branch
304 widget->next->prev = widget->prev;
305 } else {
306 /* must be the last widget, unlink from parent */
307 parent->last_child = widget->prev;
308 }
309
310 free(widget);
12
Memory is released
311 }
312
313 return ret;
314}
315
316/* region coverage flags. */
317enum {
318 POINT_LEFTOF_REGION = 1,
319 POINT_RIGHTOF_REGION = 2,
320 POINT_ABOVE_REGION = 4,
321 POINT_BELOW_REGION = 8,
322};
323
324/* Computes where a point lies in respect to an area. */
325#define REGION(x,y,cx1,cx2,cy1,cy2)(( (y) > (cy2) ? POINT_BELOW_REGION : 0) | ( (y) < (cy1
) ? POINT_ABOVE_REGION : 0) | ( (x) > (cx2) ? POINT_RIGHTOF_REGION
: 0) | ( (x) < (cx1) ? POINT_LEFTOF_REGION : 0) )
\
326 (( (y) > (cy2) ? POINT_BELOW_REGION : 0) | \
327 ( (y) < (cy1) ? POINT_ABOVE_REGION : 0) | \
328 ( (x) > (cx2) ? POINT_RIGHTOF_REGION : 0) | \
329 ( (x) < (cx1) ? POINT_LEFTOF_REGION : 0) )
330
331/* swap two integers */
332#define SWAP(a, b)do { int t; t=(a); (a)=(b); (b)=t; } while(0) do { int t; t=(a); (a)=(b); (b)=t; } while(0)
333
334/* exported function documented in fbtk.h */
335bool_Bool
336fbtk_clip_rect(const bbox_t * restrict clip, bbox_t * restrict box)
337{
338 uint8_t region1;
339 uint8_t region2;
340
341 /* ensure co-ordinates are in ascending order */
342 if (box->x1 < box->x0)
343 SWAP(box->x0, box->x1)do { int t; t=(box->x0); (box->x0)=(box->x1); (box->
x1)=t; } while(0)
;
344 if (box->y1 < box->y0)
345 SWAP(box->y0, box->y1)do { int t; t=(box->y0); (box->y0)=(box->y1); (box->
y1)=t; } while(0)
;
346
347 region1 = REGION(box->x0, box->y0, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1)(( (box->y0) > (clip->y1 - 1) ? POINT_BELOW_REGION :
0) | ( (box->y0) < (clip->y0) ? POINT_ABOVE_REGION :
0) | ( (box->x0) > (clip->x1 - 1) ? POINT_RIGHTOF_REGION
: 0) | ( (box->x0) < (clip->x0) ? POINT_LEFTOF_REGION
: 0) )
;
348 region2 = REGION(box->x1, box->y1, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1)(( (box->y1) > (clip->y1 - 1) ? POINT_BELOW_REGION :
0) | ( (box->y1) < (clip->y0) ? POINT_ABOVE_REGION :
0) | ( (box->x1) > (clip->x1 - 1) ? POINT_RIGHTOF_REGION
: 0) | ( (box->x1) < (clip->x0) ? POINT_LEFTOF_REGION
: 0) )
;
349
350 /* area lies entirely outside the clipping rectangle */
351 if ((region1 | region2) && (region1 & region2))
352 return false0;
353
354 if (box->x0 < clip->x0)
355 box->x0 = clip->x0;
356 if (box->x0 > clip->x1)
357 box->x0 = clip->x1;
358
359 if (box->x1 < clip->x0)
360 box->x1 = clip->x0;
361 if (box->x1 > clip->x1)
362 box->x1 = clip->x1;
363
364 if (box->y0 < clip->y0)
365 box->y0 = clip->y0;
366 if (box->y0 > clip->y1)
367 box->y0 = clip->y1;
368
369 if (box->y1 < clip->y0)
370 box->y1 = clip->y0;
371 if (box->y1 > clip->y1)
372 box->y1 = clip->y1;
373
374 return true1;
375}
376
377/* exported function documented in fbtk.h */
378bool_Bool
379fbtk_clip_to_widget(fbtk_widget_t *widget, bbox_t * restrict box)
380{
381 bbox_t wbox;
382 wbox.x0 = 0;
383 wbox.y0 = 0;
384 wbox.x1 = widget->width;
385 wbox.y1 = widget->height;
386 return fbtk_clip_rect(&wbox, box);
387}
388
389
390
391/* internally exported function documented in widget.h */
392int
393fbtk_set_ptr(fbtk_widget_t *widget, fbtk_callback_info *cbi)
394{
395 fbtk_widget_t *root = fbtk_get_root_widget(widget);
396 struct fbtk_bitmap *bm = cbi->context;
397
398 nsfb_cursor_set(root->u.root.fb,
399 (nsfb_colour_t *)bm->pixdata,
400 bm->width,
401 bm->height,
402 bm->width,
403 bm->hot_x,
404 bm->hot_y);
405
406 return 0;
407}
408
409
410/* internally exported function documented in widget.h */
411fbtk_widget_t *
412fbtk_get_root_widget(fbtk_widget_t *widget)
413{
414 while (widget->parent != NULL((void*)0))
415 widget = widget->parent;
416
417 /* check root widget was found */
418 if (widget->type != FB_WIDGET_TYPE_ROOT) {
419 NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 420, }; nslog__log(&_nslog_ctx
, "Widget with null parent that is not the root widget!"); } }
while(0)
420 "Widget with null parent that is not the root widget!")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 420, }; nslog__log(&_nslog_ctx
, "Widget with null parent that is not the root widget!"); } }
while(0)
;
421 return NULL((void*)0);
422 }
423
424 return widget;
425}
426
427
428/* exported function documented in fbtk.h */
429int
430fbtk_get_absx(fbtk_widget_t *widget)
431{
432 int x = widget->x;
433
434 while (widget->parent != NULL((void*)0)) {
435 widget = widget->parent;
436 x += widget->x;
437 }
438
439 return x;
440}
441
442
443/* exported function documented in fbtk.h */
444int
445fbtk_get_absy(fbtk_widget_t *widget)
446{
447 int y = widget->y;
448
449 while (widget->parent != NULL((void*)0)) {
450 widget = widget->parent;
451 y += widget->y;
452 }
453
454 return y;
455}
456
457
458/* exported function documented in fbtk.h */
459int
460fbtk_get_height(fbtk_widget_t *widget)
461{
462 return widget->height;
463}
464
465/* exported function documented in fbtk.h */
466int
467fbtk_get_width(fbtk_widget_t *widget)
468{
469 return widget->width;
470}
471
472/* exported function documented in fbtk.h */
473bool_Bool
474fbtk_get_bbox(fbtk_widget_t *widget, nsfb_bbox_t *bbox)
475{
476 bbox->x0 = widget->x;
477 bbox->y0 = widget->y;
478 bbox->x1 = widget->x + widget->width;
479 bbox->y1 = widget->y + widget->height;
480
481 widget = widget->parent;
482 while (widget != NULL((void*)0)) {
483 bbox->x0 += widget->x;
484 bbox->y0 += widget->y;
485 bbox->x1 += widget->x;
486 bbox->y1 += widget->y;
487 widget = widget->parent;
488 }
489
490 return true1;
491}
492
493bool_Bool
494fbtk_get_caret(fbtk_widget_t *widget, int *x, int *y, int *height)
495{
496 fbtk_widget_t *root = fbtk_get_root_widget(widget);
497
498 if (root->u.root.caret.owner == widget) {
499 *x = root->u.root.caret.x;
500 *y = root->u.root.caret.y;
501 *height = root->u.root.caret.height;
502
503 return true1;
504
505 } else {
506 *x = 0;
507 *y = 0;
508 *height = 0;
509
510 return false0;
511 }
512}
513
514/* exported function documented in fbtk.h */
515fbtk_widget_t *
516fbtk_get_widget_at(fbtk_widget_t *nwid, int x, int y)
517{
518 fbtk_widget_t *widget = NULL((void*)0); /* found widget */
519
520 /* require the root widget to start */
521 nwid = fbtk_get_root_widget(nwid);
522
523 while (nwid != NULL((void*)0)) {
524 if ((nwid->mapped) &&
525 (x >= nwid->x) &&
526 (y >= nwid->y) &&
527 (x < (nwid->x + nwid->width)) &&
528 (y < (nwid->y + nwid->height))) {
529 widget = nwid;
530 x -= nwid->x;
531 y -= nwid->y;
532 nwid = nwid->first_child;
533 } else {
534 nwid = nwid->next;
535 }
536 }
537
538 return widget;
539}
540
541
542
543
544/* internally exported function documented in widget.h */
545fbtk_widget_t *
546fbtk_widget_new(fbtk_widget_t *parent,
547 enum fbtk_widgettype_e type,
548 int x,
549 int y,
550 int width,
551 int height)
552{
553 fbtk_widget_t *neww; /* new widget */
554
555 if (parent == NULL((void*)0))
556 return NULL((void*)0);
557
558 neww = calloc(1, sizeof(fbtk_widget_t));
559 if (neww == NULL((void*)0))
560 return NULL((void*)0);
561
562 NSLOG(fbtk, DEBUG, "creating %p %d,%d %d,%d", neww, x, y, width, height)do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_fbtk
, NSLOG_LEVEL_DEBUG, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 562, }; nslog__log(&_nslog_ctx
, "creating %p %d,%d %d,%d", neww, x, y, width, height); } } while
(0)
;
563
564 /* make new window fit inside parent */
565 if (width == 0) {
566 width = parent->width - x;
567 } else if (width < 0) {
568 width = parent->width + width - x;
569 }
570 if ((width + x) > parent->width) {
571 width = parent->width - x;
572 }
573
574 if (height == 0) {
575 height = parent->height - y;
576 } else if (height < 0) {
577 height = parent->height + height - y;
578 }
579 if ((height + y) > parent->height) {
580 height = parent->height - y;
581 }
582
583 NSLOG(fbtk, DEBUG, "using %p %d,%d %d,%d", neww, x, y, width, height)do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_fbtk
, NSLOG_LEVEL_DEBUG, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 583, }; nslog__log(&_nslog_ctx
, "using %p %d,%d %d,%d", neww, x, y, width, height); } } while
(0)
;
584
585 /* set values */
586 neww->type = type;
587 neww->x = x;
588 neww->y = y;
589 neww->width = width;
590 neww->height = height;
591
592 /* insert into widget heiarchy */
593
594 neww->parent = parent;
595
596 if (parent->first_child == NULL((void*)0)) {
597 /* no child widgets yet */
598 parent->last_child = neww;
599 } else {
600 /* add new widget to front of sibling chain */
601 neww->next = parent->first_child;
602 neww->next->prev = neww;
603 }
604 parent->first_child = neww;
605
606 return neww;
607}
608
609/* exported function documented in fbtk.h */
610bool_Bool
611fbtk_get_redraw_pending(fbtk_widget_t *widget)
612{
613 fbtk_widget_t *root;
614
615 /* ensure we have the root widget */
616 root = fbtk_get_root_widget(widget);
617
618 return root->redraw.needed | root->redraw.child;
619}
620
621/** Perform a depth-first tree-walk, calling the redraw callback of the widgets in turn.
622 *
623 * This function makes no decisions of its own and simply walks the
624 * widget tree depth first calling widgets redraw callbacks if flagged
625 * to do so.
626 * The tree search is optimised with a flag to indicate wether the
627 * children of a node should be considered.
628 */
629static int
630do_redraw(nsfb_t *nsfb, fbtk_widget_t *widget)
631{
632 nsfb_bbox_t plot_ctx;
633 fbtk_widget_t *cwidget; /* child widget */
634
635 /* check if the widget requires redrawing */
636 if (widget->redraw.needed == true1) {
637 plot_ctx.x0 = fbtk_get_absx(widget) + widget->redraw.x;
638 plot_ctx.y0 = fbtk_get_absy(widget) + widget->redraw.y;
639 plot_ctx.x1 = plot_ctx.x0 + widget->redraw.width;
640 plot_ctx.y1 = plot_ctx.y0 + widget->redraw.height;
641
642 NSLOG(fbtk, DEBUG,do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_fbtk
, NSLOG_LEVEL_DEBUG, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 646, }; nslog__log(&_nslog_ctx
, "clipping %p %d,%d %d,%d", widget, plot_ctx.x0, plot_ctx.y0
, plot_ctx.x1, plot_ctx.y1); } } while(0)
643 "clipping %p %d,%d %d,%d",do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_fbtk
, NSLOG_LEVEL_DEBUG, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 646, }; nslog__log(&_nslog_ctx
, "clipping %p %d,%d %d,%d", widget, plot_ctx.x0, plot_ctx.y0
, plot_ctx.x1, plot_ctx.y1); } } while(0)
644 widget,do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_fbtk
, NSLOG_LEVEL_DEBUG, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 646, }; nslog__log(&_nslog_ctx
, "clipping %p %d,%d %d,%d", widget, plot_ctx.x0, plot_ctx.y0
, plot_ctx.x1, plot_ctx.y1); } } while(0)
645 plot_ctx.x0, plot_ctx.y0,do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_fbtk
, NSLOG_LEVEL_DEBUG, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 646, }; nslog__log(&_nslog_ctx
, "clipping %p %d,%d %d,%d", widget, plot_ctx.x0, plot_ctx.y0
, plot_ctx.x1, plot_ctx.y1); } } while(0)
646 plot_ctx.x1, plot_ctx.y1)do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_fbtk
, NSLOG_LEVEL_DEBUG, "frontends/framebuffer/fbtk/fbtk.c", sizeof
("frontends/framebuffer/fbtk/fbtk.c") - 1, __PRETTY_FUNCTION__
, sizeof(__PRETTY_FUNCTION__) - 1, 646, }; nslog__log(&_nslog_ctx
, "clipping %p %d,%d %d,%d", widget, plot_ctx.x0, plot_ctx.y0
, plot_ctx.x1, plot_ctx.y1); } } while(0)
;
647
648 if (nsfb_plot_set_clip(nsfb, &plot_ctx) == true1) {
649 fbtk_post_callback(widget, FBTK_CBT_REDRAW);
650 }
651 widget->redraw.needed = false0;
652 }
653
654 /* walk the widgets children if child flag is set */
655 if (widget->redraw.child) {
656 cwidget = widget->last_child;
657 while (cwidget != NULL((void*)0)) {
658 do_redraw(nsfb, cwidget);
659 cwidget = cwidget->prev;
660 }
661 widget->redraw.child = false0;
662 }
663
664 return 1;
665}
666
667/* exported function documented in fbtk.h */
668int
669fbtk_redraw(fbtk_widget_t *widget)
670{
671 fbtk_widget_t *root;
672
673 /* ensure we have the root widget */
674 root = fbtk_get_root_widget(widget);
675
676 return do_redraw(root->u.root.fb, root);
677}
678
679/* exported function documented in fbtk.h */
680fbtk_callback
681fbtk_get_handler(fbtk_widget_t *widget, fbtk_callback_type cbt)
682{
683 if ((cbt <= FBTK_CBT_START) || (cbt >= FBTK_CBT_END)) {
684 /* type out of range, no way to report error so return NULL */
685 return NULL((void*)0);
686 }
687
688 return widget->callback[cbt];
689}
690
691/* exported function documented in fbtk.h */
692fbtk_callback
693fbtk_set_handler(fbtk_widget_t *widget,
694 fbtk_callback_type cbt,
695 fbtk_callback cb,
696 void *context)
697{
698 fbtk_callback prevcb;
699
700 if ((cbt <= FBTK_CBT_START) || (cbt >= FBTK_CBT_END)) {
701 /* type out of range, no way to report error so return NULL */
702 return NULL((void*)0);
703 }
704
705 prevcb = widget->callback[cbt];
706
707 widget->callback[cbt] = cb;
708 widget->callback_context[cbt] = context;
709
710 return prevcb;
711}
712
713/* exported function docuemnted in fbtk.h */
714int
715fbtk_post_callback(fbtk_widget_t *widget, fbtk_callback_type cbt, ...)
716{
717 fbtk_callback_info cbi;
718 int ret = 0;
719 va_list ap;
720
721 if (widget == NULL((void*)0))
722 return -1;
723 /* if the widget is not mapped do not attempt to post any
724 * events to it
725 */
726 if (widget->mapped == false0)
727 return ret;
728
729 if (widget->callback[cbt] != NULL((void*)0)) {
730 cbi.type = cbt;
731 cbi.context = widget->callback_context[cbt];
732
733 va_start(ap, cbt)__builtin_va_start(ap, cbt);
734
735 switch (cbt) {
736 case FBTK_CBT_SCROLLX:
737 cbi.x = va_arg(ap,int)__builtin_va_arg(ap, int);
738 break;
739
740 case FBTK_CBT_SCROLLY:
741 cbi.y = va_arg(ap,int)__builtin_va_arg(ap, int);
742 break;
743
744 case FBTK_CBT_CLICK:
745 cbi.event = va_arg(ap, void *)__builtin_va_arg(ap, void *);
746 cbi.x = va_arg(ap, int)__builtin_va_arg(ap, int);
747 cbi.y = va_arg(ap, int)__builtin_va_arg(ap, int);
748 break;
749
750 case FBTK_CBT_INPUT:
751 cbi.event = va_arg(ap, void *)__builtin_va_arg(ap, void *);
752 break;
753
754 case FBTK_CBT_POINTERMOVE:
755 cbi.x = va_arg(ap, int)__builtin_va_arg(ap, int);
756 cbi.y = va_arg(ap, int)__builtin_va_arg(ap, int);
757 break;
758
759 case FBTK_CBT_REDRAW:
760 break;
761
762 case FBTK_CBT_USER:
763 break;
764
765 case FBTK_CBT_STRIP_FOCUS:
766 break;
767
768 default:
769 break;
770 }
771 va_end(ap)__builtin_va_end(ap);
772
773 ret = (widget->callback[cbt])(widget, &cbi);
774 }
775
776 return ret;
777}
778
779/* exported function docuemnted in fbtk.h */
780void
781fbtk_set_focus(fbtk_widget_t *widget)
782{
783 fbtk_widget_t *root;
784
785 /* ensure we have the root widget */
786 root = fbtk_get_root_widget(widget);
787
788 if (root->u.root.input != NULL((void*)0) &&
789 root->u.root.input != widget) {
790 /* inform previous holder of focus that it's being stripped
791 * of focus */
792 fbtk_post_callback(root->u.root.input, FBTK_CBT_STRIP_FOCUS);
793 }
794
795 root->u.root.input = widget;
796}
797
798
799
800/* exported function docuemnted in fbtk.h */
801nsfb_t *
802fbtk_get_nsfb(fbtk_widget_t *widget)
803{
804 fbtk_widget_t *root;
805
806 /* ensure we have the root widget */
807 root = fbtk_get_root_widget(widget);
808
809 return root->u.root.fb;
810}
811
812/* exported function docuemnted in fbtk.h */
813fbtk_widget_t *
814fbtk_init(nsfb_t *fb)
815{
816 fbtk_widget_t *root;
817
818 /* create and configure root widget */
819 root = calloc(1, sizeof(fbtk_widget_t));
820 if (root == NULL((void*)0))
821 return NULL((void*)0);
822
823 root->type = FB_WIDGET_TYPE_ROOT;
824 root->u.root.fb = fb;
825 root->u.root.caret.owner = NULL((void*)0);
826
827 nsfb_get_geometry(fb, &root->width, &root->height, NULL((void*)0));
828
829 root->mapped = true1;
830
831 return root;
832}
833
834/*
835 * Local Variables:
836 * c-basic-offset:8
837 * End:
838 */