NetSurf
local_history.c
Go to the documentation of this file.
1/*
2 * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/**
20 * \file
21 * Local history viewer implementation
22 */
23
24#include <stdlib.h>
25#include <string.h>
26
27#include "utils/nsurl.h"
28#include "utils/errors.h"
29
30#include "netsurf/types.h"
31#include "netsurf/layout.h"
33#include "netsurf/core_window.h"
34#include "netsurf/plotters.h"
35#include "netsurf/keypress.h"
36
37#include "utils/nscolour.h"
38
39#include "desktop/cw_helper.h"
46
47/**
48 * local history viewer context
49 */
54};
55
56
57/**
58 * plot style for drawing lines between nodes
59 */
62 .stroke_width = plot_style_int_to_fixed(2),
63};
64
65
66/**
67 * plot style for drawing background
68 */
71};
72
73
74/**
75 * plot style for drawing rectangle round unselected nodes
76 */
79 .stroke_width = plot_style_int_to_fixed(1),
80};
81
82
83/**
84 * plot style for drawing rectangle round selected nodes
85 */
88 .stroke_width = plot_style_int_to_fixed(3),
89};
90
91
92/**
93 * plot style for drawing rectangle round the cursor node
94 */
97 .stroke_width = plot_style_int_to_fixed(3),
98};
99
100
101/**
102 * plot style for font on unselected nodes
103 */
106 .size = 8 * PLOT_STYLE_SCALE,
107 .weight = 400,
108 .flags = FONTF_NONE,
109};
110
111
112/**
113 * plot style for font on unselected nodes
114 */
117 .size = 8 * PLOT_STYLE_SCALE,
118 .weight = 900,
119 .flags = FONTF_NONE,
120};
121
122
123/**
124 * Recursively redraw a history entry.
125 *
126 * \param history history containing the entry
127 * \param entry entry to render
128 * \param clip redraw area
129 * \param x window x offset
130 * \param y window y offset
131 * \param ctx current redraw context
132 */
133static nserror
135 struct history_entry *entry,
136 struct history_entry *cursor,
137 struct rect *clip,
138 int x, int y,
139 const struct redraw_context *ctx)
140{
141 size_t char_offset;
142 int actual_x;
143 struct history_entry *child;
144 int tailsize = 5;
145
146 plot_style_t *pstyle;
147 plot_font_style_t *pfstyle;
148 struct rect rect;
149 nserror res;
150
151 /* setup plot styles */
152 if (entry == history->current) {
153 pstyle = &pstyle_rect_sel;
154 pfstyle = &pfstyle_node_sel;
155 } else {
156 pstyle = &pstyle_rect;
157 pfstyle = &pfstyle_node;
158 }
159
160 /* Only attempt to plot bitmap if it is present */
161 if (entry->page.bitmap != NULL) {
162 res = ctx->plot->bitmap(ctx,
163 entry->page.bitmap,
164 entry->x + x,
165 entry->y + y,
168 0xffffff,
169 0);
170 if (res != NSERROR_OK) {
171 return res;
172 }
173 }
174
175 rect.x0 = entry->x - 1 + x;
176 rect.y0 = entry->y - 1 + y;
177 rect.x1 = entry->x + x + LOCAL_HISTORY_WIDTH;
178 rect.y1 = entry->y + y + LOCAL_HISTORY_HEIGHT;
179
180 /* Border */
181 if (entry != cursor) {
182 /* Not cursor position */
183 res = ctx->plot->rectangle(ctx, pstyle, &rect);
184 if (res != NSERROR_OK) {
185 return res;
186 }
187 } else {
188 /* Cursor position */
189 rect.x0 -= 1;
190 rect.y0 -= 1;
191 rect.x1 += 1;
192 rect.y1 += 1;
193 ctx->plot->rectangle(ctx, &pstyle_rect_cursor, &rect);
194 }
195
197 strlen(entry->page.title), LOCAL_HISTORY_WIDTH,
198 &char_offset, &actual_x);
199 if (res != NSERROR_OK) {
200 return res;
201 }
202
203 res = ctx->plot->text(ctx,
204 pfstyle,
205 entry->x + x,
206 entry->y + LOCAL_HISTORY_HEIGHT + 12 + y,
207 entry->page.title,
208 char_offset);
209 if (res != NSERROR_OK) {
210 return res;
211 }
212
213 /* for each child node draw a line and recurse redraw into it */
214 for (child = entry->forward; child; child = child->next) {
215 rect.x0 = entry->x + LOCAL_HISTORY_WIDTH + x;
216 rect.y0 = entry->y + LOCAL_HISTORY_HEIGHT / 2 + y;
217 rect.x1 = entry->x + LOCAL_HISTORY_WIDTH + tailsize + x;
218 rect.y1 = entry->y + LOCAL_HISTORY_HEIGHT / 2 + y;
219 res = ctx->plot->line(ctx, &pstyle_line, &rect);
220 if (res != NSERROR_OK) {
221 return res;
222 }
223
224 rect.x0 = entry->x + LOCAL_HISTORY_WIDTH + tailsize + x;
225 rect.y0 = entry->y + LOCAL_HISTORY_HEIGHT / 2 + y;
226 rect.x1 = child->x - tailsize + x;
227 rect.y1 = child->y + LOCAL_HISTORY_HEIGHT / 2 + y;
228 res = ctx->plot->line(ctx, &pstyle_line, &rect);
229 if (res != NSERROR_OK) {
230 return res;
231 }
232
233 rect.x0 = child->x - tailsize + x;
234 rect.y0 = child->y + LOCAL_HISTORY_HEIGHT / 2 + y;
235 rect.x1 = child->x + x;
236 rect.y1 = child->y + LOCAL_HISTORY_HEIGHT / 2 + y;
237 res = ctx->plot->line(ctx, &pstyle_line, &rect);
238 if (res != NSERROR_OK) {
239 return res;
240 }
241
242 res = redraw_entry(history, child, cursor, clip, x, y, ctx);
243 if (res != NSERROR_OK) {
244 return res;
245 }
246 }
247
248 return NSERROR_OK;
249}
250
251
252/**
253 * Find the history entry at a position.
254 *
255 * \param entry entry to search from
256 * \param x coordinate
257 * \param y coordinate
258 * \return an entry if found, 0 if none
259 */
260static struct history_entry *
261find_entry_position(struct history_entry *entry, int x, int y)
262{
263 struct history_entry *child;
264 struct history_entry *found;
265
266 if (!entry) {
267 return NULL;
268 }
269
270 if ((entry->x <= x) &&
271 (x <= entry->x + LOCAL_HISTORY_WIDTH) &&
272 (entry->y <= y) &&
273 (y <= entry->y + LOCAL_HISTORY_HEIGHT)) {
274 return entry;
275 }
276
277 for (child = entry->forward; child; child = child->next) {
278 found = find_entry_position(child, x, y);
279 if (found) {
280 return found;
281 }
282 }
283
284 return NULL;
285}
286
287/* exported interface documented in desktop/local_history.h */
290{
291 rect cursor;
292
293 if (session->cursor == NULL) {
294 return NSERROR_OK;
295 }
296
297 cursor.x0 = session->cursor->x - LOCAL_HISTORY_RIGHT_MARGIN / 2;
298 cursor.y0 = session->cursor->y - LOCAL_HISTORY_BOTTOM_MARGIN / 2;
299 cursor.x1 = cursor.x0 + LOCAL_HISTORY_WIDTH +
301 cursor.y1 = cursor.y0 + LOCAL_HISTORY_HEIGHT +
303
304 return cw_helper_scroll_visible(session->core_window_handle, &cursor);
305}
306
307/* exported interface documented in desktop/local_history.h */
309local_history_init(void *core_window_handle,
310 struct browser_window *bw,
311 struct local_history_session **session)
312{
313 struct local_history_session *nses;
314
317
321
326
327 nses = calloc(1, sizeof(struct local_history_session));
328 if (nses == NULL) {
329 return NSERROR_NOMEM;
330 }
331
333
334 local_history_set(nses, bw);
335
336 *session = nses;
337
338 return NSERROR_OK;
339}
340
341/* exported interface documented in desktop/local_history.h */
343{
344 free(session);
345
346 return NSERROR_OK;
347}
348
349
350/* exported interface documented in desktop/local_history.h */
353 int x,
354 int y,
355 struct rect *clip,
356 const struct redraw_context *ctx)
357{
358 struct rect r = {
359 .x0 = clip->x0 + x,
360 .y0 = clip->y0 + y,
361 .x1 = clip->x1 + x,
362 .y1 = clip->y1 + y,
363 };
364
365 if (session->bw == NULL) {
366 return NSERROR_OK;
367 }
368
369 if (session->bw->history->start == NULL) {
370 return NSERROR_OK;
371 }
372
373 ctx->plot->clip(ctx, &r);
374 ctx->plot->rectangle(ctx, &pstyle_bg, &r);
375
376 return redraw_entry(
377 session->bw->history,
378 session->bw->history->start,
379 session->cursor,
380 clip,
381 x, y,
382 ctx);
383}
384
385/* exported interface documented in desktop/local_history.h */
388 enum browser_mouse_state mouse,
389 int x,
390 int y)
391{
392 struct history_entry *entry;
393 bool new_window;
394
395 if (session->bw == NULL) {
397 }
398
399 if ((mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2)) == 0) {
401 }
402
403 entry = find_entry_position(session->bw->history->start, x, y);
404 if (entry == NULL) {
405 return NSERROR_NOT_FOUND;
406 }
407
408 if (entry == session->bw->history->current) {
409 return NSERROR_PERMISSION;
410 }
411
412 if (mouse & BROWSER_MOUSE_PRESS_1) {
413 new_window = false;
414 } else if (mouse & BROWSER_MOUSE_PRESS_2) {
415 new_window = true;
416 } else {
417 new_window = false;
418 }
419
420 browser_window_history_go(session->bw, entry, new_window);
421
422 return NSERROR_OK;
423}
424
425/**
426 * Determine the point on the parent line where this history line branches.
427 *
428 * If `branch_point` gets set then there is a guarantee that (a) `ent` is
429 * a transitive child (forward) of that point. and (b) `branch_point` has a
430 * parent.
431 *
432 * \param[in] ent The entry to work backward from
433 * \param[out] branch_point The entry to set to the branch point if one is found
434 */
435static void
437 struct history_entry **branch_point)
438{
439 if (ent->back == NULL) {
440 /* We're at the root, nothing to do */
441 return;
442 }
443 /* Start from our immediate parent */
444 ent = ent->back;
445 while (ent->back != NULL) {
446 if (ent->back->forward != ent->back->forward_last) {
447 /* This point is a branch */
448 *branch_point = ent;
449 break;
450 }
451 ent = ent->back;
452 }
453}
454
455/* exported interface documented in desktop/local_history.h */
456bool
457local_history_keypress(struct local_history_session *session, uint32_t key)
458{
459 switch (key) {
460 case NS_KEY_NL:
461 case NS_KEY_CR:
462 /* pressed enter */
463 if (session->cursor != session->bw->history->current) {
464 browser_window_history_go(session->bw, session->cursor,
465 false);
468 }
469 /* We have handled this keypress */
470 return true;
471 case NS_KEY_LEFT:
472 /* Go to parent */
473 if (session->cursor->back != NULL) {
474 session->cursor = session->cursor->back;
477 }
478 /* We have handled this keypress */
479 return true;
480 case NS_KEY_RIGHT:
481 /* Go to preferred child if there is one */
482 if (session->cursor->forward_pref != NULL) {
483 session->cursor = session->cursor->forward_pref;
486 }
487 /* We have handled this keypress */
488 return true;
489 case NS_KEY_DOWN:
490 /* Go to next sibling down, if there is one */
491 if (session->cursor->next != NULL) {
492 session->cursor = session->cursor->next;
493 } else {
494 struct history_entry *branch_point = NULL;
496 session->cursor,
497 &branch_point);
498 if (branch_point != NULL) {
499 if (branch_point->next != NULL) {
500 branch_point = branch_point->next;
501 }
502 session->cursor = branch_point;
503 }
504 }
505 /* We have handled this keypress */
508 return true;
509 case NS_KEY_UP:
510 /* Go to next sibling up, if there is one */
511 if (session->cursor->back != NULL) {
512 struct history_entry *ent = session->cursor->back->forward;
513 while (ent != session->cursor &&
514 ent->next != NULL &&
515 ent->next != session->cursor) {
516 ent = ent->next;
517 }
518 if (session->cursor != ent) {
519 session->cursor = ent;
520 } else {
521 struct history_entry *branch_point = NULL;
523 session->cursor,
524 &branch_point);
525 if (branch_point != NULL) {
526 struct history_entry *ent = branch_point->back->forward;
527 while (ent->next != NULL && ent->next != branch_point) {
528 ent = ent->next;
529 }
530 session->cursor = ent;
531 }
532 }
533 }
534 /* We have handled this keypress */
537 return true;
538 }
539 return false;
540}
541
542/* exported interface documented in desktop/local_history.h */
545 struct browser_window *bw)
546{
547 session->bw = bw;
548 session->cursor = NULL;
549
550 if (bw != NULL) {
551 assert(session->bw->history != NULL);
552 session->cursor = bw->history->current;
553
555 session->bw->history->width,
556 session->bw->history->height);
558 }
559
560 return NSERROR_OK;
561}
562
563
564/* exported interface documented in desktop/local_history.h */
567 int *width,
568 int *height)
569{
570 *width = session->bw->history->width + 20;
571 *height = session->bw->history->height + 20;
572
573 return NSERROR_OK;
574}
575
576
577/* exported interface documented in desktop/local_history.h */
580 int x, int y,
581 nsurl **url_out)
582{
583 struct history_entry *entry;
584
585 if (session->bw == NULL) {
587 }
588
589 entry = find_entry_position(session->bw->history->start, x, y);
590 if (entry == NULL) {
591 return NSERROR_NOT_FOUND;
592 }
593
594 *url_out = nsurl_ref(entry->page.url);
595
596 return NSERROR_OK;
597}
nserror browser_window_history_go(struct browser_window *bw, struct history_entry *entry, bool new_window)
Navigate to specified history entry, optionally in new window.
Interface to browser history operations.
Browser window private structure.
Browser window creation and manipulation interface.
Interface to core window handling.
nserror cw_helper_scroll_visible(struct core_window *cw_h, const struct rect *r)
Scroll a core window to make the given rectangle visible.
Definition: cw_helper.c:35
Helpers to simplify core use of corewindow.
static plot_font_style_t pfstyle_node
plot style for font on unselected nodes
static plot_style_t pstyle_bg
plot style for drawing background
Definition: local_history.c:69
static plot_style_t pstyle_line
plot style for drawing lines between nodes
Definition: local_history.c:60
static plot_style_t pstyle_rect
plot style for drawing rectangle round unselected nodes
Definition: local_history.c:77
nserror local_history_redraw(struct local_history_session *session, int x, int y, struct rect *clip, const struct redraw_context *ctx)
Redraw the local history.
nserror local_history_scroll_to_cursor(struct local_history_session *session)
Scroll the local history window to ensure the current cursor is shown.
static plot_font_style_t pfstyle_node_sel
plot style for font on unselected nodes
nserror local_history_get_size(struct local_history_session *session, int *width, int *height)
get size of local history content area.
nserror local_history_set(struct local_history_session *session, struct browser_window *bw)
Change the browser window to draw local history for.
static void _local_history_find_branch_point(struct history_entry *ent, struct history_entry **branch_point)
Determine the point on the parent line where this history line branches.
nserror local_history_fini(struct local_history_session *session)
Finalise the local history.
bool local_history_keypress(struct local_history_session *session, uint32_t key)
Key press handling.
static plot_style_t pstyle_rect_sel
plot style for drawing rectangle round selected nodes
Definition: local_history.c:86
static plot_style_t pstyle_rect_cursor
plot style for drawing rectangle round the cursor node
Definition: local_history.c:95
static nserror redraw_entry(struct history *history, struct history_entry *entry, struct history_entry *cursor, struct rect *clip, int x, int y, const struct redraw_context *ctx)
Recursively redraw a history entry.
static struct history_entry * find_entry_position(struct history_entry *entry, int x, int y)
Find the history entry at a position.
nserror local_history_init(void *core_window_handle, struct browser_window *bw, struct local_history_session **session)
Initialise the local history.
nserror local_history_get_url(struct local_history_session *session, int x, int y, nsurl **url_out)
get url of entry at position in local history content area.
nserror local_history_mouse_action(struct local_history_session *session, enum browser_mouse_state mouse, int x, int y)
Handles all kinds of mouse action.
Error codes.
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_PERMISSION
Permission error.
Definition: errors.h:58
@ NSERROR_NOT_FOUND
Requested item not found.
Definition: errors.h:34
@ NSERROR_NOT_IMPLEMENTED
Functionality is not implemented.
Definition: errors.h:61
@ NSERROR_BAD_PARAMETER
Bad Parameter.
Definition: errors.h:48
@ NSERROR_NOMEM
Memory exhaustion.
Definition: errors.h:32
@ NSERROR_OK
No error.
Definition: errors.h:30
struct netsurf_table * guit
The global interface table.
Definition: gui_factory.c:50
Interface to core interface table.
Interface to platform-specific layout operation table.
browser_mouse_state
Mouse state.
Definition: mouse.h:43
@ BROWSER_MOUSE_PRESS_1
button 1 pressed
Definition: mouse.h:50
@ BROWSER_MOUSE_PRESS_2
button 2 pressed
Definition: mouse.h:52
Target independent plotting interface.
Interface to key press operations.
@ NS_KEY_CR
Definition: keypress.h:40
@ NS_KEY_RIGHT
Definition: keypress.h:51
@ NS_KEY_LEFT
Definition: keypress.h:50
@ NS_KEY_DOWN
Definition: keypress.h:53
@ NS_KEY_NL
Definition: keypress.h:38
@ NS_KEY_UP
Definition: keypress.h:52
Interface to browser history private operations.
#define LOCAL_HISTORY_RIGHT_MARGIN
#define LOCAL_HISTORY_WIDTH
#define LOCAL_HISTORY_BOTTOM_MARGIN
#define LOCAL_HISTORY_HEIGHT
colour nscolours[NSCOLOUR__COUNT]
NetSurf UI colour table.
Definition: nscolour.c:38
NetSurf UI colours (interface).
@ NSCOLOUR_WIN_EVEN_FG
Definition: nscolour.h:44
@ NSCOLOUR_WIN_EVEN_BORDER
Definition: nscolour.h:49
@ NSCOLOUR_SEL_BG
Definition: nscolour.h:53
@ NSCOLOUR_WIN_EVEN_BG
Definition: nscolour.h:42
NetSurf URL handling (interface).
nsurl * nsurl_ref(nsurl *url)
Increment the reference count to a NetSurf URL object.
struct nsurl nsurl
NetSurf URL object.
Definition: nsurl.h:31
plot_font_style_t const *const plot_style_font
Definition: plot_style.c:165
#define plot_style_int_to_fixed(v)
Definition: plot_style.h:51
@ PLOT_OP_TYPE_DASH
Dashed plot.
Definition: plot_style.h:69
@ PLOT_OP_TYPE_SOLID
Solid colour.
Definition: plot_style.h:67
@ FONTF_NONE
Definition: plot_style.h:102
@ PLOT_FONT_FAMILY_SANS_SERIF
Definition: plot_style.h:89
#define PLOT_STYLE_SCALE
Scaling factor for plot styles.
Definition: plot_style.h:45
int width
Definition: gui.c:160
int height
Definition: gui.c:161
Interface to utility string handling.
Browser window data.
struct history * history
local history handle.
nserror(* set_extent)(struct core_window *cw, int width, int height)
Update the logical extent of the window.
Definition: core_window.h:81
nserror(* invalidate)(struct core_window *cw, const struct rect *rect)
Invalidate an area of a window.
Definition: core_window.h:71
nserror(* position)(const struct plot_font_style *fstyle, const char *string, size_t length, int x, size_t *char_offset, int *actual_x)
Find the position in a string where an x coordinate falls.
Definition: layout.h:63
A node in the history tree.
int x
Position of node.
struct history_entry * forward_last
Last child.
struct history_entry * back
Parent.
struct history_entry * forward
First child.
struct history_entry * next
Next sibling.
struct history_page page
struct history_entry * forward_pref
Child in direction of current entry.
int y
Position of node.
struct bitmap * bitmap
Thumbnail bitmap, or NULL.
char * title
Fragment identifier, or NULL.
struct nsurl * url
Page URL, never NULL.
History tree for a window.
int width
Width of layout.
int height
Height of layout.
struct history_entry * current
Current position in tree.
struct history_entry * start
First page in tree (page that window opened with).
local history viewer context
Definition: local_history.c:50
struct browser_window * bw
Definition: local_history.c:51
struct history_entry * cursor
Definition: local_history.c:53
struct core_window_table * corewindow
Core window table.
Definition: gui_table.h:75
struct gui_layout_table * layout
Layout table.
Definition: gui_table.h:163
Font style for plotting.
Definition: plot_style.h:111
plot_font_generic_family_t family
Generic family to plot with.
Definition: plot_style.h:118
colour foreground
Colour of text.
Definition: plot_style.h:123
colour background
Background colour to blend to, if appropriate.
Definition: plot_style.h:122
Plot style for stroke/fill plotters.
Definition: plot_style.h:76
colour fill_colour
Colour of fill.
Definition: plot_style.h:81
plot_operation_type_t fill_type
Fill plot type.
Definition: plot_style.h:80
colour stroke_colour
Colour of stroke.
Definition: plot_style.h:79
plot_operation_type_t stroke_type
Stroke plot type.
Definition: plot_style.h:77
nserror(* line)(const struct redraw_context *ctx, const plot_style_t *pstyle, const struct rect *line)
Plots a line.
Definition: plotters.h:170
nserror(* 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
nserror(* rectangle)(const struct redraw_context *ctx, const plot_style_t *pstyle, const struct rect *rectangle)
Plots a rectangle.
Definition: plotters.h:188
nserror(* clip)(const struct redraw_context *ctx, const struct rect *clip)
Sets a clip rectangle for subsequent plot operations.
Definition: plotters.h:111
nserror(* bitmap)(const struct redraw_context *ctx, struct bitmap *bitmap, int x, int y, int width, int height, colour bg, bitmap_flags_t flags)
Plot a bitmap.
Definition: plotters.h:257
Rectangle coordinates.
Definition: types.h:40
int x0
Definition: types.h:41
int y0
Top left.
Definition: types.h:41
int x1
Definition: types.h:42
int y1
Bottom right.
Definition: types.h:42
Redraw context.
Definition: plotters.h:51
const struct plotter_table * plot
Current plot operation table.
Definition: plotters.h:73
Interface to system colour values.
NetSurf types.
static nserror clip(const struct redraw_context *ctx, const struct rect *clip)
Sets a clip rectangle for subsequent plot operations.
Definition: plot.c:357