[project @ 2003-02-25 21:00:27 by bursa]
Bug fixes, experimental JPEG support. svn path=/import/netsurf/; revision=100
This commit is contained in:
parent
9209f8e6cb
commit
8edb43af7d
|
@ -16,6 +16,7 @@
|
|||
<p>To subscribe, send a message to <a href="mailto:netsurf-develop-request@lists.sourceforge.net">netsurf-develop-request@lists.sourceforge.net</a> with the subject <i>subscribe password</i>, replacing <i>password</i> with an identification of your choice. (The password is only used for subsequently configuring your account; it is not secure).</p>
|
||||
</td><td width=50%>
|
||||
<h2>Test pages</h2>
|
||||
<p><a href="http://www.jpeg.org/images/public_01.jpg">Test JPEG image</a></p>
|
||||
<p><a href="http://www.alanwood.net/unicode/latin_extended_a.html">Test for Unicode support</a></p>
|
||||
<p> </p>
|
||||
<h2>Known bugs</h2>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* $Id: content.c,v 1.1 2003/02/09 12:58:14 bursa Exp $
|
||||
* $Id: content.c,v 1.2 2003/02/25 21:00:27 bursa Exp $
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -8,6 +8,7 @@
|
|||
#include "netsurf/content/content.h"
|
||||
#include "netsurf/render/html.h"
|
||||
#include "netsurf/render/textplain.h"
|
||||
#include "netsurf/riscos/jpeg.h"
|
||||
#include "netsurf/utils/utils.h"
|
||||
|
||||
|
||||
|
@ -17,6 +18,7 @@ struct mime_entry {
|
|||
content_type type;
|
||||
};
|
||||
static const struct mime_entry mime_map[] = {
|
||||
{"image/jpeg", CONTENT_JPEG},
|
||||
/* {"image/png", CONTENT_PNG},
|
||||
{"text/css", CONTENT_CSS},*/
|
||||
{"text/html", CONTENT_HTML},
|
||||
|
@ -37,6 +39,7 @@ static const struct handler_entry handler_map[] = {
|
|||
{html_create, html_process_data, html_convert, html_revive, html_reformat, html_destroy},
|
||||
{textplain_create, textplain_process_data, textplain_convert,
|
||||
textplain_revive, textplain_reformat, textplain_destroy},
|
||||
{jpeg_create, jpeg_process_data, jpeg_convert, jpeg_revive, jpeg_destroy},
|
||||
/* {css_create, css_process_data, css_convert, css_revive, css_destroy},
|
||||
{png_create, png_process_data, png_convert, png_revive, png_destroy},*/
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* $Id: content.h,v 1.1 2003/02/09 12:58:14 bursa Exp $
|
||||
* $Id: content.h,v 1.2 2003/02/25 21:00:27 bursa Exp $
|
||||
*/
|
||||
|
||||
#ifndef _NETSURF_DESKTOP_CONTENT_H_
|
||||
|
@ -26,7 +26,7 @@
|
|||
* the content may be removed from the memory cache.
|
||||
*/
|
||||
|
||||
typedef enum {CONTENT_HTML, CONTENT_TEXTPLAIN, CONTENT_CSS,
|
||||
typedef enum {CONTENT_HTML, CONTENT_TEXTPLAIN, CONTENT_JPEG, CONTENT_CSS,
|
||||
CONTENT_PNG, CONTENT_OTHER} content_type;
|
||||
|
||||
struct box_position
|
||||
|
@ -44,6 +44,7 @@ struct content
|
|||
char *url;
|
||||
content_type type;
|
||||
enum {CONTENT_LOADING, CONTENT_READY} status;
|
||||
unsigned long width, height;
|
||||
|
||||
union
|
||||
{
|
||||
|
@ -72,9 +73,9 @@ struct content
|
|||
|
||||
struct
|
||||
{
|
||||
unsigned long width, height;
|
||||
char * sprite;
|
||||
} image;
|
||||
char * data;
|
||||
unsigned long length;
|
||||
} jpeg;
|
||||
|
||||
} data;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* $Id: fetch.c,v 1.1 2003/02/09 12:58:14 bursa Exp $
|
||||
* $Id: fetch.c,v 1.2 2003/02/25 21:00:27 bursa Exp $
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -9,11 +9,6 @@
|
|||
#include "netsurf/utils/utils.h"
|
||||
#include "netsurf/utils/log.h"
|
||||
|
||||
#ifndef TEST
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
struct fetch
|
||||
{
|
||||
time_t start_time;
|
||||
|
@ -94,6 +89,8 @@ struct fetch * fetch_start(char *url, char *referer,
|
|||
/* create the curl easy handle */
|
||||
fetch->curl_handle = curl_easy_init();
|
||||
assert(fetch->curl_handle != 0); /* TODO: handle curl errors */
|
||||
code = curl_easy_setopt(fetch->curl_handle, CURLOPT_VERBOSE, 1);
|
||||
assert(code == CURLE_OK);
|
||||
code = curl_easy_setopt(fetch->curl_handle, CURLOPT_URL, fetch->url);
|
||||
assert(code == CURLE_OK);
|
||||
code = curl_easy_setopt(fetch->curl_handle, CURLOPT_PRIVATE, fetch);
|
||||
|
@ -211,7 +208,7 @@ size_t fetch_curl_data(void * data, size_t size, size_t nmemb, struct fetch *f)
|
|||
{
|
||||
f->in_callback = 1;
|
||||
|
||||
LOG(("fetch %p, size %lu", f, size * nmemb));
|
||||
LOG(("fetch %p, size %u", f, size * nmemb));
|
||||
|
||||
if (!f->had_headers) {
|
||||
/* find the content type and inform the caller */
|
||||
|
@ -248,6 +245,8 @@ size_t fetch_curl_data(void * data, size_t size, size_t nmemb, struct fetch *f)
|
|||
*/
|
||||
|
||||
#ifdef TEST
|
||||
#include <unistd.h>
|
||||
|
||||
struct test {char *url; struct fetch *f;};
|
||||
|
||||
void callback(fetch_msg msg, struct test *t, char *data, unsigned long size)
|
||||
|
@ -273,8 +272,11 @@ void callback(fetch_msg msg, struct test *t, char *data, unsigned long size)
|
|||
}
|
||||
|
||||
struct test test[] = {
|
||||
{"http://127.0.0.1/", 0},
|
||||
{"http://netsurf.strcprstskrzkrk.co.uk/", 0},
|
||||
{"http://www.oxfordstudent.com/", 0},
|
||||
{"http://www.google.co.uk/", 0},
|
||||
{"http://news.bbc.co.uk/", 0},
|
||||
{"http://doesnt.exist/", 0},
|
||||
{"blah://blah", 0},
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* $Id: fetchcache.c,v 1.1 2003/02/09 12:58:14 bursa Exp $
|
||||
* $Id: fetchcache.c,v 1.2 2003/02/25 21:00:27 bursa Exp $
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -59,9 +59,15 @@ void fetchcache_free(struct fetchcache *fc)
|
|||
void fetchcache_callback(fetch_msg msg, struct fetchcache *fc, char *data, unsigned long size)
|
||||
{
|
||||
content_type type;
|
||||
char *mime_type;
|
||||
char *semic;
|
||||
switch (msg) {
|
||||
case FETCH_TYPE:
|
||||
type = content_lookup(data);
|
||||
mime_type = strdup(data);
|
||||
if ((semic = strchr(mime_type, ';')) != 0)
|
||||
*semic = 0; /* remove "; charset=..." */
|
||||
type = content_lookup(mime_type);
|
||||
free(mime_type);
|
||||
LOG(("FETCH_TYPE, type %u", type));
|
||||
if (type == CONTENT_OTHER) {
|
||||
fetch_abort(fc->f);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* $Id: browser.c,v 1.25 2003/02/09 19:33:32 bursa Exp $
|
||||
* $Id: browser.c,v 1.26 2003/02/25 21:00:27 bursa Exp $
|
||||
*/
|
||||
|
||||
#include "netsurf/content/cache.h"
|
||||
|
@ -67,7 +67,7 @@ void browser_window_reformat(struct browser_window* bw)
|
|||
gui_window_set_title(bw->window, bw->current_content->title);
|
||||
time1 = clock();
|
||||
LOG(("Setting extent"));
|
||||
gui_window_set_extent(bw->window, bw->current_content->data.html.layout->children->width, bw->current_content->data.html.layout->children->height);
|
||||
gui_window_set_extent(bw->window, bw->current_content->width, bw->current_content->height);
|
||||
LOG(("Setting scroll"));
|
||||
gui_window_set_scroll(bw->window, 0, 0);
|
||||
LOG(("Redraw window"));
|
||||
|
@ -267,7 +267,7 @@ void browser_window_callback(fetchcache_msg msg, struct content *c,
|
|||
gui_window_message(bw->window, &gmsg);
|
||||
|
||||
previous_safety = gui_window_set_redraw_safety(bw->window, UNSAFE);
|
||||
if (bw->current_content != NULL)
|
||||
if (bw->current_content != NULL && bw->current_content->type == CONTENT_HTML)
|
||||
{
|
||||
int gc;
|
||||
for (gc = 0; gc < bw->current_content->data.html.elements.numGadgets; gc++)
|
||||
|
@ -344,6 +344,7 @@ void gui_redraw_gadget2(struct browser_window* bw, struct box* box, struct gui_g
|
|||
|
||||
void gui_redraw_gadget(struct browser_window* bw, struct gui_gadget* g)
|
||||
{
|
||||
assert(bw->current_content->type == CONTENT_HTML);
|
||||
gui_redraw_gadget2(bw, bw->current_content->data.html.layout->children, g, 0, 0);
|
||||
}
|
||||
|
||||
|
@ -377,6 +378,7 @@ int browser_window_gadget_click(struct browser_window* bw, int click_x, int clic
|
|||
click_boxes = NULL;
|
||||
plot_index = 0;
|
||||
|
||||
assert(bw->current_content->type == CONTENT_HTML);
|
||||
box_under_area(bw->current_content->data.html.layout->children,
|
||||
click_x, click_y, 0, 0, &click_boxes, &found, &plot_index);
|
||||
|
||||
|
@ -501,6 +503,7 @@ void browser_window_follow_link(struct browser_window* bw,
|
|||
click_boxes = NULL;
|
||||
plot_index = 0;
|
||||
|
||||
assert(bw->current_content->type == CONTENT_HTML);
|
||||
box_under_area(bw->current_content->data.html.layout->children,
|
||||
click_x, click_y, 0, 0, &click_boxes, &found, &plot_index);
|
||||
|
||||
|
@ -557,6 +560,7 @@ void browser_window_text_selection(struct browser_window* bw,
|
|||
click_boxes = NULL;
|
||||
plot_index = 0;
|
||||
|
||||
assert(bw->current_content->type == CONTENT_HTML);
|
||||
box_under_area(bw->current_content->data.html.layout->children,
|
||||
click_x, click_y, 0, 0, &click_boxes, &found, &plot_index);
|
||||
|
||||
|
@ -700,6 +704,7 @@ void browser_window_clear_text_selection(struct browser_window* bw)
|
|||
struct box_position* old_start;
|
||||
struct box_position* old_end;
|
||||
|
||||
assert(bw->current_content->type == CONTENT_HTML);
|
||||
old_start = &(bw->current_content->data.html.text_selection.start);
|
||||
old_end = &(bw->current_content->data.html.text_selection.end);
|
||||
|
||||
|
@ -718,6 +723,7 @@ void browser_window_change_text_selection(struct browser_window* bw,
|
|||
struct box_position start;
|
||||
struct box_position end;
|
||||
|
||||
assert(bw->current_content->type == CONTENT_HTML);
|
||||
memcpy(&start, &(bw->current_content->data.html.text_selection.start), sizeof(struct box_position));
|
||||
memcpy(&end, &(bw->current_content->data.html.text_selection.end), sizeof(struct box_position));
|
||||
|
||||
|
@ -827,6 +833,7 @@ void browser_window_redraw_boxes(struct browser_window* bw, struct box_position*
|
|||
{
|
||||
int plot = 0;
|
||||
|
||||
assert(bw->current_content->type == CONTENT_HTML);
|
||||
if (box_position_eq(start, end))
|
||||
return;
|
||||
|
||||
|
|
|
@ -84,8 +84,12 @@ ________________________________________________________________________________
|
|||
|
||||
Libraries
|
||||
|
||||
Get these compiled for RISC OS with headers from
|
||||
http://netsurf.strcprstskrzkrk.co.uk/developer/
|
||||
|
||||
libxml (XML and HTML parser) http://xmlsoft.org/
|
||||
libcurl (HTTP, FTP, etc) http://curl.haxx.se/libcurl/
|
||||
OSLib (C interface to RISC OS SWIs) http://ro-oslib.sourceforge.net/
|
||||
libutf-8 http://www.whizkidtech.redprince.net/i18n/
|
||||
|
||||
________________________________________________________________________________
|
||||
|
|
5
makefile
5
makefile
|
@ -1,4 +1,4 @@
|
|||
# $Id: makefile,v 1.13 2003/02/09 12:58:14 bursa Exp $
|
||||
# $Id: makefile,v 1.14 2003/02/25 21:00:27 bursa Exp $
|
||||
|
||||
all: !NetSurf/!RunImage,ff8
|
||||
clean:
|
||||
|
@ -22,7 +22,8 @@ OBJECTS = \
|
|||
render/arm-riscos-aof/box.o render/arm-riscos-aof/css.o \
|
||||
render/arm-riscos-aof/css_enum.o render/arm-riscos-aof/html.o \
|
||||
render/arm-riscos-aof/layout.o render/arm-riscos-aof/textplain.o \
|
||||
riscos/arm-riscos-aof/font.o riscos/arm-riscos-aof/gui.o riscos/arm-riscos-aof/theme.o \
|
||||
riscos/arm-riscos-aof/font.o riscos/arm-riscos-aof/gui.o \
|
||||
riscos/arm-riscos-aof/theme.o riscos/arm-riscos-aof/jpeg.o \
|
||||
utils/arm-riscos-aof/utils.o
|
||||
HEADERS = \
|
||||
content/cache.h content/content.h content/fetch.h content/fetchcache.h \
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* $Id: html.c,v 1.1 2003/02/09 12:58:15 bursa Exp $
|
||||
* $Id: html.c,v 1.2 2003/02/25 21:00:27 bursa Exp $
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -97,6 +97,9 @@ int html_convert(struct content *c, unsigned int width, unsigned int height)
|
|||
layout_document(c->data.html.layout->children, width);
|
||||
box_dump(c->data.html.layout->children, 0);
|
||||
|
||||
c->width = c->data.html.layout->children->width;
|
||||
c->height = c->data.html.layout->children->height;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -131,12 +134,16 @@ void html_revive(struct content *c, unsigned int width, unsigned int height)
|
|||
{
|
||||
/* TODO: reload stylesheets and images and fix any pointers to them */
|
||||
layout_document(c->data.html.layout->children, width);
|
||||
c->width = c->data.html.layout->children->width;
|
||||
c->height = c->data.html.layout->children->height;
|
||||
}
|
||||
|
||||
|
||||
void html_reformat(struct content *c, unsigned int width, unsigned int height)
|
||||
{
|
||||
layout_document(c->data.html.layout->children, width);
|
||||
c->width = c->data.html.layout->children->width;
|
||||
c->height = c->data.html.layout->children->height;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* $Id: textplain.c,v 1.1 2003/02/09 12:58:15 bursa Exp $
|
||||
* $Id: textplain.c,v 1.2 2003/02/25 21:00:27 bursa Exp $
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -30,23 +30,24 @@ void textplain_process_data(struct content *c, char *data, unsigned long size)
|
|||
int textplain_convert(struct content *c, unsigned int width, unsigned int height)
|
||||
{
|
||||
htmlParseChunk(c->data.html.parser, footer, sizeof(footer), 0);
|
||||
c->type = CONTENT_HTML;
|
||||
return html_convert(c, width, height);
|
||||
}
|
||||
|
||||
|
||||
void textplain_revive(struct content *c, unsigned int width, unsigned int height)
|
||||
{
|
||||
html_revive(c, width, height);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
|
||||
void textplain_reformat(struct content *c, unsigned int width, unsigned int height)
|
||||
{
|
||||
html_reformat(c, width, height);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
|
||||
void textplain_destroy(struct content *c)
|
||||
{
|
||||
html_destroy(c);
|
||||
assert(0);
|
||||
}
|
||||
|
|
53
riscos/gui.c
53
riscos/gui.c
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* $Id: gui.c,v 1.17 2003/02/09 12:58:15 bursa Exp $
|
||||
* $Id: gui.c,v 1.18 2003/02/25 21:00:27 bursa Exp $
|
||||
*/
|
||||
|
||||
#include "netsurf/riscos/font.h"
|
||||
|
@ -10,8 +10,10 @@
|
|||
#include "oslib/os.h"
|
||||
#include "oslib/wimp.h"
|
||||
#include "oslib/colourtrans.h"
|
||||
#include "oslib/jpeg.h"
|
||||
#include "netsurf/riscos/theme.h"
|
||||
#include "netsurf/utils/log.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
@ -772,36 +774,45 @@ void ro_gui_toolbar_redraw(gui_window* g, wimp_draw* redraw)
|
|||
void ro_gui_window_redraw(gui_window* g, wimp_draw* redraw)
|
||||
{
|
||||
osbool more;
|
||||
struct content *c = g->data.browser.bw->current_content;
|
||||
|
||||
if (g->redraw_safety == SAFE && g->type == GUI_BROWSER_WINDOW)
|
||||
if (g->redraw_safety == SAFE && g->type == GUI_BROWSER_WINDOW && c != NULL)
|
||||
{
|
||||
if (g->data.browser.bw->current_content != NULL)
|
||||
more = wimp_redraw_window(redraw);
|
||||
wimp_set_font_colours(wimp_COLOUR_WHITE, wimp_COLOUR_BLACK);
|
||||
|
||||
select_on = 0;
|
||||
|
||||
while (more)
|
||||
{
|
||||
if (g->data.browser.bw->current_content->data.html.layout != NULL)
|
||||
switch (c->type)
|
||||
{
|
||||
more = wimp_redraw_window(redraw);
|
||||
wimp_set_font_colours(wimp_COLOUR_WHITE, wimp_COLOUR_BLACK);
|
||||
|
||||
select_on = 0;
|
||||
|
||||
while (more)
|
||||
{
|
||||
gadget_subtract_x = redraw->box.x0 - redraw->xscroll;
|
||||
gadget_subtract_y = redraw->box.y1 - redraw->yscroll;
|
||||
case CONTENT_HTML:
|
||||
gadget_subtract_x = redraw->box.x0 - redraw->xscroll;
|
||||
gadget_subtract_y = redraw->box.y1 - redraw->yscroll;
|
||||
assert(c->data.html.layout != NULL);
|
||||
ro_gui_window_redraw_box(g,
|
||||
g->data.browser.bw->current_content->data.html.layout->children,
|
||||
c->data.html.layout->children,
|
||||
redraw->box.x0 - redraw->xscroll, redraw->box.y1 - redraw->yscroll,
|
||||
&redraw->clip, 0xffffff);
|
||||
more = wimp_get_rectangle(redraw);
|
||||
}
|
||||
return;
|
||||
break;
|
||||
|
||||
case CONTENT_JPEG:
|
||||
xjpeg_plot_scaled(c->data.jpeg.data,
|
||||
redraw->box.x0 - redraw->xscroll,
|
||||
redraw->box.y1 - redraw->yscroll - c->height * 2,
|
||||
0, c->data.jpeg.length, 0);
|
||||
break;
|
||||
}
|
||||
more = wimp_get_rectangle(redraw);
|
||||
}
|
||||
}
|
||||
|
||||
more = wimp_redraw_window(redraw);
|
||||
while (more)
|
||||
more = wimp_get_rectangle(redraw);
|
||||
else
|
||||
{
|
||||
more = wimp_redraw_window(redraw);
|
||||
while (more)
|
||||
more = wimp_get_rectangle(redraw);
|
||||
}
|
||||
}
|
||||
|
||||
void gui_window_set_scroll(gui_window* g, int sx, int sy)
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* $Id: jpeg.c,v 1.1 2003/02/25 21:00:27 bursa Exp $
|
||||
*
|
||||
* This is just a temporary implementation using the JPEG renderer
|
||||
* available in some versions of RISC OS.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "netsurf/content/content.h"
|
||||
#include "netsurf/riscos/jpeg.h"
|
||||
#include "netsurf/utils/utils.h"
|
||||
#include "oslib/jpeg.h"
|
||||
|
||||
|
||||
void jpeg_create(struct content *c)
|
||||
{
|
||||
c->data.jpeg.data = xcalloc(0, 1);
|
||||
c->data.jpeg.length = 0;
|
||||
}
|
||||
|
||||
|
||||
void jpeg_process_data(struct content *c, char *data, unsigned long size)
|
||||
{
|
||||
c->data.jpeg.data = xrealloc(c->data.jpeg.data, c->data.jpeg.length + size);
|
||||
memcpy(c->data.jpeg.data + c->data.jpeg.length, data, size);
|
||||
c->data.jpeg.length += size;
|
||||
}
|
||||
|
||||
|
||||
int jpeg_convert(struct content *c, unsigned int width, unsigned int height)
|
||||
{
|
||||
os_error *error;
|
||||
int w, h;
|
||||
error = xjpeginfo_dimensions(c->data.jpeg.data, (int) c->data.jpeg.length,
|
||||
0, &w, &h, 0, 0, 0);
|
||||
if (error != 0)
|
||||
return 1;
|
||||
c->width = w;
|
||||
c->height = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void jpeg_revive(struct content *c, unsigned int width, unsigned int height)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void jpeg_reformat(struct content *c, unsigned int width, unsigned int height)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void jpeg_destroy(struct content *c)
|
||||
{
|
||||
xfree(c->data.jpeg.data);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* $Id: jpeg.h,v 1.1 2003/02/25 21:00:27 bursa Exp $
|
||||
*/
|
||||
|
||||
#ifndef _NETSURF_RISCOS_JPEG_H_
|
||||
#define _NETSURF_RISCOS_JPEG_H_
|
||||
|
||||
#include "netsurf/content/content.h"
|
||||
|
||||
void jpeg_create(struct content *c);
|
||||
void jpeg_process_data(struct content *c, char *data, unsigned long size);
|
||||
int jpeg_convert(struct content *c, unsigned int width, unsigned int height);
|
||||
void jpeg_revive(struct content *c, unsigned int width, unsigned int height);
|
||||
void jpeg_reformat(struct content *c, unsigned int width, unsigned int height);
|
||||
void jpeg_destroy(struct content *c);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue